def __init__(self, **kwargs): SVGMobject.__init__(self, **kwargs) self.scale_to_fit_height(self.height) self.set_stroke(color = WHITE, width = 0) self.set_fill(self.color, opacity = 1) from topics.characters import Randolph randy = Randolph(mode = "happy") randy.scale_to_fit_height(0.6*self.get_height()) randy.stretch(0.8, 0) randy.look(RIGHT) randy.move_to(self) randy.shift(0.07*self.height*(RIGHT+UP)) self.randy = self.pi_creature = randy self.add_to_back(randy) orientation_line = Line(self.get_left(), self.get_right()) orientation_line.set_stroke(width = 0) self.add(orientation_line) self.orientation_line = orientation_line for light, color in zip(self.get_lights(), self.light_colors): light.set_fill(color, 1) light.is_subpath = False self.add_treds_to_tires()
class TransformOverIncreasingOrders(SpaceFillingCurveScene): def setup(self, CurveClass): sample = CurveClass(order = 1) self.curve = Line(3*LEFT, 3*RIGHT) self.curve.gradient_highlight( sample.start_color, sample.end_color ) self.CurveClass = CurveClass self.order = 0 def construct(self, CurveClass, max_order): self.setup(CurveClass) while self.order < max_order: self.increase_order() self.dither() def increase_order(self, *other_anims): self.order += 1 new_curve = self.CurveClass(order = self.order) self.play( Transform(self.curve, new_curve), *other_anims, run_time = 3/np.sqrt(self.order) )
def construct(self): curve = HilbertCurve(order = 6) curve.highlight(WHITE) colored_curve = curve.copy() colored_curve.thin_out(3) lion = ImageMobject("lion", invert = False) lion.replace(curve, stretch = True) sparce_lion = lion.copy() sparce_lion.thin_out(100) distance_matrix = cdist(colored_curve.points, sparce_lion.points) closest_point_indices = np.apply_along_axis( np.argmin, 1, distance_matrix ) colored_curve.rgbas = sparce_lion.rgbas[closest_point_indices] line = Line(5*LEFT, 5*RIGHT) Mobject.align_data(line, colored_curve) line.rgbas = colored_curve.rgbas self.add(lion) self.play(ShowCreation(curve, run_time = 3)) self.play( FadeOut(lion), Transform(curve, colored_curve), run_time = 3 ) self.wait() self.play(Transform(curve, line, run_time = 5)) self.wait()
def generate_points(self): self.axes = VMobject() self.main_lines = VMobject() self.secondary_lines = VMobject() tuples = [ (self.x_radius, self.x_line_frequency, self.y_radius * DOWN, self.y_radius * UP, RIGHT), ( self.y_radius, self.y_line_frequency, self.x_radius * LEFT, self.x_radius * RIGHT, UP, ), ] for radius, freq, start, end, unit in tuples: main_range = np.arange(0, radius, freq) step = freq / float(freq + self.secondary_line_ratio) for v in np.arange(0, radius, step): line1 = Line(start + v * unit, end + v * unit) line2 = Line(start - v * unit, end - v * unit) if v == 0: self.axes.add(line1) elif v in main_range: self.main_lines.add(line1, line2) else: self.secondary_lines.add(line1, line2) self.add(self.secondary_lines, self.main_lines, self.axes) self.stretch(self.space_unit_to_x_unit, 0) self.stretch(self.space_unit_to_y_unit, 1) #Put x_axis before y_axis y_axis, x_axis = self.axes.split() self.axes = VMobject(x_axis, y_axis)
def construct(self): curve = HilbertCurve(order = 6) curve.highlight(WHITE) colored_curve = curve.copy() colored_curve.thin_out(3) lion = ImageMobject("lion", invert = False) lion.replace(curve, stretch = True) sparce_lion = lion.copy() sparce_lion.thin_out(100) distance_matrix = cdist(colored_curve.points, sparce_lion.points) closest_point_indices = np.apply_along_axis( np.argmin, 1, distance_matrix ) colored_curve.rgbs = sparce_lion.rgbs[closest_point_indices] line = Line(5*LEFT, 5*RIGHT) Mobject.align_data(line, colored_curve) line.rgbs = colored_curve.rgbs self.add(lion) self.play(ShowCreation(curve, run_time = 3)) self.play( FadeOut(lion), Transform(curve, colored_curve), run_time = 3 ) self.dither() self.play(Transform(curve, line, run_time = 5)) self.dither()
def construct(self): grid = get_grid() grid.sort_points(np.linalg.norm) freq_line = get_freq_line() freq_line.sort_points(lambda p : p[0]) red, blue = Color(RED), Color(BLUE) freq_line.gradient_highlight(red, blue) colors = [ Color(rgb = interpolate( np.array(red.rgb), np.array(blue.rgb), alpha )) for alpha in np.arange(4)/3. ] string = Line(3*LEFT, 3*RIGHT, color = colors[1]) vibration = Vibrate(string) vibration_copy = vibration.copy() vibration_copy.mobject.stroke_width = 1 sub_vibrations = [ Vibrate( string.copy().shift((n-1)*UP).highlight(colors[n]), overtones = 1, spatial_period = 6./(n+1), temporal_period = 1./(n+1), amplitude = 0.5/(n+1) ) for n in range(4) ] words = TexMobject("&\\vdots \\\\ \\text{thousands }& \\text{of frequencies} \\\\ &\\vdots") words.to_edge(UP, buff = 0.1) self.add(grid) self.dither() self.play(DelayByOrder(ApplyMethod( grid.gradient_highlight, red, blue ))) self.play(Transform(grid, freq_line)) self.dither() self.play( ShimmerIn( words, rate_func = squish_rate_func(smooth, 0, 0.2) ), *sub_vibrations, run_time = 5 ) self.play( *[ TransformAnimations( sub_vib, vibration ) for sub_vib in sub_vibrations ]+[FadeOut(words)] ) self.clear() self.add(freq_line) self.play(vibration)
def setup(self, CurveClass): sample = CurveClass(order = 1) self.curve = Line(3*LEFT, 3*RIGHT) self.curve.gradient_highlight( sample.start_color, sample.end_color ) self.CurveClass = CurveClass self.order = 0
def construct(self, order): if order == 2: result_tex = "(0.125, 0.75)" elif order == 3: result_tex = "(0.0758, 0.6875)" phc, arg, result = TexMobject([ "\\text{PHC}_%d"%order, "(0.3)", "= %s"%result_tex ]).to_edge(UP).split() function = TextMobject("Function", size = "\\normal") function.shift(phc.get_center()+DOWN+2*LEFT) function_arrow = Arrow(function, phc) line = Line(5*LEFT, 5*RIGHT) curve = HilbertCurve(order = order) line.match_colors(curve) grid = Grid(2**order, 2**order) grid.fade() for mob in curve, grid: mob.scale(0.7) index = int(0.3*line.get_num_points()) dot1 = Dot(line.points[index]) arrow1 = Arrow(arg, dot1, buff = 0.1) dot2 = Dot(curve.points[index]) arrow2 = Arrow(result.get_bottom(), dot2, buff = 0.1) self.add(phc) self.play( ShimmerIn(function), ShowCreation(function_arrow) ) self.dither() self.remove(function_arrow, function) self.play(ShowCreation(line)) self.dither() self.play( ShimmerIn(arg), ShowCreation(arrow1), ShowCreation(dot1) ) self.dither() self.remove(arrow1) self.play( FadeIn(grid), Transform(line, curve), Transform(dot1, dot2), run_time = 2 ) self.dither() self.play( ShimmerIn(result), ShowCreation(arrow2) ) self.dither()
def construct(self, order): if order == 2: result_tex = "(0.125, 0.75)" elif order == 3: result_tex = "(0.0758, 0.6875)" phc, arg, result = TexMobject([ "\\text{PHC}_%d"%order, "(0.3)", "= %s"%result_tex ]).to_edge(UP).split() function = TextMobject("Function", size = "\\normal") function.shift(phc.get_center()+DOWN+2*LEFT) function_arrow = Arrow(function, phc) line = Line(5*LEFT, 5*RIGHT) curve = HilbertCurve(order = order) line.match_colors(curve) grid = Grid(2**order, 2**order) grid.fade() for mob in curve, grid: mob.scale(0.7) index = int(0.3*line.get_num_points()) dot1 = Dot(line.points[index]) arrow1 = Arrow(arg, dot1, buff = 0.1) dot2 = Dot(curve.points[index]) arrow2 = Arrow(result.get_bottom(), dot2, buff = 0.1) self.add(phc) self.play( ShimmerIn(function), ShowCreation(function_arrow) ) self.wait() self.remove(function_arrow, function) self.play(ShowCreation(line)) self.wait() self.play( ShimmerIn(arg), ShowCreation(arrow1), ShowCreation(dot1) ) self.wait() self.remove(arrow1) self.play( FadeIn(grid), Transform(line, curve), Transform(dot1, dot2), run_time = 2 ) self.wait() self.play( ShimmerIn(result), ShowCreation(arrow2) ) self.wait()
def generate_points(self): self.main_line = Line(self.x_min * RIGHT, self.x_max * RIGHT) self.tick_marks = VMobject() self.add(self.main_line, self.tick_marks) for x in self.get_tick_numbers(): self.add_tick(x, self.tick_size) for x in self.numbers_with_elongated_ticks: self.add_tick(x, self.longer_tick_multiple * self.tick_size) self.stretch(self.space_unit_to_num, 0) self.shift(-self.number_to_point(self.number_at_center))
def coords_to_vector(self, vector, coords_start=2 * RIGHT + 2 * UP, clean_up=True): starting_mobjects = list(self.mobjects) array = Matrix(vector) array.shift(coords_start) arrow = Vector(vector) x_line = Line(ORIGIN, vector[0] * RIGHT) y_line = Line(x_line.get_end(), arrow.get_end()) x_line.highlight(X_COLOR) y_line.highlight(Y_COLOR) x_coord, y_coord = array.get_mob_matrix().flatten() self.play(Write(array, run_time=1)) self.dither() self.play( ApplyFunction( lambda x: self.position_x_coordinate(x, x_line, vector), x_coord)) self.play(ShowCreation(x_line)) self.play( ApplyFunction( lambda y: self.position_y_coordinate(y, y_line, vector), y_coord), FadeOut(array.get_brackets())) y_coord, brackets = self.get_mobjects_from_last_animation() self.play(ShowCreation(y_line)) self.play(ShowCreation(arrow)) self.dither() if clean_up: self.clear() self.add(*starting_mobjects)
def construct(self, order): start_color, end_color = RED, GREEN curve = HilbertCurve(order = order) line = Line(5*LEFT, 5*RIGHT) for mob in curve, line: mob.gradient_highlight(start_color, end_color) freq_line = get_freq_line() freq_line.replace(line, stretch = True) unit = 6./(2**order) #sidelength of pixel up = unit*UP right = unit*RIGHT lower_left = 3*(LEFT+DOWN) squares = Mobject(*[ Square( side_length = unit, color = WHITE ).shift(x*right+y*up) for x, y in it.product(range(2**order), range(2**order)) ]) squares.center() targets = Mobject() for square in squares.submobjects: center = square.get_center() distances = np.apply_along_axis( lambda p : np.linalg.norm(p-center), 1, curve.points ) index_along_curve = np.argmin(distances) fraction_along_curve = index_along_curve/float(curve.get_num_points()) target = square.copy().center().scale(0.8/(2**order)) line_index = int(fraction_along_curve*line.get_num_points()) target.shift(line.points[line_index]) targets.add(target) self.add(squares) self.play(ShowCreation( curve, run_time = 5, rate_func = None )) self.dither() self.play( Transform(curve, line), Transform(squares, targets), run_time = 3 ) self.dither() self.play(ShowCreation(freq_line)) self.dither()
def construct(self, max_order): sample = self.curve_class(order = 1) curve = Line(sample.radius*LEFT, sample.radius*RIGHT) curve.gradient_highlight( sample.start_color, sample.end_color ) for order in range(1, max_order): new_curve = self.curve_class(order = order) self.play( Transform(curve, new_curve), run_time = 3/np.sqrt(order), ) self.dither()
def generate_points(self): self.main_line = Line(self.x_min*RIGHT, self.x_max*RIGHT) self.tick_marks = VGroup() self.add(self.main_line, self.tick_marks) for x in self.get_tick_numbers(): if x in self.numbers_with_elongated_ticks: tick_size_used = self.longer_tick_multiple*self.tick_size else: tick_size_used = self.tick_size self.add_tick(x, tick_size_used) self.stretch(self.unit_size, 0) self.shift(-self.number_to_point(self.number_at_center))
def add_lines(self, left, right): line_kwargs = { "color": BLUE, "stroke_width": 2, } left_rows = [VMobject(*row) for row in left.get_mob_matrix()] h_lines = VMobject() for row in left_rows[:-1]: h_line = Line(row.get_left(), row.get_right(), **line_kwargs) h_line.next_to(row, DOWN, buff=left.v_buff / 2.) h_lines.add(h_line) right_cols = [ VMobject(*col) for col in np.transpose(right.get_mob_matrix()) ] v_lines = VMobject() for col in right_cols[:-1]: v_line = Line(col.get_top(), col.get_bottom(), **line_kwargs) v_line.next_to(col, RIGHT, buff=right.h_buff / 2.) v_lines.add(v_line) self.play(ShowCreation(h_lines)) self.play(ShowCreation(v_lines)) self.wait() self.show_frame()
def __init__(self, **kwargs): circle = Circle() ticks = [] for x in range(12): alpha = x / 12. point = complex_to_R3(np.exp(2 * np.pi * alpha * complex(0, 1))) length = 0.2 if x % 3 == 0 else 0.1 ticks.append(Line(point, (1 - length) * point)) self.hour_hand = Line(ORIGIN, 0.3 * UP) self.minute_hand = Line(ORIGIN, 0.6 * UP) # for hand in self.hour_hand, self.minute_hand: # #Balance out where the center is # hand.add(VectorizedPoint(-hand.get_end())) VGroup.__init__(self, circle, self.hour_hand, self.minute_hand, *ticks)
def add_treds_to_tires(self): for tire in self.get_tires(): radius = tire.get_width() / 2 center = tire.get_center() tred = Line(0.9 * radius * RIGHT, 1.4 * radius * RIGHT, stroke_width=2, color=BLACK) tred.rotate_in_place(np.pi / 4) for theta in np.arange(0, 2 * np.pi, np.pi / 4): new_tred = tred.copy() new_tred.rotate(theta, about_point=ORIGIN) new_tred.shift(center) tire.add(new_tred) return self
def construct(self): big_grid_dim = 20. small_grid_dim = 6. big_grid = Grid(64, 64, height=big_grid_dim, width=big_grid_dim) big_grid.to_corner(UP + RIGHT, buff=2) small_grid = big_grid.copy() small_grid.scale(small_grid_dim / big_grid_dim) small_grid.center() pixel = MobjectFromRegion( region_from_polygon_vertices( *0.2 * np.array([RIGHT + DOWN, RIGHT + UP, LEFT + UP, LEFT + DOWN]))) pixel.set_color(WHITE) pixel_width = big_grid.width / big_grid.columns pixel.scale_to_fit_width(pixel_width) pixel.to_corner(UP + RIGHT, buff=2) pixel.shift(5 * pixel_width * (2 * LEFT + DOWN)) freq_line = get_freq_line() dot = Dot() dot.shift(freq_line.get_center() + 2 * RIGHT) string = Line(LEFT, RIGHT, color=GREEN) arrow = Arrow(dot, string.get_center()) vibration_config = { "overtones": 1, "spatial_period": 2, } vibration, loud_vibration, quiet_vibration = [ Vibrate(string.copy(), amplitude=a, **vibration_config) for a in [0.5, 1., 0.25] ] self.add(small_grid) self.dither() self.play(Transform(small_grid, big_grid)) self.play(FadeIn(pixel)) self.dither() self.play(FadeOut(small_grid), ShowCreation(freq_line)) self.remove(small_grid) self.play(Transform(pixel, dot), ) self.dither() self.play(ShowCreation(arrow)) self.play(loud_vibration) self.play(TransformAnimations(loud_vibration, quiet_vibration), ApplyMethod(dot.fade, 0.9)) self.clear() self.add(freq_line, dot, arrow) self.play(quiet_vibration)
def construct(self): words = TextMobject("Order 2 Pseudo-Hilbert Curve") words.to_edge(UP, buff=0.3) words.highlight(GREEN) grid2 = Grid(2, 2) grid4 = Grid(4, 4, point_thickness=2) # order_1_curve = HilbertCurve(order = 1) # squaggle_curve = order_1_curve.copy().apply_function( # lambda (x, y, z) : (x + np.cos(3*y), y + np.sin(3*x), z) # ) # squaggle_curve.show() mini_curves = [ HilbertCurve(order=1).scale(0.5).shift(1.5 * vect) for vect in [LEFT + DOWN, LEFT + UP, RIGHT + UP, RIGHT + DOWN] ] last_curve = mini_curves[0] naive_curve = Mobject(last_curve) for mini_curve in mini_curves[1:]: line = Line(last_curve.points[-1], mini_curve.points[0]) naive_curve.add(line, mini_curve) last_curve = mini_curve naive_curve.ingest_sub_mobjects() naive_curve.gradient_highlight(RED, GREEN) order_2_curve = HilbertCurve(order=2) self.add(words, grid2) self.dither() self.play(ShowCreation(grid4)) self.play(*[ShowCreation(mini_curve) for mini_curve in mini_curves]) self.dither() self.play(ShowCreation(naive_curve, run_time=5)) self.remove(*mini_curves) self.dither() self.play(Transform(naive_curve, order_2_curve)) self.dither()
def __init__(self, source, target): matching_line = Line(0.5 * DOWN, 0.5 * UP) def matched_objects(source, target): matched = VGroup(source.copy(), matching_line.copy(), target.copy()) matched.arrange_submobjects(direction=DOWN) return matched final_mobj = VGroup( *(matched_objects(s, t) for (s, t) in zip(source.submobjects, target.submobjects))) self.buff = 2 * DEFAULT_MOBJECT_TO_MOBJECT_BUFFER final_mobj.arrange_submobjects(buff=self.buff) final_mobj.center() def match_animation(source, target, matched): return AnimationGroup(Transform(source, matched.submobjects[0]), ShowCreation(matched.submobjects[1]), Transform(target, matched.submobjects[2])) self.match_animations = [ match_animation(s, t, m) for (s, t, m) in zip( source.submobjects, target.submobjects, final_mobj.submobjects) ] self.matching = VGroup(*[mob[1] for mob in final_mobj])
def add_tick(self, x, size): self.tick_marks.add( Line( x * RIGHT + size * DOWN, x * RIGHT + size * UP, )) return self
def generate_points(self): start_angle = np.pi / 2 + self.arc_angle / 2 end_angle = np.pi / 2 - self.arc_angle / 2 self.add(Arc(start_angle=start_angle, angle=-self.arc_angle)) tick_angle_range = np.linspace(start_angle, end_angle, self.num_ticks) for index, angle in enumerate(tick_angle_range): vect = rotate_vector(RIGHT, angle) tick = Line((1 - self.tick_length) * vect, vect) label = TexMobject(str(10 * index)) label.scale_to_fit_height(self.tick_length) label.shift((1 + self.tick_length) * vect) self.add(tick, label) needle = Polygon(LEFT, UP, RIGHT, stroke_width=0, fill_opacity=1, fill_color=self.needle_color) needle.stretch_to_fit_width(self.needle_width) needle.stretch_to_fit_height(self.needle_height) needle.rotate(start_angle - np.pi / 2) self.add(needle) self.needle = needle self.center_offset = self.get_center()
def get_circles_and_points(self, min_input, max_input): input_left, input_right = [ self.interval.number_to_point(num) for num in min_input, max_input ] input_circle = Circle( radius = np.linalg.norm(input_left-input_right)/2, color = WHITE ) input_circle.shift((input_left+input_right)/2) input_points = Line( input_left, input_right, color = self.input_color ) output_points = Mobject(color = self.output_color) n = self.output.get_num_points() output_points.add_points( self.output.points[int(min_input*n):int(max_input*n)] ) output_center = output_points.points[int(0.5*output_points.get_num_points())] max_distance = np.linalg.norm(output_center-output_points.points[-1]) output_circle = Circle( radius = max_distance, color = WHITE ) output_circle.shift(output_center) return ( input_circle, input_points, output_circle, output_points )
def __init__(self, camera): VMobject.__init__(self) stroke = 20 factor = sum(PRODUCTION_QUALITY_CAMERA_CONFIG["pixel_shape"]) / sum( camera.pixel_shape) stroke /= factor self.add(Circle()) h1, h2, x = 1, 1.5, 0.5 y = -np.sqrt(1 - x**2) + h1 self.add(Line([-x, y, 0], [-x, y - h1, 0])) self.add(Line([0, 1, 0], [0, 1 - h2, 0])) self.add(Line([x, y, 0], [x, y - h1, 0])) self.set_stroke(color="#00ffff", width=stroke) self.to_corner(RIGHT + DOWN)
def coords_to_vector(self, vector, coords_start = 2*RIGHT+2*UP, clean_up = True): starting_mobjects = list(self.mobjects) array = Matrix(vector) array.shift(coords_start) arrow = Vector(vector) x_line = Line(ORIGIN, vector[0]*RIGHT) y_line = Line(x_line.get_end(), arrow.get_end()) x_line.highlight(X_COLOR) y_line.highlight(Y_COLOR) x_coord, y_coord = array.get_mob_matrix().flatten() self.play(Write(array, run_time = 1)) self.dither() self.play(ApplyFunction( lambda x : self.position_x_coordinate(x, x_line, vector), x_coord )) self.play(ShowCreation(x_line)) self.play( ApplyFunction( lambda y : self.position_y_coordinate(y, y_line, vector), y_coord ), FadeOut(array.get_brackets()) ) y_coord, brackets = self.get_mobjects_from_last_animation() self.play(ShowCreation(y_line)) self.play(ShowCreation(arrow)) self.dither() if clean_up: self.clear() self.add(*starting_mobjects)
def generate_points(self): if self.x_radius is None: center_to_edge = (SPACE_WIDTH + abs(self.center_point[0])) self.x_radius = center_to_edge / self.x_unit_size if self.y_radius is None: center_to_edge = (SPACE_HEIGHT + abs(self.center_point[1])) self.y_radius = center_to_edge / self.y_unit_size self.axes = VMobject() self.main_lines = VMobject() self.secondary_lines = VMobject() tuples = [ ( self.x_radius, self.x_line_frequency, self.y_radius*DOWN, self.y_radius*UP, RIGHT ), ( self.y_radius, self.y_line_frequency, self.x_radius*LEFT, self.x_radius*RIGHT, UP, ), ] for radius, freq, start, end, unit in tuples: main_range = np.arange(0, radius, freq) step = freq/float(freq + self.secondary_line_ratio) for v in np.arange(0, radius, step): line1 = Line(start+v*unit, end+v*unit) line2 = Line(start-v*unit, end-v*unit) if v == 0: self.axes.add(line1) elif v in main_range: self.main_lines.add(line1, line2) else: self.secondary_lines.add(line1, line2) self.add(self.secondary_lines, self.main_lines, self.axes) self.stretch(self.x_unit_size, 0) self.stretch(self.y_unit_size, 1) self.shift(self.center_point) #Put x_axis before y_axis y_axis, x_axis = self.axes.split() self.axes = VMobject(x_axis, y_axis)
def generate_points(self): self.main_line = Line(self.x_min * RIGHT, self.x_max * RIGHT) self.tick_marks = VGroup() self.add(self.main_line, self.tick_marks) rounding_value = int(-np.log10(0.1 * self.tick_frequency)) rounded_numbers_with_elongated_ticks = np.round( self.numbers_with_elongated_ticks, rounding_value) for x in self.get_tick_numbers(): rounded_x = np.round(x, rounding_value) if rounded_x in rounded_numbers_with_elongated_ticks: tick_size_used = self.longer_tick_multiple * self.tick_size else: tick_size_used = self.tick_size self.add_tick(x, tick_size_used) self.stretch(self.unit_size, 0) self.shift(-self.number_to_point(self.number_at_center))
def generate_points(self): self.main_line = Line(self.x_min*RIGHT, self.x_max*RIGHT) self.tick_marks = VMobject() self.add(self.main_line, self.tick_marks) for x in self.get_tick_numbers(): self.add_tick(x, self.tick_size) for x in self.numbers_with_elongated_ticks: self.add_tick(x, self.longer_tick_multiple*self.tick_size) self.stretch(self.unit_size, 0) self.shift(-self.number_to_point(self.number_at_center))
def generate_points(self): complex_power = 0.9 radius = self.initial_width / 2 circle = Circle(radius=radius) circle.scale(1.0 / radius) circle.apply_complex_function(lambda z: z**complex_power) circle.scale(radius) boundary_point_as_complex = radius * complex(-1)**complex_power boundary_points = [[ boundary_point_as_complex.real, unit * boundary_point_as_complex.imag, 0 ] for unit in -1, 1] tip = radius * (1.5 * LEFT + UP) self.little_line = Line(boundary_points[0], tip) self.circle = circle self.add(circle, self.little_line, Line(boundary_points[1], tip)) self.highlight("white") self.rotate(np.pi / 2) self.stretch_to_fit_height(self.initial_height)
def zoom_in_on(self, number, zoom_factor, run_time=2.0): unit_length_to_spatial_width = self.number_line.unit_length_to_spatial_width * zoom_factor radius = SPACE_WIDTH / unit_length_to_spatial_width tick_frequency = 10**(np.floor(np.log10(radius))) left_tick = tick_frequency * (np.ceil( (number - radius) / tick_frequency)) new_number_line = NumberLine( numerical_radius=radius, unit_length_to_spatial_width=unit_length_to_spatial_width, tick_frequency=tick_frequency, leftmost_tick=left_tick, number_at_center=number) new_displayed_numbers = new_number_line.default_numbers_to_display() new_number_mobs = new_number_line.get_number_mobjects( *new_displayed_numbers) transforms = [] additional_mobjects = [] squished_new_line = new_number_line.copy() squished_new_line.scale(1.0 / zoom_factor) squished_new_line.shift(self.number_line.number_to_point(number)) squished_new_line.points[:, 1] = self.number_line.number_to_point(0)[1] transforms.append(Transform(squished_new_line, new_number_line)) for mob, num in zip(new_number_mobs, new_displayed_numbers): point = Point(self.number_line.number_to_point(num)) point.shift(new_number_line.get_vertical_number_offset()) transforms.append(Transform(point, mob)) for mob in self.mobjects: if mob == self.number_line: new_mob = mob.copy() new_mob.shift(-self.number_line.number_to_point(number)) new_mob.stretch(zoom_factor, 0) transforms.append(Transform(mob, new_mob)) continue mob_center = mob.get_center() number_under_center = self.number_line.point_to_number(mob_center) new_point = new_number_line.number_to_point(number_under_center) new_point += mob_center[1] * UP if mob in self.number_mobs: transforms.append(Transform(mob, Point(new_point))) else: transforms.append( ApplyMethod(mob.shift, new_point - mob_center)) additional_mobjects.append(mob) line_to_hide_pixelation = Line(self.number_line.get_left(), self.number_line.get_right(), color=self.number_line.get_color()) self.add(line_to_hide_pixelation) self.play(*transforms, run_time=run_time) self.clear() self.number_line = new_number_line self.displayed_numbers = new_displayed_numbers self.number_mobs = new_number_mobs self.add(self.number_line, *self.number_mobs) self.add(*additional_mobjects)
def generate_points(self): body = Cube(side_length = 1) for dim, scale_factor in enumerate(self.body_dimensions): body.stretch(scale_factor, dim = dim) body.scale_to_fit_width(self.width) body.set_fill(self.shaded_body_color, opacity = 1) body.sort_submobjects(lambda p : p[2]) body[-1].set_fill(self.body_color) keyboard = VGroup(*[ VGroup(*[ Square(**self.key_color_kwargs) for x in range(12-y%2) ]).arrange_submobjects(RIGHT, buff = SMALL_BUFF) for y in range(4) ]).arrange_submobjects(DOWN, buff = MED_SMALL_BUFF) keyboard.stretch_to_fit_width( self.keyboard_width_to_body_width*body.get_width(), ) keyboard.stretch_to_fit_height( self.keyboard_height_to_body_height*body.get_height(), ) keyboard.next_to(body, OUT, buff = 0.1*SMALL_BUFF) keyboard.shift(MED_SMALL_BUFF*UP) body.add(keyboard) screen_plate = body.copy() screen_plate.stretch(self.screen_thickness/self.body_dimensions[2], dim = 2) screen = Rectangle( stroke_width = 0, fill_color = BLACK, fill_opacity = 1, ) screen.replace(screen_plate, stretch = True) screen.scale_in_place(self.screen_width_to_screen_plate_width) screen.next_to(screen_plate, OUT, buff = 0.1*SMALL_BUFF) screen_plate.add(screen) screen_plate.next_to(body, UP, buff = 0) screen_plate.rotate( self.open_angle, RIGHT, about_point = screen_plate.get_bottom() ) self.screen_plate = screen_plate self.screen = screen axis = Line( body.get_corner(UP+LEFT+OUT), body.get_corner(UP+RIGHT+OUT), color = BLACK, stroke_width = 2 ) self.axis = axis self.add(body, screen_plate, axis) self.rotate(5*np.pi/12, LEFT) self.rotate(np.pi/6, DOWN)
def add_lines(self, left, right): line_kwargs = { "color" : BLUE, "stroke_width" : 2, } left_rows = [ VMobject(*row) for row in left.get_mob_matrix() ] h_lines = VMobject() for row in left_rows[:-1]: h_line = Line(row.get_left(), row.get_right(), **line_kwargs) h_line.next_to(row, DOWN, buff = left.v_buff/2.) h_lines.add(h_line) right_cols = [ VMobject(*col) for col in np.transpose(right.get_mob_matrix()) ] v_lines = VMobject() for col in right_cols[:-1]: v_line = Line(col.get_top(), col.get_bottom(), **line_kwargs) v_line.next_to(col, RIGHT, buff = right.h_buff/2.) v_lines.add(v_line) self.play(ShowCreation(h_lines)) self.play(ShowCreation(v_lines)) self.dither() self.show_frame()
def construct(self): grid = Grid(64, 64) space_region = Region() space_mobject = MobjectFromRegion(space_region, DARK_GREY) curve = PeanoCurve(order = 5).replace(space_mobject) line = Line(5*LEFT, 5*RIGHT) line.gradient_highlight(curve.start_color, curve.end_color) for mob in grid, space_mobject: mob.sort_points(np.linalg.norm) infinitely = TextMobject("Infinitely") detailed = TextMobject("detailed") extending = TextMobject("extending") detailed.next_to(infinitely, RIGHT) extending.next_to(infinitely, RIGHT) Mobject(extending, infinitely, detailed).center() arrows = Mobject(*[ Arrow(2*p, 4*p) for theta in np.arange(np.pi/6, 2*np.pi, np.pi/3) for p in [rotate_vector(RIGHT, theta)] ]) self.add(grid) self.wait() self.play(Transform(grid, space_mobject, run_time = 5)) self.remove(grid) self.highlight_region(space_region, DARK_GREY) self.wait() self.add(infinitely, detailed) self.wait() self.play(DelayByOrder(Transform(detailed, extending))) self.play(ShowCreation(arrows)) self.wait() self.clear() self.highlight_region(space_region, DARK_GREY) self.play(ShowCreation(line)) self.play(Transform(line, curve, run_time = 5))
def construct(self): grid = Grid(64, 64) space_region = Region() space_mobject = MobjectFromRegion(space_region, DARK_GREY) curve = PeanoCurve(order = 5).replace(space_mobject) line = Line(5*LEFT, 5*RIGHT) line.gradient_highlight(curve.start_color, curve.end_color) for mob in grid, space_mobject: mob.sort_points(np.linalg.norm) infinitely = TextMobject("Infinitely") detailed = TextMobject("detailed") extending = TextMobject("extending") detailed.next_to(infinitely, RIGHT) extending.next_to(infinitely, RIGHT) Mobject(extending, infinitely, detailed).center() arrows = Mobject(*[ Arrow(2*p, 4*p) for theta in np.arange(np.pi/6, 2*np.pi, np.pi/3) for p in [rotate_vector(RIGHT, theta)] ]) self.add(grid) self.dither() self.play(Transform(grid, space_mobject, run_time = 5)) self.remove(grid) self.highlight_region(space_region, DARK_GREY) self.dither() self.add(infinitely, detailed) self.dither() self.play(DelayByOrder(Transform(detailed, extending))) self.play(ShowCreation(arrows)) self.dither() self.clear() self.highlight_region(space_region, DARK_GREY) self.play(ShowCreation(line)) self.play(Transform(line, curve, run_time = 5))
def label_spaces(self): input_space = TextMobject("Input Space") input_space.to_edge(UP) input_space.shift(LEFT * SPACE_WIDTH / 2) output_space = TextMobject("Output Space") output_space.to_edge(UP) output_space.shift(RIGHT * SPACE_WIDTH / 2) line = Line(UP * SPACE_HEIGHT, DOWN * SPACE_HEIGHT, color=WHITE) self.play( ShimmerIn(input_space), ShimmerIn(output_space), ShowCreation(line), ShowCreation(self.interval), ) self.dither()
def vector_to_coords(self, vector, integer_labels = True, clean_up = True): starting_mobjects = list(self.mobjects) show_creation = False if isinstance(vector, Arrow): arrow = vector vector = arrow.get_end()[:2] else: arrow = Vector(vector) show_creation = True array = vector_coordinate_label(arrow, integer_labels = integer_labels) x_line = Line(ORIGIN, vector[0]*RIGHT) y_line = Line(x_line.get_end(), arrow.get_end()) x_line.highlight(X_COLOR) y_line.highlight(Y_COLOR) x_coord, y_coord = array.get_mob_matrix().flatten() x_coord_start = self.position_x_coordinate( x_coord.copy(), x_line, vector ) y_coord_start = self.position_y_coordinate( y_coord.copy(), y_line, vector ) brackets = array.get_brackets() if show_creation: self.play(ShowCreation(arrow)) self.play( ShowCreation(x_line), Write(x_coord_start), run_time = 1 ) self.play( ShowCreation(y_line), Write(y_coord_start), run_time = 1 ) self.dither() self.play( Transform(x_coord_start, x_coord, submobject_mode = "all_at_once"), Transform(y_coord_start, y_coord, submobject_mode = "all_at_once"), Write(brackets, run_time = 1), ) self.dither() self.remove(x_coord_start, y_coord_start, brackets) self.add(array) if clean_up: self.clear() self.add(*starting_mobjects) return array, x_line, y_line
def vector_to_coords(self, vector, integer_labels=True, clean_up=True): starting_mobjects = list(self.mobjects) show_creation = False if isinstance(vector, Arrow): arrow = vector vector = arrow.get_end()[:2] else: arrow = Vector(vector) show_creation = True array = vector_coordinate_label(arrow, integer_labels=integer_labels) x_line = Line(ORIGIN, vector[0] * RIGHT) y_line = Line(x_line.get_end(), arrow.get_end()) x_line.highlight(X_COLOR) y_line.highlight(Y_COLOR) x_coord, y_coord = array.get_mob_matrix().flatten() x_coord_start = self.position_x_coordinate(x_coord.copy(), x_line, vector) y_coord_start = self.position_y_coordinate(y_coord.copy(), y_line, vector) brackets = array.get_brackets() if show_creation: self.play(ShowCreation(arrow)) self.play(ShowCreation(x_line), Write(x_coord_start), run_time=1) self.play(ShowCreation(y_line), Write(y_coord_start), run_time=1) self.dither() self.play( Transform(x_coord_start, x_coord, submobject_mode="all_at_once"), Transform(y_coord_start, y_coord, submobject_mode="all_at_once"), Write(brackets, run_time=1), ) self.dither() self.remove(x_coord_start, y_coord_start, brackets) self.add(array) if clean_up: self.clear() self.add(*starting_mobjects) return array, x_line, y_line
def construct(self): def special_rotate(mob): mob.rotate(0.9*np.pi/2, RIGHT) mob.rotate(-np.pi/4, UP) return mob plane = NumberPlane() copies = [ special_rotate(plane.copy().shift(u*n*OUT)) for n in range(1, 3) for u in -1, 1 ] line = Line(4*IN, 4*OUT) self.add(plane) self.play(*[ ApplyFunction(special_rotate, mob, run_time = 3) for mob in plane, line ]) self.dither() for copy in copies: self.play(Transform(plane.copy(), copy)) self.dither()
def construct(self): big_grid_dim = 20. small_grid_dim = 6. big_grid = Grid(64, 64, height = big_grid_dim, width = big_grid_dim) big_grid.to_corner(UP+RIGHT, buff = 2) small_grid = big_grid.copy() small_grid.scale(small_grid_dim/big_grid_dim) small_grid.center() pixel = MobjectFromRegion( region_from_polygon_vertices(*0.2*np.array([ RIGHT+DOWN, RIGHT+UP, LEFT+UP, LEFT+DOWN ])) ) pixel.set_color(WHITE) pixel_width = big_grid.width/big_grid.columns pixel.scale_to_fit_width(pixel_width) pixel.to_corner(UP+RIGHT, buff = 2) pixel.shift(5*pixel_width*(2*LEFT+DOWN)) freq_line = get_freq_line() dot = Dot() dot.shift(freq_line.get_center() + 2*RIGHT) string = Line(LEFT, RIGHT, color = GREEN) arrow = Arrow(dot, string.get_center()) vibration_config = { "overtones" : 1, "spatial_period" : 2, } vibration, loud_vibration, quiet_vibration = [ Vibrate(string.copy(), amplitude = a, **vibration_config) for a in [0.5, 1., 0.25] ] self.add(small_grid) self.dither() self.play( Transform(small_grid, big_grid) ) self.play(FadeIn(pixel)) self.dither() self.play( FadeOut(small_grid), ShowCreation(freq_line) ) self.remove(small_grid) self.play( Transform(pixel, dot), ) self.dither() self.play(ShowCreation(arrow)) self.play(loud_vibration) self.play( TransformAnimations(loud_vibration, quiet_vibration), ApplyMethod(dot.fade, 0.9) ) self.clear() self.add(freq_line, dot, arrow) self.play(quiet_vibration)
class NumberLine(VMobject): CONFIG = { "color" : BLUE, "x_min" : -SPACE_WIDTH, "x_max" : SPACE_WIDTH, "space_unit_to_num" : 1, "tick_size" : 0.1, "tick_frequency" : 0.5, "leftmost_tick" : None, #Defaults to ceil(x_min) "numbers_with_elongated_ticks" : [0], "longer_tick_multiple" : 2, "number_at_center" : 0, "propogate_style_to_family" : True } def __init__(self, **kwargs): digest_config(self, kwargs) if self.leftmost_tick is None: self.leftmost_tick = np.ceil(self.x_min) VMobject.__init__(self, **kwargs) def generate_points(self): self.main_line = Line(self.x_min*RIGHT, self.x_max*RIGHT) self.tick_marks = VMobject() self.add(self.main_line, self.tick_marks) for x in self.get_tick_numbers(): self.add_tick(x, self.tick_size) for x in self.numbers_with_elongated_ticks: self.add_tick(x, self.longer_tick_multiple*self.tick_size) self.stretch(self.space_unit_to_num, 0) self.shift(-self.number_to_point(self.number_at_center)) def add_tick(self, x, size): self.tick_marks.add(Line( x*RIGHT+size*DOWN, x*RIGHT+size*UP, )) return self def get_tick_marks(self): return self.tick_marks def get_tick_numbers(self): return np.arange(self.leftmost_tick, self.x_max, self.tick_frequency) def number_to_point(self, number): return interpolate( self.main_line.get_left(), self.main_line.get_right(), float(number-self.x_min)/(self.x_max - self.x_min) ) def point_to_number(self, point): dist_from_left = (point[0]-self.main_line.get_left()[0]) num_dist_from_left = num_dist_from_left/self.space_unit_to_num return self.x_min + dist_from_left def default_numbers_to_display(self): return self.get_tick_numbers()[::2] def get_vertical_number_offset(self, direction = DOWN): return 4*direction*self.tick_size def get_number_mobjects(self, *numbers, **kwargs): #TODO, handle decimals if len(numbers) == 0: numbers = self.default_numbers_to_display() result = [] for number in numbers: mob = TexMobject(str(int(number))) mob.scale_to_fit_height(2*self.tick_size) mob.shift( self.number_to_point(number), self.get_vertical_number_offset(**kwargs) ) result.append(mob) return result def add_numbers(self, *numbers, **kwargs): self.numbers = self.get_number_mobjects( *numbers, **kwargs ) self.add(*self.numbers) return self
class NumberLine(VMobject): CONFIG = { "color" : BLUE, "x_min" : -SPACE_WIDTH, "x_max" : SPACE_WIDTH, "unit_size" : 1, "tick_size" : 0.1, "tick_frequency" : 1, "leftmost_tick" : None, #Defaults to ceil(x_min) "numbers_with_elongated_ticks" : [0], "numbers_to_show" : None, "longer_tick_multiple" : 2, "number_at_center" : 0, "propogate_style_to_family" : True } def __init__(self, **kwargs): digest_config(self, kwargs) if self.leftmost_tick is None: self.leftmost_tick = np.ceil(self.x_min) VMobject.__init__(self, **kwargs) def generate_points(self): self.main_line = Line(self.x_min*RIGHT, self.x_max*RIGHT) self.tick_marks = VMobject() self.add(self.main_line, self.tick_marks) for x in self.get_tick_numbers(): self.add_tick(x, self.tick_size) for x in self.numbers_with_elongated_ticks: self.add_tick(x, self.longer_tick_multiple*self.tick_size) self.stretch(self.unit_size, 0) self.shift(-self.number_to_point(self.number_at_center)) def add_tick(self, x, size): self.tick_marks.add(Line( x*RIGHT+size*DOWN, x*RIGHT+size*UP, )) return self def get_tick_marks(self): return self.tick_marks def get_tick_numbers(self): epsilon = 0.001 return np.arange( self.leftmost_tick, self.x_max+epsilon, self.tick_frequency ) def number_to_point(self, number): alpha = float(number-self.x_min)/(self.x_max - self.x_min) return interpolate( self.main_line.get_start(), self.main_line.get_end(), alpha ) def point_to_number(self, point): left_point, right_point = self.main_line.get_start_and_end() full_vect = right_point-left_point def distance_from_left(p): return np.dot(p-left_point, full_vect)/np.linalg.norm(full_vect) return interpolate( self.x_min, self.x_max, distance_from_left(point)/distance_from_left(right_point) ) def default_numbers_to_display(self): if self.numbers_to_show is not None: return self.numbers_to_show return np.arange(self.leftmost_tick, self.x_max, 1) def get_vertical_number_offset(self, direction = DOWN): return 4*direction*self.tick_size def get_number_mobjects(self, *numbers, **kwargs): #TODO, handle decimals if len(numbers) == 0: numbers = self.default_numbers_to_display() result = VGroup() for number in numbers: mob = TexMobject(str(int(number))) mob.scale_to_fit_height(3*self.tick_size) mob.shift( self.number_to_point(number), self.get_vertical_number_offset(**kwargs) ) result.add(mob) return result def add_numbers(self, *numbers, **kwargs): self.numbers = self.get_number_mobjects( *numbers, **kwargs ) self.add(*self.numbers) return self