diff --git a/_2021/some1.py b/_2021/some1.py new file mode 100644 index 0000000..ffd2dbd --- /dev/null +++ b/_2021/some1.py @@ -0,0 +1,1223 @@ +from manim_imports_ext import * + + +def get_tripple_underline(mobject, buff=0.1): + ul1 = Underline(mobject, buff=buff).set_stroke(BLUE_C, 3) + ul2 = Underline(ul1).scale(0.9).set_stroke(BLUE_D, 2) + ul3 = Underline(ul2).scale(0.9).set_stroke(BLUE_E, 1) + return VGroup(ul1, ul2, ul3) + + +def get_h_line(): + line = DashedLine(ORIGIN, FRAME_WIDTH * RIGHT) + line.center() + return line + + +# Scenes + +class TableOfContents(Scene): + def construct(self): + # plane = NumberPlane() + # self.add(plane, FullScreenFadeRectangle(opacity=0.8)) + + items = VGroup( + Text("Summer of Math Exposition"), + Text("The Universal Advice"), + Text("How to structure math explanations"), + Text("Thoughts on animation software"), + Text("The 3b1b Podcast/Second channel"), + ) + items.arrange(DOWN, buff=LARGE_BUFF, aligned_edge=LEFT) + items.to_edge(LEFT, buff=0.5) + + self.add(items) + + for i in range(len(items)): + for item in items: + item.generate_target() + if item is items[i]: + height = 0.55 + opacity = 1.0 + else: + height = 0.3 + opacity = 0.25 + item.target.scale( + height / item[0].get_height(), + about_edge=LEFT + ) + item.target.set_opacity(opacity) + self.play(*map(MoveToTarget, items)) + self.wait() + + +class SoME1Name(Scene): + def construct(self): + strings = ["Summer", "of", "Math", "Exposition", "#1"] + lens = list(map(lambda s: len(s) + 1, strings)) + indices = [0, *np.cumsum(lens)] + phrase = Text(" ".join(strings)) + phrase.set_width(12) + words = VGroup() + for i1, i2 in zip(indices, indices[1:]): + words.add(phrase[i1:i2]) + + acronym = VGroup(*(word[0].copy() for word in words[:-1])) + acronym.add(words[-1][-1].copy()) + acronym.generate_target() + acronym.target.arrange(RIGHT, buff=SMALL_BUFF, aligned_edge=DOWN) + acronym.target.move_to(DOWN) + + self.play(LaggedStartMap(FadeIn, words, lag_ratio=0.5, run_time=1)) + self.wait() + self.play( + # FadeOut(phrase), + phrase.animate.move_to(UP), + MoveToTarget(acronym) + ) + self.wait() + + self.play( + ShowCreation(get_tripple_underline(words[2])), + words[2].animate.set_color(BLUE_B), + ) + self.wait() + + +class LinkAndDate(Scene): + def construct(self): + words = link, date = VGroup( + Text("https://3b1b.co/SoME1", font="CMU Serif"), + Text("August 22nd", font="CMU Serif") + ) + words.set_width(10) + words.arrange(DOWN, buff=0.5) + words.set_stroke(BLACK, 5, background=True) + + lines = get_tripple_underline(date) + + details = Text("(Full details here)") + details.to_corner(UR) + arrow = Arrow(details, link, buff=0.5) + + self.play(Write(link), run_time=1) + self.wait() + self.add(lines, words) + self.play( + FadeIn(date, scale=1.2, rate_func=squish_rate_func(smooth, 0.3, 0.7)), + ShowCreation(lines, lag_ratio=0.25) + ) + self.wait() + + self.play(FadeIn(details), GrowArrow(arrow)) + self.wait() + + +class Featuring(TeacherStudentsScene): + def construct(self): + screen = ScreenRectangle() + screen.set_height(4) + screen.to_corner(UL) + screen.set_stroke(WHITE, 2) + screen.set_fill(BLACK, 1) + + self.add(screen) + + words = TexText("Your work here") + words.set_width(screen.get_width() - 1) + words.move_to(screen) + + self.play( + self.teacher.animate.change("tease"), + self.get_student_changes(*3 * ["hooray"], look_at_arg=screen), + FadeIn(screen, UP) + ) + self.play(Write(words)) + self.play(ShowCreation(get_tripple_underline(words))) + self.wait(5) + self.student_says( + TexText("Anything\\\\else?"), + target_mode="raise_left_hand", + look_at_arg=self.teacher, + ) + self.play(self.teacher.animate.change("sassy")) + self.wait(2) + + +class Constraints(TeacherStudentsScene): + def construct(self): + self.student_says( + TexText("What are the\\\\constraints?"), + added_anims=[self.teacher.animate.change("tease")] + ) + self.wait(3) + + +class TopicChoice(TeacherStudentsScene): + def construct(self): + self.student_says( + TexText("What kind of\\\\topics?"), + added_anims=[self.teacher.animate.change("tease")], + student_index=1, + ) + self.wait(3) + + +class PartialFraction(Scene): + def construct(self): + frac = Tex( + r"\frac{x+9}{(x-3)(x+5)} = \frac{?}{x - 3} + \frac{?}{x + 5}" + ) + frac.set_width(10) + self.add(frac) + + +class TrigIdentity(Scene): + def construct(self): + plane = NumberPlane().scale(2) + circle = Circle(radius=2) + circle.set_stroke(YELLOW, 2) + + theta_tracker = ValueTracker(60 * DEGREES) + get_theta = theta_tracker.get_value + + def get_point(): + return circle.pfp(get_theta() / TAU) + + dot = Dot() + f_always(dot.move_to, get_point) + radial_line = always_redraw(lambda: Line(plane.c2p(0, 0), get_point())) + tan_line = always_redraw( + lambda: Line(get_point(), plane.c2p(1 / math.cos(get_theta()), 0), stroke_color=RED) + ) + sec_line = always_redraw( + lambda: Line(plane.c2p(0, 0), tan_line.get_end(), stroke_color=PINK) + ) + + def get_one_label(): + one = Integer(1) + one.next_to(radial_line.get_center(), UL, SMALL_BUFF) + return one + + def get_tan_label(): + label = Tex("\\tan(\\theta)") + label.set_color(RED) + point = tan_line.get_center() + label.next_to(point, UP, SMALL_BUFF) + label.rotate(tan_line.get_angle(), about_point=point) + label.set_stroke(BLACK, 3, background=True) + return label + + def get_sec_label(): + label = Tex("\\sec(\\theta)") + label.set_color(PINK) + label.next_to(sec_line, DOWN, SMALL_BUFF) + label.set_stroke(BLACK, 3, background=True) + return label + + one_label = always_redraw(get_one_label) + tan_label = always_redraw(get_tan_label) + sec_label = always_redraw(get_sec_label) + + arc = always_redraw(lambda: Arc(0, get_theta(), radius=0.25)) + arc_label = Tex("\\theta", font_size=36) + arc_label.next_to(arc, RIGHT, SMALL_BUFF, DOWN).shift(SMALL_BUFF * UP) + + equation = Tex( + "\\tan^2(\\theta) + 1 = \\sec^2(\\theta)", + tex_to_color_map={ + "\\tan": RED, + "\\sec": PINK, + }, + font_size=60 + ) + equation.to_corner(UL) + equation.set_stroke(BLACK, 7, background=True) + + self.add(plane) + self.add(circle) + self.add(equation) + + self.add(radial_line) + self.add(tan_line) + self.add(sec_line) + self.add(dot) + + self.add(one_label) + self.add(tan_label) + self.add(sec_label) + + self.add(arc) + self.add(arc_label) + + angles = [40 * DEGREES, 70 * DEGREES] + for angle in angles: + self.play(theta_tracker.animate.set_value(angle), run_time=4) + + +class TeacherStudentPairing(Scene): + def construct(self): + randy = Randolph(height=2.5) + morty = Mortimer(height=3.0) + pis = VGroup(randy, morty) + pis.arrange(RIGHT, buff=3, aligned_edge=DOWN) + pis.to_edge(DOWN, buff=1.5) + + self.add(pis) + self.add(Text("Teacher").next_to(morty, DOWN)) + self.add(Text("Student").next_to(randy, DOWN)) + + teacher_label = Text("Delivers/writes lesson", font_size=36) + student_label = Text("Produces/edits/animates", font_size=36) + teacher_label.next_to(morty, UP, buff=1.5).shift(RIGHT) + student_label.next_to(randy, UP, buff=1.5).shift(LEFT) + teacher_arrow = Arrow(teacher_label, morty) + student_arrow = Arrow(student_label, randy) + + self.play( + Write(student_label), + GrowArrow(student_arrow), + randy.animate.change("hooray", student_label) + ) + self.wait() + self.play( + Write(teacher_label), + GrowArrow(teacher_arrow), + morty.animate.change("pondering", teacher_label) + ) + self.wait() + for x in range(4): + self.play(Blink(random.choice(pis))) + self.wait(random.random()) + + +class Grey(Scene): + def construct(self): + self.add(FullScreenRectangle().set_fill(GREY_D, 1)) + + +class ButIHaveNoExperience(TeacherStudentsScene): + def construct(self): + self.student_says( + TexText("But I have no\\\\experience!"), + student_index=0, + target_mode="pleading", + ) + self.change_student_modes( + "pleading", "pondering", "pondering", + look_at_arg=self.students[0].bubble, + ) + self.students[0].look_at(self.teacher.eyes) + self.play(self.teacher.animate.change("tease", self.students[0].eyes)) + + self.wait(4) + + +class ContentAdvice(Scene): + def construct(self): + title = Text("Advice for structuring math explanations") + title.set_width(10) + title.to_edge(UP) + underline = Underline(title).scale(1.2).set_stroke(GREY_B, 2) + + self.play(FadeIn(title, UP)) + self.play(ShowCreation(underline)) + + points = VGroup( + Text("1) Concrete before abstract"), + Text("2) Topic choice > production quality"), + Text("3) Be niche"), + Text("4) Know your genre"), + Text("5) Definitions are not the beginning"), + ) + points.arrange(DOWN, buff=0.7, aligned_edge=LEFT) + points.next_to(title, DOWN, buff=1.0) + + self.play(LaggedStartMap( + FadeIn, + VGroup(*(point[:2] for point in points)), + shift=0.25 * RIGHT + )) + self.wait() + + for point in points: + self.play(Write(point[2:])) + + self.wait() + gt0 = Tex("> 0") + gt0.next_to(points[1], RIGHT) + self.play( + VGroup(points[0], *points[2:]).animate.set_opacity(0.25) + ) + self.play(Write(gt0)) + self.play(ShowCreation(get_tripple_underline( + VGroup(points[1].get_part_by_text("production quality"), gt0) + ))) + self.wait() + + +class LayersOfAbstraction(Scene): + def construct(self): + self.save_count = 0 + self.add_title() + self.show_layers() + self.show_pairwise_relations() + self.circle_certain_pairs() + + def add_title(self): + title = TexText("Layers of abstraction") + title.scale(1.5) + title.to_edge(UP, buff=MED_SMALL_BUFF) + line = Line(LEFT, RIGHT) + line.set_width(FRAME_WIDTH) + line.next_to(title, DOWN, SMALL_BUFF) + + self.add(title, line) + + def show_layers(self): + layers = self.layers = self.get_layers() + + for layer in layers: + self.play(FadeIn(layer, shift=0.1 * UP)) + + def show_pairwise_relations(self): + p1, p2 = [layer.get_left() for layer in self.layers[2:4]] + down_arrow = Arrow(p2, p1, path_arc=PI) + down_words = TexText("``For example''") + down_words.scale(0.8) + down_words.next_to(down_arrow, LEFT) + up_arrow = Arrow(p1, p2, path_arc=-PI) + up_words = TexText("``In general''") + up_words.scale(0.8) + up_words.next_to(up_arrow, LEFT) + + VGroup(up_words, down_words).set_color(YELLOW) + + self.play( + GrowArrow(down_arrow), + FadeIn(down_words) + ) + self.wait() + self.play( + ReplacementTransform(down_arrow, up_arrow, path_arc=PI), + FadeTransform(down_words, up_words) + ) + self.wait() + self.play(FadeOut(up_arrow), FadeOut(up_words)) + + def circle_certain_pairs(self): + layers = self.layers + + for l1, l2 in zip(layers, layers[1:]): + group = VGroup(l1, l2) + group.save_state() + layers.save_state() + layers.fade(0.75) + rect = SurroundingRectangle(group) + rect.set_stroke(YELLOW, 5) + group.restore() + self.add(rect) + self.wait() + self.remove(rect) + layers.restore() + + # + + def get_layers(self): + layers = VGroup(*[ + VGroup(Rectangle(height=1, width=5)) + for x in range(6) + ]) + layers.arrange(UP, buff=0) + layers.set_stroke(GREY, 2) + layers.set_gloss(1) + + # Layer 0: Quantities + triangle = Triangle().set_height(0.25) + tri_dots = VGroup(*[Dot(v) for v in triangle.get_vertices()]) + dots_rect = VGroup(*[Dot() for x in range(12)]) + dots_rect.arrange_in_grid(3, 4, buff=SMALL_BUFF) + for i, color in enumerate([RED, GREEN, BLUE]): + dots_rect[i::4].set_color(color) + pi_chart = VGroup(*[ + Sector(start_angle=a, angle=TAU / 3) + for a in np.arange(0, TAU, TAU / 3) + ]) + pi_chart.set_fill(opacity=0) + pi_chart.set_stroke(WHITE, 2) + pi_chart[0].set_fill(BLUE, 1) + pi_chart.rotate(PI / 3) + pi_chart.match_height(dots_rect) + quantities = VGroup(tri_dots, dots_rect, pi_chart) + quantities.arrange(RIGHT, buff=LARGE_BUFF) + + # Layer 1: Numbers + numbers = VGroup( + Tex("3"), + Tex("3 \\times 4"), + Tex("1 / 3"), + ) + for number, quantity in zip(numbers, quantities): + number.move_to(quantity) + + # Layer 2: Algebra + algebra = VGroup( + Tex("x^2 - 1 = (x + 1)(x - 1)") + ) + algebra.set_width(layers.get_width() - MED_LARGE_BUFF) + + # Layer 3: Functions + functions = VGroup( + Tex("f(x) = 0"), + Tex("\\frac{df}{dx}"), + ) + functions.set_height(layers[0].get_height() - 2 * SMALL_BUFF) + functions.arrange(RIGHT, buff=LARGE_BUFF) + # functions.match_width(algebra) + + # Layer 4: Vector space + t2c_map = { + "\\textbf{v}": YELLOW, + "\\textbf{w}": PINK, + } + vector_spaces = VGroup( + Tex( + "\\textbf{v} + \\textbf{w} =" + "\\textbf{w} + \\textbf{v}", + tex_to_color_map=t2c_map, + ), + Tex( + "s(\\textbf{v} + \\textbf{w}) =" + "s\\textbf{v} + s\\textbf{w}", + tex_to_color_map=t2c_map, + ), + ) + vector_spaces.arrange(DOWN, buff=MED_SMALL_BUFF) + vector_spaces.set_height(layers[0].get_height() - MED_LARGE_BUFF) + v, w = vectors = VGroup( + Vector([2, 1, 0], color=YELLOW), + Vector([1, 2, 0], color=PINK), + ) + vectors.add(DashedLine(v.get_end(), v.get_end() + w.get_vector())) + vectors.add(DashedLine(w.get_end(), w.get_end() + v.get_vector())) + vectors.match_height(vector_spaces) + vectors.next_to(vector_spaces, RIGHT) + vectors.set_stroke(width=2) + # vector_spaces.add(vectors) + + inner_product = Tex( + "\\langle f, g \\rangle =" + "\\int f(x)g(x)dx" + ) + inner_product.match_height(vector_spaces) + inner_product.next_to(vector_spaces, RIGHT) + vector_spaces.add(inner_product) + + # Layer 5: Categories + dots = VGroup(Dot(UL), Dot(UR), Dot(RIGHT)) + arrows = VGroup( + Arrow(dots[0], dots[1], buff=SMALL_BUFF), + Arrow(dots[1], dots[2], buff=SMALL_BUFF), + Arrow(dots[0], dots[2], buff=SMALL_BUFF), + ) + arrows.set_stroke(width=2) + arrow_labels = VGroup( + Tex("m_1").next_to(arrows[0], UP, SMALL_BUFF), + Tex("m_2").next_to(arrows[1], RIGHT, SMALL_BUFF), + Tex("m_2 \\circ m_1").rotate(-np.arctan(1 / 2)).move_to( + arrows[2] + ).shift(MED_SMALL_BUFF * DL) + ) + categories = VGroup(dots, arrows, arrow_labels) + categories.set_height(layers[0].get_height() - MED_SMALL_BUFF) + + # Put it all together + all_content = [ + quantities, numbers, algebra, + functions, vector_spaces, categories, + ] + + for layer, content in zip(layers, all_content): + content.move_to(layer) + layer.add(content) + layer.content = content + + layer_titles = VGroup(*map(TexText, [ + "Quantities", + "Numbers", + "Algebra", + "Functions", + "Vector spaces", + "Categories", + ])) + for layer, title in zip(layers, layer_titles): + title.next_to(layer, RIGHT) + layer.add(title) + layer.title = title + layers.titles = layer_titles + + layers.center() + layers.to_edge(DOWN) + layers.shift(0.5 * RIGHT) + return layers + + +class FractionsExample(Scene): + def construct(self): + expr = Tex("{2 \\over 3}", "+", "{1 \\over 5}") + expr.scale(1.5) + h_line = DashedLine(ORIGIN, FRAME_WIDTH * RIGHT).center() + + quantities = Text("Quantities") + quantities.to_corner(UL, buff=MED_SMALL_BUFF) + quantities.shift(FRAME_HEIGHT * DOWN / 2) + numbers = Text("Numbers") + numbers.to_corner(UL, buff=MED_SMALL_BUFF) + + def get_pie(numer, denom, color=BLUE, height=1.5): + pie = VGroup(*( + AnnularSector( + angle=TAU / denom, + start_angle=i * TAU / denom, + inner_radius=0.0, + outer_radius=1.0, + ) + for i in range(denom) + )) + pie.set_stroke(WHITE, 2) + pie.set_fill(BLACK, 1) + pie[:numer].set_fill(color) + pie.set_height(height) + return pie + + pies = VGroup( + get_pie(2, 3, color=BLUE_C), + Tex("+"), + get_pie(1, 5, color=BLUE_D), + ) + pies.arrange(RIGHT) + pies.move_to(FRAME_HEIGHT * DOWN / 4) + + self.add(expr) + self.wait() + self.play( + expr.animate.move_to(FRAME_HEIGHT * UP / 4), + ShowCreation(h_line), + Write(numbers), + ) + self.play( + *( + FadeTransform(expr[i].copy(), pies[i]) + for i in range(len(pies)) + ), + FadeTransform(numbers.copy(), quantities) + ) + self.wait() + + # Evaluate bottom + bottom_eq = Tex("=") + bottom_eq.move_to(pies[2]) + self.play( + pies.animate.next_to(bottom_eq, LEFT), + Write(bottom_eq), + ) + + bottom_rhs = VGroup( + *pies[0][:2].copy(), + pies[2][0].copy() + ) + bottom_rhs.generate_target() + bottom_rhs.target[2].shift(pies[0].get_center() - pies[2].get_center()) + bottom_rhs.target[2].rotate(TAU * 2 / 3, about_point=pies[0].get_center()) + bottom_rhs.target.next_to(bottom_eq, RIGHT) + + self.play(MoveToTarget(bottom_rhs)) + self.wait() + + # Evaluate top + rhs = Tex( + "=", + "{10 \\over 15}", + "+", + "{3 \\over 15}", + "=", + "{13 \\over 15}" + ) + rhs.match_height(expr) + rhs.next_to(expr, RIGHT) + expr.generate_target() + VGroup(expr.target, rhs).set_x(0) + + self.play( + MoveToTarget(expr), + FadeIn(rhs, lag_ratio=0.1) + ) + self.wait() + + # Show overlays + overlays = VGroup() + for pie in (*pies[::2], bottom_rhs): + overlay = get_pie(0, 15) + overlay.set_fill(BLACK, 0) + overlay.set_stroke(WHITE, 1, opacity=0.5) + overlay.move_to(pie) + overlays.add(overlay) + + self.play(ShowCreation(overlays)) + self.wait() + + +class CalculusStatement(Scene): + def construct(self): + statement = VGroup( + TexText( + "If $f(x)$ has a local maximum or minimum\\\\" + "at $x_0$, and $f$ is differentiable at $x_0$, then" + ), + Tex("\\frac{df}{dx}(x_0) = 0.") + ) + statement.arrange(DOWN) + statement[1].scale(1.5, about_edge=UP).shift(0.25 * DOWN) + self.add(statement) + + +class ExamplesOfFunctions(Scene): + def construct(self): + plane = NumberPlane((-15, 15, 5), (-10, 10, 5)) + plane.scale(0.5) + self.add(plane) + + graphs = VGroup( + plane.get_graph(lambda x: -x * (x - 4)), + plane.get_graph(lambda x: x / 3), + plane.get_graph(lambda x: (1 / 3) * x**3 - 2 * x + 1), + plane.get_graph(lambda x: -5 * x * np.exp(-x**2 / 2)), + ) + graph_labels = VGroup( + Tex("f(x) = ", "-x^2 - 4x"), + Tex("f(x) = ", "x / 3"), + Tex("f(x) = ", "x^3 / 3- 2x + 1"), + Tex("f(x) = ", "-(5x) e^{-{1 \\over 2} x^2}"), + ) + colors = [YELLOW, RED, TEAL, PINK] + for graph, color, label in zip(graphs, colors, graph_labels): + graph.set_stroke(color) + label.scale(1.5) + label[1].set_color(color) + label.next_to(plane.c2p(0, 5), UR, SMALL_BUFF) + label.set_stroke(BLACK, 3, background=True) + + self.play( + FadeIn(graph_labels[0]), ShowCreation(graphs[0]), + run_time=1.5 + ) + self.wait() + for i in range(1, len(graphs)): + self.play( + ReplacementTransform(graphs[i - 1], graphs[i]), + FadeTransform(graph_labels[i - 1], graph_labels[i]), + run_time=0.5 + ) + self.wait(1.5) + + +class SpecificCases(Scene): + def construct(self): + self.add(FullScreenRectangle()) + title = Text("Applications for optimization", font_size=72) + title.to_edge(UP) + self.add(title) + + grid = Square().get_grid(1, 2, buff=0) + grid.set_height(6) + grid.set_width(13, stretch=True) + grid.to_edge(DOWN) + grid.set_fill(BLACK, 1) + + labels = VGroup( + Text("Profit maximization"), + Text("Distance between curves"), + ) + for label, square in zip(labels, grid): + label.next_to(square.get_top(), DOWN) + + self.add(grid) + self.add(labels) + + # Fill 'em + r_axes = Axes( + x_range=(-3, 3), y_range=(-3, 3), + width=6, height=4.5, + axis_config={"include_tip": False}, + ) + r_axes.move_to(grid[1], DOWN).shift(0.25 * UP) + circle = Circle() + circle.set_height(get_norm(r_axes.c2p(0, 0) - r_axes.c2p(0, 2))) + circle.move_to(r_axes.c2p(1, 1)) + circle.set_stroke(YELLOW) + parabola = r_axes.get_graph( + lambda x: 0.2 * (x**2 - 4) + ) + parabola.set_stroke(RED_D) + smallest_line = Line( + circle.pfp(0.83), + parabola.pfp(0.76), + stroke_width=3 + ) + + self.add(circle, parabola, smallest_line) + + l_axes = Axes( + (0, 10), + (-3, 8), + width=6, height=4.5, + ) + l_axes.move_to(grid[0], DOWN).shift(0.25 * UP) + x_label = Text("production", font_size=24) + x_label.next_to(l_axes.x_axis, DOWN, SMALL_BUFF, aligned_edge=RIGHT) + y_label = Text("profit", font_size=24) + y_label.next_to(l_axes.y_axis, RIGHT, SMALL_BUFF, aligned_edge=UP) + graph = l_axes.get_graph( + lambda x: -0.07 * x * (x - 4) * (x - 9.5) + ) + graph.set_stroke(GREEN, 3) + + self.add(l_axes, x_label, y_label, graph) + + +class ConcreteToAbstract(Scene): + def construct(self): + self.add( + get_h_line().move_to(FRAME_HEIGHT * UP / 6), + get_h_line().move_to(FRAME_HEIGHT * DOWN / 6), + ) + + labels = VGroup( + Text("Algebra"), + Text("Numbers"), + Text("Quantities"), + ) + for i, label in enumerate(labels): + label.scale(30 / label.font_size) + label.to_corner(UL, buff=SMALL_BUFF) + label.shift(i * FRAME_HEIGHT * DOWN / 3) + + self.add(labels) + + # Algebra + expr = Tex( + "x^2 - y^2 = (x + y)(x - y)", + tex_to_color_map={"x": BLUE_D, "y": BLUE_B} + ) + expr.scale(1.5) + expr.move_to(FRAME_HEIGHT * UP / 3) + expr.to_edge(LEFT, buff=LARGE_BUFF) + self.add(expr) + + # Numbers + tricks = VGroup( + Tex("143 = (12 + 1)(12 - 1) = 13 \\cdot 11"), + Tex("3{,}599 = (60 + 1)(60 - 1) = 61 \\cdot 59"), + Tex("9{,}991 = (100 + 3)(100 - 3) = 103 \\cdot 97"), + ) + tricks.arrange(DOWN, aligned_edge=LEFT) + tricks[0].shift((tricks[1][0][5].get_x() - tricks[0][0][3].get_x()) * RIGHT) + tricks.set_height(FRAME_HEIGHT / 3 - 1) + tricks.center() + brace = Brace(tricks, LEFT) + words = TexText("Factoring\\\\tricks", font_size=30) + words.set_color(GREY_A) + words.next_to(brace, LEFT) + VGroup(tricks, brace, words).to_edge(LEFT, buff=MED_LARGE_BUFF) + + self.add(tricks, brace, words) + self.wait() + + # Arrows + arrow = Arrow( + ORIGIN, FRAME_HEIGHT * UP / 3, + path_arc=60 * DEGREES, + thickness=0.15, + fill_color=YELLOW, + stroke_color=YELLOW, + ) + up_arrows = VGroup(arrow.copy().shift(FRAME_HEIGHT * DOWN / 3), arrow) + up_arrows.to_edge(RIGHT, buff=1.5) + + self.play(Write(up_arrows, lag_ratio=0.5)) + self.wait() + + top_words = Text("Once you understand\n algebra...") + top_words.next_to(up_arrows, UP) + top_words.shift_onto_screen() + top_words.set_color(YELLOW) + + self.play(FadeIn(top_words, lag_ratio=0.05)) + self.play(LaggedStartMap(Rotate, up_arrows, angle=PI, axis=RIGHT)) + up_arrows.refresh_unit_normal() + self.wait() + + new_top_words = Text("If you're learning\n algebra.") + new_top_words.move_to(top_words) + new_top_words.match_color(top_words) + self.play( + FadeTransform(top_words, new_top_words), + LaggedStartMap(Rotate, up_arrows, angle=PI, axis=RIGHT) + ) + up_arrows.refresh_unit_normal() + self.wait() + + self.embed() + + +class DifferenceOfSquares(Scene): + def construct(self): + x = 6 + y = 1 + squares = VGroup(*[ + VGroup(*[ + Square() + for x in range(x) + ]).arrange(RIGHT, buff=0) + for y in range(x) + ]).arrange(DOWN, buff=0) + squares.set_height(4) + squares.set_stroke(BLUE_D, 3) + squares.set_fill(BLUE_D, 0.5) + + last_row_parts = VGroup() + for row in squares[-y:]: + row[-y:].set_color(GREY_E) + row[:-y].set_color(BLUE_B) + last_row_parts.add(row[:-y]) + squares.to_edge(LEFT) + + arrow = Vector(RIGHT, color=WHITE) + arrow.shift(1.5 * LEFT) + squares.next_to(arrow, LEFT) + + new_squares = squares[:-y].copy() + new_squares.next_to(arrow, RIGHT) + new_squares.align_to(squares, UP) + + x1 = Tex(str(x)).set_color(BLUE_D) + x2 = x1.copy() + x1.next_to(squares, UP) + x2.next_to(squares, LEFT) + y1 = Tex(str(y)).set_color(BLUE_B) + y2 = y1.copy() + y1.next_to(squares[-int(np.ceil(y / 2))], RIGHT) + y2.next_to(squares[-1][-int(np.ceil(y / 2))], DOWN) + + xpy = Tex(str(x), "+", str(y)) + xmy = Tex(str(x), "-", str(y)) + for mob in xpy, xmy: + mob[0].set_color(BLUE) + mob[2].set_color(BLUE_B) + xpy.next_to(new_squares, UP) + # xmy.rotate(90 * DEGREES) + xmy.next_to(new_squares, RIGHT) + xmy.shift(squares[0][0].get_width() * RIGHT) + + self.add(squares, x1, x2, y1, y2) + self.play( + ReplacementTransform( + squares[:-y].copy().set_fill(opacity=0), + new_squares + ), + ShowCreation(arrow), + lag_ratio=0, + ) + last_row_parts = last_row_parts.copy() + last_row_parts.save_state() + last_row_parts.set_fill(opacity=0) + self.play( + last_row_parts.restore, + last_row_parts.rotate, -90 * DEGREES, + last_row_parts.next_to, new_squares, RIGHT, {"buff": 0}, + lag_ratio=0, + ) + self.play(Write(xmy), Write(xpy)) + self.wait() + + +class AbstractVectorSpace(Scene): + def construct(self): + self.add(get_h_line()) + top_title = Text("Abstract vector space axioms") + top_title.to_edge(UP, buff=MED_SMALL_BUFF) + low_title = Text("Concrete vectors") + low_title.next_to(ORIGIN, DOWN, buff=MED_SMALL_BUFF) + self.add(top_title, low_title) + + # Vectors + kw = {"bracket_h_buff": 0.1} + columns = VGroup( + Matrix([["1"], ["1"]], **kw).set_color(BLUE_B), + Tex("+"), + Matrix([["-2"], ["3"]], **kw).set_color(BLUE_D), + Tex("="), + Matrix([["1 - 2"], ["1 + 3"]], **kw).set_color(GREEN), + ) + columns.arrange(RIGHT, buff=SMALL_BUFF) + columns.next_to(low_title, DOWN, LARGE_BUFF) + columns.to_edge(LEFT) + + arrows = VGroup( + Arrow(ORIGIN, (1, 1), fill_color=BLUE_B, buff=0), + Arrow((1, 1), (-1, 4), fill_color=BLUE_D, buff=0), + Arrow(ORIGIN, (-1, 4), fill_color=GREEN, buff=0), + ) + arrows.match_height(columns) + arrows.scale(1.5) + arrows.match_y(columns) + arrows.match_x(low_title) + + funcs = Tex( + "(f + g)(x) = f(x) + g(x)", + tex_to_color_map={"f": BLUE_B, "g": BLUE_D} + ) + funcs.next_to(arrows, RIGHT, LARGE_BUFF) + + self.add(columns) + self.add(arrows) + self.add(funcs) + + # Axioms + u_tex = "\\vec{\\textbf{u}}" + w_tex = "\\vec{\\textbf{w}}" + v_tex = "\\vec{\\textbf{v}}" + axioms = VGroup(*it.starmap(Tex, [ + ( + "1. \\,", + u_tex, "+", "(", v_tex, "+", w_tex, ")=(", + u_tex, "+", v_tex, ")+", w_tex + ), + ( + "2. \\,", + v_tex, "+", w_tex, "=", w_tex, "+", v_tex + ), + ( + "3. \\,", + "\\textbf{0}+", v_tex, + "=", v_tex, "\\text{ for all }", v_tex + ), + ( + "4. \\,", + "\\forall", v_tex, "\\;\\exists", w_tex, + "\\text{ s.t. }", v_tex, "+", w_tex, "=\\textbf{0}" + ), + ( + "5. \\,", + "a", "(", "b", v_tex, ")=(", "a", "b", ")", v_tex + ), + ( + "6. \\,", + "1", v_tex, "=", v_tex + ), + ( + "7. \\,", + "a", "(", v_tex, "+", w_tex, ")", "=", + "a", v_tex, "+", "a", w_tex + ), + ( + "8. \\,", + "(", "a", "+", "b", ")", v_tex, "=", + "a", v_tex, "+", "b", v_tex + ), + ])) + for axiom in axioms: + axiom.set_color_by_tex_to_color_map({ + u_tex: BLUE_B, + w_tex: BLUE_D, + v_tex: GREEN, + }) + axioms[:4].arrange(DOWN, buff=MED_LARGE_BUFF, aligned_edge=LEFT) + axioms[4:].arrange(DOWN, buff=MED_LARGE_BUFF, aligned_edge=LEFT) + axioms[4:].next_to(axioms[:4], RIGHT, buff=1.5) + axioms.set_height(2.5) + axioms.next_to(top_title, DOWN) + + for axiom in axioms: + self.play(FadeIn(axiom)) + + self.add(axioms) + + +class Nicheness(Scene): + def construct(self): + words = TexText( + "Perceived ", "nicheness", + " $>$ ", + "Actual ", "nichness", + ) + words[:2].set_color(BLUE_B) + words[3:].set_color(BLUE_D) + + self.add(words[:2]) + self.wait() + self.play( + FadeTransformPieces(words[:2].copy(), words[3:], path_arc=PI / 2), + GrowFromCenter(words[2]), + ) + self.wait() + + +class TransitionToProductionQuality(TeacherStudentsScene): + def construct(self): + self.play( + self.students[0].animate.change("pondering"), + self.students[2].animate.change("pondering"), + ) + self.student_says( + TexText("What parts of\\\\production quality matter?"), + student_index=1 + ) + self.play( + self.teacher.animate.change("happy"), + ) + self.wait(3) + + +class SurfaceExample(Scene): + CONFIG = { + "camera_class": ThreeDCamera, + } + + def construct(self): + torus1 = Torus(r1=1, r2=1) + torus2 = Torus(r1=3, r2=1) + sphere = Sphere(radius=2.5, resolution=torus1.resolution) + # You can texture a surface with up to two images, which will + # be interpreted as the side towards the light, and away from + # the light. These can be either urls, or paths to a local file + # in whatever you've set as the image directory in + # the custom_config.yml file + + day_texture = "EarthTextureMap" + night_texture = "NightEarthTextureMap" + + surfaces = [ + TexturedSurface(surface, day_texture, night_texture) + for surface in [sphere, torus1, torus2] + ] + + for mob in surfaces: + mob.mesh = SurfaceMesh(mob) + mob.mesh.set_stroke(BLUE, 1, opacity=0.5) + + # Set perspective + frame = self.camera.frame + frame.set_euler_angles( + theta=-30 * DEGREES, + phi=70 * DEGREES, + ) + + surface = surfaces[0] + + self.play( + FadeIn(surface), + ShowCreation(surface.mesh, lag_ratio=0.01, run_time=3), + ) + for mob in surfaces: + mob.add(mob.mesh) + surface.save_state() + self.play(Rotate(surface, PI / 2), run_time=2) + for mob in surfaces[1:]: + mob.rotate(PI / 2) + + self.play( + Transform(surface, surfaces[1]), + run_time=3 + ) + + self.play( + Transform(surface, surfaces[2]), + # Move camera frame during the transition + frame.animate.increment_phi(-10 * DEGREES), + frame.animate.increment_theta(-20 * DEGREES), + run_time=3 + ) + # Add ambient rotation + frame.add_updater(lambda m, dt: m.increment_theta(-0.1 * dt)) + + # Play around with where the light is + + light = self.camera.light_source + self.add(light) + light.save_state() + self.play(light.animate.move_to(3 * IN), run_time=5) + self.play(light.animate.shift(10 * OUT), run_time=5) + + +class Spotlight(Scene): + def construct(self): + self.add(FullScreenRectangle()) + screen = ScreenRectangle() + screen.set_height(6.0) + screen.set_stroke(WHITE, 2) + screen.set_fill(BLACK, 1) + screen.to_edge(DOWN) + animated_screen = AnimatedBoundary(screen) + self.add(screen, animated_screen) + self.wait(16) + + +class BadManimExample(Scene): + def construct(self): + words = TexText( + "Does any of this ", + "need to be ", + "animated?\\\\", + "Much less programatically?" + ) + words[-1].shift(MED_SMALL_BUFF * DOWN) + words.set_width(FRAME_WIDTH - 2) + + self.play(Write(words[0]), run_time=1) + self.play(FadeIn(words[1], scale=10, shift=0.25 * UP)) + self.play(TransformMatchingShapes(words[0].copy(), words[2], path_arc=PI / 2)) + self.wait() + self.play(Transform( + VGroup(*words[0], *words[1], *words[2]).copy(), + words[3], + lag_ratio=0.03, + run_time=1 + )) + self.wait() + + +class WhereCanIEngageWithOthers(TeacherStudentsScene): + def construct(self): + self.student_says( + TexText("Where can I find\\\\others joining SoME1?"), + student_index=0, + added_anims=[ + self.students[1].animate.change("pondering", UL), + self.students[2].animate.change("pondering", UL), + ] + ) + self.play( + self.teacher.animate.change("tease"), + ) + self.wait(4) + + +class BeTheFirst(Scene): + def construct(self): + circ = Circle(color=RED) + circ.stretch(5, 0) + circ.set_height(0.4) + + circ.to_edge(LEFT) + words = Text("Be the first!") + words.next_to(circ, RIGHT, aligned_edge=UP) + words.set_color(RED) + + self.play(ShowCreation(circ)) + self.play(Write(words)) + self.wait() + + +class SoME1EndScreen(PatreonEndScreen): + pass \ No newline at end of file