Beispiel #1
0
    def __init__(self,
                 eq1,
                 eq2,
                 regex,
                 regex2=None,
                 map_list=None,
                 align_char=None):
        # align equations
        if align_char:
            difference_vec = \
                self.mob_from_char(eq1, eq1.tex_string, align_char).get_center() - \
                self.mob_from_char(eq2, eq2.tex_string, align_char).get_center()
        else:
            difference_vec = eq1.get_center() - eq2.get_center()
        eq2.shift(difference_vec)

        if regex2 is None:
            g1 = self.split_by_regex(eq1, regex)
            g2 = self.split_by_regex(eq2, regex)
            assert (len(g1.submobjects) == len(g2.submobjects))
            trans = ReplacementTransform(g1, g2)
            AnimationGroup.__init__(self, trans)
        else:
            assert (map_list)
            g1 = self.split_by_regex(eq1, regex)
            g2 = self.split_by_regex(eq2, regex2)
            self.g1 = g1
            self.g2 = g2
            G1 = VGroup()
            G2 = VGroup()
            F1 = Group()
            F2 = Group()
            g1_nodes = set(pair[0] for pair in map_list)
            g2_nodes = set(pair[1] for pair in map_list)
            while map_list:
                l1 = [g1.submobjects[map_list[0][0]]]
                l2 = [g2.submobjects[map_list[0][1]]]
                new_list = []
                for i in range(1, len(map_list)):
                    if map_list[i][0] == map_list[0][0]:
                        l2.append(g2.submobjects[map_list[i][1]])
                    elif map_list[i][1] == map_list[0][1]:
                        l1.append(g1.submobjects[map_list[i][0]])
                    else:
                        new_list.append(map_list[i])
                map_list = new_list
                G1.submobjects.append(VGroup(*l1))
                G2.submobjects.append(VGroup(*l2))
            for i in range(len(g1.submobjects)):
                if i not in g1_nodes:
                    F1.submobjects.append(g1.submobjects[i])
            for i in range(len(g2.submobjects)):
                if i not in g2_nodes:
                    F2.submobjects.append(g2.submobjects[i])
            self.g1 = g1
            self.g2 = g2
            trans = ReplacementTransform(G1, G2)
            fadeout = FadeOut(F1)
            fadein = FadeIn(F2)
            AnimationGroup.__init__(self, trans, fadeout, fadein)
    def introduce_bubble(self, *args, **kwargs):
        if isinstance(args[0], PiCreature):
            pi_creature = args[0]
            content = args[1:]
        else:
            pi_creature = self.get_primary_pi_creature()
            content = args

        bubble_class = kwargs.pop("bubble_class", SpeechBubble)
        target_mode = kwargs.pop(
            "target_mode",
            "thinking" if bubble_class is ThoughtBubble else "speaking"
        )
        bubble_kwargs = kwargs.pop("bubble_kwargs", {})
        bubble_removal_kwargs = kwargs.pop("bubble_removal_kwargs", {})
        added_anims = kwargs.pop("added_anims", [])

        anims = []
        on_screen_mobjects = self.camera.extract_mobject_family_members(
            self.get_mobjects()
        )

        def has_bubble(pi):
            return hasattr(pi, "bubble") and \
                pi.bubble is not None and \
                pi.bubble in on_screen_mobjects

        pi_creatures_with_bubbles = list(filter(has_bubble, self.get_pi_creatures()))
        if pi_creature in pi_creatures_with_bubbles:
            pi_creatures_with_bubbles.remove(pi_creature)
            old_bubble = pi_creature.bubble
            bubble = pi_creature.get_bubble(
                *content,
                bubble_class=bubble_class,
                **bubble_kwargs
            )
            anims += [
                ReplacementTransform(old_bubble, bubble),
                ReplacementTransform(old_bubble.content, bubble.content),
                pi_creature.change_mode, target_mode
            ]
        else:
            anims.append(PiCreatureBubbleIntroduction(
                pi_creature,
                *content,
                bubble_class=bubble_class,
                bubble_kwargs=bubble_kwargs,
                target_mode=target_mode,
                **kwargs
            ))
        anims += [
            RemovePiCreatureBubble(pi, **bubble_removal_kwargs)
            for pi in pi_creatures_with_bubbles
        ]
        anims += added_anims

        self.play(*anims, **kwargs)
Beispiel #3
0
    def solve_the_equations(self):
        rects = VGroup(*[
            CoverRectangle(
                equation[0].get_exponent(), stroke_color = color,
                text = str(num), text_color = color
            )
            for equation, color, num in zip(self.equations, self.colors, self.nums)
        ])
        self.play(DrawBorderThenFill(rects))
        self.wait()

        sps = VGroup()
        for equation, num, color in zip(self.equations, self.nums, self.colors):
            sp = TexMobject("x", "^{%d}" % num, "=", "%d" % num)
            sp[1::2].set_color(color)
            sp.scale(2)
            sp.next_to(equation, DOWN, buff = 1)
            sps.add(sp)

        rss = VGroup()
        for num, sp, color in zip(self.nums, sps, self.colors):
            rs = TexMobject("x", "=", "%d" % num , "^{{1}\\over{%d}}" % num, "=\\sqrt{2}")
            for tex in (rs[2], rs[3][2]):
                tex.set_color(color)
            rs.match_height(sp).move_to(sp)
            rss.add(rs)

        tf_anims = []
        for sp, rs in zip(sps, rss):
            tf_anims.append(ReplacementTransform(sp[0], rs[0]))
            tf_anims.append(ReplacementTransform(sp[1], rs[3][2], path_arc = -TAU/4))
            tf_anims.append(ReplacementTransform(sp[2], rs[1]))
            tf_anims.append(ReplacementTransform(sp[3], rs[2]))
            tf_anims.append(Write(rs[3][:2]))

        self.play(FadeIn(sps))
        self.wait()
        self.play(AnimationGroup(*tf_anims), run_time = 2)
        self.wait()
        self.play(Write(VGroup(*[rs[4:] for rs in rss]), submobject_mode = "all_at_once"))
        self.wait()
        self.play(FadeOut(rects))
        self.wait()

        self.rss = rss
Beispiel #4
0
 def teacher_holds_up(self, mobject, target_mode="raise_right_hand", **kwargs):
     mobject.move_to(self.hold_up_spot, DOWN)
     mobject.shift_onto_screen()
     mobject_copy = mobject.copy()
     mobject_copy.shift(DOWN)
     mobject_copy.fade(1)
     self.play(
         ReplacementTransform(mobject_copy, mobject),
         self.teacher.change, target_mode,
     )
Beispiel #5
0
    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]
Beispiel #6
0
 def update_mobject(self, new_mob, animate=True):
     ret = []
     if animate:
         ret.extend(
             [ReplacementTransform(self.mobject, new_mob, parent=self)])
     else:
         if hasattr(self, "mobject"):
             self.remove(self.mobject)
         self.add(new_mob)
     self.mobject = new_mob
     return ret
Beispiel #7
0
    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
Beispiel #8
0
    def build_the_tower(self):
        highest_order = 6
        towers = [
            ExpTower(order = k, is_infinite = False)
            for k in range(1, highest_order + 1)
        ]
        towers.append(ExpTower(order = highest_order, is_infinite = True))
        heights = list(np.linspace(3, 4.5, highest_order + 2))
        for tower, height in zip(towers, heights):
            tower.set_height(height)

        init_tower = towers[0]
        final_tower = towers[-1]
        self.play(Write(init_tower))
        self.wait()
        for k, tower in enumerate(towers):
            if k < len(towers) - 2:
                new_tower = towers[k+1]
                new_exponent = new_tower.get_exponent()
                new_base = new_tower.get_base()
                self.play(
                    ReplacementTransform(tower, new_exponent),
                    Write(new_base),
                )
                self.wait()
            else:
                xs = final_tower.get_elements()
                expdots = final_tower.get_expdots()
                sur_rect = SurroundingRectangle(expdots)
                self.play(
                    ReplacementTransform(tower, xs, run_time = 1),
                    Write(expdots, run_time = 2),
                )
                self.play(
                    Indicate(expdots, run_time = 1),
                    ShowCreationThenDestruction(sur_rect, run_time = 2),
                )
                self.wait()
                break
        self.tower = final_tower
        self.highest_order = highest_order
Beispiel #9
0
    def build_the_equation(self):
        l_part = self.tower.copy()
        r_part = TexMobject("=", "2")
        r_part.match_height(l_part.get_base())
        equation = VGroup(l_part, r_part)
        equation.arrange_submobjects(RIGHT, aligned_edge = DOWN)

        self.play(
            ReplacementTransform(self.tower, l_part, run_time = 1),
            Write(r_part, run_time = 2),
        )
        self.equation = equation
Beispiel #10
0
 def update_mobject(self, new_mob, animate=True):
     """
     Returns a list of animations of the mobject being updated
     """
     ret = []
     if animate:
         if type(self.mobject) == Line and type(new_mob) == Arrow:
             ret.extend([
                 FadeOut(self.mobject, parent=self),
                 FadeIn(new_mob, parent=self),
             ])
         else:
             ret.extend(
                 [ReplacementTransform(self.mobject, new_mob, parent=self)])
     else:
         if hasattr(self, "mobject"):
             self.remove(self.mobject)
         self.add(new_mob)
     self.mobject = new_mob
     return ret
Beispiel #11
0
    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()
Beispiel #12
0
    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()
        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)
        group = VGroup(pos_axis, time_axis, pos_text, time_text)
        group.to_edge(LEFT, buff=2)
        self.add(group)

        # Some preparations
        sequences = [
            "UDDDUDUD", "DUUDDDUD", "DDUUUDUD", "UUUDDUDU", "UDDDUDUD"
        ]
        nums = [1, 3, 7, -1, 1]
        walks = [
            RandomWalk1DArrow(sequence).move_start_to(
                pos_axis.number_to_point(0)) for sequence in sequences
        ]
        parts = [walk.split_at(num) for walk, num in zip(walks, nums)]
        split_lines = [
            DashedLine(TOP, BOTTOM, color = GREY) \
            .move_to(time_axis.number_to_point(num+1))
            for num in nums
        ]
        zero_words = [
            TextMobject("“正点到家” \\\\ $P_%s$" % str((num+1)//2)) \
            .next_to(line, LEFT).shift(2.8 * DOWN).set_color(ORANGE)
            for num, line in zip(nums, split_lines)
        ]
        nocross_words = [
            TextMobject("“不经过家门” \\\\ $Q_%s$" % str(4-(num+1)//2)) \
            .next_to(line, RIGHT).shift(2.8 * DOWN).set_color(GREEN)
            for num, line in zip(nums, split_lines)
        ]
        for words, direction in zip([zero_words, nocross_words],
                                    [RIGHT, LEFT]):
            for word in words:
                text, symbol = VGroup(word[:-2]), VGroup(word[-2:])
                symbol.scale(1.5)
                symbol.next_to(text, DOWN, aligned_edge=direction)
                word.add_background_rectangle()

        # Demonstrate how to split
        self.add(walks[0], split_lines[0], zero_words[0], nocross_words[0])
        l = len(walks)
        for k in range(l - 1):
            cur_walk = walks[k]
            cur_line = split_lines[k]
            cur_zero_word = zero_words[k]
            cur_nocross_word = nocross_words[k]
            next_walk = walks[k + 1]
            next_line = split_lines[k + 1]
            next_zero_word = zero_words[k + 1]
            next_nocross_word = nocross_words[k + 1]
            part1, part2 = parts[k]
            cur_walk.save_state()
            self.play(
                part1.set_color,
                ORANGE,
                part2.set_color,
                GREEN,
            )
            self.wait()
            self.play(cur_walk.restore)
            self.wait()
            self.play(
                ReplacementTransform(cur_walk, next_walk),
                ReplacementTransform(cur_line, next_line),
                ReplacementTransform(cur_zero_word, next_zero_word),
                ReplacementTransform(cur_nocross_word, next_nocross_word),
            )
            self.wait()
Beispiel #13
0
    def show_the_solution(self):
        # Prepare for the solution
        pre_solve = VGroup(*self.question[::2])
        self.play(
            ReplacementTransform(pre_solve, self.solve),
            FadeOut(self.question[1]),
            run_time = 1,
        )
        self.wait()

        # Manipulate LHS
        old_l_part, r_part = self.equation
        new_l_part = ExpTower(order = self.highest_order+1, is_infinite = True)
        new_l_part.match_height(old_l_part)
        new_l_part.next_to(r_part, LEFT, aligned_edge = DOWN)
        old_rect, new_rect = rects = [
            CoverRectangle(part, text = "2")
            for part in (old_l_part, new_l_part.get_exponent())
        ]
        old_two, new_two = twos = [
            rect.get_text_mob()
            for rect in rects
        ]
        self.play(DrawBorderThenFill(old_rect, run_time = 1))
        self.wait()
        self.play(
            ReplacementTransform(old_l_part, new_l_part),
            ReplacementTransform(old_rect, new_rect),
        )
        self.wait()
        new_equation = VGroup(new_l_part, r_part, new_rect)
        new_equation.generate_target()
        new_equation.target.scale(0.8)
        new_equation.target.shift(UP)
        self.play(MoveToTarget(new_equation))
        self.wait()

        # A little bit clean-up
        source_eq = VGroup(*[
            mob.copy()
            for mob in (new_l_part.get_base(), new_two, r_part[0], r_part[1])
        ])
        source_eq.generate_target()
        target_eq = TexMobject("x", "^2", "=", "2")
        target_eq.scale(3).next_to(source_eq, DOWN, buff = 1)
        for k, (old_part, new_part) in enumerate(zip(source_eq.target, target_eq)):
            old_part.move_to(new_part)
            if k == 1:
                old_part.scale(0.5)
                old_part.shift(RIGHT/4)
        self.play(
            FadeOut(new_rect),
            MoveToTarget(source_eq),
        )
        self.wait()

        # Reveal the final answer
        result = TexMobject("x", "=", "\\sqrt", "2")
        result.set_height(source_eq.get_height() * 0.7)
        result.move_to(source_eq)
        self.play(*[
            ReplacementTransform(source_eq[m], result[n], path_arc = angle)
            for m, n, angle in [(0, 0, 0), (1, 2, -TAU/3), (2, 1, 0), (3, 3, 0)]
        ])
        self.wait()
        qed = QEDSymbol()
        qed.next_to(result, RIGHT, aligned_edge = DOWN, buff = 1.5)
        self.play(FadeIn(qed))
        self.wait()