def update_config(self, **kwargs): Animation.update_config(self, **kwargs) if "path_arc" in kwargs: self.path_func = path_along_arc( kwargs["path_arc"], kwargs.get("path_arc_axis", OUT) )
def __init__(self, mobject, mode="linear", **kwargs): if not isinstance(mobject, PiCreatureClass): raise Exception("FlashThroughClass mobject must be a PiCreatureClass") digest_config(self, kwargs) self.indices = list(range(mobject.height * mobject.width)) if mode == "random": np.random.shuffle(self.indices) Animation.__init__(self, mobject, **kwargs)
def __init__(self, mobject, target_mobject, **kwargs): # Copy target_mobject so as to not mess with caller self.original_target_mobject = target_mobject target_mobject = target_mobject.copy() mobject.align_data(target_mobject) self.target_mobject = target_mobject digest_config(self, kwargs) self.init_path_func() Animation.__init__(self, mobject, **kwargs) self.name += "To" + str(target_mobject)
def __init__(self, AnimationClass, mobjects, **kwargs): full_kwargs = AnimationClass.CONFIG full_kwargs.update(kwargs) full_kwargs["mobject"] = Mobject(*[ mob.get_point_mobject() for mob in mobjects ]) self.centers_container = AnimationClass(**full_kwargs) full_kwargs.pop("mobject") Animation.__init__(self, Mobject(*mobjects), **full_kwargs) self.name = str(self) + AnimationClass.__name__
def __init__(self, clock, **kwargs): digest_config(self, kwargs) assert (isinstance(clock, Clock)) rot_kwargs = {"axis": OUT, "about_point": clock.get_center()} hour_radians = -self.hours_passed * 2 * np.pi / 12 self.hour_rotation = Rotating(clock.hour_hand, radians=hour_radians, **rot_kwargs) self.minute_rotation = Rotating(clock.minute_hand, radians=12 * hour_radians, **rot_kwargs) Animation.__init__(self, clock, **kwargs)
def __init__(self, *sub_anims, **kwargs): sub_anims = [x for x in sub_anims if not(x.empty)] digest_config(self, locals()) self.update_config(**kwargs) # Handles propagation to self.sub_anims if len(sub_anims) == 0: self.empty = True self.run_time = 0 else: self.run_time = max([a.run_time for a in sub_anims]) everything = Mobject(*[a.mobject for a in sub_anims]) Animation.__init__(self, everything, **kwargs)
def __init__(self, *animations, **kwargs): if not hasattr(self, "args"): self.args = serialize_args(animations) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) digest_config(self, kwargs) self.animations = animations if self.group is None: self.group = Group(*remove_list_redundancies( [anim.mobject for anim in animations])) self.init_run_time() Animation.__init__(self, self.group, **kwargs)
def get_logo_animations(self, logo): layers = logo.spike_layers for i, layer in enumerate(layers): random.shuffle(layer.submobjects) for spike in layer: spike.save_state() spike.scale(0.5) spike.apply_complex_function(np.log) spike.rotate(-90 * DEGREES, about_point=ORIGIN) spike.set_fill(opacity=0) layer.rotate(i * PI / 5) logo.iris_background.save_state() logo.iris_background.scale(0.25) logo.iris_background.fade(1) return [ Restore( logo.iris_background, run_time=3, ), AnimationGroup(*[ LaggedStartMap( Restore, layer, run_time=3, path_arc=180 * DEGREES, # rate_func=squish_rate_func(smooth, a / 3.0, (a + 1.9) / 3.0), lag_ratio=0.8, ) for layer, a in zip(layers, [0, 0.2, 0.1, 0]) ]), Animation(logo.pupil), ]
def add_unit_square(self, animate=False, **kwargs): """ Adds a unit square to the scene via self.get_unit_square. Parameters ---------- animate (bool) Whether or not to animate the addition with DrawBorderThenFill. **kwargs Any valid keyword arguments of self.get_unit_square() Returns ------- Square The unit square. """ square = self.get_unit_square(**kwargs) if animate: self.play(DrawBorderThenFill(square), Animation(Group(*self.moving_vectors))) self.add_transformable_mobject(square) self.bring_to_front(*self.moving_vectors) self.square = square return self
def apply_function(self, function, added_anims=[], **kwargs): """ Applies the given function to each of the mobjects in self.transformable_mobjects, and plays the animation showing this. Parameters ---------- function (Function) The function that affects each point of each mobject in self.transformable_mobjects. added_anims (list) Any other animations that need to be played simulataneously with this. **kwargs Any valid keyword argument of a self.play() call. """ if "run_time" not in kwargs: kwargs["run_time"] = 3 anims = [ ApplyPointwiseFunction(function, t_mob) for t_mob in self.transformable_mobjects ] + [ self.get_vector_movement(function), self.get_transformable_label_movement(), self.get_moving_mobject_movement(function), ] + [Animation(f_mob) for f_mob in self.foreground_mobjects] + added_anims self.play(*anims, **kwargs)
def construct(self): number_line = NumberLine(x_min=-2, x_max=2) triangle = RegularPolygon(3, start_angle=-PI / 2) \ .scale(0.2) \ .next_to(number_line.get_left(), UP, buff=SMALL_BUFF) numbers = VGroup( *[TextMobject("%s" % i) \ .next_to(number_line.get_tick(i - 2), DOWN) for i in range(1, 5)] ) self.add(number_line) self.play(ShowCreation(triangle)) self.wait(0.3) self.play( ApplyMethod(triangle.shift, RIGHT * 4, rate_func=linear, run_time=4), *[ AnimationGroup(Animation(Mobject(), run_time=i + 1), Write(numbers[i]), lag_ratio=1) for i in range(4) ], ) self.wait()
def construct(self): number_line = NumberLine(x_min=-2, x_max=2) text_1 = TextMobject("Theorem of") \ .next_to(number_line, DOWN) text_2 = TextMobject("Beethoven") \ .next_to(number_line, DOWN) dashed_line = DashedLine( number_line.get_left(), number_line.get_right(), color=YELLOW, ).set_stroke(width=11) self.add(number_line, text_1) self.play( LaggedStart(*[ ShowCreationThenDestruction(dashed_segment) for dashed_segment in dashed_line ], run_time=5), AnimationGroup(Animation(Mobject(), run_time=2.1), ReplacementTransform(text_1, text_2), lag_ratio=1)) self.wait()
def __init__(self, text_mobject, **kwargs): digest_config(self, kwargs) tpc = self.time_per_char anims = it.chain(*[[ ShowIncreasingSubsets(word, run_time=tpc * len(word)), Animation(word, run_time=0.005 * len(word)**1.5), ] for word in text_mobject]) super().__init__(*anims, **kwargs)
def add_unit_square(self, animate=False, **kwargs): square = self.get_unit_square(**kwargs) if animate: self.play(DrawBorderThenFill(square), Animation(Group(*self.moving_vectors))) self.add_transformable_mobject(square) self.bring_to_front(*self.moving_vectors) self.square = square return self
def __init__(self, clock, **kwargs): if not hasattr(self, "args"): self.args = serialize_args([clock]) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) digest_config(self, kwargs) assert (isinstance(clock, Clock)) rot_kwargs = {"axis": OUT, "about_point": clock.get_center()} hour_radians = -self.hours_passed * 2 * np.pi / 12 self.hour_rotation = Rotating(clock.hour_hand, radians=hour_radians, **rot_kwargs) self.hour_rotation.begin() self.minute_rotation = Rotating(clock.minute_hand, radians=12 * hour_radians, **rot_kwargs) self.minute_rotation.begin() Animation.__init__(self, clock, **kwargs)
def __init__(self, start_anim: Animation, end_anim: Animation, **kwargs): digest_config(self, kwargs, locals()) if "run_time" in kwargs: self.run_time = kwargs.pop("run_time") else: self.run_time = max(start_anim.run_time, end_anim.run_time) for anim in start_anim, end_anim: anim.set_run_time(self.run_time) if start_anim.starting_mobject.get_num_points() != end_anim.starting_mobject.get_num_points(): start_anim.starting_mobject.align_data_and_family(end_anim.starting_mobject) for anim in start_anim, end_anim: if hasattr(anim, "target_mobject"): anim.starting_mobject.align_data_and_family(anim.target_mobject) Transform.__init__(self, start_anim.mobject, end_anim.mobject, **kwargs) # Rewire starting and ending mobjects start_anim.mobject = self.starting_mobject end_anim.mobject = self.target_mobject
def apply_function(self, function, added_anims=[], **kwargs): if "run_time" not in kwargs: kwargs["run_time"] = 3 anims = [ ApplyPointwiseFunction(function, t_mob) for t_mob in self.transformable_mobjects ] + [ self.get_vector_movement(function), self.get_transformable_label_movement(), self.get_moving_mobject_movement(function), ] + [Animation(f_mob) for f_mob in self.submobjects] + added_anims self.play(*anims, **kwargs)
def __init__(self, clock, **kwargs): digest_config(self, kwargs) assert(isinstance(clock, Clock)) rot_kwargs = { "axis": OUT, "about_point": clock.get_center() } hour_radians = -self.hours_passed * 2 * np.pi / 12 self.hour_rotation = Rotating( clock.hour_hand, radians=hour_radians, **rot_kwargs ) self.hour_rotation.begin() self.minute_rotation = Rotating( clock.minute_hand, radians=12 * hour_radians, **rot_kwargs ) self.minute_rotation.begin() Animation.__init__(self, clock, **kwargs)
def turn_animation_into_updater(animation: Animation, cycle: bool = False, **kwargs) -> Mobject: """ Add an updater to the animation's mobject which applies the interpolation and update functions of the animation If cycle is True, this repeats over and over. Otherwise, the updater will be popped uplon completion """ mobject = animation.mobject animation.update_config(**kwargs) animation.suspend_mobject_updating = False animation.begin() animation.total_time = 0 def update(m, dt): run_time = animation.get_run_time() time_ratio = animation.total_time / run_time if cycle: alpha = time_ratio % 1 else: alpha = clip(time_ratio, 0, 1) if alpha >= 1: animation.finish() m.remove_updater(update) return animation.interpolate(alpha) animation.update_mobjects(dt) animation.total_time += dt mobject.add_updater(update) return mobject
def show_reflines(self): reflines = VGroup(*[rhombus.get_refline() for rhombus in self.rhombi]) eqtri_text = self.bg_texts[1] self.play(Write(eqtri_text), ShowCreation(reflines), Animation(self.rhombi), run_time=3) self.play( Indicate(VGroup(self.rhombi, reflines), scale_factor=1.05), run_time=2, ) self.wait() self.reflines = reflines
def __init__(self, AnimationClass, mobject, arg_creator=None, **kwargs): digest_config(self, kwargs) for key in "rate_func", "run_time", "lag_ratio": if key in kwargs: kwargs.pop(key) if arg_creator is None: def arg_creator(mobject): return (mobject,) self.subanimations = [ AnimationClass( *arg_creator(submob), run_time=self.run_time, rate_func=squish_rate_func( self.rate_func, beta, beta + self.lag_ratio ), **kwargs ) for submob, beta in zip( mobject, np.linspace(0, 1 - self.lag_ratio, len(mobject)) ) ] Animation.__init__(self, mobject, **kwargs)
def construct(self): number_line = NumberLine(x_min=-2, x_max=2) triangle = RegularPolygon(3, start_angle=-PI / 2) \ .scale(0.2) \ .next_to(number_line.get_left(), UP, buff=SMALL_BUFF) text_1 = TextMobject("1") \ .next_to(number_line.get_tick(-1), DOWN) text_2 = TextMobject("2") \ .next_to(number_line.get_tick(0), DOWN) text_3 = TextMobject("3") \ .next_to(number_line.get_tick(1), DOWN) text_4 = TextMobject("4") \ .next_to(number_line.get_tick(2), DOWN) self.add(number_line) self.play(ShowCreation(triangle)) self.wait(0.3) self.play( ApplyMethod(triangle.shift, RIGHT * 4, rate_func=linear, run_time=4), AnimationGroup(Animation(Mobject(), run_time=1), Write(text_1), lag_ratio=1), AnimationGroup(Animation(Mobject(), run_time=2), Write(text_2), lag_ratio=1), AnimationGroup(Animation(Mobject(), run_time=3), Write(text_3), lag_ratio=1), AnimationGroup(Animation(Mobject(), run_time=4), Write(text_4), lag_ratio=1)) self.wait()
def __init__(self, text_mobject, **kwargs): if not hasattr(self, "args"): self.args = serialize_args([text_mobject]) if not hasattr(self, "config"): self.config = serialize_config({ **kwargs, }) digest_config(self, kwargs) tpc = self.time_per_char anims = it.chain(*[ [ ShowIncreasingSubsets(word, run_time=tpc * len(word)), Animation(word, run_time=0.005 * len(word)**1.5), ] for word in text_mobject ]) super().__init__(*anims, **kwargs)
def get_logo_animations(self, logo): layers = logo.spike_layers for j, layer in enumerate(layers): for i, spike in enumerate(layer): spike.angle = (13 * (i + 1) * (j + 1) * TAU / 28) % TAU if spike.angle > PI: spike.angle -= TAU spike.save_state() spike.rotate(spike.angle, about_point=ORIGIN) # spike.get_points()[1] = rotate_vector( # spike.get_points()[1], TAU/28, # ) # spike.get_points()[-1] = rotate_vector( # spike.get_points()[-1], -TAU/28, # ) def get_spike_animation(spike, **kwargs): return Restore(spike, path_arc=-spike.angle, **kwargs) logo.iris_background.save_state() # logo.iris_background.scale(0.49) logo.iris_background.set_fill(GREY_D, 0.5) return [ Restore( logo.iris_background, rate_func=squish_rate_func(smooth, 2.0 / 3, 1), run_time=3, ), AnimationGroup(*[ LaggedStartMap( get_spike_animation, layer, run_time=2, # rate_func=squish_rate_func(smooth, a / 3.0, (a + 0.9) / 3.0), lag_ratio=0.2, ) for layer, a in zip(layers, [0, 2, 1, 0]) ]), Animation(logo.pupil), ]
def show_border_and_reflines(self): self.set_camera_orientation(*DIAG_POS) self.wait() init_ct = self.cts[0] border = init_ct.get_border() reflines = Reflines(init_ct) self.play(ShowCreation(border)) self.wait(3) self.play( Write(reflines, rate_func=smooth, submobject_mode="lagged_start"), Animation(border), run_time=3, ) self.play( Indicate(VGroup(border, reflines), scale_factor=1.05), run_time=2, ) self.wait() self.border = border self.reflines = reflines
def construct(self): number_line = NumberLine(x_min=-2, x_max=2) text = TextMobject("Text") \ .next_to(number_line, DOWN) dashed_line = DashedLine( number_line.get_left(), number_line.get_right(), color=YELLOW, ).set_stroke(width=11) self.add(number_line) self.wait(0.3) self.play( LaggedStart(*[ ShowCreationThenDestruction(dashed_segment) for dashed_segment in dashed_line ], run_time=5), AnimationGroup(Animation(Mobject(), run_time=2.1), Write(text), lag_ratio=1)) self.wait()
def __init__(self, mobject, path, **kwargs): digest_config(self, kwargs, locals()) Animation.__init__(self, mobject, **kwargs)
def __init__(self, tex_list, **kwargs): mobject = TexMobject(self.curr_tex).shift(start_center) Animation.__init__(self, mobject, **kwargs)
def __init__(self, *args, **kwargs): """ Each arg will either be an animation, or an animation class followed by its arguments (and potentially a dict for configuration). """ animations = [] state = { "animations": animations, "curr_class": None, "curr_class_args": [], "curr_class_config": {}, } def invoke_curr_class(state): if state["curr_class"] is None: return anim = state["curr_class"]( *state["curr_class_args"], **state["curr_class_config"] ) state["animations"].append(anim) anim.update(1) state["curr_class"] = None state["curr_class_args"] = [] state["curr_class_config"] = {} for arg in args: if isinstance(arg, Animation): animations.append(arg) arg.update(1) invoke_curr_class(state) elif isinstance(arg, type) and issubclass(arg, Animation): invoke_curr_class(state) state["curr_class"] = arg elif isinstance(arg, dict): state["curr_class_config"] = arg else: state["curr_class_args"].append(arg) invoke_curr_class(state) for anim in animations: anim.update(0) animations = [x for x in animations if not(x.empty)] self.run_times = [anim.run_time for anim in animations] if "run_time" in kwargs: run_time = kwargs.pop("run_time") warnings.warn( "Succession doesn't currently support explicit run_time.") run_time = sum(self.run_times) self.num_anims = len(animations) if self.num_anims == 0: self.empty = True self.animations = animations # Have to keep track of this run_time, because Scene.play # might very well mess with it. self.original_run_time = run_time # critical_alphas[i] is the start alpha of self.animations[i] # critical_alphas[i + 1] is the end alpha of self.animations[i] critical_times = np.concatenate(([0], np.cumsum(self.run_times))) self.critical_alphas = [np.true_divide( x, run_time) for x in critical_times] if self.num_anims > 0 else [0.0] # self.scene_mobjects_at_time[i] is the scene's mobjects at start of self.animations[i] # self.scene_mobjects_at_time[i + 1] is the scene mobjects at end of self.animations[i] self.scene_mobjects_at_time = [None for i in range(self.num_anims + 1)] self.scene_mobjects_at_time[0] = Group() for i in range(self.num_anims): self.scene_mobjects_at_time[i + 1] = self.scene_mobjects_at_time[i].copy() self.animations[i].clean_up(self.scene_mobjects_at_time[i + 1]) self.current_alpha = 0 # If self.num_anims == 0, this is an invalid index, but so it goes self.current_anim_index = 0 if self.num_anims > 0: self.mobject = self.scene_mobjects_at_time[0] self.mobject.add(self.animations[0].mobject) else: self.mobject = Group() Animation.__init__(self, self.mobject, run_time=run_time, **kwargs)
def __init__(self, *args, **kwargs): return Animation.__init__(self, Group(), *args, **kwargs)
def __init__(self, vmobject, **kwargs): if not isinstance(vmobject, VMobject): raise Exception("DrawBorderThenFill only works for VMobjects") self.reached_halfway_point_before = False Animation.__init__(self, vmobject, **kwargs)
def __init__(self, word, **kwargs): assert (isinstance(word, SingleStringTexMobject)) digest_config(self, kwargs) run_time = kwargs.pop("run_time", self.time_per_char * len(word)) Animation.__init__(self, word, run_time=run_time, **kwargs)
def update_config(self, **kwargs): Animation.update_config(self, **kwargs) if "path_arc" in kwargs: self.path_func = path_along_arc(kwargs["path_arc"], kwargs.get("path_arc_axis", OUT))
def construct(self): # Add title title = self.title = TextMobject("Clicky Stuffs") title.scale(1.5) title.to_edge(UP, buff=MED_SMALL_BUFF) pi_creatures = VGroup(Randolph(), Mortimer()) for pi, vect in zip(pi_creatures, [LEFT, RIGHT]): pi.set_height(title.get_height()) pi.change_mode("thinking") pi.look(DOWN) pi.next_to(title, vect, buff=MED_LARGE_BUFF) self.add(title, pi_creatures) # Set the top of the screen logo_box = Square(side_length=2.5) logo_box.to_corner(DOWN + LEFT, buff=MED_LARGE_BUFF) black_rect = Rectangle( fill_color=BLACK, fill_opacity=1, stroke_width=3, stroke_color=BLACK, width=FRAME_WIDTH, height=0.6 * FRAME_HEIGHT, ) black_rect.to_edge(UP, buff=0) line = DashedLine(FRAME_X_RADIUS * LEFT, FRAME_X_RADIUS * RIGHT) line.move_to(ORIGIN) # Add thanks thanks = TextMobject(self.thanks_words) thanks.scale(0.9) thanks.next_to(black_rect.get_bottom(), UP, SMALL_BUFF) thanks.set_color(YELLOW) underline = Line(LEFT, RIGHT) underline.match_width(thanks) underline.scale(1.1) underline.next_to(thanks, DOWN, SMALL_BUFF) thanks.add(underline) # Build name list file_name = os.path.join(get_directories()["data"], "patrons.txt") with open(file_name, "r") as fp: names = [ self.modify_patron_name(name.strip()) for name in fp.readlines() ] if self.randomize_order: random.shuffle(names) else: names.sort() name_labels = VGroup(*map(TextMobject, names)) name_labels.scale(self.patron_scale_val) for label in name_labels: if label.get_width() > self.max_patron_width: label.set_width(self.max_patron_width) columns = VGroup(*[ VGroup(*name_labels[i::self.n_patron_columns]) for i in range(self.n_patron_columns) ]) column_x_spacing = 0.5 + max([c.get_width() for c in columns]) for i, column in enumerate(columns): for n, name in enumerate(column): name.shift(n * self.name_y_spacing * DOWN) name.align_to(ORIGIN, LEFT) column.move_to(i * column_x_spacing * RIGHT, UL) columns.center() max_width = FRAME_WIDTH - 1 if columns.get_width() > max_width: columns.set_width(max_width) underline.match_width(columns) columns.next_to(underline, DOWN, buff=3) # Set movement columns.generate_target() distance = columns.get_height() + 2 wait_time = self.scroll_time frame = self.camera.frame frame_shift = ApplyMethod( frame.shift, distance * DOWN, run_time=wait_time, rate_func=linear, ) blink_anims = [] blank_mob = Mobject() for x in range(wait_time): if random.random() < 0.25: blink_anims.append(Blink(random.choice(pi_creatures))) else: blink_anims.append(Animation(blank_mob)) blinks = Succession(*blink_anims) static_group = VGroup(black_rect, line, thanks, pi_creatures, title) static_group.fix_in_frame() self.add(columns, static_group) self.play(frame_shift, blinks)