From fb23644b5af2b29ef75585c3d4750c90f92cf213 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 23 Jan 2018 14:03:25 -0800 Subject: [PATCH 1/6] Further fourier work --- .gitignore | 2 +- active_projects/fourier.py | 50 +++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index ea54dace..f0f3ca3f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .DS_Store homeless.py ka_playgrounds/ -grant_playground.py +playground.py special_animations.py prettiness_hall_of_fame.py files/ diff --git a/active_projects/fourier.py b/active_projects/fourier.py index 395d834c..c3a513d4 100644 --- a/active_projects/fourier.py +++ b/active_projects/fourier.py @@ -2474,14 +2474,13 @@ class WhiteComplexExponentialExpression(DrawFrequencyPlot): v_line.put_start_and_end_on( plane.coords_to_point(x, 0), point ) - lines_update_anim = UpdateFromFunc(lines, lines_update) + lines_update_anim = ContinualUpdateFromFunc(lines, lines_update) lines_update_anim.update(0) - self.add(lines) + self.add(lines_update_anim) self.change_frequency( 2.04, added_anims = [ - lines_update_anim, self.center_of_mass_dot_anim, ], run_time = 15, @@ -2496,15 +2495,60 @@ class WhiteComplexExponentialExpression(DrawFrequencyPlot): self.time_axes_group, self.pol_graph, self.wps_label ) plane = self.circle_plane + dot = self.center_of_mass_dot complex_plane_title = TextMobject("Complex plane") complex_plane_title.add_background_rectangle() complex_plane_title.to_edge(UP) coordinate_labels = plane.get_coordinate_labels() + number_label = DecimalNumber( + 0, include_background_rectangle = True, + ) + number_label_update_anim = ContinualChangingDecimal( + number_label, + lambda a : plane.point_to_number(dot.get_center()), + position_update_func = lambda l : l.next_to( + # plane.coords_to_point(1, 1), DOWN+RIGHT, + dot, DOWN+RIGHT, + buff = SMALL_BUFF + ), + ) + number_label_update_anim.update(0) + arrow = Arrow(RIGHT, LEFT, color = RED) + def update_arrow(arrow): + arrow.put_start_and_end_on( + number_label.get_left(), + dot.get_center(), + ) + arrow.scale(0.9) + return arrow + arrow_update_anim = ContinualUpdateFromFunc(arrow, update_arrow) + arrow_update_anim.update(0) + flower_path = ParametricFunction( + lambda t : plane.coords_to_point( + np.sin(2*t)*np.cos(t), + np.sin(2*t)*np.sin(t), + ), + t_min = 0, t_max = TAU, + ) + flower_path.move_to(self.center_of_mass_dot) self.play(FadeOut(to_fade)) self.play(Write(complex_plane_title)) self.play(Write(coordinate_labels)) self.wait() + self.play( + FadeIn(number_label), + # GrowArrow(arrow) + ) + self.add(number_label_update_anim) + # self.add(arrow_update_anim) + self.play(MoveAlongPath( + dot, flower_path, + run_time = 10, + rate_func = bezier([0, 0, 1, 1]) + )) + self.wait() + def show_eulers_formula(self): From 82905e38bda4024cbcfb6fc5ce5d60106ef91245 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Wed, 24 Jan 2018 08:54:36 -0800 Subject: [PATCH 2/6] Removed axes config from Rotating animation --- animation/simple_animations.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/animation/simple_animations.py b/animation/simple_animations.py index bb703443..853f218f 100644 --- a/animation/simple_animations.py +++ b/animation/simple_animations.py @@ -12,20 +12,19 @@ from transform import Transform class Rotating(Animation): CONFIG = { - "axes" : [], "axis" : OUT, "radians" : 2*np.pi, "run_time" : 5, "rate_func" : None, "in_place" : True, "about_point" : None, + "about_edge" : None, } def update_submobject(self, submobject, starting_submobject, alpha): submobject.points = np.array(starting_submobject.points) def update_mobject(self, alpha): Animation.update_mobject(self, alpha) - axes = self.axes if self.axes else [self.axis] about_point = None if self.about_point is not None: about_point = self.about_point @@ -33,8 +32,9 @@ class Rotating(Animation): self.about_point = self.mobject.get_center() self.mobject.rotate( alpha*self.radians, - axes = axes, - about_point = self.about_point + axis = self.axis, + about_point = self.about_point, + about_edge = self.about_edge, ) class ShowPartial(Animation): From b3d6ab9d47c5683ae38e7811ef6e5324928abd46 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Wed, 24 Jan 2018 08:55:26 -0800 Subject: [PATCH 3/6] Added background rectangle to DecimalNumber --- topics/numerals.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/topics/numerals.py b/topics/numerals.py index e1e049dd..44e28323 100644 --- a/topics/numerals.py +++ b/topics/numerals.py @@ -58,13 +58,17 @@ class DecimalNumber(VMobject): self[-1].align_to(self, UP) # if self.include_background_rectangle: - #TODO, is this the best way to handle - #background rectangles? - self.background_rectangle = BackgroundRectangle(self) - self.submobjects = [ - self.background_rectangle, - VGroup(*self.submobjects) - ] + self.add_background_rectangle() + + def add_background_rectangle(self): + #TODO, is this the best way to handle + #background rectangles? + self.background_rectangle = BackgroundRectangle(self) + self.submobjects = [ + self.background_rectangle, + VGroup(*self.submobjects) + ] + return self class Integer(DecimalNumber): CONFIG = { @@ -87,6 +91,8 @@ class ChangingDecimal(Animation): value = getattr(self, attr) if value is not None: self.decimal_number_config[attr] = value + if hasattr(self.decimal_number_mobject, "background_rectangle"): + self.decimal_number_config["include_background_rectangle"] = True if self.tracked_mobject: dmc = decimal_number_mobject.get_center() tmc = self.tracked_mobject.get_center() From 239addea7233e62996047ee693f2596eca41c8f9 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Wed, 24 Jan 2018 08:55:53 -0800 Subject: [PATCH 4/6] Finished WriteComplexExponentialExpression of fourier --- active_projects/fourier.py | 489 +++++++++++++++++++++++++++++++++++-- 1 file changed, 464 insertions(+), 25 deletions(-) diff --git a/active_projects/fourier.py b/active_projects/fourier.py index c3a513d4..8b44f9fd 100644 --- a/active_projects/fourier.py +++ b/active_projects/fourier.py @@ -2392,7 +2392,7 @@ class ApplyFourierToFourier(DrawFrequencyPlot): kwargs["scale_val"] = 1.0 return DrawFrequencyPlot.get_cosine_wave(self, freq, **kwargs) -class WhiteComplexExponentialExpression(DrawFrequencyPlot): +class WriteComplexExponentialExpression(DrawFrequencyPlot): CONFIG = { "signal_frequency" : 2.0, "default_num_v_lines_indicating_periods" : 0, @@ -2404,15 +2404,16 @@ class WhiteComplexExponentialExpression(DrawFrequencyPlot): self.show_winding_with_both_coordinates() self.show_plane_as_complex_plane() self.show_eulers_formula() - self.reference_other_video() self.show_winding_graph_expression() + self.find_center_of_mass() def setup_plane(self): circle_plane = ComplexPlane( unit_size = 2, - y_radius = SPACE_HEIGHT+LARGE_BUFF + y_radius = SPACE_HEIGHT+LARGE_BUFF, + x_radius = SPACE_WIDTH+LARGE_BUFF ) - circle_plane.shift(DOWN) + circle_plane.shift(DOWN+LEFT) circle = DashedLine(ORIGIN, TAU*UP) circle.apply_complex_function( lambda z : R3_to_complex( @@ -2507,22 +2508,11 @@ class WhiteComplexExponentialExpression(DrawFrequencyPlot): number_label, lambda a : plane.point_to_number(dot.get_center()), position_update_func = lambda l : l.next_to( - # plane.coords_to_point(1, 1), DOWN+RIGHT, dot, DOWN+RIGHT, buff = SMALL_BUFF ), ) number_label_update_anim.update(0) - arrow = Arrow(RIGHT, LEFT, color = RED) - def update_arrow(arrow): - arrow.put_start_and_end_on( - number_label.get_left(), - dot.get_center(), - ) - arrow.scale(0.9) - return arrow - arrow_update_anim = ContinualUpdateFromFunc(arrow, update_arrow) - arrow_update_anim.update(0) flower_path = ParametricFunction( lambda t : plane.coords_to_point( np.sin(2*t)*np.cos(t), @@ -2536,32 +2526,481 @@ class WhiteComplexExponentialExpression(DrawFrequencyPlot): self.play(Write(complex_plane_title)) self.play(Write(coordinate_labels)) self.wait() - self.play( - FadeIn(number_label), - # GrowArrow(arrow) - ) + self.play(FadeIn(number_label)) self.add(number_label_update_anim) - # self.add(arrow_update_anim) self.play(MoveAlongPath( dot, flower_path, run_time = 10, rate_func = bezier([0, 0, 1, 1]) )) self.wait() + self.play(ShowCreation( + self.pol_graph, run_time = 3, + )) + self.play(FadeOut(self.pol_graph)) + self.wait() + self.play(FadeOut(VGroup( + dot, self.dot_component_anim.mobject, number_label + ))) + self.remove(self.dot_component_anim) + self.remove(number_label_update_anim) - + self.set_variables_as_attrs( + number_label, + number_label_update_anim, + complex_plane_title, + ) def show_eulers_formula(self): - pass + plane = self.circle_plane - def reference_other_video(self): - pass + ghost_dot = Dot(ORIGIN, fill_opacity = 0) + def get_t(): + return ghost_dot.get_center()[0] + def get_circle_point(scalar = 1, t_shift = 0): + return plane.number_to_point( + scalar*np.exp(complex(0, get_t()+t_shift)) + ) + vector = Vector(plane.number_to_point(1), color = GREEN) + exp_base = TexMobject("e").scale(1.3) + exp_base.add_background_rectangle() + exp_decimal = DecimalNumber(0, unit = "i", include_background_rectangle = True) + exp_decimal.scale(0.75) + VGroup(exp_base, exp_decimal).match_color(vector) + exp_decimal_update = ContinualChangingDecimal( + exp_decimal, lambda a : get_t(), + position_update_func = lambda d : d.move_to( + exp_base.get_corner(UP+RIGHT), DOWN+LEFT + ) + ) + exp_base_update = ContinualUpdateFromFunc( + exp_base, lambda e : e.move_to(get_circle_point( + scalar = 1.1, t_shift = 0.01*TAU + )) + ) + vector_update = ContinualUpdateFromFunc( + vector, lambda v : v.put_start_and_end_on( + plane.number_to_point(0), get_circle_point() + ) + ) + updates = [exp_base_update, exp_decimal_update, vector_update] + for update in updates: + update.update(0) + + #Show initial vector + self.play( + GrowArrow(vector), + FadeIn(exp_base), + Write(exp_decimal) + ) + self.add(*updates) + self.play(ghost_dot.shift, 2*RIGHT, run_time = 3) + self.wait() + + #Show arc + arc, circle = [ + Line(ORIGIN, t*UP) + for t in get_t(), TAU + ] + for mob in arc, circle: + mob.insert_n_anchor_points(20) + mob.set_stroke(RED, 4) + mob.apply_function( + lambda p : plane.number_to_point( + np.exp(R3_to_complex(p)) + ) + ) + distance_label = DecimalNumber( + exp_decimal.number, + unit = "\\text{units}" + ) + distance_label[-1].shift(SMALL_BUFF*RIGHT) + distance_label.match_color(arc) + distance_label.add_background_rectangle() + distance_label.move_to( + plane.number_to_point( + 1.1*np.exp(complex(0, 0.4*get_t())), + ), + DOWN+LEFT + ) + + self.play(ShowCreation(arc)) + self.play(ReplacementTransform( + exp_decimal.copy(), distance_label + )) + self.wait() + self.play(FadeOut(distance_label)) + + #Show full cycle + self.remove(arc) + self.play( + ghost_dot.move_to, TAU*RIGHT, + ShowCreation( + circle, + rate_func = lambda a : interpolate( + 2.0/TAU, 1, smooth(a) + ), + ), + run_time = 6, + ) + self.wait() + + #Write exponential expression + exp_expression = TexMobject("e", "^{-", "2\\pi i", "f", "t}") + e, minus, two_pi_i, f, t = exp_expression + exp_expression.next_to( + plane.coords_to_point(1, 1), + UP+RIGHT + ) + f.highlight(RED) + t.highlight(YELLOW) + exp_expression.add_background_rectangle() + two_pi_i_f_t_group = VGroup(two_pi_i, f, t) + two_pi_i_f_t_group.save_state() + two_pi_i_f_t_group.move_to(minus, LEFT) + exp_expression[1].remove(minus) + t.save_state() + t.align_to(f, LEFT) + exp_expression[1].remove(f) + + labels = VGroup() + for sym, word in (t, "Time"), (f, "Frequency"): + label = TextMobject(word) + label.match_style(sym) + label.next_to(sym, UP, buff = MED_LARGE_BUFF) + label.add_background_rectangle() + label.arrow = Arrow(label, sym, buff = SMALL_BUFF) + label.arrow.match_style(sym) + labels.add(label) + time_label, frequency_label = labels + example_frequency = TexMobject("f = 1/10") + example_frequency.add_background_rectangle() + example_frequency.match_style(frequency_label) + example_frequency.move_to(frequency_label, DOWN) + + self.play(ReplacementTransform( + VGroup(exp_base[1], exp_decimal[1]).copy(), + exp_expression + )) + self.play(FadeOut(circle)) + self.wait() + + ghost_dot.move_to(ORIGIN) + ambient_ghost_dot_movement = AmbientMovement( + ghost_dot, rate = TAU + ) + self.add(ambient_ghost_dot_movement) + + self.play( + Write(time_label), + GrowArrow(time_label.arrow), + ) + self.wait(6.5) #Leave time to say let's slow down + self.remove(ambient_ghost_dot_movement) + self.play( + FadeOut(time_label), + FadeIn(frequency_label), + t.restore, + GrowFromPoint(f, frequency_label.get_center()), + ReplacementTransform( + time_label.arrow, + frequency_label.arrow, + ) + ) + ghost_dot.move_to(ORIGIN) + ambient_ghost_dot_movement = AmbientMovement( + ghost_dot, rate = 0.1*TAU + ) + self.add(ambient_ghost_dot_movement) + self.wait(3) + self.play( + FadeOut(frequency_label), + FadeIn(example_frequency) + ) + self.wait(15) #Give time to reference other video + #Reverse directions + ambient_ghost_dot_movement.rate *= -1 + self.play( + FadeOut(example_frequency), + FadeOut(frequency_label.arrow), + GrowFromCenter(minus), + two_pi_i_f_t_group.restore + ) + self.wait(4) + + ambient_ghost_dot_movement.rate = 0 + self.remove(*updates) + self.play(*map(FadeOut, [ + update.mobject + for update in updates + if update.mobject is not vector + ])) + self.play(ghost_dot.move_to, ORIGIN) + + exp_expression[1].add(minus, f) + exp_expression[1].sort_submobjects(lambda p : p[0]) + + self.set_variables_as_attrs( + ambient_ghost_dot_movement, ghost_dot, + vector, vector_update, exp_expression + ) def show_winding_graph_expression(self): - pass + ambient_ghost_dot_movement = self.ambient_ghost_dot_movement + ghost_dot = self.ghost_dot + vector = self.vector + exp_expression = self.exp_expression + plane = self.circle_plane + time_axes_group = self.time_axes_group + graph = self.graph + pol_graph = self.get_polarized_mobject(graph, freq = 0.2) + g_label = TexMobject("g(t)") + g_label.match_color(graph) + g_label.next_to(graph, UP) + g_label.add_background_rectangle() + g_scalar = g_label.copy() + g_scalar.move_to(exp_expression, DOWN+LEFT) + + vector_animations = self.get_vector_animations(graph) + vector_animations[1].mobject = vector + graph_y_vector = vector_animations[0].mobject + + self.play( + FadeIn(time_axes_group), + FadeOut(self.complex_plane_title) + ) + self.play(Write(g_label)) + self.wait() + self.play( + ReplacementTransform(g_label.copy(), g_scalar), + exp_expression.next_to, g_scalar, RIGHT, SMALL_BUFF, + exp_expression.shift, 0.5*SMALL_BUFF*UP, + ) + self.play(*vector_animations, run_time = 15) + self.add(*self.mobjects_from_last_animation) + self.wait() + + integrand = VGroup(g_scalar, exp_expression) + rect = SurroundingRectangle(integrand) + morty = Mortimer() + morty.next_to(rect, DOWN+RIGHT) + morty.shift_onto_screen() + self.play( + ShowCreation(rect), + FadeIn(morty) + ) + self.play(morty.change, "raise_right_hand") + self.play(Blink(morty)) + self.play(morty.change, "hooray", rect) + self.wait(2) + self.play(*map(FadeOut, [ + morty, rect, graph_y_vector, vector + ])) + + self.integrand = integrand + + def find_center_of_mass(self): + integrand = self.integrand + integrand.generate_target() + integrand.target.to_edge(RIGHT, buff = LARGE_BUFF) + integrand.target.shift(MED_LARGE_BUFF*DOWN) + sum_expr = TexMobject( + "{1", "\\over", "N}", + "\\sum", "_{k = 1}", "^N", + ) + sum_expr.add_background_rectangle() + sum_expr.shift(SMALL_BUFF*(UP+5*RIGHT)) + sum_expr.next_to(integrand.target, LEFT) + + integral = TexMobject( + "{1", "\\over", "t_2 - t_1}", + "\\int", "_{t_1}", "^{t_2}" + ) + integral.move_to(sum_expr, RIGHT) + time_interval_indicator = SurroundingRectangle(integral[2]) + integral.add_background_rectangle() + axes = self.time_axes + time_interval = Line( + axes.coords_to_point(axes.x_min, 0), + axes.coords_to_point(axes.x_max, 0), + ) + time_interval.match_style(time_interval_indicator) + time_interval_indicator.add(time_interval) + dt_mob = TexMobject("dt") + dt_mob.next_to(integrand.target, RIGHT, SMALL_BUFF, DOWN) + dt_mob.add_background_rectangle() + + dots = self.show_center_of_mass_sampling(20) + self.wait() + self.play( + Write(sum_expr), + MoveToTarget(integrand), + ) + + #Add k subscript to t's + t1 = integrand[0][1][2] + t2 = integrand[1][1][-1] + t_mobs = VGroup(t1, t2) + t_mobs.save_state() + t_mobs.generate_target() + for i, t_mob in enumerate(t_mobs.target): + k = TexMobject("k") + k.match_style(t_mob) + k.match_height(t_mob) + k.scale(0.5) + k.move_to(t_mob.get_corner(DOWN+RIGHT), LEFT) + k.add_background_rectangle() + t_mob.add(k) + if i == 0: + t_mob.shift(0.5*SMALL_BUFF*LEFT) + + self.play(MoveToTarget(t_mobs)) + self.play(LaggedStart( + Indicate, dots[1], + rate_func = there_and_back, + color = TEAL, + )) + self.show_center_of_mass_sampling(100) + dots = self.show_center_of_mass_sampling(500) + self.wait() + self.play(FadeOut(dots)) + self.play( + ReplacementTransform(sum_expr, integral), + FadeIn(dt_mob), + t_mobs.restore, + ) + self.wait() + self.play(ShowCreation(time_interval_indicator)) + self.wait() + self.play(FadeOut(time_interval_indicator)) + self.wait() + + #Show confusion + randy = Randolph() + randy.flip() + randy.next_to(integrand, DOWN, LARGE_BUFF) + randy.to_edge(RIGHT) + full_expression_rect = SurroundingRectangle( + VGroup(integral, dt_mob), color = RED + ) + com_dot = self.center_of_mass_dot + self.center_of_mass_dot_anim.update(0) + com_arrow = Arrow( + full_expression_rect.get_left(), com_dot, + buff = SMALL_BUFF + ) + com_arrow.match_color(com_dot) + self.play(FadeIn(randy)) + self.play(randy.change, "confused", integral) + self.play(Blink(randy)) + self.wait(2) + self.play(ShowCreation(full_expression_rect)) + self.play( + randy.change, "thinking", self.pol_graph, + GrowArrow(com_arrow), + GrowFromCenter(com_dot), + ) + self.play(Blink(randy)) + self.wait(2) + def show_center_of_mass_sampling(self, n_dots): + time_graph = self.graph + pol_graph = self.graph.polarized_mobject + axes = self.time_axes + + dot = Dot(radius = 0.05, color = PINK) + pre_dots = VGroup(*[ + dot.copy().move_to(axes.coords_to_point(t, 0)) + for t in np.linspace(axes.x_min, axes.x_max, n_dots) + ]) + pre_dots.set_fill(opacity = 0) + for graph in time_graph, pol_graph: + if hasattr(graph, "dots"): + graph.dot_fade_anims = [FadeOut(graph.dots)] + else: + graph.dot_fade_anims = [] + graph.save_state() + graph.generate_target() + if not hasattr(graph, "is_faded"): + graph.target.fade(0.7) + graph.is_faded = True + graph.dots = VGroup(*[ + dot.copy().move_to(graph.point_from_proportion(a)) + for a in np.linspace(0, 1, n_dots) + ]) + + self.play( + ReplacementTransform( + pre_dots, time_graph.dots, + submobject_mode = "lagged_start", + run_time = 2, + ), + MoveToTarget(time_graph), + *time_graph.dot_fade_anims + ) + self.play( + ReplacementTransform( + time_graph.copy(), pol_graph.target + ), + MoveToTarget(pol_graph), + ReplacementTransform( + time_graph.dots.copy(), + pol_graph.dots, + ), + *pol_graph.dot_fade_anims, + run_time = 2 + ) + return VGroup(time_graph.dots, pol_graph.dots) + + +class WhyAreYouTellingUsThis(TeacherStudentsScene): + def construct(self): + self.student_says("Why are you \\\\ telling us this?") + self.play(self.teacher.change, "happy") + self.wait(2) + +class BuildUpExpressionStepByStep(TeacherStudentsScene): + def construct(self): + expression = TexMobject( + "\\frac{1}{t_2 - t_1}", "\\int_{t_1}^{t_2}", + "g(t)", "e", "^{2\\pi i", "f", "t}", "dt" + ) + frac, integral, g, e, two_pi_i, f, t, dt = expression + expression.next_to(self.teacher, UP+LEFT) + t.highlight(YELLOW) + f.highlight(RED) + t.save_state() + t.move_to(f, LEFT) + + self.play( + self.teacher.change, "raise_right_hand", + FadeIn(e), + FadeIn(two_pi_i), + ) + self.play( + self.get_student_changes(*["pondering"]*3), + FadeIn(t), + ) + self.play( + FadeIn(f), + t.restore, + ) + self.wait() + self.play(FadeIn(g), Blink(self.students[1])) + self.wait() + self.play( + FadeIn(integral), + FadeIn(frac), + FadeIn(dt), + ) + self.wait(3) + self.teacher_says( + "Just one final \\\\ distinction.", + added_anims = [expression.to_corner, UP+LEFT] + ) + self.wait(3) From c7fa8c59adf7d18e4591e398c5418ab58a6dde92 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Wed, 24 Jan 2018 11:25:55 -0800 Subject: [PATCH 5/6] Made slicing into mobjects return a Group or VGroup instead of a list --- mobject/mobject.py | 19 +++++++++++++------ mobject/vectorized_mobject.py | 3 +++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/mobject/mobject.py b/mobject/mobject.py index c8bfc5d3..f079b330 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -15,11 +15,11 @@ class Mobject(object): Mathematical Object """ CONFIG = { - "color" : WHITE, + "color" : WHITE, "stroke_width" : DEFAULT_POINT_THICKNESS, - "name" : None, - "dim" : 3, - "target" : None, + "name" : None, + "dim" : 3, + "target" : None, } def __init__(self, *submobjects, **kwargs): digest_config(self, kwargs) @@ -663,8 +663,12 @@ class Mobject(object): ## Family matters - def __getitem__(self, index): - return self.split()[index] + def __getitem__(self, value): + self_list = self.split() + if isinstance(value, slice): + GroupClass = self.get_group_class() + return GroupClass(*self_list.__getitem__(value)) + return self_list.__getitem__(value) def __iter__(self): return iter(self.split()) @@ -672,6 +676,9 @@ class Mobject(object): def __len__(self): return len(self.split()) + def get_group_class(self): + return Group + def split(self): result = [self] if len(self.points) > 0 else [] return result + self.submobjects diff --git a/mobject/vectorized_mobject.py b/mobject/vectorized_mobject.py index 264181fd..4b1a37e6 100644 --- a/mobject/vectorized_mobject.py +++ b/mobject/vectorized_mobject.py @@ -19,6 +19,9 @@ class VMobject(Mobject): "make_smooth_after_applying_functions" : False, } + def get_group_class(self): + return VGroup + ## Colors def init_colors(self): self.set_style_data( From ebf44f9bdbbec7c34a29c0301ac15ec8fd712914 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Wed, 24 Jan 2018 11:26:13 -0800 Subject: [PATCH 6/6] Scaffolding for ScaleUpCenterOfMass scene in fourier --- active_projects/fourier.py | 61 +++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/active_projects/fourier.py b/active_projects/fourier.py index 8b44f9fd..f7c1d745 100644 --- a/active_projects/fourier.py +++ b/active_projects/fourier.py @@ -2396,6 +2396,8 @@ class WriteComplexExponentialExpression(DrawFrequencyPlot): CONFIG = { "signal_frequency" : 2.0, "default_num_v_lines_indicating_periods" : 0, + "time_axes_scale_val" : 0.7, + "initial_winding_frequency" : 0.1, } def construct(self): self.remove(self.pi_creature) @@ -2428,7 +2430,7 @@ class WriteComplexExponentialExpression(DrawFrequencyPlot): fill_opacity = 0.9, buff = MED_SMALL_BUFF, )) - time_axes.scale(0.7) + time_axes.scale(self.time_axes_scale_val) time_axes.to_corner(UP+LEFT, buff = 0) time_axes.set_stroke(color = WHITE, width = 1) @@ -2445,7 +2447,7 @@ class WriteComplexExponentialExpression(DrawFrequencyPlot): scale_val = 0.5, shift_val = 0.75, ) - freq = 0.1 + freq = self.initial_winding_frequency pol_graph = self.get_polarized_mobject(graph, freq = freq) wps_label = self.get_winding_frequency_label() ChangeDecimalToValue(wps_label[0], freq).update(1) @@ -2970,7 +2972,9 @@ class BuildUpExpressionStepByStep(TeacherStudentsScene): frac, integral, g, e, two_pi_i, f, t, dt = expression expression.next_to(self.teacher, UP+LEFT) t.highlight(YELLOW) - f.highlight(RED) + g[2].highlight(YELLOW) + dt[1].highlight(YELLOW) + f.highlight(GREEN) t.save_state() t.move_to(f, LEFT) @@ -2998,14 +3002,63 @@ class BuildUpExpressionStepByStep(TeacherStudentsScene): self.wait(3) self.teacher_says( "Just one final \\\\ distinction.", - added_anims = [expression.to_corner, UP+LEFT] + bubble_kwargs = {"height" : 2.5, "width" : 3.5}, + added_anims = [expression.to_corner, UP+RIGHT] ) self.wait(3) +class ScaleUpCenterOfMass(WriteComplexExponentialExpression): + CONFIG = { + "time_axes_scale_val" : 0.6, + "initial_winding_frequency" : 1.95 + } + def construct(self): + self.remove(self.pi_creature) + self.setup_plane() + self.setup_graph() + self.add_expression() + self.add_center_of_mass_dot() + + self.cross_out_denominator() + self.scale_up_center_of_mass() + self.what_this_means_for_various_winding_frequencies() + def add_expression(self): + expression = TexMobject( + "\\frac{1}{t_2 - t_1}", "\\int_{t_1}^{t_2}", + "g(t)", "e", "^{2\\pi i", "f", "t}", "dt" + ) + frac, integral, g, e, two_pi_i, f, t, dt = expression + expression.to_corner(UP+RIGHT) + t.highlight(YELLOW) + g[2].highlight(YELLOW) + dt[1].highlight(YELLOW) + f.highlight(GREEN) + expression.add_background_rectangle() + self.expression = expression + self.add(expression) + + self.winding_freq_label.to_edge(RIGHT) + self.winding_freq_label[1].match_color(f) + + def add_center_of_mass_dot(self): + self.center_of_mass_dot = self.get_center_of_mass_dot() + self.generate_center_of_mass_dot_update_anim() + self.add(self.center_of_mass_dot) + def cross_out_denominator(self): + frac = self.expression[0] + integral = VGroup(*self.expression[1:]) + + + def scale_up_center_of_mass(self): + pass + + + def what_this_means_for_various_winding_frequencies(self): + pass class CloseWithAPuzzle(TeacherStudentsScene):