2020-12-31 13:05:22 -08:00
|
|
|
from imports_3b1b 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,
|
|
|
|
}
|
2021-01-01 14:48:59 -08:00
|
|
|
|
|
|
|
|
|
|
|
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)
|