from manim_imports_ext import * import math class StreamIntro(Scene): def construct(self): # Add logo logo = Logo() spikes = VGroup(*[ spike for layer in logo.spike_layers for spike in layer ]) self.add(*logo.family_members_with_points()) # Add label label = TextMobject("The lesson will\\\\begin shortly") label.scale(2) label.next_to(logo, DOWN) self.add(label) self.camera.frame.move_to(DOWN) for spike in spikes: point = spike.get_start() spike.angle = angle_of_vector(point) anims = [] for spike in spikes: anims.append(Rotate( spike, spike.angle * 28 * 2, about_point=ORIGIN, rate_func=linear, )) self.play(*anims, run_time=60 * 5) self.wait(20) class OldStreamIntro(Scene): def construct(self): morty = Mortimer() morty.flip() morty.set_height(2) morty.to_corner(DL) self.play(PiCreatureSays( morty, "The lesson will\\\\begin soon.", bubble_kwargs={ "height": 2, "width": 3, }, target_mode="hooray", )) bound = AnimatedBoundary(morty.bubble.content, max_stroke_width=1) self.add(bound, morty.bubble, morty.bubble.content) self.remove(morty.bubble.content) morty.bubble.set_fill(opacity=0) self.camera.frame.scale(0.6, about_edge=DL) self.play(Blink(morty)) self.wait(5) self.play(Blink(morty)) self.wait(3) return text = TextMobject("The lesson will\\\\begin soon.") text.set_height(1.5) text.to_corner(DL, buff=LARGE_BUFF) self.add(text) class QuadraticFormula(TeacherStudentsScene): def construct(self): formula = TexMobject( "\\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}", ) formula.next_to(self.students, UP, buff=MED_LARGE_BUFF, aligned_edge=LEFT) self.add(formula) self.change_student_modes( "angry", "tired", "sad", look_at_arg=formula, ) self.teacher_says( "It doesn't have\\\\to be this way.", bubble_kwargs={ "width": 4, "height": 3, } ) self.wait(5) self.change_student_modes( "pondering", "thinking", "erm", look_at_arg=formula ) self.wait(12) class SimplerQuadratic(Scene): def construct(self): tex = TexMobject("m \\pm \\sqrt{m^2 - p}") tex.set_stroke(BLACK, 12, background=True) tex.scale(1.5) self.add(tex) class CosGraphs(Scene): def construct(self): axes = Axes( x_min=-0.75 * TAU, x_max=0.75 * TAU, y_min=-1.5, y_max=1.5, x_axis_config={ "tick_frequency": PI / 4, "include_tip": False, }, y_axis_config={ "tick_frequency": 0.5, "include_tip": False, "unit_size": 1.5, } ) graph1 = axes.get_graph(np.cos) graph2 = axes.get_graph(lambda x: np.cos(x)**2) graph1.set_stroke(YELLOW, 5) graph2.set_stroke(BLUE, 5) label1 = TexMobject("\\cos(x)") label2 = TexMobject("\\cos^2(x)") label1.match_color(graph1) label1.set_height(0.75) label1.next_to(axes.input_to_graph_point(-PI, graph1), DOWN) label2.match_color(graph2) label2.set_height(0.75) label2.next_to(axes.input_to_graph_point(PI, graph2), UP) for mob in [graph1, graph2, label1, label2]: mc = mob.copy() mc.set_stroke(BLACK, 10, background=True) self.add(mc) self.add(axes) self.add(graph1) self.add(graph2) self.add(label1) self.add(label2) self.embed() class SineWave(Scene): def construct(self): w_axes = self.get_wave_axes() square, circle, c_axes = self.get_edge_group() self.add(w_axes) self.add(square, circle, c_axes) theta_tracker = ValueTracker(0) c_dot = Dot(color=YELLOW) c_line = Line(DOWN, UP, color=GREEN) w_dot = Dot(color=YELLOW) w_line = Line(DOWN, UP, color=GREEN) def update_c_dot(dot, axes=c_axes, tracker=theta_tracker): theta = tracker.get_value() dot.move_to(axes.c2p( np.cos(theta), np.sin(theta), )) def update_c_line(line, axes=c_axes, tracker=theta_tracker): theta = tracker.get_value() x = np.cos(theta) y = np.sin(theta) if y == 0: y = 1e-6 line.put_start_and_end_on( axes.c2p(x, 0), axes.c2p(x, y), ) def update_w_dot(dot, axes=w_axes, tracker=theta_tracker): theta = tracker.get_value() dot.move_to(axes.c2p(theta, np.sin(theta))) def update_w_line(line, axes=w_axes, tracker=theta_tracker): theta = tracker.get_value() x = theta y = np.sin(theta) if y == 0: y = 1e-6 line.put_start_and_end_on( axes.c2p(x, 0), axes.c2p(x, y), ) def get_partial_circle(circle=circle, tracker=theta_tracker): result = circle.copy() theta = tracker.get_value() result.pointwise_become_partial( circle, 0, clip(theta / TAU, 0, 1), ) result.set_stroke(RED, width=3) return result def get_partial_wave(axes=w_axes, tracker=theta_tracker): theta = tracker.get_value() graph = axes.get_graph(np.sin, x_min=0, x_max=theta, step_size=0.025) graph.set_stroke(BLUE, 3) return graph def get_h_line(axes=w_axes, tracker=theta_tracker): theta = tracker.get_value() return Line( axes.c2p(0, 0), axes.c2p(theta, 0), stroke_color=RED ) c_dot.add_updater(update_c_dot) c_line.add_updater(update_c_line) w_dot.add_updater(update_w_dot) w_line.add_updater(update_w_line) partial_circle = always_redraw(get_partial_circle) partial_wave = always_redraw(get_partial_wave) h_line = always_redraw(get_h_line) self.add(partial_circle) self.add(partial_wave) self.add(h_line) self.add(c_line, c_dot) self.add(w_line, w_dot) sin_label = TexMobject( "\\sin\\left(\\theta\\right)", tex_to_color_map={"\\theta": RED} ) sin_label.next_to(w_axes.get_top(), UR) self.add(sin_label) self.play( theta_tracker.set_value, 1.25 * TAU, run_time=15, rate_func=linear, ) def get_wave_axes(self): wave_axes = Axes( x_min=0, x_max=1.25 * TAU, y_min=-1.0, y_max=1.0, x_axis_config={ "tick_frequency": TAU / 8, "unit_size": 1.0, }, y_axis_config={ "tick_frequency": 0.5, "include_tip": False, "unit_size": 1.5, } ) wave_axes.y_axis.add_numbers( -1, 1, number_config={"num_decimal_places": 1} ) wave_axes.to_edge(RIGHT, buff=MED_SMALL_BUFF) pairs = [ (PI / 2, "\\frac{\\pi}{2}"), (PI, "\\pi"), (3 * PI / 2, "\\frac{3\\pi}{2}"), (2 * PI, "2\\pi"), ] syms = VGroup() for val, tex in pairs: sym = TexMobject(tex) sym.scale(0.5) sym.next_to(wave_axes.c2p(val, 0), DOWN, MED_SMALL_BUFF) syms.add(sym) wave_axes.add(syms) theta = TexMobject("\\theta") theta.set_color(RED) theta.next_to(wave_axes.x_axis.get_end(), UP) wave_axes.add(theta) return wave_axes def get_edge_group(self): axes_max = 1.25 radius = 1.5 axes = Axes( x_min=-axes_max, x_max=axes_max, y_min=-axes_max, y_max=axes_max, axis_config={ "tick_frequency": 0.5, "include_tip": False, "numbers_with_elongated_ticks": [-1, 1], "tick_size": 0.05, "unit_size": radius, }, ) axes.to_edge(LEFT, buff=MED_LARGE_BUFF) background = SurroundingRectangle(axes, buff=MED_SMALL_BUFF) background.set_stroke(WHITE, 1) background.set_fill(GREY_E, 1) circle = Circle(radius=radius) circle.move_to(axes) circle.set_stroke(WHITE, 1) nums = VGroup() for u in 1, -1: num = Integer(u) num.set_height(0.2) num.set_stroke(BLACK, 3, background=True) num.next_to(axes.c2p(u, 0), DOWN + u * RIGHT, SMALL_BUFF) nums.add(num) axes.add(nums) return background, circle, axes class CosWave(SineWave): CONFIG = { "include_square": False, } def construct(self): w_axes = self.get_wave_axes() square, circle, c_axes = self.get_edge_group() self.add(w_axes) self.add(square, circle, c_axes) theta_tracker = ValueTracker(0) c_dot = Dot(color=YELLOW) c_line = Line(DOWN, UP, color=GREEN) w_dot = Dot(color=YELLOW) w_line = Line(DOWN, UP, color=GREEN) def update_c_dot(dot, axes=c_axes, tracker=theta_tracker): theta = tracker.get_value() dot.move_to(axes.c2p( np.cos(theta), np.sin(theta), )) def update_c_line(line, axes=c_axes, tracker=theta_tracker): theta = tracker.get_value() x = np.cos(theta) y = np.sin(theta) line.set_points_as_corners([ axes.c2p(0, y), axes.c2p(x, y), ]) def update_w_dot(dot, axes=w_axes, tracker=theta_tracker): theta = tracker.get_value() dot.move_to(axes.c2p(theta, np.cos(theta))) def update_w_line(line, axes=w_axes, tracker=theta_tracker): theta = tracker.get_value() x = theta y = np.cos(theta) if y == 0: y = 1e-6 line.set_points_as_corners([ axes.c2p(x, 0), axes.c2p(x, y), ]) def get_partial_circle(circle=circle, tracker=theta_tracker): result = circle.copy() theta = tracker.get_value() result.pointwise_become_partial( circle, 0, clip(theta / TAU, 0, 1), ) result.set_stroke(RED, width=3) return result def get_partial_wave(axes=w_axes, tracker=theta_tracker): theta = tracker.get_value() graph = axes.get_graph(np.cos, x_min=0, x_max=theta, step_size=0.025) graph.set_stroke(PINK, 3) return graph def get_h_line(axes=w_axes, tracker=theta_tracker): theta = tracker.get_value() return Line( axes.c2p(0, 0), axes.c2p(theta, 0), stroke_color=RED ) def get_square(line=c_line): square = Square() square.set_stroke(WHITE, 1) square.set_fill(MAROON_B, opacity=0.5) square.match_width(line) square.move_to(line, DOWN) return square def get_square_graph(axes=w_axes, tracker=theta_tracker): theta = tracker.get_value() graph = axes.get_graph( lambda x: np.cos(x)**2, x_min=0, x_max=theta, step_size=0.025 ) graph.set_stroke(MAROON_B, 3) return graph c_dot.add_updater(update_c_dot) c_line.add_updater(update_c_line) w_dot.add_updater(update_w_dot) w_line.add_updater(update_w_line) h_line = always_redraw(get_h_line) partial_circle = always_redraw(get_partial_circle) partial_wave = always_redraw(get_partial_wave) self.add(partial_circle) self.add(partial_wave) self.add(h_line) self.add(c_line, c_dot) self.add(w_line, w_dot) if self.include_square: self.add(always_redraw(get_square)) self.add(always_redraw(get_square_graph)) cos_label = TexMobject( "\\cos\\left(\\theta\\right)", tex_to_color_map={"\\theta": RED} ) cos_label.next_to(w_axes.get_top(), UR) self.add(cos_label) self.play( theta_tracker.set_value, 1.25 * TAU, run_time=15, rate_func=linear, ) class CosSquare(CosWave): CONFIG = { "include_square": True } class ComplexNumberPreview(Scene): def construct(self): plane = ComplexPlane(axis_config={"stroke_width": 4}) plane.add_coordinates() z = complex(2, 1) dot = Dot() dot.move_to(plane.n2p(z)) label = TexMobject("2+i") label.set_color(YELLOW) dot.set_color(YELLOW) label.next_to(dot, UR, SMALL_BUFF) label.set_stroke(BLACK, 5, background=True) line = Line(plane.n2p(0), plane.n2p(z)) arc = Arc(start_angle=0, angle=np.log(z).imag, radius=0.5) self.add(plane) self.add(line, arc) self.add(dot) self.add(label) self.embed() class ComplexMultiplication(Scene): def construct(self): # Add plane plane = ComplexPlane() plane.add_coordinates() z = complex(2, 1) z_dot = Dot(color=PINK) z_dot.move_to(plane.n2p(z)) z_label = TexMobject("z") z_label.next_to(z_dot, UR, buff=0.5 * SMALL_BUFF) z_label.match_color(z_dot) self.add(plane) self.add(z_dot) self.add(z_label) # Show 1 one_vect = Vector(RIGHT) one_vect.set_color(YELLOW) one_vect.target = Vector(plane.n2p(z)) one_vect.target.match_style(one_vect) z_rhs = TexMobject("=", "z \\cdot 1") z_rhs[1].match_color(one_vect) z_rhs.next_to(z_label, RIGHT, 1.5 * SMALL_BUFF, aligned_edge=DOWN) z_rhs.set_stroke(BLACK, 3, background=True) one_label, i_label = [l for l in plane.coordinate_labels if l.get_value() == 1] self.play(GrowArrow(one_vect)) self.wait() self.add(one_vect, z_dot) self.play( MoveToTarget(one_vect), TransformFromCopy(one_label, z_rhs), ) self.wait() # Show i i_vect = Vector(UP, color=GREEN) zi_point = plane.n2p(z * complex(0, 1)) i_vect.target = Vector(zi_point) i_vect.target.match_style(i_vect) i_vect_label = TexMobject("z \\cdot i") i_vect_label.match_color(i_vect) i_vect_label.set_stroke(BLACK, 3, background=True) i_vect_label.next_to(zi_point, UL, SMALL_BUFF) self.play(GrowArrow(i_vect)) self.wait() self.play( MoveToTarget(i_vect), TransformFromCopy(i_label, i_vect_label), run_time=1, ) self.wait() self.play( TransformFromCopy(one_vect, i_vect.target, path_arc=-90 * DEGREES), ) self.wait() # Transform plane plane.generate_target() for mob in plane.target.family_members_with_points(): if isinstance(mob, Line): mob.set_stroke(GREY, opacity=0.5) new_plane = ComplexPlane(faded_line_ratio=0) self.remove(plane) self.add(plane, new_plane, *self.mobjects) new_plane.generate_target() new_plane.target.apply_complex_function(lambda w, z=z: w * z) self.play( MoveToTarget(plane), MoveToTarget(new_plane), run_time=6, rate_func=there_and_back_with_pause ) self.wait() # Show Example Point w = complex(2, -1) w_dot = Dot(plane.n2p(w), color=WHITE) one_vects = VGroup(*[Vector(RIGHT) for x in range(2)]) one_vects.arrange(RIGHT, buff=0) one_vects.move_to(plane.n2p(0), LEFT) one_vects.set_color(YELLOW) new_i_vect = Vector(DOWN) new_i_vect.move_to(plane.n2p(2), UP) new_i_vect.set_color(GREEN) vects = VGroup(*one_vects, new_i_vect) vects.set_opacity(0.8) w_group = VGroup(*vects, w_dot) w_group.target = VGroup( one_vect.copy().set_opacity(0.8), one_vect.copy().shift(plane.n2p(z)).set_opacity(0.8), i_vect.copy().rotate(PI, about_point=ORIGIN).shift(2 * plane.n2p(z)).set_opacity(0.8), Dot(plane.n2p(w * z), color=WHITE) ) self.play(FadeInFromLarge(w_dot)) self.wait() self.play(ShowCreation(vects)) self.wait() self.play( MoveToTarget(plane), MoveToTarget(new_plane), MoveToTarget(w_group), run_time=2, path_arc=np.log(z).imag, ) self.wait() class RotatePiCreature(Scene): def construct(self): randy = Randolph(mode="thinking") randy.set_height(6) plane = ComplexPlane(x_min=-12, x_max=12) plane.add_coordinates() self.camera.frame.move_to(3 * RIGHT) self.add(randy) self.wait() self.play(Rotate(randy, 30 * DEGREES, run_time=3)) self.wait() self.play(Rotate(randy, -30 * DEGREES)) self.add(plane, randy) self.play( ShowCreation(plane), randy.set_opacity, 0.75, ) self.wait() dots = VGroup() for mob in randy.family_members_with_points(): for point in mob.get_anchors(): dot = Dot(point) dot.set_height(0.05) dots.add(dot) self.play(ShowIncreasingSubsets(dots)) self.wait() label = VGroup( TexMobject("(x + iy)"), Vector(DOWN), TexMobject("(\\cos(30^\\circ) + i\\sin(30^\\circ))", "(x + iy)"), ) label[2][0].set_color(YELLOW) label.arrange(DOWN) label.to_corner(DR) label.shift(3 * RIGHT) for mob in label: mob.add_background_rectangle() self.play(FadeIn(label)) self.wait() randy.add(dots) self.play(Rotate(randy, 30 * DEGREES), run_time=3) self.wait() class ExpMeaning(Scene): CONFIG = { "include_circle": True } def construct(self): # Plane plane = ComplexPlane(y_min=-6, y_max=6) plane.shift(1.5 * DOWN) plane.add_coordinates() if self.include_circle: circle = Circle(radius=1) circle.set_stroke(RED, 1) circle.move_to(plane.n2p(0)) plane.add(circle) # Equation equation = TexMobject( "\\text{exp}(i\\theta) = ", "1 + ", "i\\theta + ", "{(i\\theta)^2 \\over 2} + ", "{(i\\theta)^3 \\over 6} + ", "{(i\\theta)^4 \\over 24} + ", "\\cdots", tex_to_color_map={ "\\theta": YELLOW, "i": GREEN, }, ) equation.add_background_rectangle(buff=MED_SMALL_BUFF, opacity=1) equation.to_edge(UL, buff=0) # Label theta_tracker = ValueTracker(0) theta_label = VGroup( TexMobject("\\theta = "), DecimalNumber(0, num_decimal_places=4) ) theta_decimal = theta_label[1] theta_decimal.add_updater( lambda m, tt=theta_tracker: m.set_value(tt.get_value()) ) theta_label.arrange(RIGHT, buff=SMALL_BUFF) theta_label.set_color(YELLOW) theta_label.add_to_back(BackgroundRectangle( theta_label, buff=MED_SMALL_BUFF, fill_opacity=1, )) theta_label.next_to(equation, DOWN, aligned_edge=LEFT, buff=0) # Vectors def get_vectors(n_vectors=20, plane=plane, tracker=theta_tracker): last_tip = plane.n2p(0) z = complex(0, tracker.get_value()) vects = VGroup() colors = color_gradient([GREEN, YELLOW, RED], 6) for i, color in zip(range(n_vectors), it.cycle(colors)): vect = Vector(complex_to_R3(z**i / math.factorial(i))) vect.set_color(color) vect.shift(last_tip) last_tip = vect.get_end() vects.add(vect) return vects vectors = always_redraw(get_vectors) dot = Dot() dot.set_height(0.03) dot.add_updater(lambda m, vs=vectors: m.move_to(vs[-1].get_end())) self.add(plane) self.add(vectors) self.add(dot) self.add(equation) self.add(theta_label) self.play( theta_tracker.set_value, 1, run_time=3, rate_func=smooth, ) self.wait() for target in PI, TAU: self.play( theta_tracker.set_value, target, run_time=10, ) self.wait() self.embed() class ExpMeaningWithoutCircle(ExpMeaning): CONFIG = { "include_circle": False, } class PositionAndVelocityExample(Scene): def construct(self): plane = NumberPlane() self.add(plane) self.embed() class EulersFormula(Scene): def construct(self): kw = {"tex_to_color_map": {"\\theta": YELLOW}} formula = TexMobject( "&e^{i\\theta} = \\\\ &\\cos\\left(\\theta\\right) + i\\cdot\\sin\\left(\\theta\\right)", )[0] formula[:4].scale(2, about_edge=UL) formula[:4].shift(SMALL_BUFF * RIGHT + MED_LARGE_BUFF * UP) VGroup(formula[2], formula[8], formula[17]).set_color(YELLOW) formula.scale(1.5) formula.set_stroke(BLACK, 5, background=True) self.add(formula) class EtoILimit(Scene): def construct(self): tex = TexMobject( "\\lim_{n \\to \\infty} \\left(1 + \\frac{it}{n}\\right)^n", )[0] VGroup(tex[3], tex[12], tex[14]).set_color(YELLOW) tex[9].set_color(BLUE) tex.scale(1.5) tex.set_stroke(BLACK, 5, background=True) # self.add(tex) text = TextMobject("Interest rate\\\\of ", "$\\sqrt{-1}$") text[1].set_color(BLUE) text.scale(1.5) text.set_stroke(BLACK, 5, background=True) self.add(text) class ImaginaryInterestRates(Scene): def construct(self): plane = ComplexPlane(x_min=-20, x_max=20, y_min=-20, y_max=20) plane.add_coordinates() circle = Circle(radius=1) circle.set_stroke(YELLOW, 1) self.add(plane, circle) frame = self.camera.frame frame.save_state() frame.generate_target() frame.target.set_width(25) frame.target.move_to(8 * RIGHT + 2 * DOWN) dt_tracker = ValueTracker(1) def get_vectors(tracker=dt_tracker, plane=plane, T=8): dt = tracker.get_value() last_z = 1 vects = VGroup() for t in np.arange(0, T, dt): next_z = last_z + complex(0, 1) * last_z * dt vects.add(Arrow( plane.n2p(last_z), plane.n2p(next_z), buff=0, )) last_z = next_z vects.set_submobject_colors_by_gradient(YELLOW, GREEN, BLUE) return vects vects = get_vectors() line = Line() line.add_updater(lambda m, v=vects: m.put_start_and_end_on( ORIGIN, v[-1].get_start() if len(v) > 0 else RIGHT, )) self.add(line) self.play( ShowIncreasingSubsets( vects, rate_func=linear, int_func=np.ceil, ), MoveToTarget( frame, rate_func=squish_rate_func(smooth, 0.5, 1), ), run_time=8, ) self.wait() self.play(FadeOut(line)) self.remove(vects) vects = always_redraw(get_vectors) self.add(vects) self.play( Restore(frame), dt_tracker.set_value, 0.2, run_time=5, ) self.wait() self.play(dt_tracker.set_value, 0.01, run_time=3) vects.clear_updaters() self.wait() theta_tracker = ValueTracker(0) def get_arc(tracker=theta_tracker): theta = tracker.get_value() arc = Arc( radius=1, stroke_width=3, stroke_color=RED, start_angle=0, angle=theta ) return arc arc = always_redraw(get_arc) dot = Dot() dot.add_updater(lambda m, arc=arc: m.move_to(arc.get_end())) label = VGroup( DecimalNumber(0, num_decimal_places=3), TextMobject("Years") ) label.arrange(RIGHT, aligned_edge=DOWN) label.move_to(3 * LEFT + 1.5 * UP) label[0].set_color(RED) label[0].add_updater(lambda m, tt=theta_tracker: m.set_value(tt.get_value())) self.add(BackgroundRectangle(label), label, arc, dot) for n in range(1, 5): target = n * PI / 2 self.play( theta_tracker.set_value, target, run_time=3 ) self.wait(2) class Logs(Scene): def construct(self): log = TexMobject( "&\\text{log}(ab) = \\\\ &\\text{log}(a) + \\text{log}(b)", tex_to_color_map={"a": BLUE, "b": YELLOW}, alignment="", ) log.scale(1.5) log.set_stroke(BLACK, 5, background=True) self.add(log) class LnX(Scene): def construct(self): sym = TexMobject("\\ln(x)") sym.scale(3) sym.shift(UP) sym.set_stroke(BLACK, 5, background=True) word = TextMobject("Natural?") word.scale(1.5) word.set_color(YELLOW) word.set_stroke(BLACK, 5, background=True) word.next_to(sym, DOWN, buff=0.5) arrow = Arrow(word.get_top(), sym[0][1].get_bottom()) self.add(sym, word, arrow) class HarmonicSum(Scene): def construct(self): axes = Axes( x_min=0, x_max=13, y_min=0, y_max=1.25, y_axis_config={ "unit_size": 4, "tick_frequency": 0.25, } ) axes.to_corner(DL, buff=1) axes.x_axis.add_numbers() axes.y_axis.add_numbers( *np.arange(0.25, 1.25, 0.25), number_config={"num_decimal_places": 2}, ) self.add(axes) graph = axes.get_graph(lambda x: 1 / x, x_min=0.1, x_max=15) graph_fill = graph.copy() graph_fill.add_line_to(axes.c2p(15, 0)) graph_fill.add_line_to(axes.c2p(1, 0)) graph_fill.add_line_to(axes.c2p(1, 1)) graph.set_stroke(WHITE, 3) graph_fill.set_fill(BLUE_E, 0.5) graph_fill.set_stroke(width=0) self.add(graph, graph_fill) bars = VGroup() bar_labels = VGroup() for x in range(1, 15): line = Line(axes.c2p(x, 0), axes.c2p(x + 1, 1 / x)) bar = Rectangle() bar.set_fill(GREEN_E, 1) bar.replace(line, stretch=True) bars.add(bar) label = TexMobject(f"1 \\over {x}") label.set_height(0.7) label.next_to(bar, UP, SMALL_BUFF) bar_labels.add(label) bars.set_submobject_colors_by_gradient(GREEN_C, GREEN_E) bars.set_stroke(WHITE, 1) bars.set_fill(opacity=0.25) self.add(bars) self.add(bar_labels) self.embed() class PowerTower(Scene): def construct(self): mob = TexMobject("4 = x^{x^{{x^{x^{x^{\cdot^{\cdot^{\cdot}}}}}}}}") mob[0][-1].shift(0.1 * DL) mob[0][-2].shift(0.05 * DL) mob.set_height(4) mob.set_stroke(BLACK, 5, background=True) self.add(mob) class ItoTheI(Scene): def construct(self): tex = TexMobject("i^i") # tex = TexMobject("\\sqrt{-1}^{\\sqrt{-1}}") tex.set_height(3) tex.set_stroke(BLACK, 8, background=True) self.add(tex) class ComplexExponentialPlay(Scene): def setup(self): self.transform_alpha = 0 def construct(self): # Plane plane = ComplexPlane( x_min=-2 * FRAME_WIDTH, x_max=2 * FRAME_WIDTH, y_min=-2 * FRAME_HEIGHT, y_max=2 * FRAME_HEIGHT, ) plane.add_coordinates() self.add(plane) # R Dot r_dot = Dot(color=YELLOW) def update_r_dot(dot, point_tracker=self.mouse_drag_point): point = point_tracker.get_location() if abs(point[0]) < 0.1: point[0] = 0 if abs(point[1]) < 0.1: point[1] = 0 dot.move_to(point) r_dot.add_updater(update_r_dot) self.mouse_drag_point.move_to(plane.n2p(1)) # Transformed sample dots def func(z, dot=r_dot, plane=plane): r = plane.p2n(dot.get_center()) result = np.exp(r * z) if abs(result) > 20: result *= 20 / abs(result) return result sample_dots = VGroup() dot_template = Dot(radius=0.05) dot_template.set_opacity(0.8) spacing = 0.05 for x in np.arange(-7, 7, spacing): dot = dot_template.copy() dot.set_color(TEAL) dot.z = x dot.move_to(plane.n2p(dot.z)) sample_dots.add(dot) for y in np.arange(-6, 6, spacing): dot = dot_template.copy() dot.set_color(MAROON) dot.z = complex(0, y) dot.move_to(plane.n2p(dot.z)) sample_dots.add(dot) special_values = [1, complex(0, 1), -1, complex(0, -1)] special_dots = VGroup(*[ list(filter(lambda d: abs(d.z - x) < 0.01, sample_dots))[0] for x in special_values ]) for dot in special_dots: dot.set_fill(opacity=1) dot.scale(1.2) dot.set_stroke(WHITE, 2) sample_dots.save_state() def update_sample(sample, f=func, plane=plane, scene=self): sample.restore() sample.apply_function_to_submobject_positions( lambda p: interpolate( p, plane.n2p(f(plane.p2n(p))), scene.transform_alpha, ) ) return sample sample_dots.add_updater(update_sample) # Sample lines x_line = Line(plane.n2p(plane.x_min), plane.n2p(plane.x_max)) y_line = Line(plane.n2p(plane.y_min), plane.n2p(plane.y_max)) y_line.rotate(90 * DEGREES) x_line.set_color(GREEN) y_line.set_color(PINK) axis_lines = VGroup(x_line, y_line) for line in axis_lines: line.insert_n_curves(50) axis_lines.save_state() def update_axis_liens(lines=axis_lines, f=func, plane=plane, scene=self): lines.restore() lines.apply_function( lambda p: interpolate( p, plane.n2p(f(plane.p2n(p))), scene.transform_alpha, ) ) lines.make_smooth() axis_lines.add_updater(update_axis_liens) # Labels labels = VGroup( TexMobject("f(1)"), TexMobject("f(i)"), TexMobject("f(-1)"), TexMobject("f(-i)"), ) for label, dot in zip(labels, special_dots): label.set_height(0.3) label.match_color(dot) label.set_stroke(BLACK, 3, background=True) label.add_background_rectangle(opacity=0.5) def update_labels(labels, dots=special_dots, scene=self): for label, dot in zip(labels, dots): label.next_to(dot, UR, 0.5 * SMALL_BUFF) label.set_opacity(self.transform_alpha) labels.add_updater(update_labels) # Titles title = TexMobject( "f(x) =", "\\text{exp}(r\\cdot x)", tex_to_color_map={"r": YELLOW} ) title.to_corner(UL) title.set_stroke(BLACK, 5, background=True) brace = Brace(title[1:], UP, buff=SMALL_BUFF) e_pow = TexMobject("e^{rx}", tex_to_color_map={"r": YELLOW}) e_pow.add_background_rectangle() e_pow.next_to(brace, UP, buff=SMALL_BUFF) title.add(brace, e_pow) r_eq = VGroup( TexMobject("r=", tex_to_color_map={"r": YELLOW}), DecimalNumber(1) ) r_eq.arrange(RIGHT, aligned_edge=DOWN) r_eq.next_to(title, DOWN, aligned_edge=LEFT) r_eq[0].set_stroke(BLACK, 5, background=True) r_eq[1].set_color(YELLOW) r_eq[1].add_updater(lambda m: m.set_value(plane.p2n(r_dot.get_center()))) self.add(title) self.add(r_eq) # self.add(axis_lines) self.add(sample_dots) self.add(r_dot) self.add(labels) # Animations def update_transform_alpha(mob, alpha, scene=self): scene.transform_alpha = alpha frame = self.camera.frame frame.set_height(10) r_dot.clear_updaters() r_dot.move_to(plane.n2p(1)) self.play( UpdateFromAlphaFunc( VectorizedPoint(), update_transform_alpha, ) ) self.play(r_dot.move_to, plane.n2p(2)) self.wait() self.play(r_dot.move_to, plane.n2p(PI)) self.wait() self.play(r_dot.move_to, plane.n2p(np.log(2))) self.wait() self.play(r_dot.move_to, plane.n2p(complex(0, np.log(2))), path_arc=90 * DEGREES, run_time=2) self.wait() self.play(r_dot.move_to, plane.n2p(complex(0, PI / 2))) self.wait() self.play(r_dot.move_to, plane.n2p(np.log(2)), run_time=2) self.wait() self.play(frame.set_height, 14) self.play(r_dot.move_to, plane.n2p(complex(np.log(2), PI)), run_time=3) self.wait() self.play(r_dot.move_to, plane.n2p(complex(np.log(2), TAU)), run_time=3) self.wait() self.embed() def on_mouse_scroll(self, point, offset): frame = self.camera.frame if self.zoom_on_scroll: factor = 1 + np.arctan(10 * offset[1]) frame.scale(factor, about_point=ORIGIN) else: self.transform_alpha = clip(self.transform_alpha + 5 * offset[1], 0, 1) class LDMEndScreen(PatreonEndScreen): CONFIG = { "scroll_time": 20, } class ProbDiagram(Scene): def construct(self): square = Square(side_length=1) square.move_to(ORIGIN, DL) square.set_stroke(width=0) square.set_fill(BLUE_E, 1) frame = self.camera.frame frame.set_height(1.5) frame.move_to(square) tri = Polygon(ORIGIN, UP, UR) tri.set_fill(BLUE_E, 1) tri.set_stroke(width=0) tris = VGroup(tri) N = 1000 for n in range(1, N): tri = Polygon( ORIGIN, RIGHT + UP / n, RIGHT + UP / (n + 1), ) tri.set_stroke(width=0) color = BLUE_E if (n % 2 == 0) else RED_D tri.set_fill(color, 1) tris.add(tri) self.add(tris)