def construct(self): # Generate transformation animations of the twin dragon curve anims = list() fractal = VMobject() fractal.shift(UP) for order in range(-1, self.max_order + 1): new_fractal = TwinDragon(order=order) new_fractal.shift(UP) run_time = 0.5 if order >= 0 else 0 anims.append( Transform( fractal, new_fractal, submobject_mode="all_at_once", run_time=run_time, )) fractal = new_fractal # Add the channel name text = TextMobject("Solara570") text.scale(2).to_edge(DOWN, buff=1.2) # Now sit back and watch self.play( Succession(*anims, rate_func=smooth), Write(text, lag_factor=2.5), run_time=4.5, )
def construct(self): formula = TexMobject(*([ "{%d \\over %d} \\cdot" % (wallis_numer(n), wallis_denom(n)) for n in range(1, self.n_terms + 1) ] + ["\\cdots"])) result = TexMobject("=", "{\\pi \\over 2}") result.scale(2) pi = result[-1][0] pi.set_color(YELLOW) circle = Circle(color=YELLOW) circle.surround(pi) question = TexMobject("?", color=YELLOW) question.scale(2).next_to(circle, RIGHT, buff=0.4) result_group = VGroup(result, circle, question) result_group.next_to(formula, DOWN) group = VGroup(formula, result_group) group.center().set_width(10) bg_rect = BackgroundRectangle(group, fill_opacity=0.5, buff=0.2) random_walks = VGroup(*[ RandomWalk1DArrow(random_walk_string(30), step_size=0.5) for k in range(self.n_walks) ]) for k, walk in enumerate(random_walks): walk.shift(random.randrange(-5, 5) * 2 * walk.step_size * UP) random_walks.center() text = TextMobject(self.part).scale(3).set_color(YELLOW) text.to_corner(RIGHT + DOWN) self.add(random_walks) self.add(FullScreenFadeRectangle()) self.add(bg_rect, group, text)
def ask_to_solve(self): question = TextMobject("解", "方程($x>0$)", ":") solve = TextMobject("解", ":") for tex in (question, solve): tex.scale(1.2) tex.to_corner(LEFT+UP) self.play(Write(question), run_time = 1) self.wait() self.question = question self.solve = solve
def add_title(self, title, scale_factor=1.5, animate=False): if not isinstance(title, Mobject): title = TextMobject(title).scale(scale_factor) title.to_edge(UP) title.add_background_rectangle() if animate: self.play(Write(title)) self.add_foreground_mobject(title) self.title = title return self
def add_words(self): # Wallis product product = TexMobject(*(["\\text{Wallis公式:}"] + [ "{%d \\over %d} \\," % (wallis_numer(n), wallis_denom(n)) for n in range(1, 8) ] + ["\\cdots = {\\pi \\over 2}"])).set_color(YELLOW) rect = SurroundingRectangle(product, color=YELLOW, buff=0.25) wallis_product = VGroup(product, rect) wallis_product.set_width(6) # All those steps nums = [TextMobject("%d. " % k) for k in [1, 2, 3, 4]] words = [ TextMobject(word) for word in [ "构造合适的矩形边长", "同种颜色的矩形的面积之和恒为1", "整个图形又像一个${1 \\over 4}$圆,半径是", "比较${1 \\over 4}$圆与矩形的面积", ] ] formulae = [ TextMobject(formula) for formula in [ "$a_0 = 1,\\, a_n = {1 \\over 2} \cdot {3 \\over 4} \cdots {2n-1 \\over 2n} (n \geq 1)$", "$a_0 a_n + a_1 a_{n-1} + \\cdots + a_n a_0 = 1$", "$\\begin{aligned} \ r_n & = a_0 + a_1 + \\cdots + a_{n-1} \\\\ \ & = \\textstyle{3 \\over 2} \cdot {5 \\over 4} \cdots {2n-1 \\over 2n-2} \ \\quad (n \geq 2) \ \\end{aligned}$", "${1 \\over 4} \\pi {r_n}^2 \\approx n \\quad \\Rightarrow \\quad \\text{Wallis公式}$" ] ] steps = VGroup() for num, word, formula in zip(nums, words, formulae): num.next_to(word, LEFT) formula.next_to(word, DOWN, aligned_edge=LEFT) steps.add(VGroup(num, word, formula)) steps.arrange_submobjects(DOWN, buff=0.6, aligned_edge=LEFT) steps.set_width(6) steps.next_to(wallis_product, DOWN) VGroup(wallis_product, steps).center().to_edge(RIGHT, buff=0.15) # Sep line and QED sep_line = DashedLine(2 * TOP, 2 * BOTTOM, color=GREY, buff=0.5) sep_line.next_to(steps, LEFT) qed = QEDSymbol(height=0.570 / 2) qed.next_to(steps[-1][-1][-1], RIGHT, aligned_edge=DOWN) # Add everything self.add(wallis_product, steps, sep_line, qed)
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 __init__(self, mob_or_text, **kwargs): digest_config(self, kwargs) if isinstance(mob_or_text, str): mobject = TextMobject(mob_or_text) else: mobject = mob_or_text if "run_time" not in kwargs: self.establish_run_time(mobject) if "lag_factor" not in kwargs: if len(mobject.family_members_with_points()) < 4: min_lag_factor = 1 else: min_lag_factor = 2 self.lag_factor = max(self.run_time - 1, min_lag_factor) ShowCreation.__init__(self, mobject, **kwargs)
def __init__(self, mob_or_text, **kwargs): digest_config(self, kwargs) if isinstance(mob_or_text, str): mobject = TextMobject(mob_or_text) else: mobject = mob_or_text if "run_time" not in kwargs: self.establish_run_time(mobject) if "lag_factor" not in kwargs: if len(mobject.family_members_with_points()) < 4: min_lag_factor = 1 else: min_lag_factor = 2 self.lag_factor = max(self.run_time - 1, min_lag_factor) ShowCreation.__init__(self, mobject, **kwargs)
def tex(self, latex): eq = TextMobject(latex) anims = [] anims.append(Write(eq)) for mobject in self.mobjects: anims.append(ApplyMethod(mobject.shift, 2 * UP)) self.play(*anims)
def construct(self): author = TextMobject("@Solara570") support = TextMobject("(Powered by @3Blue1Brown)") author.scale(1.8) support.match_width(author) group = VGroup(author, support) group.arrange_submobjects(DOWN) group.to_corner(RIGHT+DOWN) self.play(FadeIn(group)) self.wait(2)
def generate_points(self): rect = SurroundingRectangle(self.covered_mob) rect.set_stroke(color = self.stroke_color, width = self.stroke_width) rect.set_fill(color = self.fill_color, opacity = self.fill_opacity) text = TextMobject(str(self.text)) text.set_color(self.text_color) text.set_height(rect.get_height() * self.text_height_factor) text.move_to(rect) self.group = VGroup(rect, text) self.add(self.group)
def get_det_text(matrix, determinant=None, background_rect=True, initial_scale_factor=2): parens = TexMobject(["(", ")"]) parens.scale(initial_scale_factor) parens.stretch_to_fit_height(matrix.get_height()) l_paren, r_paren = parens.split() l_paren.next_to(matrix, LEFT, buff=0.1) r_paren.next_to(matrix, RIGHT, buff=0.1) det = TextMobject("det").next_to(l_paren, LEFT, buff=0.1) if background_rect: det.add_background_rectangle() det_text = VMobject(det, l_paren, r_paren) if determinant is not None: eq = TexMobject("=") eq.next_to(r_paren, RIGHT, buff=0.1) result = TexMobject(str(determinant)) result.next_to(eq, RIGHT, buff=0.2) det_text.add(eq, result) return det_text
def get_corner_numbers(self, value, symbol): value_mob = TextMobject(value) width = self.get_width() / self.card_width_to_corner_num_width height = self.get_height() / self.card_height_to_corner_num_height value_mob.scale_to_fit_width(width) value_mob.stretch_to_fit_height(height) value_mob.next_to(self.get_corner(UP + LEFT), DOWN + RIGHT, buff=MED_LARGE_BUFF * width) value_mob.set_color(symbol.get_color()) corner_symbol = symbol.copy() corner_symbol.scale_to_fit_width(width) corner_symbol.next_to(value_mob, DOWN, buff=MED_SMALL_BUFF * width) corner_group = VGroup(value_mob, corner_symbol) opposite_corner_group = corner_group.copy() opposite_corner_group.rotate(np.pi, about_point=self.get_center()) return VGroup(corner_group, opposite_corner_group)
def setup(self): MovingCameraScene.setup(self) frame = self.camera_frame frame.shift(DOWN) self.logo = Logo() name = TextMobject("3Blue1Brown") name.scale(2.5) name.next_to(self.logo, DOWN, buff=MED_LARGE_BUFF) name.set_sheen(-0.2, DR) self.channel_name = name
def add_title(self, title="Sample space", buff=MED_SMALL_BUFF): # TODO, should this really exist in SampleSpaceScene title_mob = TextMobject(title) if title_mob.get_width() > self.get_width(): title_mob.scale_to_fit_width(self.get_width()) title_mob.next_to(self, UP, buff=buff) self.title = title_mob self.add(title_mob)
def add_title(self): title = self.title = TextMobject("Clicky Stuffs") title.scale(1.5) title.to_edge(UP, buff=MED_SMALL_BUFF) randy, morty = self.pi_creatures = VGroup(Randolph(), Mortimer()) for pi, vect in (randy, LEFT), (morty, 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_foreground_mobjects(title, randy, morty)
def choose_two_special_numbers(self): two_and_four_text = TextMobject("现在选择两个特殊的数...") two_and_four_text.set_color(YELLOW) two_and_four_text.to_edge(UP) self.play(Transform(self.anything_text, two_and_four_text)) self.wait() two_equation = self.equation four_equation = two_equation.copy() self.play(four_equation.to_edge, RIGHT, self.tower_edge_buff) self.wait() nums = [2, 4] colors = [GREEN, RED] equations = [two_equation, four_equation] targets = [equation[1][1] for equation in equations] two, four = num_texs = [ TexMobject(str(num)).set_color(color).match_height(target).move_to(target) for num, color, equation, target in zip(nums, colors, equations, targets) ] for N_tex, num_tex in zip(targets, num_texs): self.play(Transform(N_tex, num_tex)) self.wait(0.5) self.wait(0.5) self.nums = nums self.colors = colors self.equations = equations self.x_towers = VGroup(*[equation[0] for equation in equations])
def rewind_and_play_again(self): watch_again = TextMobject("再看一遍...") watch_again.set_color(YELLOW) rewind, play = buttons = VGroup(*[ Button().get_symbol().set_color(YELLOW).set_height(1) for Button in (RewindButton, PlayButton) ]) group = VGroup(watch_again, rewind) group.arrange_submobjects(DOWN, aligned_edge = RIGHT) group.to_corner(DOWN+RIGHT) play.move_to(rewind, aligned_edge = RIGHT) self.play(Write(watch_again), run_time = 0.5) self.wait() self.add(rewind) self.words.reverse() for word in self.words: self.play(FadeOut(VGroup(word)), run_time = 0.2) self.wait(0.1) self.remove(rewind) self.add(play) self.play(FadeOut(watch_again), run_time = 0.5) self.wait(0.5) self.remove(play)
def get_bubble(self, *content, **kwargs): bubble_class = kwargs.get("bubble_class", ThoughtBubble) bubble = bubble_class(**kwargs) if len(content) > 0: if isinstance(content[0], str): content_mob = TextMobject(*content) else: content_mob = content[0] bubble.add_content(content_mob) if "height" not in kwargs and "width" not in kwargs: bubble.resize_to_content() bubble.pin_to(self) self.bubble = bubble return bubble
def setup(self): frame = self.camera_frame frame.shift(DOWN) self.logo = Logo() name = TextMobject("3Blue1Brown") name.scale(2.5) name.next_to(logo, DOWN, buff=MED_LARGE_BUFF) self.name = name
def add_title(self, title, scale_factor=1.5, animate=False): if not isinstance(title, Mobject): title = TextMobject(title).scale(scale_factor) title.to_edge(UP) title.add_background_rectangle() if animate: self.play(Write(title)) self.add_foreground_mobject(title) self.title = title return self
def rhs_could_be_any_number(self): rhs_list = [ "2", # The journey starts here. "3", # The first number that pops into your head when you hear "2". "\\pi", # The good ol' pi. "\\sqrt{2}", # The (most) famous irrational number. "42", # The answer to everything. "17.29", # TAXI.CAB "-1", # A negative number, because why not? "e", # The (most) famous mathematical constant. "\\dfrac{3+\\sqrt{13}}{2}", # The bronze ratio... and a fraction. "570", # 1/3 of the author. "\\varphi", # The golden ratio. "g_{64}", # Gigigigigigigigantic... "0", # And... stop! "N", ] anything_text = TextMobject("等号右边似乎可以放任何数...") anything_text.set_color(YELLOW) anything_text.to_edge(UP) equations = [ VGroup(ExpTower(order = 5), TexMobject("=", rhs).scale(0.8)).scale(2.5) for rhs in rhs_list ] init_equation = equations[0] init_equation.arrange_submobjects(RIGHT, aligned_edge = DOWN) init_equation.next_to(anything_text, DOWN, buff = self.tower_edge_buff) init_equation.to_edge(LEFT, buff = self.tower_edge_buff) for equation in equations: equation[0].move_to(init_equation[0]) equation[1][0].move_to(init_equation[1][0]) equation[1][1].move_to(init_equation[1][1], aligned_edge = LEFT) self.play(FadeIn(init_equation)) self.wait() self.play(Write(anything_text), run_time = 1) self.play( ShowCreationThenDestruction(SurroundingRectangle(init_equation[1][1])), run_time = 2 ) self.wait() for k, equation in enumerate(equations): if k > 0 and k != len(equations)-1: equation[0].move_to(init_equation[0]) equation[1].move_to(init_equation[1], aligned_edge = LEFT) self.remove(equations[k-1]) self.add(equations[k]) self.wait(1./3) elif k == len(equations)-1: self.wait() self.play(ReplacementTransform(equations[k-1], equations[k])) self.wait() self.anything_text = anything_text self.equation = equations[-1]
def setup(self): pos_axis = NumberLine(x_min=-4.5, x_max=2.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() vec = pos_axis.number_to_point(0) - time_axis.number_to_point(0) time_axis.shift(vec) pos_text = TextMobject("位置") pos_text.next_to(pos_axis.number_to_point(2.5), LEFT) time_text = TextMobject("时间") time_text.next_to(time_axis.number_to_point(9.5), DOWN) axes_group = VGroup(pos_axis, time_axis, pos_text, time_text) axes_group.center() title_pq = TexMobject("P_4", "570", "Q_4") title_pq.scale(1.5) title_pq.to_corner(UP + RIGHT) for part, color in zip(title_pq, [ORANGE, BLACK, GREEN]): part.set_color(color) r_arrow = TexMobject("\\rightarrow") l_arrow = TexMobject("\\leftarrow") for arrow in (r_arrow, l_arrow): arrow.scale(1.5) arrow.move_to(title_pq[1]) sequence_p, sequence_q = sequences = ["UDUUDUDD", "DDUDDUDD"] colors = [ORANGE, GREEN] walk_p, walk_q = walks = [ RandomWalk1DArrow(sequence, up_color = color, down_color = color) \ .move_start_to(pos_axis.number_to_point(0)) for sequence, color in zip(sequences, colors) ] parts_p, parts_q = [walk.split_at(3) for walk in walks] self.axes_group = axes_group self.title_pq = title_pq self.walk_p = walk_p self.walk_q = walk_q self.parts_p = parts_p self.parts_q = parts_q self.r_arrow = r_arrow self.l_arrow = l_arrow
def get_corner_numbers(self, value, symbol): value_mob = TextMobject(value) width = self.get_width() / self.card_width_to_corner_num_width height = self.get_height() / self.card_height_to_corner_num_height value_mob.scale_to_fit_width(width) value_mob.stretch_to_fit_height(height) value_mob.next_to( self.get_corner(UP + LEFT), DOWN + RIGHT, buff=MED_LARGE_BUFF * width ) value_mob.set_color(symbol.get_color()) corner_symbol = symbol.copy() corner_symbol.scale_to_fit_width(width) corner_symbol.next_to( value_mob, DOWN, buff=MED_SMALL_BUFF * width ) corner_group = VGroup(value_mob, corner_symbol) opposite_corner_group = corner_group.copy() opposite_corner_group.rotate( np.pi, about_point=self.get_center() ) return VGroup(corner_group, opposite_corner_group)
def show_comments(self): height = 1.5 simple, but, trap = texts = TextMobject("简单直观", "但是", "暗藏陷阱") texts.scale(1.5) texts.arrange_submobjects(DOWN, buff = 0.8) tick = TickButton() tick.set_height(height) tick.next_to(simple, RIGHT) danger = DangerSign() danger.set_height(height) danger.next_to(trap, LEFT) words = [(simple, tick), (but, ), (danger, trap)] colors = [GREEN, WHITE, RED] for word, color in zip(words, colors): VGroup(word).set_color(color) self.play(FadeIn(VGroup(word)), run_time = 1) self.wait(0.5) self.wait() self.words = words
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 get_det_text(matrix, determinant=None, background_rect=True, initial_scale_factor=2): parens = TexMobject(["(", ")"]) parens.scale(initial_scale_factor) parens.stretch_to_fit_height(matrix.get_height()) l_paren, r_paren = parens.split() l_paren.next_to(matrix, LEFT, buff=0.1) r_paren.next_to(matrix, RIGHT, buff=0.1) det = TextMobject("det") det.scale(initial_scale_factor) det.next_to(l_paren, LEFT, buff=0.1) if background_rect: det.add_background_rectangle() det_text = VMobject(det, l_paren, r_paren) if determinant is not None: eq = TexMobject("=") eq.next_to(r_paren, RIGHT, buff=0.1) result = TexMobject(str(determinant)) result.next_to(eq, RIGHT, buff=0.2) det_text.add(eq, result) return det_text
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 reveal_2_is_4(self): sqrt2_towers = VGroup(*[ ExpTower(element = "\\sqrt{2}", order = 5).match_height(x_tower) \ .move_to(x_tower, aligned_edge = RIGHT) for x_tower in self.x_towers ]) self.play( Transform(self.x_towers, sqrt2_towers, submobject_mode = "lagged_start"), run_time = 2, ) self.wait() self.play(FadeOut(self.rss)) self.wait() two_equals_four = TexMobject("2", "=", "4") for tex, color in zip(two_equals_four, [GREEN, WHITE, RED]): tex.set_color(color) two_equals_four.scale(3) two_equals_four.to_edge(DOWN, buff = 1) sources = VGroup(*[ self.equations[i][j][k].copy() for i, j, k in [(0, 1, 1), (1, 1, 0), (1, 1, 1)] ]) for source, target in zip(sources, two_equals_four): self.play(Transform(source, target)) self.wait() fake_qed = FakeQEDSymbol(order = 2, jagged_percentage = 0.3) fake_qed.next_to(two_equals_four, RIGHT, aligned_edge = DOWN, buff = 1) self.play(FadeIn(fake_qed)) self.wait() issue = TextMobject("思考:\\\\问题在哪?") issue.set_color(YELLOW) issue.to_corner(RIGHT+DOWN) self.play(Write(issue), run_time = 1) self.wait(2)
def get_text(self, *text, **kwargs): text_mob = TextMobject(*text) self.put_at_tip(text_mob, **kwargs) return text_mob
def setup_axes(self, animate=False): # TODO, once eoc is done, refactor this to be less redundant. x_num_range = float(self.x_max - self.x_min) self.space_unit_to_x = self.x_axis_width / x_num_range if self.x_labeled_nums is None: self.x_labeled_nums = [] if self.x_leftmost_tick is None: self.x_leftmost_tick = self.x_min x_axis = NumberLine(x_min=self.x_min, x_max=self.x_max, unit_size=self.space_unit_to_x, tick_frequency=self.x_tick_frequency, leftmost_tick=self.x_leftmost_tick, numbers_with_elongated_ticks=self.x_labeled_nums, color=self.axes_color) x_axis.shift(self.graph_origin - x_axis.number_to_point(0)) if len(self.x_labeled_nums) > 0: if self.exclude_zero_label: self.x_labeled_nums = filter(lambda x: x != 0, self.x_labeled_nums) x_axis.add_numbers(*self.x_labeled_nums) if self.x_axis_label: x_label = TextMobject(self.x_axis_label) x_label.next_to(x_axis.get_tick_marks(), UP + RIGHT, buff=SMALL_BUFF) x_label.shift_onto_screen() x_axis.add(x_label) self.x_axis_label_mob = x_label y_num_range = float(self.y_max - self.y_min) self.space_unit_to_y = self.y_axis_height / y_num_range if self.y_labeled_nums is None: self.y_labeled_nums = [] if self.y_bottom_tick is None: self.y_bottom_tick = self.y_min y_axis = NumberLine( x_min=self.y_min, x_max=self.y_max, unit_size=self.space_unit_to_y, tick_frequency=self.y_tick_frequency, leftmost_tick=self.y_bottom_tick, numbers_with_elongated_ticks=self.y_labeled_nums, color=self.axes_color, line_to_number_vect=LEFT, ) y_axis.shift(self.graph_origin - y_axis.number_to_point(0)) y_axis.rotate(np.pi / 2, about_point=y_axis.number_to_point(0)) if len(self.y_labeled_nums) > 0: if self.exclude_zero_label: self.y_labeled_nums = filter(lambda y: y != 0, self.y_labeled_nums) y_axis.add_numbers(*self.y_labeled_nums) if self.y_axis_label: y_label = TextMobject(self.y_axis_label) y_label.next_to(y_axis.get_tick_marks(), UP + RIGHT, buff=SMALL_BUFF) y_label.shift_onto_screen() y_axis.add(y_label) self.y_axis_label_mob = y_label if animate: self.play(Write(VGroup(x_axis, y_axis))) else: self.add(x_axis, y_axis) self.x_axis, self.y_axis = self.axes = VGroup(x_axis, y_axis) self.default_graph_colors = it.cycle(self.default_graph_colors)
def write(self, *text): self.add_content(TextMobject(*text)) return self
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()