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.set_color(X_COLOR) y_line.set_color(Y_COLOR) x_coord, y_coord = array.get_mob_matrix().flatten() self.play(Write(array, run_time=1)) self.wait() 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.wait() if clean_up: self.clear() self.add(*starting_mobjects)
def add_lines(self, left, right): line_kwargs = { "color": BLUE, "stroke_width": 2, } left_rows = [VGroup(*row) for row in left.get_mob_matrix()] h_lines = VGroup() 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 = [ VGroup(*col) for col in np.transpose(right.get_mob_matrix()) ] v_lines = VGroup() 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 construct(self): # Setup pos_axis = NumberLine(x_min=-3.5, x_max=3.5, color=WHITE) pos_axis.rotate(np.pi / 2) pos_axis.add_tip() time_axis = NumberLine(x_min=0, x_max=9.5, color=WHITE) time_axis.add_tip() house = House() house.rotate(np.pi / 2) house.place_on(pos_axis.number_to_point(0)) zero_drunk = Drunk(direction=UP, color=self.zero_color) zero_drunk.step_on(pos_axis.number_to_point(0)) neg_drunk = Drunk(direction=UP, color=self.neg_color) neg_drunk.step_on(pos_axis.number_to_point(0)) group = VGroup(house, VGroup(pos_axis, time_axis), zero_drunk, neg_drunk) group.to_edge(LEFT) pos_text = TextMobject("位置") pos_text.next_to(pos_axis.number_to_point(3.5), LEFT) time_text = TextMobject("时间") time_text.next_to(time_axis.number_to_point(9.5), DOWN) self.add(group, pos_text, time_text) old_zero_drunk = zero_drunk.copy() old_neg_drunk = neg_drunk.copy() # Start Wandering zero_sequence = "UUUDDDDU" zero_walk = RandomWalk1DArrow( zero_sequence, up_color=self.zero_color, down_color=self.zero_color, ) zero_walk.move_start_to(pos_axis.number_to_point(0)) neg_sequence = "DDUDDUDU" neg_walk = RandomWalk1DArrow( neg_sequence, up_color=self.neg_color, down_color=self.neg_color, ) neg_walk.move_start_to(pos_axis.number_to_point(0)) for k, (zero_char, neg_char) in enumerate(zip(zero_sequence, neg_sequence)): zero_increment = 1 if zero_char == "U" else -1 neg_increment = 1 if neg_char == "U" else -1 zero_arrow = zero_walk.get_arrow_by_number(k) neg_arrow = neg_walk.get_arrow_by_number(k) self.play(DrunkWander(zero_drunk, zero_increment, direction=UP), DrunkWander(neg_drunk, neg_increment, direction=UP), ShowCreation(zero_arrow), ShowCreation(neg_arrow)) self.wait() # Reset self.play( Transform(zero_drunk, old_zero_drunk), Transform(neg_drunk, old_neg_drunk), FadeOut(zero_walk), FadeOut(neg_walk), ) self.wait()
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.set_color(X_COLOR) y_line.set_color(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.wait() 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.wait() 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 add_vector(self, vector, color=YELLOW, animate=True, **kwargs): if not isinstance(vector, Arrow): vector = Vector(vector, color=color, **kwargs) if animate: self.play(ShowCreation(vector)) self.add(vector) return vector
def add_T_label(self, x_val, side=RIGHT, label=None, color=WHITE, animated=False, **kwargs): triangle = RegularPolygon(n=3, start_angle=np.pi / 2) triangle.scale_to_fit_height(MED_SMALL_BUFF) triangle.move_to(self.coords_to_point(x_val, 0), UP) triangle.set_fill(color, 1) triangle.set_stroke(width=0) if label == None: T_label = TexMobject(self.variable_point_label, fill_color=color) else: T_label = TexMobject(label, fill_color=color) T_label.next_to(triangle, DOWN) v_line = self.get_vertical_line_to_graph(x_val, self.v_graph, color=YELLOW) if animated: self.play(DrawBorderThenFill(triangle), ShowCreation(v_line), Write(T_label, run_time=1), **kwargs) if np.all(side == LEFT): self.left_T_label_group = VGroup(T_label, triangle) self.left_v_line = v_line self.add(self.left_T_label_group, self.left_v_line) elif np.all(side == RIGHT): self.right_T_label_group = VGroup(T_label, triangle) self.right_v_line = v_line self.add(self.right_T_label_group, self.right_v_line)
def update_labels(self, new_labels, **kwargs): assert (type(new_labels) == OrderedDict) # make sure labels are different for old_label in self.labels.values(): for new_label in new_labels.values(): assert (id(old_label) != id(new_label)) anims = [] # delete for key, val in new_labels.items(): if val is None: anims.append(Uncreate(self.labels[key])) self.remove(self.labels[key]) del new_labels[key] del self.labels[key] # scale for label in new_labels.values(): if type(label) == Arrow: continue # TODO scale_factor = self.get_label_scale_factor(label, len(new_labels)) label.scale(scale_factor) # place new_labels = self.place_labels(new_labels, **kwargs) # animate if "animate" not in kwargs or kwargs["animate"]: for name in new_labels.keys(): if name in self.labels: anims.extend([ ReplacementTransform(self.labels[name], new_labels[name], parent=self) ]) else: anims.extend([ShowCreation(new_labels[name])]) self.add(new_labels[name]) for name in self.labels: if name not in new_labels: anims.extend([Uncreate(self.labels[name])]) self.remove(self.labels[name]) else: for name in new_labels.keys(): if name not in self.labels: self.add(new_labels[name]) else: self.add(new_labels[name]) self.remove(self.labels[name]) for name in self.labels: if name not in new_labels: self.remove(self.labels[name]) self.labels = new_labels return anims
def construct(self): # Setup self.set_camera_orientation(phi = np.pi/3, theta = 3*np.pi/4) self.begin_ambient_camera_rotation(np.pi/50) # Part 1: Increasing the order for order in range(1, self.max_order+1): if order == 1: fractal = HilbertCurve3D(order = 1) self.play(ShowCreation(fractal), run_time = 2) cur_order = fractal.order else: new_fractal = HilbertCurve3D(order = cur_order + 1) self.play(Transform(fractal, new_fractal)) cur_order = new_fractal.order self.wait(2) self.wait(5) self.play(FadeOut(fractal)) self.wait(3) # Part 2: Show one-touch construction self.play(ShowCreation(fractal, run_time = 60)) self.wait(5) # Part 3: Decreasing the order till it vanishes for k in reversed(range(1, self.max_order)): new_fractal = HilbertCurve3D(order = cur_order - 1) self.play(Transform(fractal, new_fractal)) cur_order = new_fractal.order self.wait(2) self.play(Uncreate(fractal), run_time = 1) # The end self.stop_ambient_camera_rotation() self.set_camera_orientation(phi = 0, theta = -np.pi/2) author = TextMobject("@Solara570") author.scale(1.5) author.to_corner(RIGHT+DOWN) self.play(FadeIn(author), run_time = 1) self.wait(2)
def add_unit_square(self, color=YELLOW, opacity=0.3, animate=False): square = Square(color=color, side_length=1) square.shift(-square.get_corner(DOWN + LEFT)) if animate: added_anims = map(Animation, self.moving_vectors) self.play(ShowCreation(square), *added_anims) self.play(square.set_fill, color, opacity, *added_anims) else: square.set_fill(color, opacity) self.add_transformable_mobject(square) self.bring_to_front(*self.moving_vectors) self.square = square return self
def get_digit_increment_animations(self): result = [] self.number += 1 is_next_digit = self.is_next_digit() if is_next_digit: self.max_place += 1 new_number_mob = self.get_number_mob(self.number) new_number_mob.move_to(self.number_mob, RIGHT) if is_next_digit: self.add_configuration() place = len(new_number_mob.split()) - 1 result.append(FadeIn(self.dot_templates[place])) arrow = Arrow(new_number_mob[place].get_top(), self.dot_templates[place].get_bottom(), color=self.digit_place_colors[place]) self.arrows.add(arrow) result.append(ShowCreation(arrow)) result.append( Transform(self.number_mob, new_number_mob, submobject_mode="lagged_start")) return result
def place_cursors(self, indices=None, block=None): """ place cursors on the blocks denoted by indices if it was passed, otherwise the blocks denoted by self.cursor_indices """ if indices is None and len(self.cursor_indices) == 0: raise Exception("no indices to use") elif indices is None: indices = self.cursor_indices if block is None: cur_block = self else: cur_block = block cursors = [] for block_idx in indices: cur_block = cur_block.submobjects[block_idx] cursor = TexMobject("\\blacktriangleright") cursor.next_to(cur_block[0], LEFT) cursors.append(cursor) self.cursors.extend(cursors) return [ShowCreation(Group(*cursors))]
def construct(self): # Setup pos_axis = NumberLine(x_min=-3.5, x_max=3.5, color=WHITE) pos_axis.rotate(np.pi / 2) pos_axis.add_tip() time_axis = NumberLine(x_min=0, x_max=9.5, color=WHITE) time_axis.add_tip() house = House() house.rotate(np.pi / 2) house.place_on(pos_axis.number_to_point(0)) drunk = Drunk(direction=UP) drunk.step_on(pos_axis.number_to_point(0)) group = VGroup(house, VGroup(pos_axis, time_axis), drunk) group.to_edge(LEFT) pos_text = TextMobject("位置") pos_text.next_to(pos_axis.number_to_point(3.5), LEFT) time_text = TextMobject("时间") time_text.next_to(time_axis.number_to_point(9.5), DOWN) self.add(group, pos_text, time_text) old_drunk = drunk.copy() # Start Wandering sequence = "UDUDDDUD" random_walk = RandomWalk1DArrow(sequence) random_walk.move_start_to(pos_axis.number_to_point(0)) for k, walk_char in enumerate(sequence): increment = 1 if walk_char == "U" else -1 arrow = random_walk.get_arrow_by_number(k) self.play( DrunkWander(drunk, increment, direction=UP), ShowCreation(arrow), ) self.wait() # Reset self.play(Transform(drunk, old_drunk), FadeOut(random_walk)) self.wait()
def add_axes(self, animate=False, color=WHITE, **kwargs): axes = Axes(color=color, tick_frequency=1) if animate: self.play(ShowCreation(axes, submobject_mode="one_at_a_time")) self.add(axes) return axes
def add_plane(self, animate=False, **kwargs): plane = NumberPlane(**kwargs) if animate: self.play(ShowCreation(plane, submobject_mode="lagged_start")) self.add(plane) return plane
def construct(self): # Setup axes_group = self.axes_group pos_axis, time_axis = axes_group[:2] title_pq = self.title_pq walk_q = self.walk_q parts_q = self.parts_q l_arrow = self.l_arrow self.add(axes_group, title_pq, walk_q, l_arrow) walk_q_copy = walk_q.copy() # Q_4 -> P_4 steps_qp = VGroup(*[ TextMobject(text) for text in [ "1. 找到路径终点的位置坐标$h$", "2. 找到最晚一次穿过$\\frac{h}{2}$的时刻", "3. 在这个时刻上进行分割", "4. 将第一段水平翻转", "5. 拼接两个片段" ] ]) for step in steps_qp: step.set_color(YELLOW) step.add_background_rectangle() step1_qp, step2_qp, step3_qp, step4_qp, step5_qp = steps_qp # 1. Find the endpoint step1_qp.next_to(time_axis.number_to_point(4.5), UP) end_horiz_line = DashedLine(LEFT_SIDE, RIGHT_SIDE, color=YELLOW) end_horiz_line.move_to(pos_axis.number_to_point(-4)) end_horiz_line.horizontally_center() end_brace_line = DashedLine(time_axis.number_to_point(8), walk_q.get_end_point()) end_brace = Brace(end_brace_line, direction=RIGHT, color=YELLOW) h = TexMobject("h").set_color(YELLOW) end_brace.put_at_tip(h) self.play(Write(step1_qp), ShowCreation(end_horiz_line), run_time=1) self.play(GrowFromCenter(end_brace), GrowFromCenter(h)) self.wait(1.5) self.play(FadeOut(step1_qp)) # 2. Find the last time it GOES THROUGH half its final value half_point = walk_q.get_arrow_end_point(3) step2_qp.next_to(time_axis.number_to_point(4.5), UP) half_horiz_line = end_horiz_line.copy().shift(2 * UP) half_brace_line = DashedLine(time_axis.number_to_point(4), half_point) half_brace = Brace(half_brace_line, direction=RIGHT, color=YELLOW) half_h = TexMobject("\\frac{h}{2}").set_color(YELLOW) half_brace.put_at_tip(half_h) half_dot = Dot(half_point, color=YELLOW) self.play(FadeIn(step2_qp), run_time=1) self.wait(0.5) self.play( ReplacementTransform(end_brace, half_brace), ReplacementTransform(end_horiz_line, half_horiz_line), ReplacementTransform(h, half_h[0]), Write(half_h[1:]), ) self.play(DrawBorderThenFill(half_dot)) self.wait(1.5) self.play( FadeOut(VGroup(step2_qp, half_horiz_line, half_brace, half_h))) # 3. Split vert_line = DashedLine(2.5 * UP, 2.5 * DOWN, color=YELLOW) vert_line.move_to(half_point) step3_qp.next_to(vert_line, UP) left_part_q, right_part_q = parts_q self.play(ShowCreation(vert_line), Write(step3_qp), run_time=1) self.play( FadeOut(half_dot), left_part_q.shift, 0.5 * DOWN + 0.5 * LEFT, right_part_q.shift, 0.5 * UP + 0.5 * RIGHT, ) self.wait(1.5) self.play(FadeOut(vert_line), FadeOut(step3_qp)) # 4. Flip the first segment horizontally flip_axis = DashedLine(2 * UP, 2 * DOWN, color=GREY) flip_axis.move_to(left_part_q) step4_qp.next_to(flip_axis, DOWN) self.play( ShowCreation(flip_axis), Write(step4_qp), run_time=1, ) self.play( left_part_q.flip, Animation(flip_axis), ) self.wait(1.5) self.play(FadeOut(step4_qp), FadeOut(flip_axis)) # 5. Put the pieces together step5_qp.shift(2.5 * DOWN) flip_arrow_anims = walk_q.get_flip_arrows_animation(3, color=ORANGE) self.play(Write(step5_qp), run_time=1) self.wait(0.5) self.play(flip_arrow_anims, right_part_q.set_color, ORANGE) self.wait(0.5) self.play( left_part_q.shift, 2.5 * UP + 0.5 * RIGHT, right_part_q.shift, 3.5 * UP + 0.5 * LEFT, Animation(step5_qp), ) self.wait(0.5) self.play(FadeOut(step5_qp)) self.wait(1.5) # Now Reset self.play(FadeOut(walk_q)) self.play(FadeIn(walk_q_copy)) self.wait()
def construct(self): # Setup axes_group = self.axes_group title_pq = self.title_pq walk_p = self.walk_p parts_p = self.parts_p r_arrow = self.r_arrow self.add(axes_group, title_pq, walk_p, r_arrow) walk_p_copy = walk_p.copy() # P_4 -> Q_4 steps_pq = VGroup(*[ TextMobject(text) for text in [ "1. 第一步是沿着正方向走的", "2. 找到第一次到达最大值的时刻", "3. 在这个时刻上进行分割", "4. 将第一段水平翻转", "5. 拼接两个片段" ] ]) for step in steps_pq: step.set_color(YELLOW) step.add_background_rectangle() step1_pq, step2_pq, step3_pq, step4_pq, step5_pq = steps_pq # 1. Check the first step of the walk step1_circle = Circle(color=YELLOW) first_arrow = walk_p.get_arrow_by_number(0) step1_circle.surround(first_arrow) step1_pq.next_to(step1_circle, RIGHT + DOWN) self.play(ShowCreation(step1_circle), Write(step1_pq), run_time=1) self.wait(1.5) self.play(FadeOut(step1_circle), FadeOut(step1_pq)) # 2. Find the first time it reaches the maximum peak = walk_p.get_arrow_end_point(3) horiz_line = DashedLine(2.5 * LEFT, 2.5 * RIGHT, color=YELLOW) horiz_line.move_to(peak) dot = Dot(color=YELLOW) dot.move_to(peak) step2_pq.next_to(horiz_line, UP) self.play(ShowCreation(horiz_line), DrawBorderThenFill(dot), Write(step2_pq), run_time=1) self.wait(1.5) self.play(FadeOut(horiz_line), FadeOut(step2_pq)) # 3. Split vert_line = DashedLine(2.5 * UP, 2.5 * DOWN, color=YELLOW) vert_line.move_to(peak) step3_pq.next_to(vert_line, DOWN) left_part_p, right_part_p = parts_p self.play(ShowCreation(vert_line), Write(step3_pq), run_time=1) self.play( FadeOut(dot), left_part_p.shift, 0.5 * DOWN + 0.5 * LEFT, right_part_p.shift, DOWN + 0.5 * RIGHT, ) self.wait(1.5) self.play(FadeOut(vert_line), FadeOut(step3_pq)) # 4. Flip the first segment horizontally flip_axis = DashedLine(2 * UP, 2 * DOWN, color=GREY) flip_axis.move_to(left_part_p) step4_pq.next_to(flip_axis, DOWN) self.play( ShowCreation(flip_axis), Write(step4_pq), run_time=1, ) self.play( left_part_p.flip, Animation(flip_axis), ) self.wait(1.5) self.play(FadeOut(step4_pq), FadeOut(flip_axis)) # 5. Put the pieces together step5_pq.move_to(dot) flip_arrow_anims = walk_p.get_flip_arrows_animation(3, color=GREEN) self.play(Write(step5_pq), run_time=1) self.wait(0.5) self.play(flip_arrow_anims, right_part_p.set_color, GREEN) self.wait(0.5) self.play( left_part_p.shift, 1.5 * DOWN + 0.5 * RIGHT, right_part_p.shift, 3 * DOWN + 0.5 * LEFT, Animation(step5_pq), ) self.wait(0.5) self.play(FadeOut(step5_pq)) self.wait(1.5) # Now Reset self.play(FadeOut(walk_p)) self.play(FadeIn(walk_p_copy)) self.wait()