Files
manim/old_projects/eoc/chapter3.py
2019-05-02 20:36:14 -07:00

2826 lines
87 KiB
Python

from manimlib.imports import *
from old_projects.eoc.chapter2 import DISTANCE_COLOR, TIME_COLOR, \
VELOCITY_COLOR, Car, MoveCar
OUTPUT_COLOR = DISTANCE_COLOR
INPUT_COLOR = TIME_COLOR
DERIVATIVE_COLOR = VELOCITY_COLOR
class Chapter3OpeningQuote(OpeningQuote):
CONFIG = {
"quote" : [
"You know, for a mathematician, he did not have \\\\ enough",
"imagination.",
"But he has become a poet and \\\\ now he is fine.",
],
"highlighted_quote_terms" : {
"imagination." : BLUE,
},
"author" : "David Hilbert"
}
class PoseAbstractDerivative(TeacherStudentsScene):
def construct(self):
self.teacher_says("""
Given $f(x) = x^2 \\sin(x)$, \\\\
compute $\\frac{df}{dx}(x)$
""")
content_copy = self.teacher.bubble.content.copy()
self.change_student_modes("sad", "confused", "erm")
self.wait()
self.student_says(
"Why?", target_mode = "sassy",
added_anims = [
content_copy.scale, 0.8,
content_copy.to_corner, UP+LEFT
]
)
self.play(self.teacher.change_mode, "pondering")
self.wait(2)
class ContrastAbstractAndConcrete(Scene):
def construct(self):
v_line = Line(UP, DOWN).scale(FRAME_Y_RADIUS)
l_title = TextMobject("Abstract functions")
l_title.shift(FRAME_X_RADIUS*LEFT/2)
l_title.to_edge(UP)
r_title = TextMobject("Applications")
r_title.shift(FRAME_X_RADIUS*RIGHT/2)
r_title.to_edge(UP)
h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS)
h_line.shift((r_title.get_bottom()[1]-MED_SMALL_BUFF)*UP)
functions = VGroup(*list(map(TexMobject, [
"f(x) = 2x^2 - x^3",
"f(x) = \\sin(x)",
"f(x) = e^x",
"\\v_dots"
])))
functions.arrange(
DOWN,
aligned_edge = LEFT,
buff = LARGE_BUFF
)
functions.shift(FRAME_X_RADIUS*LEFT/2)
functions[-1].shift(MED_LARGE_BUFF*RIGHT)
self.add(l_title, r_title)
self.play(*list(map(ShowCreation, [h_line, v_line])))
self.play(Write(functions))
self.wait()
anims = [
method(func_mob)
for func_mob, method in zip(functions, [
self.get_car_anim,
self.get_spring_anim,
self.get_population_anim,
])
]
for anim in anims:
self.play(FadeIn(anim.mobject))
self.play(anim)
self.play(FadeOut(anim.mobject))
def get_car_anim(self, alignement_mob):
car = Car()
point = 2*RIGHT + alignement_mob.get_bottom()[1]*UP
target_point = point + 5*RIGHT
car.move_to(point)
return MoveCar(
car, target_point,
run_time = 5,
)
def get_spring_anim(self, alignement_mob):
compact_spring, extended_spring = [
ParametricFunction(
lambda t : (t/denom)*RIGHT+np.sin(t)*UP+np.cos(t)*OUT,
t_max = 12*np.pi,
)
for denom in (12.0, 4.0)
]
for spring in compact_spring, extended_spring:
spring.scale(0.5)
spring.rotate(np.pi/6, UP)
spring.set_color(GREY)
spring.next_to(ORIGIN, RIGHT)
spring.shift(
alignement_mob.get_center()[1]*UP + SMALL_BUFF*RIGHT \
-spring.points[0]
)
weight = Square(
side_length = 0.5,
stroke_width = 0,
fill_color = LIGHT_GREY,
fill_opacity = 1,
)
weight.move_to(spring.points[-1])
spring.add(weight)
return Transform(
compact_spring, extended_spring,
rate_func = lambda t : 1+np.sin(6*np.pi*t),
run_time = 5
)
def get_population_anim(self, alignement_mob):
colors = color_gradient([BLUE_B, BLUE_E], 12)
pis = VGroup(*[
Randolph(
mode = "happy",
color = random.choice(colors)
).shift(
4*x*RIGHT + 4*y*UP + \
2*random.random()*RIGHT + \
2*random.random()*UP
)
for x in range(20)
for y in range(10)
])
pis.set_height(3)
pis.center()
pis.to_edge(DOWN, buff = SMALL_BUFF)
pis.shift(FRAME_X_RADIUS*RIGHT/2.)
anims = []
for index, pi in enumerate(pis):
if index < 2:
anims.append(FadeIn(pi))
continue
mom_index, dad_index = random.choice(
list(it.combinations(list(range(index)), 2))
)
pi.parents = VGroup(pis[mom_index], pis[dad_index]).copy()
pi.parents.set_fill(opacity = 0)
exp = 1
while 2**exp < len(pis):
low_index = 2**exp
high_index = min(2**(exp+1), len(pis))
these_pis = pis[low_index:high_index]
anims.append(Transform(
VGroup(*[pi.parents for pi in these_pis]),
VGroup(*[VGroup(pi, pi.copy()) for pi in these_pis]),
lag_ratio = 0.5,
run_time = 2,
))
exp += 1
return Succession(*anims, rate_func=linear)
class ApplicationNames(Scene):
def construct(self):
for name in "Velocity", "Oscillation", "Population growth":
mob = TextMobject(name)
mob.scale(2)
self.play(Write(mob))
self.wait(2)
self.play(FadeOut(mob))
class ListOfRules(PiCreatureScene):
CONFIG = {
"use_morty" : False,
}
def construct(self):
rules = VGroup(*list(map(TexMobject, [
"\\frac{d}{dx} x^n = nx^{n-1}",
"\\frac{d}{dx} \\sin(x) = \\cos(x)",
"\\frac{d}{dx} \\cos(x) = -\\sin(x)",
"\\frac{d}{dx} a^x = \\ln(a) a^x",
"\\vdots"
])))
rules.arrange(
DOWN, buff = MED_LARGE_BUFF,
aligned_edge = LEFT,
)
rules[-1].shift(MED_LARGE_BUFF*RIGHT)
rules.set_height(FRAME_HEIGHT-1)
rules.next_to(self.pi_creature, RIGHT)
rules.to_edge(DOWN)
self.play(
Write(rules),
self.pi_creature.change_mode, "pleading",
)
self.change_mode("tired")
self.wait()
class DerivativeOfXSquaredAsGraph(GraphScene, ZoomedScene, PiCreatureScene):
CONFIG = {
"start_x" : 2,
"big_x" : 3,
"dx" : 0.1,
"x_min" : -9,
"x_labeled_nums" : list(range(-8, 0, 2)) + list(range(2, 10, 2)),
"y_labeled_nums" : list(range(2, 12, 2)),
"little_rect_nudge" : 0.5*(1.5*UP+RIGHT),
"graph_origin" : 2.5*DOWN + LEFT,
"zoomed_canvas_corner" : UP+LEFT,
"zoomed_canvas_frame_shape" : (4, 4),
}
def construct(self):
self.draw_graph()
self.ask_about_df_dx()
self.show_differing_slopes()
self.mention_alternate_view()
def draw_graph(self):
self.setup_axes(animate = True)
graph = self.get_graph(lambda x : x**2)
label = self.get_graph_label(
graph, "f(x) = x^2",
)
self.play(ShowCreation(graph))
self.play(Write(label))
self.wait()
self.graph = graph
def ask_about_df_dx(self):
ss_group = self.get_secant_slope_group(
self.start_x, self.graph,
dx = self.dx,
dx_label = "dx",
df_label = "df",
)
secant_line = ss_group.secant_line
ss_group.remove(secant_line)
v_line, nudged_v_line = [
self.get_vertical_line_to_graph(
x, self.graph,
line_class = DashedLine,
color = RED,
dash_length = 0.025
)
for x in (self.start_x, self.start_x+self.dx)
]
df_dx = TexMobject("\\frac{df}{dx} ?")
VGroup(*df_dx[:2]).set_color(ss_group.df_line.get_color())
VGroup(*df_dx[3:5]).set_color(ss_group.dx_line.get_color())
df_dx.next_to(
self.input_to_graph_point(self.start_x, self.graph),
DOWN+RIGHT,
buff = MED_SMALL_BUFF
)
derivative_q = TextMobject("Derivative?")
derivative_q.next_to(self.pi_creature.get_corner(UP+LEFT), UP)
self.play(
Write(derivative_q, run_time = 1),
self.pi_creature.change_mode, "speaking"
)
self.wait()
self.play(
FadeOut(derivative_q),
self.pi_creature.change_mode, "plain"
)
self.play(ShowCreation(v_line))
self.wait()
self.play(Transform(v_line.copy(), nudged_v_line))
self.remove(self.get_mobjects_from_last_animation()[0])
self.add(nudged_v_line)
self.wait()
self.activate_zooming()
self.little_rectangle.replace(self.big_rectangle)
self.play(
FadeIn(self.little_rectangle),
FadeIn(self.big_rectangle),
)
self.play(
ApplyFunction(
lambda r : self.position_little_rectangle(r, ss_group),
self.little_rectangle
),
self.pi_creature.change_mode, "pondering",
self.pi_creature.look_at, ss_group
)
self.play(
ShowCreation(ss_group.dx_line),
Write(ss_group.dx_label),
)
self.wait()
self.play(
ShowCreation(ss_group.df_line),
Write(ss_group.df_label),
)
self.wait()
self.play(Write(df_dx))
self.wait()
self.play(*list(map(FadeOut, [
v_line, nudged_v_line,
])))
self.ss_group = ss_group
def position_little_rectangle(self, rect, ss_group):
rect.set_width(3*self.dx)
rect.move_to(
ss_group.dx_line.get_left()
)
rect.shift(
self.dx*self.little_rect_nudge
)
return rect
def show_differing_slopes(self):
ss_group = self.ss_group
def rect_update(rect):
self.position_little_rectangle(rect, ss_group)
self.play(
ShowCreation(ss_group.secant_line),
self.pi_creature.change_mode, "thinking"
)
ss_group.add(ss_group.secant_line)
self.wait()
for target_x in self.big_x, -self.dx/2, 1, 2:
self.animate_secant_slope_group_change(
ss_group, target_x = target_x,
added_anims = [
UpdateFromFunc(self.little_rectangle, rect_update)
]
)
self.wait()
def mention_alternate_view(self):
self.remove(self.pi_creature)
everything = VGroup(*self.get_mobjects())
self.add(self.pi_creature)
self.disactivate_zooming()
self.play(
ApplyMethod(
everything.shift, FRAME_WIDTH*LEFT,
rate_func = lambda t : running_start(t, -0.1)
),
self.pi_creature.change_mode, "happy"
)
self.say("Let's try \\\\ another view.", target_mode = "speaking")
self.wait(2)
class NudgeSideLengthOfSquare(PiCreatureScene):
CONFIG = {
"square_width" : 3,
"alt_square_width" : 5,
"dx" : 0.25,
"alt_dx" : 0.01,
"square_color" : GREEN,
"square_fill_opacity" : 0.75,
"three_color" : GREEN,
"dx_color" : BLUE_B,
"is_recursing_on_dx" : False,
"is_recursing_on_square_width" : False,
}
def construct(self):
ApplyMethod(self.pi_creature.change_mode, "speaking").update(1)
self.add_function_label()
self.introduce_square()
self.increase_area()
self.write_df_equation()
self.set_color_shapes()
self.examine_thin_rectangles()
self.examine_tiny_square()
self.show_smaller_dx()
self.rule_of_thumb()
self.write_out_derivative()
def add_function_label(self):
label = TexMobject("f(x) = x^2")
label.next_to(ORIGIN, RIGHT, buff = (self.square_width-3)/2.)
label.to_edge(UP)
self.add(label)
self.function_label = label
def introduce_square(self):
square = Square(
side_length = self.square_width,
stroke_width = 0,
fill_opacity = self.square_fill_opacity,
fill_color = self.square_color,
)
square.to_corner(UP+LEFT, buff = LARGE_BUFF)
x_squared = TexMobject("x^2")
x_squared.move_to(square)
braces = VGroup()
for vect in RIGHT, DOWN:
brace = Brace(square, vect)
text = brace.get_text("$x$")
brace.add(text)
braces.add(brace)
self.play(
DrawBorderThenFill(square),
self.pi_creature.change_mode, "plain"
)
self.play(*list(map(GrowFromCenter, braces)))
self.play(Write(x_squared))
self.change_mode("pondering")
self.wait()
self.square = square
self.side_braces = braces
def increase_area(self):
color_kwargs = {
"fill_color" : YELLOW,
"fill_opacity" : self.square_fill_opacity,
"stroke_width" : 0,
}
right_rect = Rectangle(
width = self.dx,
height = self.square_width,
**color_kwargs
)
bottom_rect = right_rect.copy().rotate(-np.pi/2)
right_rect.next_to(self.square, RIGHT, buff = 0)
bottom_rect.next_to(self.square, DOWN, buff = 0)
corner_square = Square(
side_length = self.dx,
**color_kwargs
)
corner_square.next_to(self.square, DOWN+RIGHT, buff = 0)
right_line = Line(
self.square.get_corner(UP+RIGHT),
self.square.get_corner(DOWN+RIGHT),
stroke_width = 0
)
bottom_line = Line(
self.square.get_corner(DOWN+RIGHT),
self.square.get_corner(DOWN+LEFT),
stroke_width = 0
)
corner_point = VectorizedPoint(
self.square.get_corner(DOWN+RIGHT)
)
little_braces = VGroup()
for vect in RIGHT, DOWN:
brace = Brace(
corner_square, vect,
buff = SMALL_BUFF,
)
text = brace.get_text("$dx$", buff = SMALL_BUFF)
text.set_color(self.dx_color)
brace.add(text)
little_braces.add(brace)
right_brace, bottom_brace = self.side_braces
self.play(
Transform(right_line, right_rect),
Transform(bottom_line, bottom_rect),
Transform(corner_point, corner_square),
right_brace.next_to, right_rect, RIGHT, SMALL_BUFF,
bottom_brace.next_to, bottom_rect, DOWN, SMALL_BUFF,
)
self.remove(corner_point, bottom_line, right_line)
self.add(corner_square, bottom_rect, right_rect)
self.play(*list(map(GrowFromCenter, little_braces)))
self.wait()
self.play(*it.chain(*[
[mob.shift, vect*SMALL_BUFF]
for mob, vect in [
(right_rect, RIGHT),
(bottom_rect, DOWN),
(corner_square, DOWN+RIGHT),
(right_brace, RIGHT),
(bottom_brace, DOWN),
(little_braces, DOWN+RIGHT)
]
]))
self.change_mode("thinking")
self.wait()
self.right_rect = right_rect
self.bottom_rect = bottom_rect
self.corner_square = corner_square
self.little_braces = little_braces
def write_df_equation(self):
right_rect = self.right_rect
bottom_rect = self.bottom_rect
corner_square = self.corner_square
df_equation = VGroup(
TexMobject("df").set_color(right_rect.get_color()),
TexMobject("="),
right_rect.copy(),
TextMobject("+"),
right_rect.copy(),
TexMobject("+"),
corner_square.copy()
)
df_equation.arrange()
df_equation.next_to(
self.function_label, DOWN,
aligned_edge = LEFT,
buff = SMALL_BUFF
)
df, equals, r1, plus1, r2, plus2, s = df_equation
pairs = [
(df, self.function_label[0]),
(r1, right_rect),
(r2, bottom_rect),
(s, corner_square),
]
for mover, origin in pairs:
mover.save_state()
Transform(mover, origin).update(1)
self.play(df.restore)
self.wait()
self.play(
*[
mob.restore
for mob in (r1, r2, s)
]+[
Write(symbol)
for symbol in (equals, plus1, plus2)
],
run_time = 2
)
self.change_mode("happy")
self.wait()
self.df_equation = df_equation
def set_color_shapes(self):
df, equals, r1, plus1, r2, plus2, s = self.df_equation
tups = [
(self.right_rect, self.bottom_rect, r1, r2),
(self.corner_square, s)
]
for tup in tups:
self.play(
*it.chain(*[
[m.scale_in_place, 1.2, m.set_color, RED]
for m in tup
]),
rate_func = there_and_back
)
self.wait()
def examine_thin_rectangles(self):
df, equals, r1, plus1, r2, plus2, s = self.df_equation
rects = VGroup(r1, r2)
thin_rect_brace = Brace(rects, DOWN)
text = thin_rect_brace.get_text("$2x \\, dx$")
VGroup(*text[-2:]).set_color(self.dx_color)
text.save_state()
alt_text = thin_rect_brace.get_text("$2(3)(0.01)$")
alt_text[2].set_color(self.three_color)
VGroup(*alt_text[-5:-1]).set_color(self.dx_color)
example_value = TexMobject("=0.06")
example_value.next_to(alt_text, DOWN)
self.play(GrowFromCenter(thin_rect_brace))
self.play(
Write(text),
self.pi_creature.change_mode, "pondering"
)
self.wait()
xs = VGroup(*[
brace[-1]
for brace in self.side_braces
])
dxs = VGroup(*[
brace[-1]
for brace in self.little_braces
])
for group, tex, color in (xs, "3", self.three_color), (dxs, "0.01", self.dx_color):
group.save_state()
group.generate_target()
for submob in group.target:
number = TexMobject(tex)
number.set_color(color)
number.move_to(submob, LEFT)
Transform(submob, number).update(1)
self.play(MoveToTarget(xs))
self.play(MoveToTarget(dxs))
self.wait()
self.play(Transform(text, alt_text))
self.wait()
self.play(Write(example_value))
self.wait()
self.play(
FadeOut(example_value),
*[
mob.restore
for mob in (xs, dxs, text)
]
)
self.remove(text)
text.restore()
self.add(text)
self.wait()
self.dxs = dxs
self.thin_rect_brace = thin_rect_brace
self.thin_rect_area = text
def examine_tiny_square(self):
text = TexMobject("dx^2")
VGroup(*text[:2]).set_color(self.dx_color)
text.next_to(self.df_equation[-1], UP)
text.save_state()
alt_text = TextMobject("0.0001")
alt_text.move_to(text)
self.play(Write(text))
self.change_mode("surprised")
self.wait()
self.play(
MoveToTarget(self.dxs),
self.pi_creature.change_mode, "plain"
)
for submob in self.dxs.target:
number = TexMobject("0.01")
number.set_color(self.dx_color)
number.move_to(submob, LEFT)
Transform(submob, number).update(1)
self.play(MoveToTarget(self.dxs))
self.play(
Transform(text, alt_text),
self.pi_creature.change_mode, "raise_right_hand"
)
self.wait(2)
self.play(*[
mob.restore
for mob in (self.dxs, text)
] + [
self.pi_creature.change_mode, "erm"
])
self.dx_squared = text
def show_smaller_dx(self):
self.mobjects_at_start_of_show_smaller_dx = [
mob.copy() for mob in self.get_mobjects()
]
if self.is_recursing_on_dx:
return
alt_scene = self.__class__(
skip_animations = True,
dx = self.alt_dx,
is_recursing_on_dx = True
)
for mob in self.get_mobjects():
mob.save_state()
self.play(*[
Transform(*pair)
for pair in zip(
self.get_mobjects(),
alt_scene.mobjects_at_start_of_show_smaller_dx,
)
])
self.wait()
self.play(*[
mob.restore
for mob in self.get_mobjects()
])
self.change_mode("happy")
self.wait()
def rule_of_thumb(self):
circle = Circle(color = RED)
dx_squared_group = VGroup(self.dx_squared, self.df_equation[-1])
circle.replace(dx_squared_group, stretch = True)
dx_squared_group.add(self.df_equation[-2])
circle.scale_in_place(1.5)
safe_to_ignore = TextMobject("Safe to ignore")
safe_to_ignore.next_to(circle, DOWN, aligned_edge = LEFT)
safe_to_ignore.set_color(circle.get_color())
self.play(ShowCreation(circle))
self.play(
Write(safe_to_ignore, run_time = 2),
self.pi_creature.change_mode, "raise_right_hand"
)
self.play(
FadeOut(circle),
FadeOut(safe_to_ignore),
dx_squared_group.fade, 0.5,
dx_squared_group.to_corner, UP+RIGHT,
self.pi_creature.change_mode, "plain"
)
self.wait()
def write_out_derivative(self):
df, equals, r1, plus1, r2, plus2, s = self.df_equation
frac_line = TexMobject("-")
frac_line.stretch_to_fit_width(df.get_width())
frac_line.move_to(df)
dx = VGroup(*self.thin_rect_area[-2:])
x = self.thin_rect_area[1]
self.play(
Transform(r1, self.right_rect),
Transform(r2, self.bottom_rect),
FadeOut(plus1),
FadeOut(self.thin_rect_brace)
)
self.play(
self.thin_rect_area.next_to, VGroup(df, equals),
RIGHT, MED_SMALL_BUFF, UP,
self.pi_creature.change_mode, "thinking"
)
self.wait(2)
self.play(
ApplyMethod(df.next_to, frac_line, UP, SMALL_BUFF),
ApplyMethod(dx.next_to, frac_line, DOWN, SMALL_BUFF),
Write(frac_line),
path_arc = -np.pi
)
self.wait()
brace_xs = [
brace[-1]
for brace in self.side_braces
]
xs = list(brace_xs) + [x]
for x_mob in xs:
number = TexMobject("(%d)"%self.square_width)
number.move_to(x_mob, LEFT)
number.shift(
(x_mob.get_bottom()[1] - number[1].get_bottom()[1])*UP
)
x_mob.save_state()
x_mob.target = number
self.play(*list(map(MoveToTarget, xs)))
self.wait(2)
#Recursively transform to what would have happened
#with a wider square width
self.mobjects_at_end_of_write_out_derivative = self.get_mobjects()
if self.is_recursing_on_square_width or self.is_recursing_on_dx:
return
alt_scene = self.__class__(
skip_animations = True,
square_width = self.alt_square_width,
is_recursing_on_square_width = True,
)
self.play(*[
Transform(*pair)
for pair in zip(
self.mobjects_at_end_of_write_out_derivative,
alt_scene.mobjects_at_end_of_write_out_derivative
)
])
self.change_mode("happy")
self.wait(2)
class ChangeInAreaOverChangeInX(Scene):
def construct(self):
fractions = []
for pair in ("Change in area", "Change in $x$"), ("$d(x^2)$", "$dx$"):
top, bottom = list(map(TextMobject, pair))
top.set_color(YELLOW)
bottom.set_color(BLUE_B)
frac_line = TexMobject("-")
frac_line.stretch_to_fit_width(top.get_width())
top.next_to(frac_line, UP, SMALL_BUFF)
bottom.next_to(frac_line, DOWN, SMALL_BUFF)
fractions.append(VGroup(
top, frac_line, bottom
))
words, symbols = fractions
self.play(Write(words[0], run_time = 1))
self.play(*list(map(Write, words[1:])), run_time = 1)
self.wait()
self.play(Transform(words, symbols))
self.wait()
class NudgeSideLengthOfCube(Scene):
CONFIG = {
"x_color" : BLUE,
"dx_color" : GREEN,
"df_color" : YELLOW,
"use_morty" : False,
"x" : 3,
"dx" : 0.2,
"alt_dx" : 0.02,
"offset_vect" : OUT,
"pose_angle" : np.pi/12,
"pose_axis" : UP+RIGHT,
"small_piece_scaling_factor" : 0.7,
"allow_recursion" : True,
}
def construct(self):
self.states = dict()
if self.allow_recursion:
self.alt_scene = self.__class__(
skip_animations = True,
allow_recursion = False,
dx = self.alt_dx,
)
self.add_title()
self.introduce_cube()
self.write_df_equation()
self.write_derivative()
def add_title(self):
title = TexMobject("f(x) = x^3")
title.shift(FRAME_X_RADIUS*LEFT/2)
title.to_edge(UP)
self.play(Write(title))
self.wait()
def introduce_cube(self):
cube = self.get_cube()
cube.to_edge(LEFT, buff = 2*LARGE_BUFF)
cube.shift(DOWN)
dv_pieces = self.get_dv_pices(cube)
original_dx = self.dx
self.dx = 0
alt_dv_pieces = self.get_dv_pices(cube)
self.dx = original_dx
alt_dv_pieces.set_fill(opacity = 0)
x_brace = Brace(cube, LEFT, buff = SMALL_BUFF)
dx_brace = Brace(
dv_pieces[1], LEFT, buff = SMALL_BUFF,
)
dx_brace.stretch_in_place(1.5, 1)
for brace, tex in (x_brace, "x"), (dx_brace, "dx"):
brace.scale_in_place(0.95)
brace.rotate_in_place(-np.pi/96)
brace.shift(0.3*(UP+LEFT))
brace.add(brace.get_text("$%s$"%tex))
cube_group = VGroup(cube, dv_pieces, alt_dv_pieces)
self.pose_3d_mobject(cube_group)
self.play(DrawBorderThenFill(cube))
self.play(GrowFromCenter(x_brace))
self.wait()
self.play(Transform(alt_dv_pieces, dv_pieces))
self.remove(alt_dv_pieces)
self.add(dv_pieces)
self.play(GrowFromCenter(dx_brace))
self.wait()
for piece in dv_pieces:
piece.on_cube_state = piece.copy()
self.play(*[
ApplyMethod(
piece.shift,
0.5*(piece.get_center()-cube.get_center())
)
for piece in dv_pieces
]+[
ApplyMethod(dx_brace.shift, 0.7*UP)
])
self.wait()
self.cube = cube
self.dx_brace = dx_brace
self.faces, self.bars, self.corner_cube = [
VGroup(*[
piece
for piece in dv_pieces
if piece.type == target_type
])
for target_type in ("face", "bar", "corner_cube")
]
def write_df_equation(self):
df_equation = VGroup(
TexMobject("df"),
TexMobject("="),
self.organize_faces(self.faces.copy()),
TexMobject("+"),
self.organize_bars(self.bars.copy()),
TexMobject("+"),
self.corner_cube.copy()
)
df, equals, faces, plus1, bars, plus2, corner_cube = df_equation
df.set_color(self.df_color)
for three_d_mob in faces, bars, corner_cube:
three_d_mob.scale(self.small_piece_scaling_factor)
# self.pose_3d_mobject(three_d_mob)
faces.set_fill(opacity = 0.3)
df_equation.arrange(RIGHT)
df_equation.next_to(ORIGIN, RIGHT)
df_equation.to_edge(UP)
faces_brace = Brace(faces, DOWN)
derivative = faces_brace.get_tex("3x^2", "\\, dx")
extras_brace = Brace(VGroup(bars, corner_cube), DOWN)
ignore_text = extras_brace.get_text(
"Multiple \\\\ of $dx^2$"
)
ignore_text.scale_in_place(0.7)
x_squared_dx = TexMobject("x^2", "\\, dx")
self.play(*list(map(Write, [df, equals])))
self.grab_pieces(self.faces, faces)
self.wait()
self.shrink_dx("Faces are introduced")
face = self.faces[0]
face.save_state()
self.play(face.shift, FRAME_X_RADIUS*RIGHT)
x_squared_dx.next_to(face, LEFT)
self.play(Write(x_squared_dx, run_time = 1))
self.wait()
for submob, sides in zip(x_squared_dx, [face[0], VGroup(*face[1:])]):
self.play(
submob.set_color, RED,
sides.set_color, RED,
rate_func = there_and_back
)
self.wait()
self.play(
face.restore,
Transform(
x_squared_dx, derivative,
replace_mobject_with_target_in_scene = True
),
GrowFromCenter(faces_brace)
)
self.wait()
self.grab_pieces(self.bars, bars, plus1)
self.grab_pieces(self.corner_cube, corner_cube, plus2)
self.play(
GrowFromCenter(extras_brace),
Write(ignore_text)
)
self.wait()
self.play(*[
ApplyMethod(mob.fade, 0.7)
for mob in [
plus1, bars, plus2, corner_cube,
extras_brace, ignore_text
]
])
self.wait()
self.df_equation = df_equation
self.derivative = derivative
def write_derivative(self):
df, equals, faces, plus1, bars, plus2, corner_cube = self.df_equation
df = df.copy()
equals = equals.copy()
df_equals = VGroup(df, equals)
derivative = self.derivative.copy()
dx = derivative[1]
extra_stuff = TexMobject("+(\\dots)", "dx^2")
dx_squared = extra_stuff[1]
derivative.generate_target()
derivative.target.shift(2*DOWN)
extra_stuff.next_to(derivative.target)
self.play(
MoveToTarget(derivative),
df_equals.next_to, derivative.target[0], LEFT,
df_equals.shift, 0.07*DOWN
)
self.play(Write(extra_stuff))
self.wait()
frac_line = TexMobject("-")
frac_line.replace(df)
extra_stuff.generate_target()
extra_stuff.target.next_to(derivative[0])
frac_line2 = TexMobject("-")
frac_line2.stretch_to_fit_width(
extra_stuff.target[1].get_width()
)
frac_line2.move_to(extra_stuff.target[1])
extra_stuff.target[1].next_to(frac_line2, UP, buff = SMALL_BUFF)
dx_below_dx_squared = TexMobject("dx")
dx_below_dx_squared.next_to(frac_line2, DOWN, buff = SMALL_BUFF)
self.play(
FadeIn(frac_line),
FadeIn(frac_line2),
df.next_to, frac_line, UP, SMALL_BUFF,
dx.next_to, frac_line, DOWN, SMALL_BUFF,
MoveToTarget(extra_stuff),
Write(dx_below_dx_squared),
path_arc = -np.pi
)
self.wait()
inner_dx = VGroup(*dx_squared[:-1])
self.play(
FadeOut(frac_line2),
FadeOut(dx_below_dx_squared),
dx_squared[-1].set_color, BLACK,
inner_dx.next_to, extra_stuff[0], RIGHT, SMALL_BUFF
)
self.wait()
self.shrink_dx("Derivative is written", restore = False)
self.play(*[
ApplyMethod(mob.fade, 0.7)
for mob in (extra_stuff, inner_dx)
])
self.wait(2)
anims = []
for mob in list(self.faces)+list(self.bars)+list(self.corner_cube):
vect = mob.get_center()-self.cube.get_center()
anims += [
mob.shift, -(1./3)*vect
]
anims += self.dx_brace.shift, 0.7*DOWN
self.play(*anims)
self.wait()
def grab_pieces(self, start_pieces, end_pices, to_write = None):
for piece in start_pieces:
piece.generate_target()
piece.target.rotate_in_place(
np.pi/12, piece.get_center()-self.cube.get_center()
)
piece.target.set_color(RED)
self.play(*list(map(MoveToTarget, start_pieces)), rate_func = wiggle)
self.wait()
added_anims = []
if to_write is not None:
added_anims.append(Write(to_write))
self.play(
Transform(start_pieces.copy(), end_pices),
*added_anims
)
def shrink_dx(self, state_name, restore = True):
mobjects = self.get_mobjects()
mobjects_with_points = [
m for m in mobjects
if m.get_num_points() > 0
]
#Alt_scene will reach this point, and save copy of self
#in states dict
self.states[state_name] = [
mob.copy() for mob in mobjects_with_points
]
if not self.allow_recursion:
return
if restore:
movers = self.states[state_name]
for mob in movers:
mob.save_state()
self.remove(*mobjects)
else:
movers = mobjects_with_points
self.play(*[
Transform(*pair)
for pair in zip(
movers,
self.alt_scene.states[state_name]
)
])
self.wait()
if restore:
self.play(*[m.restore for m in movers])
self.remove(*movers)
self.mobjects = mobjects
def get_cube(self):
cube = self.get_prism(self.x, self.x, self.x)
cube.set_fill(color = BLUE, opacity = 0.3)
cube.set_stroke(color = WHITE, width = 1)
return cube
def get_dv_pices(self, cube):
pieces = VGroup()
for vect in it.product([0, 1], [0, 1], [0, 1]):
if np.all(vect == ORIGIN):
continue
args = [
self.x if bit is 0 else self.dx
for bit in vect
]
piece = self.get_prism(*args)
piece.next_to(cube, np.array(vect), buff = 0)
pieces.add(piece)
if sum(vect) == 1:
piece.type = "face"
elif sum(vect) == 2:
piece.type = "bar"
else:
piece.type = "corner_cube"
return pieces
def organize_faces(self, faces):
self.unpose_3d_mobject(faces)
for face in faces:
dimensions = [
face.length_over_dim(dim)
for dim in range(3)
]
thin_dim = np.argmin(dimensions)
if thin_dim == 0:
face.rotate(np.pi/2, DOWN)
elif thin_dim == 1:
face.rotate(np.pi/2, RIGHT)
faces.arrange(OUT, buff = LARGE_BUFF)
self.pose_3d_mobject(faces)
return faces
def organize_bars(self, bars):
self.unpose_3d_mobject(bars)
for bar in bars:
dimensions = [
bar.length_over_dim(dim)
for dim in range(3)
]
thick_dim = np.argmax(dimensions)
if thick_dim == 0:
bar.rotate(np.pi/2, OUT)
elif thick_dim == 2:
bar.rotate(np.pi/2, LEFT)
bars.arrange(OUT, buff = LARGE_BUFF)
self.pose_3d_mobject(bars)
return bars
def get_corner_cube(self):
return self.get_prism(self.dx, self.dx, self.dx)
def get_prism(self, width, height, depth):
color_kwargs = {
"fill_color" : YELLOW,
"fill_opacity" : 0.4,
"stroke_color" : WHITE,
"stroke_width" : 0.1,
}
front = Rectangle(
width = width,
height = height,
**color_kwargs
)
face = VGroup(front)
for vect in LEFT, RIGHT, UP, DOWN:
if vect is LEFT or vect is RIGHT:
side = Rectangle(
height = height,
width = depth,
**color_kwargs
)
else:
side = Rectangle(
height = depth,
width = width,
**color_kwargs
)
side.next_to(front, vect, buff = 0)
side.rotate(
np.pi/2, rotate_vector(vect, -np.pi/2),
about_point = front.get_edge_center(vect)
)
face.add(side)
return face
def pose_3d_mobject(self, mobject):
mobject.rotate_in_place(self.pose_angle, self.pose_axis)
return mobject
def unpose_3d_mobject(self, mobject):
mobject.rotate_in_place(-self.pose_angle, self.pose_axis)
return mobject
class ShowCubeDVIn3D(Scene):
def construct(self):
raise Exception("This scene is only here for the stage_scenes script.")
class GraphOfXCubed(GraphScene):
CONFIG = {
"x_min" : -6,
"x_max" : 6,
"x_axis_width" : FRAME_WIDTH,
"x_labeled_nums" : list(range(-6, 7)),
"y_min" : -35,
"y_max" : 35,
"y_axis_height" : FRAME_HEIGHT,
"y_tick_frequency" : 5,
"y_labeled_nums" : list(range(-30, 40, 10)),
"graph_origin" : ORIGIN,
"dx" : 0.2,
"deriv_x_min" : -3,
"deriv_x_max" : 3,
}
def construct(self):
self.setup_axes(animate = False)
graph = self.get_graph(lambda x : x**3)
label = self.get_graph_label(
graph, "f(x) = x^3",
direction = LEFT,
)
deriv_graph, full_deriv_graph = [
self.get_derivative_graph(
graph,
color = DERIVATIVE_COLOR,
x_min = low_x,
x_max = high_x,
)
for low_x, high_x in [
(self.deriv_x_min, self.deriv_x_max),
(self.x_min, self.x_max),
]
]
deriv_label = self.get_graph_label(
deriv_graph,
"\\frac{df}{dx}(x) = 3x^2",
x_val = -3,
direction = LEFT
)
deriv_label.shift(0.5*DOWN)
ss_group = self.get_secant_slope_group(
self.deriv_x_min, graph,
dx = self.dx,
dx_line_color = WHITE,
df_line_color = WHITE,
secant_line_color = YELLOW,
)
self.play(ShowCreation(graph))
self.play(Write(label, run_time = 1))
self.wait()
self.play(Write(deriv_label, run_time = 1))
self.play(ShowCreation(ss_group, lag_ratio = 0))
self.animate_secant_slope_group_change(
ss_group,
target_x = self.deriv_x_max,
run_time = 10,
added_anims = [
ShowCreation(deriv_graph, run_time = 10)
]
)
self.play(FadeIn(full_deriv_graph))
self.wait()
for x_val in -2, -self.dx/2, 2:
self.animate_secant_slope_group_change(
ss_group,
target_x = x_val,
run_time = 2
)
if x_val != -self.dx/2:
v_line = self.get_vertical_line_to_graph(
x_val, deriv_graph,
line_class = DashedLine
)
self.play(ShowCreation(v_line))
self.play(FadeOut(v_line))
class PatternForPowerRule(PiCreatureScene):
CONFIG = {
"num_exponents" : 5,
}
def construct(self):
self.introduce_pattern()
self.generalize_pattern()
self.show_hopping()
def introduce_pattern(self):
exp_range = list(range(1, 1+self.num_exponents))
colors = color_gradient([BLUE_D, YELLOW], self.num_exponents)
derivatives = VGroup()
for exponent, color in zip(exp_range, colors):
derivative = TexMobject(
"\\frac{d(x^%d)}{dx} = "%exponent,
"%d x^{%d}"%(exponent, exponent-1)
)
VGroup(*derivative[0][2:4]).set_color(color)
derivatives.add(derivative)
derivatives.arrange(
DOWN, aligned_edge = LEFT,
buff = MED_LARGE_BUFF
)
derivatives.set_height(FRAME_HEIGHT-1)
derivatives.to_edge(LEFT)
self.play(FadeIn(derivatives[0]))
for d1, d2 in zip(derivatives, derivatives[1:]):
self.play(Transform(
d1.copy(), d2,
replace_mobject_with_target_in_scene = True
))
self.change_mode("thinking")
self.wait()
for derivative in derivatives[-2:]:
derivative.save_state()
self.play(
derivative.scale, 2,
derivative.next_to, derivative,
RIGHT, SMALL_BUFF, DOWN,
)
self.wait(2)
self.play(derivative.restore)
self.remove(derivative)
derivative.restore()
self.add(derivative)
self.derivatives = derivatives
self.colors = colors
def generalize_pattern(self):
derivatives = self.derivatives
power_rule = TexMobject(
"\\frac{d (x^n)}{dx} = ",
"nx^{n-1}"
)
title = TextMobject("``Power rule''")
title.next_to(power_rule, UP, MED_LARGE_BUFF)
lines = VGroup(*[
Line(
deriv.get_right(), power_rule.get_left(),
buff = MED_SMALL_BUFF,
color = deriv[0][2].get_color()
)
for deriv in derivatives
])
self.play(
Transform(
VGroup(*[d[0].copy() for d in derivatives]),
VGroup(power_rule[0]),
replace_mobject_with_target_in_scene = True
),
ShowCreation(lines),
lag_ratio = 0.5,
run_time = 2,
)
self.wait()
self.play(Write(power_rule[1]))
self.wait()
self.play(
Write(title),
self.pi_creature.change_mode, "speaking"
)
self.wait()
def show_hopping(self):
exp_range = list(range(2, 2+self.num_exponents-1))
self.change_mode("tired")
for exp, color in zip(exp_range, self.colors[1:]):
form = TexMobject(
"x^",
str(exp),
"\\rightarrow",
str(exp),
"x^",
str(exp-1)
)
form.set_color(color)
form.to_corner(UP+RIGHT, buff = LARGE_BUFF)
lhs = VGroup(*form[:2])
lhs_copy = lhs.copy()
rhs = VGroup(*form[-2:])
arrow = form[2]
self.play(Write(lhs))
self.play(
lhs_copy.move_to, rhs, DOWN+LEFT,
Write(arrow)
)
self.wait()
self.play(
ApplyMethod(
lhs_copy[1].replace, form[3],
path_arc = np.pi,
rate_func = running_start,
),
FadeIn(
form[5],
rate_func = squish_rate_func(smooth, 0.5, 1)
)
)
self.wait()
self.play(
self.pi_creature.change_mode, "hesitant",
self.pi_creature.look_at, lhs_copy
)
self.play(*list(map(FadeOut, [form, lhs_copy])))
class PowerRuleAlgebra(Scene):
CONFIG = {
"dx_color" : YELLOW,
"x_color" : BLUE,
}
def construct(self):
x_to_n = TexMobject("x^n")
down_arrow = Arrow(UP, DOWN, buff = MED_LARGE_BUFF)
paren_strings = ["(", "x", "+", "dx", ")"]
x_dx_to_n = TexMobject(*paren_strings +["^n"])
equals = TexMobject("=")
equals2 = TexMobject("=")
full_product = TexMobject(
*paren_strings*3+["\\cdots"]+paren_strings
)
x_to_n.set_color(self.x_color)
for mob in x_dx_to_n, full_product:
mob.set_color_by_tex("dx", self.dx_color)
mob.set_color_by_tex("x", self.x_color)
nudge_group = VGroup(x_to_n, down_arrow, x_dx_to_n)
nudge_group.arrange(DOWN)
nudge_group.to_corner(UP+LEFT)
down_arrow.next_to(x_to_n[0], DOWN)
equals.next_to(x_dx_to_n)
full_product.next_to(equals)
equals2.next_to(equals, DOWN, 1.5*LARGE_BUFF)
nudge_brace = Brace(x_dx_to_n, DOWN)
nudged_output = nudge_brace.get_text("Nudged \\\\ output")
product_brace = Brace(full_product, UP)
product_brace.add(product_brace.get_text("$n$ times"))
self.add(x_to_n)
self.play(ShowCreation(down_arrow))
self.play(
FadeIn(x_dx_to_n),
GrowFromCenter(nudge_brace),
GrowFromCenter(nudged_output)
)
self.wait()
self.play(
Write(VGroup(equals, full_product)),
GrowFromCenter(
product_brace,
rate_func = squish_rate_func(smooth, 0.6, 1)
),
run_time = 3
)
self.wait()
self.workout_product(equals2, full_product)
def workout_product(self, equals, full_product):
product_part_tex_pairs = list(zip(full_product, full_product.expression_parts))
xs, dxs = [
VGroup(*[
submob
for submob, tex in product_part_tex_pairs
if tex == target_tex
])
for target_tex in ("x", "dx")
]
x_to_n = TexMobject("x^n")
extra_stuff = TexMobject("+(\\text{Multiple of }\\, dx^2)")
# extra_stuff.scale(0.8)
VGroup(*extra_stuff[-4:-2]).set_color(self.dx_color)
x_to_n.next_to(equals, RIGHT, align_using_submobjects = True)
x_to_n.set_color(self.x_color)
xs_copy = xs.copy()
full_product.save_state()
self.play(full_product.set_color, WHITE)
self.play(xs_copy.set_color, self.x_color)
self.play(
Write(equals),
Transform(xs_copy, x_to_n)
)
self.wait()
brace, derivative_term = self.pull_out_linear_terms(
x_to_n, product_part_tex_pairs, xs, dxs
)
self.wait()
circle = Circle(color = DERIVATIVE_COLOR)
circle.replace(derivative_term, stretch = True)
circle.scale_in_place(1.4)
circle.rotate_in_place(
Line(
derivative_term.get_corner(DOWN+LEFT),
derivative_term.get_corner(UP+RIGHT),
).get_angle()
)
extra_stuff.next_to(brace, aligned_edge = UP)
self.play(Write(extra_stuff), full_product.restore)
self.wait()
self.play(ShowCreation(circle))
self.wait()
def pull_out_linear_terms(self, x_to_n, product_part_tex_pairs, xs, dxs):
last_group = None
all_linear_terms = VGroup()
for dx_index, dx in enumerate(dxs):
if dx is dxs[-1]:
v_dots = TexMobject("\\vdots")
v_dots.next_to(last_group[0], DOWN)
h_dots_list = [
submob
for submob, tex in product_part_tex_pairs
if tex == "\\cdots"
]
h_dots_copy = h_dots_list[0].copy()
self.play(ReplacementTransform(
h_dots_copy, v_dots,
))
last_group.add(v_dots)
all_linear_terms.add(v_dots)
dx_copy = dx.copy()
xs_copy = xs.copy()
xs_copy.remove(xs_copy[dx_index])
self.play(
dx_copy.set_color, self.dx_color,
xs_copy.set_color, self.x_color,
rate_func = squish_rate_func(smooth, 0, 0.5)
)
dx_copy.generate_target()
xs_copy.generate_target()
target_list = [dx_copy.target] + list(xs_copy.target)
target_list.sort(
key=lambda m: m.get_center()[0]
)
dots = TexMobject("+", ".", ".", "\\dots")
for dot_index, dot in enumerate(dots):
target_list.insert(2*dot_index, dot)
group = VGroup(*target_list)
group.arrange(RIGHT, SMALL_BUFF)
if last_group is None:
group.next_to(x_to_n, RIGHT)
else:
group.next_to(last_group, DOWN, aligned_edge = LEFT)
last_group = group
self.play(
MoveToTarget(dx_copy),
MoveToTarget(xs_copy),
Write(dots)
)
all_linear_terms.add(dx_copy, xs_copy, dots)
all_linear_terms.generate_target()
all_linear_terms.target.scale(0.7)
brace = Brace(all_linear_terms.target, UP)
compact = TexMobject("+\\,", "n", "x^{n-1}", "\\,dx")
compact.set_color_by_tex("x^{n-1}", self.x_color)
compact.set_color_by_tex("\\,dx", self.dx_color)
compact.next_to(brace, UP)
brace.add(compact)
derivative_term = VGroup(*compact[1:3])
VGroup(brace, all_linear_terms.target).shift(
x_to_n[0].get_right()+MED_LARGE_BUFF*RIGHT - \
compact[0].get_left()
)
self.play(MoveToTarget(all_linear_terms))
self.play(Write(brace, run_time = 1))
return brace, derivative_term
class ReactToFullExpansion(Scene):
def construct(self):
randy = Randolph()
self.add(randy)
self.play(randy.change_mode, "pleading")
self.play(Blink(randy))
self.play(randy.change_mode, "angry")
self.wait()
self.play(randy.change_mode, "thinking")
self.play(Blink(randy))
self.wait()
class OneOverX(PiCreatureScene, GraphScene):
CONFIG = {
"unit_length" : 3.0,
"graph_origin" : (FRAME_X_RADIUS - LARGE_BUFF)*LEFT + 2*DOWN,
"rectangle_color_kwargs" : {
"fill_color" : BLUE,
"fill_opacity" : 0.5,
"stroke_width" : 1,
"stroke_color" : WHITE,
},
"x_axis_label" : "",
"y_axis_label" : "",
"x_min" : 0,
"y_min" : 0,
"x_tick_frequency" : 0.5,
"y_tick_frequency" : 0.5,
"x_labeled_nums" : list(range(0, 4)),
"y_labeled_nums" : [1],
"y_axis_height" : 10,
"morty_scale_val" : 0.8,
"area_label_scale_factor" : 0.75,
"dx" : 0.1,
"start_x_value" : 1.3,
"dx_color" : GREEN,
"df_color" : RED,
}
def setup(self):
for c in self.__class__.__bases__:
c.setup(self)
self.x_max = self.x_axis_width/self.unit_length
self.y_max = self.y_axis_height/self.unit_length
def construct(self):
self.force_skipping()
self.introduce_function()
self.introduce_puddle()
self.introduce_graph()
self.perform_nudge()
def introduce_function(self):
func = TexMobject("f(x) = ", "\\frac{1}{x}")
func.to_edge(UP)
recip_copy = func[1].copy()
x_to_neg_one = TexMobject("x^{-1}")
x_to_neg_one.submobjects.reverse()
neg_one = VGroup(*x_to_neg_one[:2])
neg_two = TexMobject("-2")
self.play(
Write(func),
self.pi_creature.change_mode, "pondering"
)
self.wait()
self.play(
recip_copy.next_to, self.pi_creature, UP+LEFT,
self.pi_creature.change_mode, "raise_right_hand"
)
x_to_neg_one.move_to(recip_copy)
neg_two.replace(neg_one)
self.play(ReplacementTransform(recip_copy, x_to_neg_one))
self.wait()
self.play(
neg_one.scale, 1.5,
neg_one.next_to, x_to_neg_one, LEFT, SMALL_BUFF, DOWN,
rate_func = running_start,
path_arc = np.pi
)
self.play(FadeIn(neg_two))
self.wait()
self.say(
"More geometry!",
target_mode = "hooray",
added_anims = [
FadeOut(x_to_neg_one),
FadeOut(neg_two),
],
run_time = 2
)
self.wait()
self.play(RemovePiCreatureBubble(self.pi_creature))
def introduce_puddle(self):
rect_group = self.get_rectangle_group(self.start_x_value)
self.play(
DrawBorderThenFill(rect_group.rectangle),
Write(rect_group.area_label),
self.pi_creature.change_mode, "thinking"
)
self.play(
GrowFromCenter(rect_group.x_brace),
Write(rect_group.x_label),
)
self.wait()
self.play(
GrowFromCenter(rect_group.recip_brace),
Write(rect_group.recip_label),
)
self.setup_axes(animate = True)
self.wait()
for d in 2, 3:
self.change_rectangle_group(
rect_group, d,
target_group_kwargs = {
"x_label" : str(d),
"one_over_x_label" : "\\frac{1}{%d}"%d,
},
run_time = 2
)
self.wait()
self.change_rectangle_group(rect_group, 3)
self.wait()
self.rect_group = rect_group
def introduce_graph(self):
rect_group = self.rect_group
graph = self.get_graph(lambda x : 1./x)
graph.points = np.array(list(reversed(graph.points)))
self.change_rectangle_group(
rect_group, 0.01,
added_anims = [
ShowCreation(graph)
],
run_time = 5,
)
self.change_mode("happy")
self.change_rectangle_group(rect_group, self.start_x_value)
self.wait()
self.graph = graph
def perform_nudge(self):
rect_group = self.rect_group
graph = self.graph
rect_copy = rect_group.rectangle.copy()
rect_copy.set_fill(opacity = 0)
new_rect = self.get_rectangle(
self.start_x_value + self.dx
)
recip_brace = rect_group.recip_brace
recip_brace.generate_target()
recip_brace.target.next_to(
new_rect, RIGHT,
buff = SMALL_BUFF,
aligned_edge = DOWN,
)
recip_label = rect_group.recip_label
recip_label.generate_target()
recip_label.target.next_to(recip_brace.target, RIGHT)
h_lines = VGroup(*[
DashedLine(
ORIGIN, (rect_copy.get_width()+LARGE_BUFF)*RIGHT,
color = self.df_color,
stroke_width = 2
).move_to(rect.get_corner(UP+LEFT), LEFT)
for rect in (rect_group.rectangle, new_rect)
])
v_lines = VGroup(*[
DashedLine(
ORIGIN, (rect_copy.get_height()+MED_LARGE_BUFF)*UP,
color = self.dx_color,
stroke_width = 2
).move_to(rect.get_corner(DOWN+RIGHT), DOWN)
for rect in (rect_group.rectangle, new_rect)
])
dx_brace = Brace(v_lines, UP, buff = 0)
dx_label = dx_brace.get_text("$dx$")
dx_brace.add(dx_label)
df_brace = Brace(h_lines, RIGHT, buff = 0)
df_label = df_brace.get_text("$d\\left(\\frac{1}{x}\\right)$")
df_brace.add(df_label)
negative = TextMobject("Negative")
negative.set_color(RED)
negative.next_to(df_label, UP+RIGHT)
negative.shift(RIGHT)
negative_arrow = Arrow(
negative.get_left(),
df_label.get_corner(UP+RIGHT),
color = RED
)
area_changes = VGroup()
point_pairs = [
(new_rect.get_corner(UP+RIGHT), rect_copy.get_corner(DOWN+RIGHT)),
(new_rect.get_corner(UP+LEFT), rect_copy.get_corner(UP+RIGHT))
]
for color, point_pair in zip([self.dx_color, self.df_color], point_pairs):
area_change_rect = Rectangle(
fill_opacity = 1,
fill_color = color,
stroke_width = 0
)
area_change_rect.replace(
VGroup(*list(map(VectorizedPoint, point_pair))),
stretch = True
)
area_changes.add(area_change_rect)
area_gained, area_lost = area_changes
area_gained_label = TextMobject("Area gained")
area_gained_label.scale(0.75)
area_gained_label.next_to(
rect_copy.get_corner(DOWN+RIGHT),
UP+LEFT, buff = SMALL_BUFF
)
area_gained_arrow = Arrow(
area_gained_label.get_top(),
area_gained.get_center(),
buff = 0,
color = WHITE
)
area_lost_label = TextMobject("Area lost")
area_lost_label.scale(0.75)
area_lost_label.next_to(rect_copy.get_left(), RIGHT)
area_lost_arrow = Arrow(
area_lost_label.get_top(),
area_lost.get_center(),
buff = 0,
color = WHITE
)
question = TexMobject(
"\\frac{d(1/x)}{dx} = ???"
)
question.next_to(
self.pi_creature.get_corner(UP+LEFT),
UP, buff = MED_SMALL_BUFF,
)
self.play(
FadeOut(rect_group.area_label),
ReplacementTransform(rect_copy, new_rect),
MoveToTarget(recip_brace),
MoveToTarget(recip_label),
self.pi_creature.change_mode, "pondering"
)
self.play(
GrowFromCenter(dx_brace),
*list(map(ShowCreation, v_lines))
)
self.wait()
self.play(
GrowFromCenter(df_brace),
*list(map(ShowCreation, h_lines))
)
self.change_mode("confused")
self.wait()
self.play(
FadeIn(area_gained),
Write(area_gained_label, run_time = 2),
ShowCreation(area_gained_arrow)
)
self.wait()
self.play(
FadeIn(area_lost),
Write(area_lost_label, run_time = 2),
ShowCreation(area_lost_arrow)
)
self.wait()
self.revert_to_original_skipping_status()###
self.play(
Write(negative),
ShowCreation(negative_arrow)
)
self.wait()
self.play(
Write(question),
self.pi_creature.change_mode, "raise_right_hand"
)
self.wait(2)
########
def create_pi_creature(self):
morty = PiCreatureScene.create_pi_creature(self)
morty.scale(
self.morty_scale_val,
about_point = morty.get_corner(DOWN+RIGHT)
)
return morty
def draw_graph(self):
self.setup_axes()
graph = self.get_graph(lambda x : 1./x)
rect_group = self.get_rectangle_group(0.5)
self.add(rect_group)
self.wait()
self.change_rectangle_group(
rect_group, 2,
target_group_kwargs = {
"x_label" : "2",
"one_over_x_label" : "\\frac{1}{2}",
},
added_anims = [ShowCreation(graph)]
)
self.wait()
def get_rectangle_group(
self, x,
x_label = "x",
one_over_x_label = "\\frac{1}{x}"
):
result = VGroup()
result.x_val = x
result.rectangle = self.get_rectangle(x)
result.x_brace, result.recip_brace = braces = [
Brace(result.rectangle, vect)
for vect in (UP, RIGHT)
]
result.labels = VGroup()
for brace, label in zip(braces, [x_label, one_over_x_label]):
brace.get_text("$%s$"%label)
result.labels.add(brace.get_text("$%s$"%label))
result.x_label, result.recip_label = result.labels
area_label = TextMobject("Area = 1")
area_label.scale(self.area_label_scale_factor)
max_width = max(result.rectangle.get_width()-2*SMALL_BUFF, 0)
if area_label.get_width() > max_width:
area_label.set_width(max_width)
area_label.move_to(result.rectangle)
result.area_label = area_label
result.add(
result.rectangle,
result.x_brace,
result.recip_brace,
result.labels,
result.area_label,
)
return result
def get_rectangle(self, x):
try:
y = 1./x
except ZeroDivisionError:
y = 100
rectangle = Rectangle(
width = x*self.unit_length,
height = y*self.unit_length,
**self.rectangle_color_kwargs
)
rectangle.move_to(self.graph_origin, DOWN+LEFT)
return rectangle
def change_rectangle_group(
self,
rect_group, target_x,
target_group_kwargs = None,
added_anims = [],
**anim_kwargs
):
target_group_kwargs = target_group_kwargs or {}
if "run_time" not in anim_kwargs:
anim_kwargs["run_time"] = 3
target_group = self.get_rectangle_group(target_x, **target_group_kwargs)
target_labels = target_group.labels
labels_transform = Transform(
rect_group.labels,
target_group.labels
)
start_x = float(rect_group.x_val)
def update_rect_group(group, alpha):
x = interpolate(start_x, target_x, alpha)
new_group = self.get_rectangle_group(x, **target_group_kwargs)
Transform(group, new_group).update(1)
labels_transform.update(alpha)
for l1, l2 in zip(rect_group.labels, new_group.labels):
l1.move_to(l2)
return rect_group
self.play(
UpdateFromAlphaFunc(rect_group, update_rect_group),
*added_anims,
**anim_kwargs
)
rect_group.x_val = target_x
class AskRecipriocalQuestion(Scene):
def construct(self):
tex = TexMobject(
"(\\text{What number?})",
"\\cdot x = 1"
)
arrow = Arrow(DOWN+LEFT, UP+RIGHT)
arrow.move_to(tex[0].get_top(), DOWN+LEFT)
self.play(Write(tex))
self.play(ShowCreation(arrow))
self.wait()
class SquareRootOfX(Scene):
CONFIG = {
"square_color_kwargs" : {
"stroke_color" : WHITE,
"stroke_width" : 1,
"fill_color" : BLUE_E,
"fill_opacity" : 1,
},
"bigger_square_color_kwargs" : {
"stroke_color" : WHITE,
"stroke_width" : 1,
"fill_color" : YELLOW,
"fill_opacity" : 0.7,
},
"square_corner" : 6*LEFT+3*UP,
"square_width" : 3,
"d_sqrt_x" : 0.3,
}
def construct(self):
self.add_title()
self.introduce_square()
self.nudge_square()
def add_title(self):
title = TexMobject("f(x) = \\sqrt{x}")
title.next_to(ORIGIN, RIGHT)
title.to_edge(UP)
self.add(title)
def introduce_square(self):
square = Square(
side_length = self.square_width,
**self.square_color_kwargs
)
square.move_to(self.square_corner, UP+LEFT)
area_label = TextMobject("Area $ = x$")
area_label.move_to(square)
bottom_brace, right_brace = braces = VGroup(*[
Brace(square, vect)
for vect in (DOWN, RIGHT)
])
for brace in braces:
brace.add(brace.get_text("$\\sqrt{x}$"))
self.play(
DrawBorderThenFill(square),
Write(area_label)
)
self.play(*list(map(FadeIn, braces)))
self.wait()
self.square = square
self.area_label = area_label
self.braces = braces
def nudge_square(self):
square = self.square
area_label = self.area_label
bottom_brace, right_brace = self.braces
bigger_square = Square(
side_length = self.square_width + self.d_sqrt_x,
**self.bigger_square_color_kwargs
)
bigger_square.move_to(self.square_corner, UP+LEFT)
square_copy = square.copy()
lines = VGroup(*[
DashedLine(
ORIGIN,
(self.square_width + MED_LARGE_BUFF)*vect,
color = WHITE,
stroke_width = 3
).shift(s.get_corner(corner))
for corner, vect in [(DOWN+LEFT, RIGHT), (UP+RIGHT, DOWN)]
for s in [square, bigger_square]
])
little_braces = VGroup(*[
Brace(VGroup(*line_pair), vect, buff = 0)
for line_pair, vect in [(lines[:2], RIGHT), (lines[2:], DOWN)]
])
for brace in little_braces:
tex = brace.get_text("$d\\sqrt{x}$", buff = SMALL_BUFF)
tex.scale_in_place(0.8)
brace.add(tex)
area_increase = TextMobject("$dx$ = New area")
area_increase.set_color(bigger_square.get_color())
area_increase.next_to(square, RIGHT, 4)
question = TexMobject("\\frac{d\\sqrt{x}}{dx} = ???")
VGroup(*question[5:7]).set_color(bigger_square.get_color())
question.next_to(
area_increase, DOWN,
aligned_edge = LEFT,
buff = LARGE_BUFF
)
self.play(
Transform(square_copy, bigger_square),
Animation(square),
Animation(area_label),
bottom_brace.next_to, bigger_square, DOWN, SMALL_BUFF, LEFT,
right_brace.next_to, bigger_square, RIGHT, SMALL_BUFF, UP,
)
self.play(Write(area_increase))
self.play(*it.chain(
list(map(ShowCreation, lines)),
list(map(FadeIn, little_braces))
))
self.play(Write(question))
self.wait()
class MentionSine(TeacherStudentsScene):
def construct(self):
self.teacher_says("Let's tackle $\\sin(\\theta)$")
self.change_student_modes("pondering", "hooray", "erm")
self.wait(2)
self.student_thinks("")
self.zoom_in_on_thought_bubble()
class NameUnitCircle(Scene):
def construct(self):
words = TextMobject("Unit circle")
words.scale(2)
words.set_color(BLUE)
self.play(Write(words))
self.wait()
class DerivativeOfSineIsSlope(Scene):
def construct(self):
tex = TexMobject(
"\\frac{d(\\sin(\\theta))}{d\\theta} = ",
"\\text{Slope of this graph}"
)
tex.set_width(FRAME_WIDTH-1)
tex.to_edge(DOWN)
VGroup(*tex[0][2:8]).set_color(BLUE)
VGroup(*tex[1][-9:]).set_color(BLUE)
self.play(Write(tex, run_time = 2))
self.wait()
class IntroduceUnitCircleWithSine(GraphScene):
CONFIG = {
"unit_length" : 2.5,
"graph_origin" : ORIGIN,
"x_axis_width" : 15,
"y_axis_height" : 10,
"x_min" : -3,
"x_max" : 3,
"y_min" : -2,
"y_max" : 2,
"x_labeled_nums" : [-2, -1, 1, 2],
"y_labeled_nums" : [-1, 1],
"x_tick_frequency" : 0.5,
"y_tick_frequency" : 0.5,
"circle_color" : BLUE,
"example_radians" : 0.8,
"rotations_per_second" : 0.25,
"include_radial_line_dot" : True,
"remove_angle_label" : True,
"line_class" : DashedLine,
"theta_label" : "= 0.8",
}
def construct(self):
self.setup_axes()
self.add_title()
self.introduce_unit_circle()
self.draw_example_radians()
self.label_sine()
self.walk_around_circle()
def add_title(self):
title = TexMobject("f(\\theta) = \\sin(\\theta)")
title.to_corner(UP+LEFT)
self.add(title)
self.title = title
def introduce_unit_circle(self):
circle = self.get_unit_circle()
radial_line = Line(ORIGIN, self.unit_length*RIGHT)
radial_line.set_color(RED)
if self.include_radial_line_dot:
dot = Dot()
dot.move_to(radial_line.get_end())
radial_line.add(dot)
self.play(ShowCreation(radial_line))
self.play(
ShowCreation(circle),
Rotate(radial_line, 2*np.pi),
run_time = 2,
)
self.wait()
self.circle = circle
self.radial_line = radial_line
def draw_example_radians(self):
circle = self.circle
radial_line = self.radial_line
line = Line(
ORIGIN, self.example_radians*self.unit_length*UP,
color = YELLOW,
)
line.shift(FRAME_X_RADIUS*RIGHT/3).to_edge(UP)
line.insert_n_curves(10)
line.make_smooth()
arc = Arc(
self.example_radians, radius = self.unit_length,
color = line.get_color(),
)
arc_copy = arc.copy().set_color(WHITE)
brace = Brace(line, RIGHT)
brace_text = brace.get_text("$\\theta%s$"%self.theta_label)
brace_text.set_color(line.get_color())
theta_copy = brace_text[0].copy()
self.play(
GrowFromCenter(line),
GrowFromCenter(brace),
)
self.play(Write(brace_text))
self.wait()
self.play(
line.move_to, radial_line.get_end(), DOWN,
FadeOut(brace)
)
self.play(ReplacementTransform(line, arc))
self.wait()
self.play(
Rotate(radial_line, self.example_radians),
ShowCreation(arc_copy)
)
self.wait()
arc_copy.generate_target()
arc_copy.target.scale(0.2)
theta_copy.generate_target()
theta_copy.target.next_to(
arc_copy.target, RIGHT,
aligned_edge = DOWN,
buff = SMALL_BUFF
)
theta_copy.target.shift(SMALL_BUFF*UP)
self.play(*list(map(MoveToTarget, [arc_copy, theta_copy])))
self.wait()
self.angle_label = VGroup(arc_copy, theta_copy)
self.example_theta_equation = brace_text
def label_sine(self):
radial_line = self.radial_line
drop_point = radial_line.get_end()[0]*RIGHT
v_line = self.line_class(radial_line.get_end(), drop_point)
brace = Brace(v_line, RIGHT)
brace_text = brace.get_text("$\\sin(\\theta)$")
brace_text[-2].set_color(YELLOW)
self.play(ShowCreation(v_line))
self.play(
GrowFromCenter(brace),
Write(brace_text)
)
self.wait()
faders = [brace, brace_text, self.example_theta_equation]
if self.remove_angle_label:
faders += self.angle_label
self.play(*list(map(FadeOut, faders)))
self.v_line = v_line
def walk_around_circle(self):
radial_line = self.radial_line
v_line = self.v_line
def v_line_update(v_line):
drop_point = radial_line.get_end()[0]*RIGHT
v_line.put_start_and_end_on(
radial_line.get_end(), drop_point
)
return v_line
filler_arc = self.circle.copy()
filler_arc.set_color(YELLOW)
curr_arc_portion = self.example_radians/(2*np.pi)
filler_portion = 1 - curr_arc_portion
filler_arc.pointwise_become_partial(filler_arc, curr_arc_portion, 1)
self.play(
Rotate(radial_line, filler_portion*2*np.pi),
ShowCreation(filler_arc),
UpdateFromFunc(v_line, v_line_update),
run_time = filler_portion/self.rotations_per_second,
rate_func=linear,
)
for x in range(5):
self.play(
Rotate(radial_line, 2*np.pi),
UpdateFromFunc(v_line, v_line_update),
run_time = 1./self.rotations_per_second,
rate_func=linear,
)
##############
def setup_axes(self):
GraphScene.setup_axes(self)
VGroup(*self.x_axis.numbers[:2]).shift(MED_SMALL_BUFF*LEFT)
VGroup(*self.x_axis.numbers[2:]).shift(SMALL_BUFF*RIGHT)
self.y_axis.numbers[0].shift(MED_SMALL_BUFF*DOWN)
self.y_axis.numbers[1].shift(MED_SMALL_BUFF*UP)
def get_unit_circle(self):
return Circle(
radius = self.unit_length,
color = self.circle_color,
)
class DerivativeIntuitionFromSineGraph(GraphScene):
CONFIG = {
"graph_origin" : 6*LEFT,
"x_axis_width" : 11,
"x_min" : 0,
"x_max" : 4*np.pi,
"x_labeled_nums" : np.arange(0, 4*np.pi, np.pi),
"x_tick_frequency" : np.pi/4,
"x_axis_label" : "$\\theta$",
"y_axis_height" : 6,
"y_min" : -2,
"y_max" : 2,
"y_tick_frequency" : 0.5,
"y_axis_label" : "",
}
def construct(self):
self.setup_axes()
self.draw_sine_graph()
self.draw_derivative_from_slopes()
self.alter_derivative_graph()
def draw_sine_graph(self):
graph = self.get_graph(np.sin)
v_line = DashedLine(ORIGIN, UP)
rps = IntroduceUnitCircleWithSine.CONFIG["rotations_per_second"]
self.play(
ShowCreation(graph),
UpdateFromFunc(v_line, lambda v : self.v_line_update(v, graph)),
run_time = 2./rps,
rate_func=linear
)
self.wait()
self.graph = graph
def draw_derivative_from_slopes(self):
ss_group = self.get_secant_slope_group(
0, self.graph,
dx = 0.01,
secant_line_color = RED,
)
deriv_graph = self.get_graph(np.cos, color = DERIVATIVE_COLOR)
v_line = DashedLine(
self.graph_origin, self.coords_to_point(0, 1),
color = RED
)
self.play(ShowCreation(ss_group, lag_ratio = 0))
self.play(ShowCreation(v_line))
self.wait()
last_theta = 0
next_theta = np.pi/2
while last_theta < self.x_max:
deriv_copy = deriv_graph.copy()
self.animate_secant_slope_group_change(
ss_group,
target_x = next_theta,
added_anims = [
ShowCreation(
deriv_copy,
rate_func = lambda t : interpolate(
last_theta/self.x_max,
next_theta/self.x_max,
smooth(t)
),
run_time = 3,
),
UpdateFromFunc(
v_line,
lambda v : self.v_line_update(v, deriv_copy),
run_time = 3
),
]
)
self.wait()
if next_theta == 2*np.pi:
words = TextMobject("Looks a lot like $\\cos(\\theta)$")
words.next_to(self.graph_origin, RIGHT)
words.to_edge(UP)
arrow = Arrow(
words.get_bottom(),
deriv_graph.point_from_proportion(0.45)
)
VGroup(words, arrow).set_color(deriv_graph.get_color())
self.play(
Write(words),
ShowCreation(arrow)
)
self.remove(deriv_copy)
last_theta = next_theta
next_theta += np.pi/2
self.add(deriv_copy)
self.deriv_graph = deriv_copy
def alter_derivative_graph(self):
func_list = [
lambda x : 0.5*(np.cos(x)**3 + np.cos(x)),
lambda x : 0.75*(np.sign(np.cos(x))*np.cos(x)**2 + np.cos(x)),
lambda x : 2*np.cos(x),
lambda x : np.cos(x),
]
for func in func_list:
new_graph = self.get_graph(func, color = DERIVATIVE_COLOR)
self.play(
Transform(self.deriv_graph, new_graph),
run_time = 2
)
self.wait()
######
def v_line_update(self, v_line, graph):
point = graph.point_from_proportion(1)
drop_point = point[0]*RIGHT
v_line.put_start_and_end_on(drop_point, point)
return v_line
def setup_axes(self):
GraphScene.setup_axes(self)
self.x_axis.remove(self.x_axis.numbers)
self.remove(self.x_axis.numbers)
for x in range(1, 4):
if x == 1:
label = TexMobject("\\pi")
else:
label = TexMobject("%d\\pi"%x)
label.next_to(self.coords_to_point(x*np.pi, 0), DOWN, MED_LARGE_BUFF)
self.add(label)
self.x_axis_label_mob.set_color(YELLOW)
class LookToFunctionsMeaning(TeacherStudentsScene):
def construct(self):
self.teacher_says("""
Look to the function's
actual meaning
""")
self.change_student_modes(*["pondering"]*3)
self.wait(3)
class DerivativeFromZoomingInOnSine(IntroduceUnitCircleWithSine, ZoomedScene):
CONFIG = {
"zoom_factor" : 10,
"zoomed_canvas_frame_shape" : (3, 4.5),
"include_radial_line_dot" : False,
"remove_angle_label" : False,
"theta_label" : "",
"line_class" : Line,
"example_radians" : 1.0,
"zoomed_canvas_corner_buff" : SMALL_BUFF,
"d_theta" : 0.05,
}
def construct(self):
self.setup_axes()
self.add_title()
self.introduce_unit_circle()
self.draw_example_radians()
self.label_sine()
self.zoom_in()
self.perform_nudge()
self.show_similar_triangles()
self.analyze_ratios()
def zoom_in(self):
self.activate_zooming()
self.little_rectangle.next_to(self.radial_line.get_end(), UP, LARGE_BUFF)
self.play(*list(map(FadeIn, [
self.little_rectangle, self.big_rectangle
])))
self.play(
self.little_rectangle.move_to,
self.radial_line.get_end(), DOWN+RIGHT,
self.little_rectangle.shift,
SMALL_BUFF*(DOWN+RIGHT)
)
self.wait()
def perform_nudge(self):
d_theta_arc = Arc(
start_angle = self.example_radians,
angle = self.d_theta,
radius = self.unit_length,
color = MAROON_B,
stroke_width = 6
)
d_theta_arc.scale(self.zoom_factor)
d_theta_brace = Brace(
d_theta_arc,
rotate_vector(RIGHT, self.example_radians)
)
d_theta_label = TexMobject("d\\theta")
d_theta_label.next_to(
d_theta_brace.get_center(), d_theta_brace.direction,
MED_LARGE_BUFF
)
d_theta_label.set_color(d_theta_arc.get_color())
group = VGroup(d_theta_arc, d_theta_brace, d_theta_label)
group.scale(1./self.zoom_factor)
point = self.radial_line.get_end()
nudged_point = d_theta_arc.point_from_proportion(1)
interim_point = nudged_point[0]*RIGHT+point[1]*UP
h_line = DashedLine(
interim_point, point,
dash_length = 0.01
)
d_sine_line = Line(interim_point, nudged_point, color = DERIVATIVE_COLOR)
d_sine_brace = Brace(Line(ORIGIN, UP), LEFT)
d_sine_brace.set_height(d_sine_line.get_height())
d_sine_brace.next_to(d_sine_line, LEFT, buff = SMALL_BUFF/self.zoom_factor)
d_sine = TexMobject("d(\\sin(\\theta))")
d_sine.set_color(d_sine_line.get_color())
d_sine.set_width(1.5*self.d_theta*self.unit_length)
d_sine.next_to(d_sine_brace, LEFT, SMALL_BUFF/self.zoom_factor)
self.play(ShowCreation(d_theta_arc))
self.play(
GrowFromCenter(d_theta_brace),
FadeIn(d_theta_label)
)
self.wait()
self.play(
ShowCreation(h_line),
ShowCreation(d_sine_line)
)
self.play(
GrowFromCenter(d_sine_brace),
Write(d_sine)
)
self.wait()
self.little_triangle = Polygon(
nudged_point, point, interim_point
)
self.d_theta_group = VGroup(d_theta_brace, d_theta_label)
self.d_sine_group = VGroup(d_sine_brace, d_sine)
def show_similar_triangles(self):
little_triangle = self.little_triangle
big_triangle = Polygon(
self.graph_origin,
self.radial_line.get_end(),
self.radial_line.get_end()[0]*RIGHT,
)
for triangle in little_triangle, big_triangle:
triangle.set_color(GREEN)
triangle.set_fill(GREEN, opacity = 0.5)
big_triangle_copy = big_triangle.copy()
big_triangle_copy.next_to(ORIGIN, UP+LEFT)
new_angle_label = self.angle_label.copy()
new_angle_label.scale(
little_triangle.get_width()/big_triangle.get_height()
)
new_angle_label.rotate(-np.pi/2)
new_angle_label.shift(little_triangle.points[0])
new_angle_label[1].rotate_in_place(np.pi/2)
little_triangle_lines = VGroup(*[
Line(*list(map(little_triangle.get_corner, pair)))
for pair in [
(DOWN+RIGHT, UP+LEFT),
(UP+LEFT, DOWN+LEFT)
]
])
little_triangle_lines.set_color(little_triangle.get_color())
self.play(DrawBorderThenFill(little_triangle))
self.play(
little_triangle.scale, 2, little_triangle.get_corner(DOWN+RIGHT),
little_triangle.set_color, YELLOW,
rate_func = there_and_back
)
self.wait()
groups = [self.d_theta_group, self.d_sine_group]
for group, line in zip(groups, little_triangle_lines):
self.play(ApplyMethod(
line.rotate_in_place, np.pi/12,
rate_func = wiggle,
remover = True,
))
self.play(
group.scale, 1.2, group.get_corner(DOWN+RIGHT),
group.set_color, YELLOW,
rate_func = there_and_back,
)
self.wait()
self.play(ReplacementTransform(
little_triangle.copy().set_fill(opacity = 0),
big_triangle_copy,
path_arc = np.pi/2,
run_time = 2
))
self.wait()
self.play(
ReplacementTransform(big_triangle_copy, big_triangle),
Animation(self.angle_label)
)
self.wait()
self.play(
self.radial_line.rotate_in_place, np.pi/12,
Animation(big_triangle),
rate_func = wiggle,
)
self.wait()
self.play(
ReplacementTransform(
big_triangle.copy().set_fill(opacity = 0),
little_triangle,
path_arc = -np.pi/2,
run_time = 3,
),
ReplacementTransform(
self.angle_label.copy(),
new_angle_label,
path_arc = -np.pi/2,
run_time = 3,
),
)
self.play(
new_angle_label.scale_in_place, 2,
new_angle_label.set_color, RED,
rate_func = there_and_back
)
self.wait()
def analyze_ratios(self):
d_ratio = TexMobject("\\frac{d(\\sin(\\theta))}{d\\theta} = ")
VGroup(*d_ratio[:9]).set_color(GREEN)
VGroup(*d_ratio[10:12]).set_color(MAROON_B)
trig_ratio = TexMobject("\\frac{\\text{Adj.}}{\\text{Hyp.}}")
VGroup(*trig_ratio[:4]).set_color(GREEN)
VGroup(*trig_ratio[5:9]).set_color(MAROON_B)
cos = TexMobject("= \\cos(\\theta)")
cos.add_background_rectangle()
group = VGroup(d_ratio, trig_ratio, cos)
group.arrange()
group.next_to(
self.title, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
for mob in group:
self.play(Write(mob))
self.wait()
class TryWithCos(Scene):
def construct(self):
words = TextMobject("What about $\\cos(\\theta)$?")
words.set_color(YELLOW)
self.play(Write(words))
self.wait()
class NextVideo(TeacherStudentsScene):
def construct(self):
series = VideoSeries()
next_video = series[3]
series.to_edge(UP)
d_sum = TexMobject("\\frac{d}{dx}(x^3 + x^2)")
d_product = TexMobject("\\frac{d}{dx} \\sin(x)x^2")
d_composition = TexMobject("\\frac{d}{dx} \\cos\\left(\\frac{1}{x}\\right)")
group = VGroup(d_sum, d_product, d_composition)
group.arrange(RIGHT, buff = 2*LARGE_BUFF)
group.next_to(VGroup(*self.get_pi_creatures()), UP, buff = LARGE_BUFF)
self.play(
FadeIn(
series,
lag_ratio = 0.5,
run_time = 3,
),
*[
ApplyMethod(pi.look_at, next_video)
for pi in self.get_pi_creatures()
]
)
self.play(
next_video.set_color, YELLOW,
next_video.shift, MED_LARGE_BUFF*DOWN
)
self.wait()
for mob in group:
self.play(
Write(mob, run_time = 1),
*[
ApplyMethod(pi.look_at, mob)
for pi in self.get_pi_creatures()
]
)
self.wait(3)
class Chapter3PatreonThanks(PatreonThanks):
CONFIG = {
"specific_patrons" : [
"Ali Yahya",
"CrypticSwarm ",
"Yu Jun",
"Shelby Doolittle",
"Dave Nicponski",
"Damion Kistler",
"Juan Benet",
"Othman Alikhan",
"Markus Persson",
"Dan Buchoff",
"Derek Dai",
"Joseph John Cox",
"Luc Ritchie",
"Guido Gambardella",
"Jerry Ling",
"Mark Govea",
"Vecht ",
"Jonathan Eppele",
"Shimin Kuang",
"Rish Kundalia",
"Achille Brighton",
"Kirk Werklund",
"Ripta Pasay",
"Felipe Diniz",
]
}
class Promotion(PiCreatureScene):
CONFIG = {
"seconds_to_blink" : 5,
}
def construct(self):
url = TextMobject("https://brilliant.org/3b1b/")
url.to_corner(UP+LEFT)
rect = Rectangle(height = 9, width = 16)
rect.set_height(5.5)
rect.next_to(url, DOWN)
rect.to_edge(LEFT)
self.play(
Write(url),
self.pi_creature.change, "raise_right_hand"
)
self.play(ShowCreation(rect))
self.wait(2)
self.change_mode("thinking")
self.wait()
self.look_at(url)
self.wait(10)
self.change_mode("happy")
self.wait(10)
self.change_mode("raise_right_hand")
self.wait(10)
class Thumbnail(NudgeSideLengthOfCube):
def construct(self):
self.introduce_cube()
VGroup(*self.get_mobjects()).to_edge(DOWN)
formula = TexMobject(
"\\frac{d(x^3)}{dx} = 3x^2"
)
VGroup(*formula[:5]).set_color(YELLOW)
VGroup(*formula[-3:]).set_color(GREEN_B)
formula.set_width(FRAME_X_RADIUS-1)
formula.to_edge(RIGHT)
self.add(formula)
title = TextMobject("Geometric derivatives")
title.set_width(FRAME_WIDTH-1)
title.to_edge(UP)
self.add(title)