def scroll_through_patrons(self): logo_box = Square(side_length=2.5) logo_box.to_corner(DOWN + LEFT, buff=MED_LARGE_BUFF) total_width = FRAME_X_RADIUS - logo_box.get_right()[0] black_rect = Rectangle( fill_color=BLACK, fill_opacity=1, stroke_width=0, 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) self.add(line) thanks = TextMobject("Funded by the community, with special thanks to:") thanks.scale(0.9) thanks.next_to(black_rect.get_bottom(), UP, SMALL_BUFF) thanks.set_color(YELLOW) underline = Line(LEFT, RIGHT) underline.scale_to_fit_width(thanks.get_width() + MED_SMALL_BUFF) underline.next_to(thanks, DOWN, SMALL_BUFF) thanks.add(underline) self.add(thanks) patrons = VGroup(*map(TextMobject, self.specific_patrons)) patrons.scale(self.patron_scale_val) for patron in patrons: if patron.get_width() > self.max_patron_width: patron.scale_to_fit_width(self.max_patron_width) columns = VGroup(*[ VGroup(*patrons[i::self.n_patron_columns]) for i in range(self.n_patron_columns) ]) for column in columns: for n, name in enumerate(column): name.shift(n * self.name_y_spacing * DOWN) columns.arrange_submobjects( RIGHT, buff=LARGE_BUFF, aligned_edge=UP, ) columns.scale_to_fit_width(total_width - 1) columns.next_to(black_rect, DOWN, 3 * LARGE_BUFF) columns.to_edge(RIGHT) thanks.align_to(columns, alignment_vect=RIGHT) self.play( columns.move_to, 2 * DOWN, DOWN, columns.to_edge, RIGHT, Animation(black_rect), Animation(line), Animation(thanks), rate_func=None, run_time=self.run_time, )
def generate_symbol(self): symbol = VGroup(*[ RegularPolygon( n=3, stroke_width=0, fill_color=self.color, fill_opacity=1) for i in range(2) ]) symbol.arrange_submobjects(RIGHT, buff=0) symbol.set_height(self.inner_radius * 0.7) return symbol
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 arrange_subparts(self, *subparts): for i, piece in enumerate(subparts): piece.rotate(i * np.pi / 12, about_point=ORIGIN) p1, p2, p3, p4, p5, p6, p7 = subparts center_row = VGroup(p1, p4, p7) center_row.arrange_submobjects(RIGHT, buff=0) for p in p2, p3, p5, p6: p.set_width(p1.get_width()) p2.move_to(p1.get_top(), DOWN + LEFT) p3.move_to(p1.get_bottom(), UP + LEFT) p5.move_to(p4.get_top(), DOWN + LEFT) p6.move_to(p4.get_bottom(), UP + LEFT)
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
def arrange_subparts(self, *subparts): for i, piece in enumerate(subparts): piece.rotate(i * np.pi / 12, about_point=ORIGIN) p1, p2, p3, p4, p5, p6, p7 = subparts center_row = VGroup(p1, p4, p7) center_row.arrange_submobjects(RIGHT, buff=0) for p in p2, p3, p5, p6: p.scale_to_fit_width(p1.get_width()) p2.move_to(p1.get_top(), DOWN + LEFT) p3.move_to(p1.get_bottom(), UP + LEFT) p5.move_to(p4.get_top(), DOWN + LEFT) p6.move_to(p4.get_bottom(), UP + LEFT)
def generate_symbol(self): symbol = VGroup(*[ Rectangle( length=2, width=0.5, stroke_width=0, fill_color=self.color, fill_opacity=1, ) for i in range(2) ]) symbol.arrange_submobjects(RIGHT, buff=0.5) symbol.set_height(self.inner_radius) return symbol
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 scroll_through_patrons(self): logo_box = Square(side_length=2.5) logo_box.to_corner(DOWN + LEFT, buff=MED_LARGE_BUFF) total_width = FRAME_X_RADIUS - logo_box.get_right()[0] black_rect = Rectangle(fill_color=BLACK, fill_opacity=1, stroke_width=0, width=FRAME_WIDTH, height=1.1 * FRAME_Y_RADIUS) black_rect.to_edge(UP, buff=0) line = DashedLine(FRAME_X_RADIUS * LEFT, FRAME_X_RADIUS * RIGHT) line.move_to(black_rect, DOWN) line.shift(SMALL_BUFF * SMALL_BUFF * DOWN) self.add(line) patrons = VGroup(*map(TextMobject, self.specific_patrons)) patrons.scale(self.patron_scale_val) for patron in patrons: if patron.get_width() > self.max_patron_width: patron.scale_to_fit_width(self.max_patron_width) columns = VGroup(*[ VGroup(*patrons[i::self.n_patron_columns]) for i in range(self.n_patron_columns) ]) for column in columns: for n, name in enumerate(column): name.shift(n * self.name_y_spacing * DOWN) columns.arrange_submobjects( RIGHT, buff=LARGE_BUFF, aligned_edge=UP, ) columns.scale_to_fit_width(total_width - 1) columns.next_to(black_rect, DOWN, 3 * LARGE_BUFF) columns.to_edge(RIGHT) self.play( columns.move_to, 2 * DOWN, DOWN, columns.to_edge, RIGHT, Animation(black_rect), rate_func=None, run_time=self.run_time, )
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 organize_matrices(self, left, right, result): equals = TexMobject("=") everything = VGroup(left, right, equals, result) everything.arrange_submobjects() everything.scale_to_fit_width(FRAME_WIDTH - 1) self.add(everything)
def construct(self): colors = ["#FF0000", "#FF8000", "#FFFF00", "#00FF00", "#0080FF"] wallis_rects_4 = WallisRectangles( order=5, rect_colors=colors, ) vert_lines = VGroup(*[ Line(3.5*UP, 3.5*DOWN, color = GREY, stroke_width = 3) \ .next_to(wallis_rects_4.get_rectangle(0, k), direction, buff = 0) for k, direction in zip(list(range(5))+[4], [LEFT]*5+[RIGHT]) ]) horiz_lines = VGroup(*[ Line(3.5*LEFT, 3.5*RIGHT, color = GREY, stroke_width = 3) \ .next_to(wallis_rects_4.get_rectangle(k, 0), direction, buff = 0) for k, direction in zip(list(range(5))+[4], [DOWN]*5+[UP]) ]) for vert_line in vert_lines: vert_line.vertically_center() for horiz_line in horiz_lines: horiz_line.horizontally_center() vert_labels = VGroup(*[ TexMobject("a_%d" % k) \ .move_to((vert_lines[k].get_center() + vert_lines[k+1].get_center())/2) \ .shift(3.5*DOWN) for k in range(5) ]) horiz_labels = VGroup(*[ TexMobject("a_%d" % k) \ .move_to((horiz_lines[k].get_center() + horiz_lines[k+1].get_center())/2) \ .shift(3.5*LEFT) for k in range(5) ]) area_texs = VGroup() factors = [1.25, 1, 0.9, 0.7, 0.6] for p in range(5): for q in range(5 - p): rect = wallis_rects_4.get_rectangle(p, q) tex = TexMobject("{a_%d} {a_%d}" % (q, p)) tex.scale(factors[p + q]) tex.move_to(rect) area_texs.add(tex) figure = VGroup() figure.add(wallis_rects_4, vert_lines, horiz_lines, vert_labels, horiz_labels, area_texs) figure.to_edge(LEFT) self.add(figure) tex_list = VGroup() for p in range(5): formula_string = ( " + ".join(["a_%d a_%d" % (q, p - q) for q in range(p + 1)]) + "=1") formula = TexMobject(formula_string) tex_list.add(formula) # tex_list.add(TexMobject("\\vdots")) tex_factors = np.linspace(1, 0.7, 5) for tex, color, factor in zip(tex_list, colors, tex_factors): tex.set_color(color) tex.scale(factor) tex_list.arrange_submobjects(DOWN, aligned_edge=LEFT) tex_list.to_edge(RIGHT) self.add(tex_list) self.wait()
def construct(self): # Chart on the left colors = [WHITE, ORANGE, GREEN] titles = VGroup(*[ TexMobject(text).set_color(color) for text, color in zip(["n", "p_n", "q_n"], colors) ]) contents = VGroup(*[ VGroup(*[ TexMobject("%d" % num) for num in [k, central_binomial_coeff(k), central_binomial_coeff(k)] ]) for k in range(8) ]) titles.arrange_submobjects(RIGHT, buff=1) for num, line in enumerate(contents): for k, element in enumerate(line): buff = 0.6 + 0.8 * num element.next_to(titles[k], DOWN, aligned_edge=LEFT, buff=buff) element.set_color(colors[k]) sep_line = Line(ORIGIN, 4.5 * RIGHT, stroke_width=5) sep_line.next_to(titles, DOWN) chart = VGroup(titles, contents, sep_line) chart.set_height(7) chart.center().to_edge(LEFT) self.add(chart) # Figures on the right std_zero_pos_axis = NumberLine(x_min=-2, x_max=2, color=GREY, unit_size=0.25, tick_size=0.05) std_zero_pos_axis.rotate(np.pi / 2) std_nocross_pos_axis = NumberLine(x_min=-4, x_max=4, color=GREY, unit_size=0.25, tick_size=0.05) std_nocross_pos_axis.rotate(np.pi / 2) std_time_axis = NumberLine(x_min=0, x_max=5.5, color=GREY, unit_size=0.25, tick_size=0.05) std_zero_axes = VGroup(std_zero_pos_axis, std_time_axis) std_nocross_axes = VGroup(std_nocross_pos_axis, std_time_axis) zero_walks = VGroup() for sequence in ["UUDD", "UDUD", "UDDU", "DDUU", "DUDU", "DUUD"]: axes = std_zero_axes.copy() zero_walk = RandomWalk1DArrow(sequence, step_size=0.25) zero_walk.move_start_to(axes[0].number_to_point(0)) zero_walks.add(VGroup(axes, zero_walk)) zero_walks.arrange_submobjects_in_grid(2, 3, buff=0.5) zero_rect = SurroundingRectangle(zero_walks, color=ORANGE, buff=0.4) zero_walks.add(zero_rect) nocross_walks = VGroup() for sequence in ["DDDD", "DDUD", "DDDU", "UUUU", "UUDU", "UUUD"]: axes = std_nocross_axes.copy() nocross_walk = RandomWalk1DArrow(sequence, step_size=0.25) nocross_walk.move_start_to(axes[0].number_to_point(0)) nocross_walks.add(VGroup(axes, nocross_walk)) nocross_walks.arrange_submobjects_in_grid(2, 3, buff=0.5) nocross_rect = SurroundingRectangle(nocross_walks, color=GREEN, buff=0.4) nocross_walks.add(nocross_rect) relation = TexMobject("p_2", "=", "q_2", "=", "6") relation[0].set_color(ORANGE) relation[2].set_color(GREEN) relation.scale(1.5) figure = VGroup(zero_walks, relation, nocross_walks) figure.arrange_submobjects(DOWN) figure.set_height(7) figure.center().to_edge(RIGHT) self.add(figure) self.wait()
class TeacherStudentsScene(PiCreatureScene): CONFIG = { "student_colors": [BLUE_D, BLUE_E, BLUE_C], "student_scale_factor": 0.8, "seconds_to_blink": 2, "screen_height": 3, } def setup(self): PiCreatureScene.setup(self) self.screen = ScreenRectangle(height=self.screen_height) self.screen.to_corner(UP + LEFT) self.hold_up_spot = self.teacher.get_corner(UP + LEFT) + MED_LARGE_BUFF * UP def create_pi_creatures(self): self.teacher = Mortimer(color=self.default_pi_creature_kwargs["color"]) self.teacher.to_corner(DOWN + RIGHT) self.teacher.look(DOWN + LEFT) self.students = VGroup( *[Randolph(color=c) for c in self.student_colors]) self.students.arrange_submobjects(RIGHT) self.students.scale(self.student_scale_factor) self.students.to_corner(DOWN + LEFT) self.teacher.look_at(self.students[-1].eyes) for student in self.students: student.look_at(self.teacher.eyes) return [self.teacher] + list(self.students) def get_teacher(self): return self.teacher def get_students(self): return self.students def teacher_says(self, *content, **kwargs): return self.pi_creature_says(self.get_teacher(), *content, **kwargs) def student_says(self, *content, **kwargs): if "target_mode" not in kwargs: target_mode = random.choice([ "raise_right_hand", "raise_left_hand", ]) kwargs["target_mode"] = target_mode student = self.get_students()[kwargs.get("student_index", 1)] return self.pi_creature_says(student, *content, **kwargs) def teacher_thinks(self, *content, **kwargs): return self.pi_creature_thinks(self.get_teacher(), *content, **kwargs) def student_thinks(self, *content, **kwargs): student = self.get_students()[kwargs.get("student_index", 1)] return self.pi_creature_thinks(student, *content, **kwargs) def change_all_student_modes(self, mode, **kwargs): self.change_student_modes(*[mode] * len(self.students), **kwargs) def change_student_modes(self, *modes, **kwargs): added_anims = kwargs.pop("added_anims", []) self.play(self.get_student_changes(*modes, **kwargs), *added_anims) def get_student_changes(self, *modes, **kwargs): pairs = zip(self.get_students(), modes) pairs = [(s, m) for s, m in pairs if m is not None] start = VGroup(*[s for s, m in pairs]) target = VGroup(*[s.copy().change_mode(m) for s, m in pairs]) if "look_at_arg" in kwargs: for pi in target: pi.look_at(kwargs["look_at_arg"]) submobject_mode = kwargs.get("submobject_mode", "lagged_start") return Transform(start, target, submobject_mode=submobject_mode, run_time=2) def zoom_in_on_thought_bubble(self, bubble=None, radius=FRAME_Y_RADIUS + FRAME_X_RADIUS): if bubble is None: for pi in self.get_pi_creatures(): if hasattr(pi, "bubble") and isinstance( pi.bubble, ThoughtBubble): bubble = pi.bubble break if bubble is None: raise Exception("No pi creatures have a thought bubble") vect = -bubble.get_bubble_center() def func(point): centered = point + vect return radius * centered / np.linalg.norm(centered) self.play( * [ApplyPointwiseFunction(func, mob) for mob in self.get_mobjects()]) 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, )
class TeacherStudentsScene(PiCreatureScene): CONFIG = { "student_colors": [BLUE_D, BLUE_E, BLUE_C], "teacher_color": GREY_BROWN, "student_scale_factor": 0.8, "seconds_to_blink": 2, "screen_height": 3, } def setup(self): PiCreatureScene.setup(self) self.screen = ScreenRectangle(height=self.screen_height) self.screen.to_corner(UP + LEFT) self.hold_up_spot = self.teacher.get_corner(UP + LEFT) + MED_LARGE_BUFF * UP def create_pi_creatures(self): self.teacher = Mortimer(color=self.teacher_color) self.teacher.to_corner(DOWN + RIGHT) self.teacher.look(DOWN + LEFT) self.students = VGroup(*[ Randolph(color=c) for c in self.student_colors ]) self.students.arrange_submobjects(RIGHT) self.students.scale(self.student_scale_factor) self.students.to_corner(DOWN + LEFT) self.teacher.look_at(self.students[-1].eyes) for student in self.students: student.look_at(self.teacher.eyes) return [self.teacher] + list(self.students) def get_teacher(self): return self.teacher def get_students(self): return self.students def teacher_says(self, *content, **kwargs): return self.pi_creature_says( self.get_teacher(), *content, **kwargs ) def student_says(self, *content, **kwargs): if "target_mode" not in kwargs: target_mode = random.choice([ "raise_right_hand", "raise_left_hand", ]) kwargs["target_mode"] = target_mode student = self.get_students()[kwargs.get("student_index", 1)] return self.pi_creature_says( student, *content, **kwargs ) def teacher_thinks(self, *content, **kwargs): return self.pi_creature_thinks( self.get_teacher(), *content, **kwargs ) def student_thinks(self, *content, **kwargs): student = self.get_students()[kwargs.get("student_index", 1)] return self.pi_creature_thinks(student, *content, **kwargs) def change_all_student_modes(self, mode, **kwargs): self.change_student_modes(*[mode] * len(self.students), **kwargs) def change_student_modes(self, *modes, **kwargs): added_anims = kwargs.pop("added_anims", []) self.play( self.get_student_changes(*modes, **kwargs), *added_anims ) def get_student_changes(self, *modes, **kwargs): pairs = zip(self.get_students(), modes) pairs = [(s, m) for s, m in pairs if m is not None] start = VGroup(*[s for s, m in pairs]) target = VGroup(*[s.copy().change_mode(m) for s, m in pairs]) if "look_at_arg" in kwargs: for pi in target: pi.look_at(kwargs["look_at_arg"]) submobject_mode = kwargs.get("submobject_mode", "lagged_start") return Transform( start, target, submobject_mode=submobject_mode, run_time=2 ) def zoom_in_on_thought_bubble(self, bubble=None, radius=FRAME_Y_RADIUS + FRAME_X_RADIUS): if bubble is None: for pi in self.get_pi_creatures(): if hasattr(pi, "bubble") and isinstance(pi.bubble, ThoughtBubble): bubble = pi.bubble break if bubble is None: raise Exception("No pi creatures have a thought bubble") vect = -bubble.get_bubble_center() def func(point): centered = point + vect return radius * centered / np.linalg.norm(centered) self.play(*[ ApplyPointwiseFunction(func, mob) for mob in self.get_mobjects() ]) def teacher_holds_up(self, mobject, target_mode="raise_right_hand", added_anims=None, **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) added_anims = added_anims or [] self.play( ReplacementTransform(mobject_copy, mobject), self.teacher.change, target_mode, *added_anims )