3b1b-manim/old_projects/eoc/chapter4.py

2288 lines
73 KiB
Python
Raw Normal View History

from big_ol_pile_of_manim_imports import *
2017-04-17 10:19:30 -07:00
SINE_COLOR = BLUE
X_SQUARED_COLOR = GREEN
SUM_COLOR = YELLOW
PRODUCT_COLOR = YELLOW
class Chapter4OpeningQuote(OpeningQuote):
CONFIG = {
"quote" : [
2017-04-17 10:19:30 -07:00
"Using the chain rule is like peeling an onion: ",
"you have to deal with each layer at a time, and ",
"if it is too big you will start crying."
],
2017-04-17 10:19:30 -07:00
"author" : "(Anonymous professor)"
}
2017-04-17 10:19:30 -07:00
class TransitionFromLastVideo(TeacherStudentsScene):
def construct(self):
2018-08-09 17:56:05 -07:00
simple_rules = VGroup(*list(map(TexMobject, [
2017-04-17 10:19:30 -07:00
"\\frac{d(x^3)}{dx} = 3x^2",
"\\frac{d(\\sin(x))}{dx} = \\cos(x)",
"\\frac{d(1/x)}{dx} = -\\frac{1}{x^2}",
2018-08-09 17:56:05 -07:00
])))
2017-04-17 10:19:30 -07:00
combination_rules = VGroup(*[
TexMobject("\\frac{d}{dx}\\left(%s\\right)"%tex)
for tex in [
"\\sin(x) + x^2",
"\\sin(x)(x^2)",
"\\sin(x^2)",
]
])
for rules in simple_rules, combination_rules:
2019-02-04 14:54:25 -08:00
rules.arrange(buff = LARGE_BUFF)
2017-04-17 10:19:30 -07:00
rules.next_to(self.get_teacher(), UP, buff = MED_LARGE_BUFF)
rules.to_edge(LEFT)
2017-02-14 15:57:55 -08:00
series = VideoSeries()
series.to_edge(UP)
last_video = series[2]
last_video.save_state()
this_video = series[3]
2017-04-17 10:19:30 -07:00
brace = Brace(last_video)
2017-02-14 15:57:55 -08:00
2017-04-17 10:19:30 -07:00
#Simple rules
2017-02-14 15:57:55 -08:00
self.add(series)
self.play(
2017-04-17 10:19:30 -07:00
FadeIn(brace),
2018-03-30 11:51:31 -07:00
last_video.set_color, YELLOW
2017-02-14 15:57:55 -08:00
)
2017-04-17 10:19:30 -07:00
for rule in simple_rules:
self.play(
Write(rule, run_time = 2),
self.get_teacher().change_mode, "raise_right_hand",
*[
ApplyMethod(pi.change_mode, "pondering")
for pi in self.get_students()
]
)
2018-01-15 19:15:05 -08:00
self.wait()
self.wait(2)
2017-04-17 10:19:30 -07:00
self.play(simple_rules.replace, last_video)
2017-02-14 15:57:55 -08:00
self.play(
2017-04-17 10:19:30 -07:00
last_video.restore,
Animation(simple_rules),
brace.next_to, this_video, DOWN,
2018-03-30 11:51:31 -07:00
this_video.set_color, YELLOW
2017-02-14 15:57:55 -08:00
)
2017-04-17 10:19:30 -07:00
#Combination rules
self.play(
Write(combination_rules),
*[
ApplyMethod(pi.change_mode, "confused")
for pi in self.get_students()
]
2017-02-14 15:57:55 -08:00
)
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-04-17 10:19:30 -07:00
for rule in combination_rules:
interior = VGroup(*rule[5:-1])
added_anims = []
if rule is combination_rules[-1]:
inner_func = VGroup(*rule[-4:-2])
self.play(inner_func.shift, 0.5*UP)
added_anims = [
inner_func.shift, 0.5*DOWN,
2018-03-30 11:51:31 -07:00
inner_func.set_color, YELLOW
2017-04-17 10:19:30 -07:00
]
self.play(
2018-03-30 11:51:31 -07:00
interior.set_color, YELLOW,
2017-04-17 10:19:30 -07:00
*added_anims,
submobject_mode = "lagged_start"
)
2018-01-15 19:15:05 -08:00
self.wait()
self.wait()
2017-02-14 15:57:55 -08:00
2017-04-17 10:19:30 -07:00
#Address subtraction and division
subtraction = TexMobject("\\sin(x)", "-", "x^2")
decomposed_subtraction = TexMobject("\\sin(x)", "+(-1)\\cdot", "x^2")
pre_division = TexMobject("\\frac{\\sin(x)}{x^2}")
division = VGroup(
VGroup(*pre_division[:6]),
VGroup(*pre_division[6:7]),
VGroup(*pre_division[7:]),
)
pre_decomposed_division = TexMobject("\\sin(x)\\cdot\\frac{1}{x^2}")
decomposed_division = VGroup(
VGroup(*pre_decomposed_division[:6]),
VGroup(*pre_decomposed_division[6:9]),
VGroup(*pre_decomposed_division[9:]),
)
for mob in subtraction, decomposed_subtraction, division, decomposed_division:
mob.next_to(
VGroup(self.get_teacher(), self.get_students()[-1]),
UP, buff = MED_LARGE_BUFF
)
2017-02-14 15:57:55 -08:00
2017-04-17 10:19:30 -07:00
top_group = VGroup(series, simple_rules, brace)
combination_rules.save_state()
self.play(
top_group.next_to, FRAME_Y_RADIUS*UP, UP,
2017-04-17 10:19:30 -07:00
combination_rules.to_edge, UP,
)
pairs = [
(subtraction, decomposed_subtraction),
(division, decomposed_division)
2017-02-14 15:57:55 -08:00
]
2017-04-17 10:19:30 -07:00
for question, answer in pairs:
self.play(
Write(question),
combination_rules.fade, 0.2,
self.get_students()[2].change_mode, "raise_right_hand",
self.get_teacher().change_mode, "plain",
)
2018-01-15 19:15:05 -08:00
self.wait()
2018-03-30 11:51:31 -07:00
answer[1].set_color(GREEN)
2017-04-17 10:19:30 -07:00
self.play(
Transform(question, answer),
self.get_teacher().change_mode, "hooray",
self.get_students()[2].change_mode, "plain",
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(FadeOut(question))
#Monstrous expression
monster = TexMobject(
"\\Big(",
"e^{\\sin(x)} \\cdot",
"\\cos\\Big(",
"\\frac{1}{x^3}",
" + x^3",
"\\Big)",
"\\Big)^4"
)
monster.next_to(self.get_pi_creatures(), UP)
parts = [
VGroup(*monster[3][2:]),
VGroup(*monster[3][:2]),
monster[4],
VGroup(monster[2], monster[5]),
monster[1],
VGroup(monster[0], monster[6])
]
modes = 3*["erm"] + 3*["pleading"]
for part, mode in zip(parts, modes):
self.play(
FadeIn(part, submobject_mode = "lagged_start"),
self.get_teacher().change_mode, "raise_right_hand",
*[
ApplyMethod(pi.change_mode, mode)
for pi in self.get_students()
]
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.change_student_modes(*["happy"]*3)
2018-08-09 17:56:05 -07:00
words = list(map(TextMobject, [
2017-04-17 10:19:30 -07:00
"composition", "product",
"composition", "sum",
"composition"
2018-08-09 17:56:05 -07:00
]))
2017-04-17 10:19:30 -07:00
for word, part in zip(words, reversed(parts)):
2018-03-30 11:51:31 -07:00
word.set_color(YELLOW)
2017-04-17 10:19:30 -07:00
word.next_to(monster, UP)
self.play(
FadeIn(word),
part.scale_in_place, 1.2,
2018-03-30 11:51:31 -07:00
part.set_color, YELLOW
)
2018-01-15 19:15:05 -08:00
self.wait()
2018-08-09 17:56:05 -07:00
self.play(*list(map(FadeOut, [word, part])))
2017-04-17 10:19:30 -07:00
self.play(FadeOut(parts[0]))
#Bring back combinations
2017-02-14 15:57:55 -08:00
self.play(
2017-04-17 10:19:30 -07:00
combination_rules.restore,
*[
ApplyMethod(pi_creature.change_mode, "pondering")
for pi_creature in self.get_pi_creatures()
]
2017-02-14 15:57:55 -08:00
)
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-02-14 15:57:55 -08:00
2017-04-17 10:19:30 -07:00
class DampenedSpring(Scene):
def construct(self):
compact_spring, extended_spring = [
ParametricFunction(
lambda t : (t/denom)*RIGHT+np.sin(t)*UP+np.cos(t)*OUT,
t_max = 12*np.pi,
color = GREY,
).shift(3*LEFT)
for denom in (12.0, 2.0)
2017-04-17 10:19:30 -07:00
]
for spring in compact_spring, extended_spring:
spring.scale(0.5)
spring.rotate(np.pi/6, UP)
2018-03-30 11:51:31 -07:00
spring.set_color(GREY)
2017-04-17 10:19:30 -07:00
spring.shift(-spring.points[0] + 3*LEFT)
moving_spring = compact_spring.copy()
def update_spring(spring, a):
spring.interpolate(
compact_spring,
extended_spring,
0.5*(np.exp(-4*a)*np.cos(40*a)+1)
)
2017-02-20 17:23:20 -08:00
2017-04-17 10:19:30 -07:00
equation = TexMobject(
"\\text{Length} = 2 + e^{-4t}\\cos(20t)"
2017-03-22 15:06:17 -07:00
)
2017-04-17 10:19:30 -07:00
equation.to_edge(UP)
2017-04-17 10:19:30 -07:00
self.add(moving_spring, equation)
self.play(UpdateFromAlphaFunc(
moving_spring, update_spring, run_time = 10,
rate_func=linear
2017-04-17 10:19:30 -07:00
))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
class ComingUp(Scene):
def construct(self):
rect = Rectangle(height = 9, width = 16)
rect.set_stroke(WHITE)
rect.set_height(FRAME_HEIGHT-2)
2017-04-17 10:19:30 -07:00
title = TextMobject("Coming up...")
title.to_edge(UP)
rect.next_to(title, DOWN)
self.play(Write(title))
self.play(ShowCreation(rect))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
class PreSumRuleDiscussion(Scene):
def construct(self):
title = TextMobject("Sum rule")
title.to_edge(UP)
self.add(title)
specific = TexMobject(
"\\frac{d}{dx}(", "\\sin(x)", "+", "x^2", ")",
"=", "\\cos(x)", "+", "2x"
)
general = TexMobject(
"\\frac{d}{dx}(", "g(x)", "+", "h(x)", ")",
"=", "\\frac{dg}{dx}", "+", "\\frac{dh}{dx}"
)
for formula in specific, general:
2018-03-30 11:51:31 -07:00
formula[1].set_color(SINE_COLOR)
formula[6].set_color(SINE_COLOR)
formula[3].set_color(X_SQUARED_COLOR)
formula[8].set_color(X_SQUARED_COLOR)
2019-02-04 14:54:25 -08:00
VGroup(specific, general).arrange(DOWN, buff = LARGE_BUFF)
2017-04-17 10:19:30 -07:00
#Add on rules
self.add(specific)
for i in 0, 4, 5:
self.add(general[i])
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-04-17 10:19:30 -07:00
for indices in [(1, 2, 3), (6,), (7, 8)]:
self.play(*[
ReplacementTransform(
specific[i].copy(), general[i]
)
for i in indices
])
2018-01-15 19:15:05 -08:00
self.wait()
2017-03-22 15:06:17 -07:00
2017-04-17 10:19:30 -07:00
#Highlight parts
for i in 1, 3, -1, 6, 8:
if i < 0:
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
else:
part = specific[i]
self.play(
2018-03-30 11:51:31 -07:00
part.set_color, YELLOW,
2017-04-17 10:19:30 -07:00
part.scale_in_place, 1.2,
rate_func = there_and_back
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
class SumRule(GraphScene):
CONFIG = {
"x_labeled_nums" : [],
"y_labeled_nums" : [],
"y_axis_label" : "",
"x_max" : 4,
"x_axis_width" : FRAME_WIDTH,
2017-04-17 10:19:30 -07:00
"y_max" : 3,
"graph_origin" : 2.5*DOWN + 2.5*LEFT,
"graph_label_x_value" : 1.5,
"example_input" : 0.5,
"example_input_string" : "0.5",
"dx" : 0.05,
"v_lines_x_min" : -1,
"v_lines_x_max" : 2,
"graph_scale_factor" : 2,
"tex_scale_factor" : 0.8,
}
def construct(self):
self.write_function()
self.add_graphs()
self.zoom_in_on_graph()
self.show_example_stacking()
self.show_df()
self.expand_derivative()
def write_function(self):
func_mob = TexMobject("f(x)", "=", "\\sin(x)", "+", "x^2")
func_mob.scale(self.tex_scale_factor)
2018-03-30 11:51:31 -07:00
func_mob.set_color_by_tex("f(x)", SUM_COLOR)
func_mob.set_color_by_tex("\\sin(x)", SINE_COLOR)
func_mob.set_color_by_tex("x^2", X_SQUARED_COLOR)
2017-04-17 10:19:30 -07:00
func_mob.to_corner(UP+LEFT)
self.add(func_mob)
self.func_mob = func_mob
def add_graphs(self):
self.setup_axes()
sine_graph = self.get_graph(np.sin, color = SINE_COLOR)
parabola = self.get_graph(lambda x : x**2, color = X_SQUARED_COLOR)
sum_graph = self.get_graph(
lambda x : np.sin(x) + x**2,
color = SUM_COLOR
)
sine_label = self.get_graph_label(
sine_graph, "\\sin(x)",
x_val = self.graph_label_x_value,
direction = UP+RIGHT,
buff = 0,
)
sine_label.scale_in_place(self.tex_scale_factor)
parabola_label = self.get_graph_label(
parabola, "x^2", x_val = self.graph_label_x_value,
)
parabola_label.scale_in_place(self.tex_scale_factor)
graphs = VGroup(sine_graph, parabola)
labels = VGroup(sine_label, parabola_label)
for label in labels:
label.add_background_rectangle()
for graph, label in zip(graphs, labels):
self.play(
ShowCreation(graph),
Write(label)
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-03-22 15:06:17 -07:00
2017-04-17 10:19:30 -07:00
num_lines = (self.v_lines_x_max-self.v_lines_x_min)/self.dx
sine_v_lines, parabox_v_lines = v_line_sets = [
self.get_vertical_lines_to_graph(
graph,
x_min = self.v_lines_x_min,
x_max = self.v_lines_x_max,
num_lines = num_lines,
stroke_width = 2
)
2017-04-17 10:19:30 -07:00
for graph in graphs
]
sine_v_lines.shift(0.02*RIGHT)
for v_lines in v_line_sets:
self.play(ShowCreation(v_lines), Animation(labels))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(*it.chain(
[
ApplyMethod(l2.move_to, l1.get_top(), DOWN)
for l1, l2, in zip(*v_line_sets)
],
[graph.fade for graph in graphs],
[Animation(labels)]
))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(ShowCreation(sum_graph))
2018-01-15 19:15:05 -08:00
self.wait()
2017-03-22 15:06:17 -07:00
2017-04-17 10:19:30 -07:00
self.sum_graph = sum_graph
self.parabola = parabola
self.sine_graph = sine_graph
self.graph_labels = labels
self.v_line_sets = v_line_sets
def zoom_in_on_graph(self):
graph_parts = VGroup(
self.axes,
self.sine_graph, self.parabola, self.sum_graph,
*self.v_line_sets
)
graph_parts.remove(self.func_mob, *self.graph_labels)
graph_parts.generate_target()
self.graph_labels.generate_target()
for mob in graph_parts, self.graph_labels:
mob.target.scale(
self.graph_scale_factor,
about_point = self.graph_origin,
)
for mob in self.graph_labels.target:
mob.scale(
1./self.graph_scale_factor,
about_point = mob.get_bottom()
)
mob.shift_onto_screen()
2018-08-09 17:56:05 -07:00
self.play(*list(map(MoveToTarget, [
2017-04-17 10:19:30 -07:00
graph_parts, self.graph_labels
2018-08-09 17:56:05 -07:00
])))
2018-01-15 19:15:05 -08:00
self.wait()
2017-03-22 15:06:17 -07:00
2017-04-17 10:19:30 -07:00
def show_example_stacking(self):
v_line_sets = self.v_line_sets
num_lines = len(v_line_sets[0])
example_v_lines, nudged_v_lines = [
VGroup(*[v_lines[index] for v_lines in v_line_sets])
for index in (num_lines/2, num_lines/2+1)
]
for line in nudged_v_lines:
line.save_state()
sine_lines, parabola_lines = [
VGroup(example_v_lines[i], nudged_v_lines[i])
for i in (0, 1)
2017-04-17 10:19:30 -07:00
]
2018-08-09 17:56:05 -07:00
faders = VGroup(*[line for line in it.chain(*v_line_sets) if line not in example_v_lines])
2017-04-17 10:19:30 -07:00
label_groups = []
for line, tex, vect in zip(sine_lines, ["", "+dx"], [LEFT, RIGHT]):
dot = Dot(line.get_bottom(), radius = 0.03, color = YELLOW)
label = TexMobject(
"x=" + str(self.example_input) + tex
)
label.next_to(dot, DOWN+vect, buff = MED_LARGE_BUFF)
arrow = Arrow(
label.get_corner(UP-vect), dot,
buff = SMALL_BUFF,
color = WHITE,
tip_length = 0.1
)
label_groups.append(VGroup(label, arrow, dot))
2017-03-22 15:06:17 -07:00
2017-04-17 10:19:30 -07:00
line_tex_direction_triplets = [
(sine_lines[0], "\\sin(0.5)", LEFT),
(sine_lines[1], "\\sin(0.5+dx)", RIGHT),
(parabola_lines[0], "(0.5)^2", LEFT),
(parabola_lines[1], "(0.5+dx)^2", RIGHT),
]
for line, tex, direction in line_tex_direction_triplets:
line.brace = Brace(
line, direction,
buff = SMALL_BUFF,
min_num_quads = 2,
)
2018-03-30 11:51:31 -07:00
line.brace.set_color(line.get_color())
2017-04-17 10:19:30 -07:00
line.brace.add_background_rectangle()
line.brace_text = line.brace.get_text("$%s$"%tex)
line.brace_text.scale(
self.tex_scale_factor,
about_point = line.brace_text.get_edge_center(-direction)
)
line.brace_text.add_background_rectangle()
line.brace_anim = MaintainPositionRelativeTo(
VGroup(line.brace, line.brace_text), line
)
##Look at example lines
self.play(
example_v_lines.set_stroke, None, 4,
faders.fade,
Animation(self.graph_labels),
Write(label_groups[0]),
)
for line in example_v_lines:
line.save_state()
2018-01-15 19:15:05 -08:00
self.wait()
self.play(
2017-04-17 10:19:30 -07:00
GrowFromCenter(sine_lines[0].brace),
Write(sine_lines[0].brace_text),
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(
sine_lines[0].shift, UP+4*LEFT,
sine_lines[0].brace_anim,
parabola_lines[0].move_to, sine_lines[0], DOWN
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
parabola_lines[0].brace_anim.update(1)
self.play(
GrowFromCenter(parabola_lines[0].brace),
Write(parabola_lines[0].brace_text),
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(*it.chain(*[
[line.restore, line.brace_anim]
for line in example_v_lines
]))
2017-04-17 10:19:30 -07:00
## Nudged_lines
self.play(
Write(label_groups[1]),
*it.chain(*[
[line.restore, line.set_stroke, None, 4]
for line in nudged_v_lines
])
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for line in nudged_v_lines:
self.play(
2017-04-17 10:19:30 -07:00
GrowFromCenter(line.brace),
Write(line.brace_text)
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-02-14 15:57:55 -08:00
2017-04-17 10:19:30 -07:00
self.sine_lines = sine_lines
self.parabola_lines = parabola_lines
2017-02-14 15:57:55 -08:00
2017-04-17 10:19:30 -07:00
def show_df(self):
sine_lines = self.sine_lines
parabola_lines = self.parabola_lines
2017-04-17 10:19:30 -07:00
df, equals, d_sine, plus, d_x_squared = deriv_mob = TexMobject(
"df", "=", "d(\\sin(x))", "+", "d(x^2)"
)
2018-03-30 11:51:31 -07:00
df.set_color(SUM_COLOR)
d_sine.set_color(SINE_COLOR)
d_x_squared.set_color(X_SQUARED_COLOR)
2017-04-17 10:19:30 -07:00
deriv_mob.scale(self.tex_scale_factor)
deriv_mob.next_to(
self.func_mob, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
for submob in deriv_mob:
submob.add_to_back(BackgroundRectangle(submob))
2017-04-17 10:19:30 -07:00
df_lines = self.show_difference(parabola_lines, df, equals)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(FadeOut(df_lines))
self.play(
parabola_lines[0].shift,
(parabola_lines[1].get_bottom()[1]-parabola_lines[0].get_bottom()[1])*UP,
parabola_lines[0].brace_anim
)
d_sine_lines = self.show_difference(sine_lines, d_sine, plus)
d_x_squared_lines = self.show_difference(parabola_lines, d_x_squared, VGroup())
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.deriv_mob = deriv_mob
self.d_sine_lines = d_sine_lines
self.d_x_squared_lines = d_x_squared_lines
2017-04-17 10:19:30 -07:00
def show_difference(self, v_lines, target_tex, added_tex):
distance = v_lines[1].get_top()[1]-v_lines[0].get_top()[1]
h_lines = VGroup(*[
DashedLine(ORIGIN, 2*RIGHT, stroke_width = 3)
for x in range(2)
])
2019-02-04 14:54:25 -08:00
h_lines.arrange(DOWN, buff = distance)
2017-04-17 10:19:30 -07:00
h_lines.move_to(v_lines[1].get_top(), UP+RIGHT)
2017-04-17 10:19:30 -07:00
brace = Brace(h_lines, LEFT)
brace_text = target_tex.copy()
brace_text.next_to(brace, LEFT)
2017-04-17 10:19:30 -07:00
self.play(ShowCreation(h_lines))
self.play(GrowFromCenter(brace), Write(brace_text))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(
ReplacementTransform(brace_text.copy(), target_tex),
Write(added_tex)
)
return VGroup(h_lines, brace, brace_text)
2017-04-17 10:19:30 -07:00
def expand_derivative(self):
expanded_deriv = TexMobject(
"df", "=", "\\cos(x)", "\\,dx", "+", "2x", "\\,dx"
)
2018-03-30 11:51:31 -07:00
expanded_deriv.set_color_by_tex("df", SUM_COLOR)
VGroup(*expanded_deriv[2:4]).set_color(SINE_COLOR)
VGroup(*expanded_deriv[5:7]).set_color(X_SQUARED_COLOR)
2017-04-17 10:19:30 -07:00
expanded_deriv.scale(self.tex_scale_factor)
expanded_deriv.next_to(
self.deriv_mob, DOWN,
buff = MED_LARGE_BUFF,
2017-04-17 10:19:30 -07:00
aligned_edge = LEFT
)
2017-04-17 10:19:30 -07:00
background_rect = BackgroundRectangle(expanded_deriv)
2017-04-17 10:19:30 -07:00
rearranged_deriv = TexMobject(
"{df \\over", "dx}", "=", "\\cos(x)", "+", "2x"
)
2018-03-30 11:51:31 -07:00
rearranged_deriv[0].set_color(SUM_COLOR)
rearranged_deriv[3].set_color(SINE_COLOR)
rearranged_deriv[5].set_color(X_SQUARED_COLOR)
2017-04-17 10:19:30 -07:00
rearranged_deriv.scale(self.tex_scale_factor)
rearranged_deriv.move_to(expanded_deriv, UP+LEFT)
deriv_target_indices = [0, 2, 3, 1, 4, 5, 1]
self.play(
FadeIn(
2017-04-17 10:19:30 -07:00
background_rect,
rate_func = squish_rate_func(smooth, 0.6, 1)
),
2017-04-17 10:19:30 -07:00
Write(expanded_deriv)
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
tex_group_pairs = [
("\\cos(0.5)dx", self.d_sine_lines),
("2(0.5)dx", self.d_x_squared_lines),
]
def indicate(mob):
self.play(
2018-03-30 11:51:31 -07:00
mob.set_color, YELLOW,
2017-04-17 10:19:30 -07:00
mob.scale_in_place, 1.2,
rate_func = there_and_back
)
for tex, group in tex_group_pairs:
old_label = group[-1]
new_label = TexMobject(tex)
pre_dx = VGroup(*new_label[:-2])
dx = VGroup(*new_label[-2:])
new_label.add_background_rectangle()
new_label.scale(self.tex_scale_factor)
new_label.move_to(old_label, RIGHT)
2018-03-30 11:51:31 -07:00
new_label.set_color(old_label.get_color())
2017-04-17 10:19:30 -07:00
self.play(FocusOn(old_label))
indicate(old_label)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(FadeOut(old_label))
self.play(FadeIn(new_label))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
indicate(dx)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
indicate(pre_dx)
2018-01-15 19:15:05 -08:00
self.wait()
self.wait()
2017-04-17 10:19:30 -07:00
self.play(*[
Transform(
expanded_deriv[i], rearranged_deriv[j],
path_arc = -np.pi/2
)
for i, j in enumerate(deriv_target_indices)
])
2018-01-15 19:15:05 -08:00
self.wait()
2017-03-22 15:06:17 -07:00
2017-04-17 10:19:30 -07:00
class DiscussProducts(TeacherStudentsScene):
def construct(self):
wrong_product_rule = TexMobject(
"\\frac{d(\\sin(x)x^2)}{dx}",
"\\ne",
"\\left(\\frac{d(\\sin(x))}{dx}\\right)",
"\\left(\\frac{d(x^2)}{dx}\\right)",
)
not_equals = wrong_product_rule[1]
2018-03-30 11:51:31 -07:00
wrong_product_rule[2].set_color(SINE_COLOR)
wrong_product_rule[3].set_color(X_SQUARED_COLOR)
2017-04-17 10:19:30 -07:00
wrong_product_rule.next_to(
self.get_teacher().get_corner(UP+LEFT),
UP,
buff = MED_LARGE_BUFF
).shift_onto_screen()
2017-03-22 15:06:17 -07:00
2017-04-17 10:19:30 -07:00
self.teacher_says(
"Products are a bit different",
target_mode = "sassy"
2017-03-22 15:06:17 -07:00
)
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-04-17 10:19:30 -07:00
self.play(RemovePiCreatureBubble(
self.get_teacher(),
target_mode = "raise_right_hand"
))
self.play(Write(wrong_product_rule))
self.change_student_modes(
"pondering", "confused", "erm",
added_anims = [
not_equals.scale_in_place, 1.3,
2018-03-30 11:51:31 -07:00
not_equals.set_color, RED
2017-04-17 10:19:30 -07:00
]
2017-03-22 15:06:17 -07:00
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.teacher_says(
"Think about the \\\\ underlying meaning",
bubble_kwargs = {"height" : 3},
added_anims = [
wrong_product_rule.scale, 0.7,
wrong_product_rule.to_corner, UP+LEFT
]
)
2017-04-17 10:19:30 -07:00
self.change_student_modes(*["pondering"]*3)
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-04-17 10:19:30 -07:00
class NotGraphsForProducts(GraphScene):
CONFIG = {
2017-04-17 10:19:30 -07:00
"y_max" : 25,
"x_max" : 7,
}
def construct(self):
self.setup_axes()
2017-04-17 10:19:30 -07:00
sine_graph = self.get_graph(np.sin, color = SINE_COLOR)
sine_graph.label = self.get_graph_label(
sine_graph, "\\sin(x)",
x_val = 3*np.pi/2,
direction = DOWN
)
parabola = self.get_graph(
lambda x : x**2, color = X_SQUARED_COLOR
)
parabola.label = self.get_graph_label(
parabola, "x^2",
x_val = 2.5,
direction = UP+LEFT,
)
product_graph = self.get_graph(
lambda x : np.sin(x)*(x**2), color = PRODUCT_COLOR
)
product_graph.label = self.get_graph_label(
product_graph, "\\sin(x)x^2",
x_val = 2.8,
direction = UP+RIGHT,
buff = 0
)
2017-04-17 10:19:30 -07:00
graphs = [sine_graph, parabola, product_graph]
for graph in graphs:
self.play(
ShowCreation(graph),
Write(graph.label, run_time = 2)
)
2018-01-15 19:15:05 -08:00
self.wait()
2018-08-09 17:56:05 -07:00
everything = VGroup(*[m for m in self.get_mobjects() if not m.is_subpath])
2017-04-17 10:19:30 -07:00
words = TextMobject("Not the best visualization")
words.scale(1.5)
words.shift(FRAME_Y_RADIUS*UP/2)
2017-04-17 10:19:30 -07:00
words.add_background_rectangle()
2018-03-30 11:51:31 -07:00
words.set_color(RED)
2017-04-17 10:19:30 -07:00
self.play(
everything.fade,
Write(words)
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
class ConfusedMorty(Scene):
def construct(self):
morty = Mortimer()
self.add(morty)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(morty.change_mode, "confused")
self.play(Blink(morty))
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-04-17 10:19:30 -07:00
class IntroduceProductAsArea(ReconfigurableScene):
CONFIG = {
2017-04-17 10:19:30 -07:00
"top_func" : np.sin,
"top_func_label" : "\\sin(x)",
"top_func_nudge_label" : "d(\\sin(x))",
"top_func_derivative" : "\\cos(x)",
"side_func" : lambda x : x**2,
"side_func_label" : "x^2",
"side_func_nudge_label" : "d(x^2)",
"side_func_derivative" : "2x",
"x_unit_to_space_unit" : 3,
"box_kwargs" : {
"fill_color" : YELLOW,
"fill_opacity" : 0.75,
"stroke_width" : 1,
},
"df_box_kwargs" : {
"fill_color" : GREEN,
"fill_opacity" : 0.75,
"stroke_width" : 0,
},
"box_corner_location" : 6*LEFT+2.5*UP,
"slider_center" : 3.5*RIGHT+2*DOWN,
"slider_width" : 6,
"slider_x_max" : 3,
"x_slider_handle_height" : 0.25,
"slider_handle_color" : BLUE,
"default_x" : .75,
"dx" : 0.1,
"tiny_dx" : 0.01,
}
def construct(self):
2017-04-17 10:19:30 -07:00
self.introduce_box()
self.talk_though_sine()
self.define_f_of_x()
self.nudge_x()
self.write_df()
self.show_thinner_dx()
self.expand_derivative()
self.write_derivative_abstractly()
self.write_mneumonic()
def introduce_box(self):
box, labels = self.box_label_group = self.get_box_label_group(self.default_x)
self.x_slider = self.get_x_slider(self.default_x)
self.play(Write(labels))
self.play(DrawBorderThenFill(box))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for mob in self.x_slider:
self.play(Write(mob, run_time = 1))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for new_x in 0.5, 2, self.default_x:
self.animate_x_change(
new_x, run_time = 2
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
def talk_though_sine(self):
x_axis = self.x_slider[0]
graph = FunctionGraph(
np.sin, x_min = 0, x_max = np.pi,
color = SINE_COLOR
)
2017-04-17 10:19:30 -07:00
scale_factor = self.x_slider.get_width()/self.slider_x_max
graph.scale(scale_factor)
graph.move_to(x_axis.number_to_point(0), DOWN+LEFT)
2017-04-17 10:19:30 -07:00
label = TexMobject("\\sin(x)")
2018-03-30 11:51:31 -07:00
label.set_color(SINE_COLOR)
2017-04-17 10:19:30 -07:00
label.next_to(graph, UP)
2017-04-17 10:19:30 -07:00
y_axis = x_axis.copy()
y_axis.remove(*y_axis.numbers)
2017-04-17 10:19:30 -07:00
v_line = Line(ORIGIN, UP, color = WHITE, stroke_width = 2)
def v_line_update(v_line):
x = x_axis.point_to_number(self.x_slider[1].get_top())
v_line.set_height(np.sin(x)*scale_factor)
2017-04-17 10:19:30 -07:00
v_line.move_to(x_axis.number_to_point(x), DOWN)
v_line_update(v_line)
self.play(
2017-04-17 10:19:30 -07:00
Rotate(y_axis, np.pi/2, about_point = y_axis.get_left()),
Animation(x_axis)
)
self.play(
2017-04-17 10:19:30 -07:00
ShowCreation(graph),
Write(label, run_time = 1)
)
2017-04-17 10:19:30 -07:00
self.play(ShowCreation(v_line))
for x, rt in zip([0.25, np.pi/2, 3, self.default_x], [2, 4, 4, 2]):
self.animate_x_change(
x, run_time = rt,
added_anims = [
UpdateFromFunc(v_line, v_line_update)
]
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(*it.chain(
2018-08-09 17:56:05 -07:00
list(map(FadeOut, [y_axis, graph, label, v_line])),
2017-04-17 10:19:30 -07:00
[Animation(x_axis)]
))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for x in 1, 0.5, self.default_x:
self.animate_x_change(x)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
def define_f_of_x(self):
f_def = TexMobject(
"f(x)", "=",
self.top_func_label,
self.side_func_label,
"=",
"\\text{Area}"
2017-03-22 15:06:17 -07:00
)
2017-04-17 10:19:30 -07:00
f_def.to_corner(UP+RIGHT)
2018-03-30 11:51:31 -07:00
f_def[-1].set_color(self.box_kwargs["fill_color"])
2017-04-17 10:19:30 -07:00
box, labels = self.box_label_group
2017-04-17 10:19:30 -07:00
self.play(Write(VGroup(*f_def[:-1])))
self.play(Transform(
box.copy().set_fill(opacity = 0), f_def[-1],
run_time = 1.5,
2017-03-22 15:06:17 -07:00
))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.f_def = f_def
def nudge_x(self):
box, labels = self.box_label_group
nudge_label_group = self.get_nudge_label_group()
original_dx = self.dx
self.dx = self.tiny_dx
thin_df_boxes = self.get_df_boxes()
self.dx = original_dx
df_boxes = self.get_df_boxes()
right_box, corner_box, right_box = df_boxes
self.play(FocusOn(nudge_label_group))
2018-08-09 17:56:05 -07:00
self.play(*list(map(GrowFromCenter, nudge_label_group)))
2017-04-17 10:19:30 -07:00
self.animate_x_change(
self.default_x+self.dx,
rate_func = there_and_back,
run_time = 2,
added_anims = [Animation(nudge_label_group)]
)
2018-01-15 19:15:05 -08:00
self.wait()
self.play(
2017-04-17 10:19:30 -07:00
ReplacementTransform(thin_df_boxes, df_boxes),
VGroup(*labels[1]).shift, right_box.get_width()*RIGHT,
)
2017-04-17 10:19:30 -07:00
self.play(
df_boxes.space_out_submobjects, 1.1,
df_boxes.move_to, box, UP+LEFT,
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-03-22 15:06:17 -07:00
2017-04-17 10:19:30 -07:00
self.df_boxes = df_boxes
self.df_box_labels = self.get_df_box_labels(df_boxes)
self.x_slider.add(nudge_label_group)
def get_nudge_label_group(self):
line, triangle, x_mob = self.x_slider
dx_line = Line(*[
line.number_to_point(self.x_slider.x_val + num)
for num in (0, self.dx,)
2017-04-17 10:19:30 -07:00
])
dx_line.set_stroke(
self.df_box_kwargs["fill_color"],
width = 6
)
brace = Brace(dx_line, UP, buff = SMALL_BUFF)
brace.stretch_to_fit_height(0.2)
brace.next_to(dx_line, UP, buff = SMALL_BUFF)
brace.set_stroke(width = 1)
dx = TexMobject("dx")
dx.scale(0.7)
dx.next_to(brace, UP, buff = SMALL_BUFF)
2018-03-30 11:51:31 -07:00
dx.set_color(dx_line.get_color())
2017-04-17 10:19:30 -07:00
return VGroup(dx_line, brace, dx)
def get_df_boxes(self):
box, labels = self.box_label_group
alt_box = self.get_box(self.x_slider.x_val + self.dx)
h, w = box.get_height(), box.get_width()
dh, dw = alt_box.get_height()-h, alt_box.get_width()-w
heights_and_widths = [(dh, w), (dh, dw), (h, dw)]
vects = [DOWN, DOWN+RIGHT, RIGHT]
df_boxes = VGroup(*[
Rectangle(
height = height, width = width, **self.df_box_kwargs
).next_to(box, vect, buff = 0)
for (height, width), vect in zip(
heights_and_widths, vects
2017-03-22 15:06:17 -07:00
)
])
2017-04-17 10:19:30 -07:00
return df_boxes
def get_df_box_labels(self, df_boxes):
bottom_box, corner_box, right_box = df_boxes
result = VGroup()
quads = [
(right_box, UP, self.top_func_nudge_label, LEFT),
(corner_box, RIGHT, self.side_func_nudge_label, ORIGIN),
]
for box, vect, label_tex, aligned_edge in quads:
brace = Brace(box, vect)
label = TexMobject(label_tex)
label.next_to(
brace, vect,
aligned_edge = aligned_edge,
buff = SMALL_BUFF
)
2018-03-30 11:51:31 -07:00
label.set_color(df_boxes[0].get_color())
2017-04-17 10:19:30 -07:00
result.add(VGroup(brace, label))
return result
def write_df(self):
deriv = TexMobject(
"df", "=",
self.top_func_label,
self.side_func_nudge_label,
"+",
self.side_func_label,
self.top_func_nudge_label,
)
deriv.scale(0.9)
deriv.next_to(self.f_def, DOWN, buff = LARGE_BUFF)
deriv.to_edge(RIGHT)
for submob, tex in zip(deriv, deriv.expression_parts):
if tex.startswith("d"):
2018-03-30 11:51:31 -07:00
submob.set_color(self.df_box_kwargs["fill_color"])
2017-04-17 10:19:30 -07:00
bottom_box_area = VGroup(*deriv[2:4])
right_box_area = VGroup(*deriv[5:7])
bottom_box, corner_box, right_box = self.df_boxes
plus = TexMobject("+").set_fill(opacity = 0)
df_boxes_copy = VGroup(
bottom_box.copy(),
plus,
right_box.copy(),
plus.copy(),
corner_box.copy(),
)
self.deriv = deriv
self.df_boxes_copy = df_boxes_copy
box, labels = self.box_label_group
self.full_box_parts = VGroup(*it.chain(
[box], self.df_boxes, labels, self.df_box_labels
))
self.play(Write(VGroup(*deriv[:2])))
self.play(
2019-02-04 14:54:25 -08:00
df_boxes_copy.arrange,
2017-04-17 10:19:30 -07:00
df_boxes_copy.set_fill, None, self.df_box_kwargs["fill_opacity"],
df_boxes_copy.next_to, deriv[1]
)
2017-04-17 10:19:30 -07:00
deriv.submobjects[4] = df_boxes_copy[1]
2018-01-15 19:15:05 -08:00
self.wait()
2018-03-30 11:51:31 -07:00
self.set_color_right_boxes()
self.set_color_bottom_boxes()
2017-04-17 10:19:30 -07:00
self.describe_bottom_box(bottom_box_area)
self.describe_right_box(right_box_area)
self.ignore_corner()
2017-04-17 10:19:30 -07:00
# self.add(deriv)
2018-03-30 11:51:31 -07:00
def set_color_boxes_and_label(self, boxes, label):
2017-04-17 10:19:30 -07:00
boxes.save_state()
label.save_state()
2017-04-17 10:19:30 -07:00
self.play(GrowFromCenter(label))
self.play(
2018-03-30 11:51:31 -07:00
boxes.set_color, RED,
label.set_color, RED,
)
self.play(
2017-04-17 10:19:30 -07:00
label[1].scale_in_place, 1.1,
rate_func = there_and_back
)
self.play(boxes.restore, label.restore)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
2018-03-30 11:51:31 -07:00
def set_color_right_boxes(self):
self.set_color_boxes_and_label(
2017-04-17 10:19:30 -07:00
VGroup(*self.df_boxes[1:]),
self.df_box_labels[0]
)
2017-04-17 10:19:30 -07:00
2018-03-30 11:51:31 -07:00
def set_color_bottom_boxes(self):
self.set_color_boxes_and_label(
2017-04-17 10:19:30 -07:00
VGroup(*self.df_boxes[:-1]),
self.df_box_labels[1]
)
def describe_bottom_box(self, bottom_box_area):
bottom_box = self.df_boxes[0]
bottom_box_copy = self.df_boxes_copy[0]
other_box_copies = VGroup(*self.df_boxes_copy[1:])
top_label = self.box_label_group[1][0]
right_label = self.df_box_labels[1]
2018-08-09 17:56:05 -07:00
faders = VGroup(*[m for m in self.full_box_parts if m not in [bottom_box, top_label, right_label]])
2017-04-17 10:19:30 -07:00
faders.save_state()
self.play(faders.fade, 0.8)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(FocusOn(bottom_box_copy))
self.play(
2017-04-17 10:19:30 -07:00
ReplacementTransform(bottom_box_copy, bottom_box_area),
other_box_copies.next_to, bottom_box_area, RIGHT
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(faders.restore)
def describe_right_box(self, right_box_area):
right_box = self.df_boxes[2]
right_box_copy = self.df_boxes_copy[2]
right_box_area.next_to(self.df_boxes_copy[1])
other_box_copies = VGroup(*self.df_boxes_copy[3:])
top_label = self.df_box_labels[0]
right_label = self.box_label_group[1][1]
2018-08-09 17:56:05 -07:00
faders = VGroup(*[m for m in self.full_box_parts if m not in [right_box, top_label, right_label]])
2017-04-17 10:19:30 -07:00
faders.save_state()
2017-02-19 20:24:25 -08:00
2017-04-17 10:19:30 -07:00
self.play(faders.fade, 0.8)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(FocusOn(right_box_copy))
self.play(
ReplacementTransform(right_box_copy, right_box_area),
other_box_copies.next_to, right_box_area, DOWN,
MED_SMALL_BUFF, RIGHT,
2017-03-22 15:06:17 -07:00
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(faders.restore)
def ignore_corner(self):
corner = self.df_boxes[1]
corner.save_state()
corner_copy = VGroup(*self.df_boxes_copy[-2:])
words = TextMobject("Ignore")
2018-03-30 11:51:31 -07:00
words.set_color(RED)
2017-04-17 10:19:30 -07:00
words.next_to(corner_copy, LEFT, buff = LARGE_BUFF)
words.shift(MED_SMALL_BUFF*DOWN)
arrow = Arrow(words, corner_copy, buff = SMALL_BUFF, color = RED)
self.play(
2018-03-30 11:51:31 -07:00
corner.set_color, RED,
corner_copy.set_color, RED,
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(Write(words), ShowCreation(arrow))
2018-01-15 19:15:05 -08:00
self.wait()
2018-08-09 17:56:05 -07:00
self.play(*list(map(FadeOut, [words, arrow, corner_copy])))
2018-01-15 19:15:05 -08:00
self.wait()
2018-03-30 11:51:31 -07:00
corner_copy.set_color(BLACK)
2017-04-17 10:19:30 -07:00
def show_thinner_dx(self):
self.transition_to_alt_config(dx = self.tiny_dx)
def expand_derivative(self):
# self.play(
# self.deriv.next_to, self.f_def, DOWN, MED_LARGE_BUFF,
# self.deriv.shift_onto_screen
# )
2018-01-15 19:15:05 -08:00
# self.wait()
2017-04-17 10:19:30 -07:00
expanded_deriv = TexMobject(
"df", "=",
self.top_func_label,
self.side_func_derivative,
"\\,dx",
"+",
self.side_func_label,
self.top_func_derivative,
"\\,dx"
)
final_deriv = TexMobject(
"{df \\over ", "dx}", "=",
self.top_func_label,
self.side_func_derivative,
"+",
self.side_func_label,
self.top_func_derivative,
)
color = self.deriv[0].get_color()
for new_deriv in expanded_deriv, final_deriv:
for submob, tex in zip(new_deriv, new_deriv.expression_parts):
for substr in "df", "dx", self.top_func_derivative, self.side_func_derivative:
if substr in tex:
2018-03-30 11:51:31 -07:00
submob.set_color(color)
2017-04-17 10:19:30 -07:00
new_deriv.scale(0.9)
new_deriv.next_to(self.deriv, DOWN, buff = MED_LARGE_BUFF)
new_deriv.shift_onto_screen()
def indicate(mob):
self.play(
mob.scale_in_place, 1.2,
2018-03-30 11:51:31 -07:00
mob.set_color, YELLOW,
2017-04-17 10:19:30 -07:00
rate_func = there_and_back
)
for index in 6, 3:
self.deriv.submobjects.insert(
index+1, self.deriv[index].copy()
)
2018-08-09 17:56:05 -07:00
non_deriv_indices = list(range(len(expanded_deriv)))
2017-04-17 10:19:30 -07:00
for indices in [(3, 4), (7, 8)]:
top_part = VGroup()
bottom_part = VGroup()
for i in indices:
non_deriv_indices.remove(i)
top_part.add(self.deriv[i].copy())
bottom_part.add(expanded_deriv[i])
self.play(top_part.move_to, bottom_part)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
indicate(top_part)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(ReplacementTransform(top_part, bottom_part))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
top_part = VGroup()
bottom_part = VGroup()
for i in non_deriv_indices:
top_part.add(self.deriv[i].copy())
bottom_part.add(expanded_deriv[i])
self.play(ReplacementTransform(
top_part, bottom_part
))
2017-02-20 17:23:20 -08:00
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(*[
ReplacementTransform(
expanded_deriv[i], final_deriv[j],
path_arc = -np.pi/2
)
for i, j in [
(0, 0),
(1, 2),
(2, 3),
(3, 4),
(4, 1),
(5, 5),
(6, 6),
(7, 7),
(8, 1),
]
])
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for index in 0, 1, 3, 4, 6, 7:
indicate(final_deriv[index])
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
def write_derivative_abstractly(self):
self.transition_to_alt_config(
return_to_original_configuration = False,
top_func_label = "g(x)",
top_func_nudge_label = "dg",
top_func_derivative = "\\frac{dg}{dx}",
side_func_label = "h(x)",
side_func_nudge_label = "dh",
side_func_derivative = "\\frac{dh}{dx}",
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-02-20 17:23:20 -08:00
2017-04-17 10:19:30 -07:00
def write_mneumonic(self):
morty = Mortimer()
morty.scale(0.7)
morty.to_edge(DOWN)
morty.shift(2*LEFT)
words = TextMobject(
"``Left ", "d(Right) ", "+", " Right ", "d(Left)", "''",
arg_separator = ""
)
2018-03-30 11:51:31 -07:00
VGroup(words[1], words[4]).set_color(self.df_boxes[0].get_color())
2017-04-17 10:19:30 -07:00
words.scale(0.7)
words.next_to(morty.get_corner(UP+LEFT), UP)
words.shift_onto_screen()
self.play(FadeIn(morty))
2017-02-20 17:23:20 -08:00
self.play(
2017-04-17 10:19:30 -07:00
morty.change_mode, "raise_right_hand",
Write(words)
2017-02-20 17:23:20 -08:00
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
###############
def animate_x_change(
self, target_x,
box_label_group = None,
x_slider = None,
**kwargs
):
box_label_group = box_label_group or self.box_label_group
x_slider = x_slider or self.x_slider
kwargs["run_time"] = kwargs.get("run_time", 2)
added_anims = kwargs.get("added_anims", [])
start_x = x_slider.x_val
def update_box_label_group(box_label_group, alpha):
new_x = interpolate(start_x, target_x, alpha)
new_box_label_group = self.get_box_label_group(new_x)
Transform(box_label_group, new_box_label_group).update(1)
def update_x_slider(x_slider, alpha):
new_x = interpolate(start_x, target_x, alpha)
new_x_slider = self.get_x_slider(new_x)
Transform(x_slider, new_x_slider).update(1)
2017-02-20 17:23:20 -08:00
self.play(
2017-04-17 10:19:30 -07:00
UpdateFromAlphaFunc(
box_label_group,
update_box_label_group
),
UpdateFromAlphaFunc(
x_slider,
update_x_slider
),
*added_anims,
**kwargs
)
x_slider.x_val = target_x
def get_x_slider(self, x):
2018-08-09 17:56:05 -07:00
numbers = list(range(int(self.slider_x_max) + 1))
2017-04-17 10:19:30 -07:00
line = NumberLine(
x_min = 0,
x_max = self.slider_x_max,
unit_size = float(self.slider_width)/self.slider_x_max,
2017-04-17 10:19:30 -07:00
color = GREY,
numbers_with_elongated_ticks = numbers,
tick_frequency = 0.25,
)
line.add_numbers(*numbers)
line.numbers.next_to(line, UP, buff = SMALL_BUFF)
for number in line.numbers:
number.add_background_rectangle()
line.move_to(self.slider_center)
triangle = RegularPolygon(
3, start_angle = np.pi/2,
fill_color = self.slider_handle_color,
fill_opacity = 0.8,
stroke_width = 0,
)
triangle.set_height(self.x_slider_handle_height)
2017-04-17 10:19:30 -07:00
triangle.move_to(line.number_to_point(x), UP)
x_mob = TexMobject("x")
x_mob.next_to(triangle, DOWN, buff = SMALL_BUFF)
result = VGroup(line, triangle, x_mob)
result.x_val = x
return result
def get_box_label_group(self, x):
box = self.get_box(x)
labels = self.get_box_labels(box)
return VGroup(box, labels)
def get_box(self, x):
box = Rectangle(
width = self.x_unit_to_space_unit * self.top_func(x),
height = self.x_unit_to_space_unit * self.side_func(x),
**self.box_kwargs
)
box.move_to(self.box_corner_location, UP+LEFT)
return box
def get_box_labels(self, box):
result = VGroup()
for label_tex, vect in (self.top_func_label, UP), (self.side_func_label, RIGHT):
brace = Brace(box, vect, min_num_quads = 5)
label = TexMobject(label_tex)
label.next_to(brace, vect, buff = SMALL_BUFF)
result.add(VGroup(brace, label))
return result
class WriteDXSquared(Scene):
def construct(self):
term = TexMobject("(...)(dx)^2")
2018-03-30 11:51:31 -07:00
term.set_color(RED)
2017-04-17 10:19:30 -07:00
self.play(Write(term))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
class MneumonicExample(TeacherStudentsScene):
def construct(self):
d, left, right, rp = deriv_q = TexMobject(
"\\frac{d}{dx}(", "\\sin(x)", "x^2", ")"
2017-02-20 17:23:20 -08:00
)
2017-04-17 10:19:30 -07:00
deriv_q.to_edge(UP)
2017-02-20 17:23:20 -08:00
2017-04-17 10:19:30 -07:00
words = TextMobject(
"Left ", "d(Right) ", "+", " Right ", "d(Left)",
arg_separator = ""
)
deriv = TexMobject("\\sin(x)", "2x", "+", "x^2", "\\cos(x)")
for mob in words, deriv:
2018-03-30 11:51:31 -07:00
VGroup(mob[1], mob[4]).set_color(GREEN)
2017-04-17 10:19:30 -07:00
mob.next_to(deriv_q, DOWN, buff = MED_LARGE_BUFF)
deriv.shift(words[2].get_center()-deriv[2].get_center())
2017-04-17 10:19:30 -07:00
self.add(words)
2017-03-22 15:06:17 -07:00
self.play(
2017-04-17 10:19:30 -07:00
Write(deriv_q),
self.get_teacher().change_mode, "raise_right_hand"
)
2017-04-17 10:19:30 -07:00
self.change_student_modes(*["pondering"]*3)
2017-04-17 10:19:30 -07:00
left_words = VGroup(*words[:2])
left_terms = VGroup(*deriv[:2])
self.play(
left_words.next_to, left_terms, DOWN,
MED_LARGE_BUFF, RIGHT
)
self.play(ReplacementTransform(
left_words.copy(), left_terms
))
2018-01-15 19:15:05 -08:00
self.wait()
2018-08-09 17:56:05 -07:00
self.play(*list(map(Indicate, [left, left_words[0], left_terms[0]])))
2018-01-15 19:15:05 -08:00
self.wait()
2018-08-09 17:56:05 -07:00
self.play(*list(map(Indicate, [right, left_words[1], left_terms[1]])))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
right_words = VGroup(*words[2:])
right_terms = VGroup(*deriv[2:])
self.play(
right_words.next_to, right_terms, DOWN,
MED_LARGE_BUFF, LEFT
)
self.play(ReplacementTransform(
right_words.copy(), right_terms
))
2018-01-15 19:15:05 -08:00
self.wait()
2018-08-09 17:56:05 -07:00
self.play(*list(map(Indicate, [right, right_words[1], right_terms[1]])))
2018-01-15 19:15:05 -08:00
self.wait()
2018-08-09 17:56:05 -07:00
self.play(*list(map(Indicate, [left, right_words[2], right_terms[2]])))
2018-01-15 19:15:05 -08:00
self.wait(3)
2017-04-17 10:19:30 -07:00
self.play(self.get_teacher().change_mode, "shruggie")
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.change_student_modes(*["confused"]*3)
2018-01-15 19:15:05 -08:00
self.wait(3)
2017-04-17 10:19:30 -07:00
class ConstantMultiplication(TeacherStudentsScene):
def construct(self):
question = TextMobject("What about $\\dfrac{d}{dx}(2\\sin(x))$?")
answer = TextMobject("2\\cos(x)")
self.teacher_says(question)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.student_says(
answer, target_mode = "hooray",
added_anims = [question.copy().to_edge, UP]
)
self.play(self.get_teacher().change_mode, "happy")
self.change_student_modes("pondering", "hooray", "pondering")
2018-01-15 19:15:05 -08:00
self.wait(3)
2017-04-17 10:19:30 -07:00
class ConstantMultiplicationFigure(IntroduceProductAsArea):
2017-03-22 15:06:17 -07:00
CONFIG = {
2017-04-17 10:19:30 -07:00
"side_func" : lambda x : 1,
"side_func_label" : "\\text{Constant}",
"side_func_nudge_label" : "",
"side_func_derivative" : "",
"x_unit_to_space_unit" : 3,
"default_x" : 0.5,
"dx" : 0.1
2017-03-22 15:06:17 -07:00
}
2017-04-17 10:19:30 -07:00
def construct(self):
self.box_label_group = self.get_box_label_group(self.default_x)
self.x_slider = self.get_x_slider(self.default_x)
# df_boxes = self.get_df_boxes()
# df_box_labels = self.get_df_box_labels(df_boxes)
2017-02-16 20:21:35 -08:00
2017-04-17 10:19:30 -07:00
self.add(self.box_label_group, self.x_slider)
self.nudge_x()
class ShoveXSquaredInSine(Scene):
2017-03-22 15:06:17 -07:00
def construct(self):
2017-04-17 10:19:30 -07:00
title = TextMobject("Function composition")
title.to_edge(UP)
sine = TexMobject("g(", "x", ")", "=", "\\sin(", "x", ")")
2018-03-30 11:51:31 -07:00
sine.set_color(SINE_COLOR)
2017-04-17 10:19:30 -07:00
x_squared = TexMobject("h(x)", "=", "x^2")
2018-03-30 11:51:31 -07:00
x_squared.set_color(X_SQUARED_COLOR)
2017-04-17 10:19:30 -07:00
group = VGroup(sine, x_squared)
2019-02-04 14:54:25 -08:00
group.arrange(buff = LARGE_BUFF)
2017-04-17 10:19:30 -07:00
group.shift(UP)
composition = TexMobject(
"g(", "h(x)", ")", "=", "\\sin(", "x^2", ")"
)
for i in 0, 2, 4, 6:
2018-03-30 11:51:31 -07:00
composition[i].set_color(SINE_COLOR)
2017-04-17 10:19:30 -07:00
for i in 1, 5:
2018-03-30 11:51:31 -07:00
composition[i].set_color(X_SQUARED_COLOR)
2017-04-17 10:19:30 -07:00
composition.next_to(group, DOWN, buff = LARGE_BUFF)
brace = Brace(VGroup(*composition[-3:]), DOWN)
deriv_q = brace.get_text("Derivative?")
self.add(group)
self.play(Write(title))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
triplets = [
[sine, (0, 2), (0, 2)],
[x_squared, (0,), (1,)],
[sine, (3, 4, 6), (3, 4, 6)],
[x_squared, (2,), (5,)]
]
for premob, pre_indices, comp_indicies in triplets:
self.play(*[
ReplacementTransform(
premob[i].copy(), composition[j]
)
for i, j in zip(pre_indices, comp_indicies)
])
2018-01-15 19:15:05 -08:00
self.wait()
self.wait()
2017-04-17 10:19:30 -07:00
self.play(
GrowFromCenter(brace),
Write(deriv_q)
2017-03-22 15:06:17 -07:00
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-02-16 20:21:35 -08:00
2017-04-17 10:19:30 -07:00
class ThreeLinesChainRule(ReconfigurableScene):
CONFIG = {
"start_x" : 0.5,
2017-04-21 17:40:49 -07:00
"max_x" : 1,
"min_x" : 0,
2017-04-17 10:19:30 -07:00
"top_x" : 3,
"example_x" : 1.5,
"dx" : 0.1,
"line_configs" : [
{
"func" : lambda x : x,
"func_label" : "x",
"triangle_color" : WHITE,
"center_y" : 3,
"x_min" : 0,
"x_max" : 3,
2018-08-09 17:56:05 -07:00
"numbers_to_show" : list(range(4)),
"numbers_with_elongated_ticks" : list(range(4)),
2017-04-17 10:19:30 -07:00
"tick_frequency" : 0.25,
},
{
"func" : lambda x : x**2,
"func_label" : "x^2",
"triangle_color" : X_SQUARED_COLOR,
"center_y" : 0.5,
"x_min" : 0,
"x_max" : 10,
2018-08-09 17:56:05 -07:00
"numbers_to_show" : list(range(0, 11)),
"numbers_with_elongated_ticks" : list(range(0, 11, 1)),
2017-04-17 10:19:30 -07:00
"tick_frequency" : 0.25,
},
{
"func" : lambda x : np.sin(x**2),
"func_label" : "\\sin(x^2)",
"triangle_color" : SINE_COLOR,
"center_y" : -2,
"x_min" : -2,
"x_max" : 2,
2018-08-09 17:56:05 -07:00
"numbers_to_show" : list(range(-2, 3)),
"numbers_with_elongated_ticks" : list(range(-2, 3)),
2017-04-17 10:19:30 -07:00
"tick_frequency" : 0.25,
},
],
"line_width" : 8,
"triangle_height" : 0.25,
}
def construct(self):
self.introduce_line_group()
self.draw_function_arrows()
self.talk_through_movement()
self.nudge_x()
self.give_example_of_meaning()
def introduce_line_group(self):
self.line_group = self.get_line_group(self.start_x)
lines, labels = self.line_group
for line in lines:
self.play(Write(line, run_time = 2))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
last_label = labels[0].copy()
last_label.to_corner(UP+LEFT)
last_label.set_fill(opacity = 0)
for label in labels:
self.play(ReplacementTransform(
last_label.copy(), label
))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
last_label = label
2017-04-21 17:40:49 -07:00
for x in self.max_x, self.min_x, self.start_x:
2017-04-17 10:19:30 -07:00
self.animate_x_change(x, run_time = 1)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
def draw_function_arrows(self):
lines, line_labels = self.line_group
labels = VGroup(*[
2018-03-30 11:51:31 -07:00
TexMobject("(\\dots)^2").set_color(X_SQUARED_COLOR),
TexMobject("\\sin(\\dots)").set_color(SINE_COLOR)
2017-04-17 10:19:30 -07:00
])
arrows = VGroup()
for lines_subset, label in zip([lines[:2], lines[1:]], labels):
arrow = Arc(start_angle = np.pi/3, angle = -2*np.pi/3)
arrow.add_tip()
2018-03-30 11:51:31 -07:00
arrow.set_color(label.get_color())
2017-04-17 10:19:30 -07:00
arrow.next_to(VGroup(*lines_subset))
arrows.add(arrow)
label.next_to(arrow, RIGHT)
self.play(
ShowCreation(arrow),
Write(label)
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.arrows = arrows
self.arrow_labels = labels
def talk_through_movement(self):
lines, labels = self.line_group
self.animate_x_change(self.top_x, run_time = 4)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for label in labels[0], labels[1]:
oval = Circle(color = YELLOW)
oval.replace(label, stretch = True)
oval.scale(2.5)
oval.move_to(label.get_bottom())
self.play(ShowCreation(oval))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(FadeOut(oval))
sine_text = TexMobject("\\sin(9) \\approx 0.412")
sine_text.move_to(labels[-1][-1])
sine_text.to_edge(DOWN)
sine_arrow = Arrow(
sine_text.get_top(),
labels[-1][0].get_bottom(),
buff = SMALL_BUFF,
2017-02-16 20:21:35 -08:00
)
2017-04-17 10:19:30 -07:00
self.play(
FadeIn(sine_text),
ShowCreation(sine_arrow)
2017-02-16 20:21:35 -08:00
)
2018-01-15 19:15:05 -08:00
self.wait(2)
2018-08-09 17:56:05 -07:00
self.play(*list(map(FadeOut, [sine_text, sine_arrow])))
2017-04-17 10:19:30 -07:00
self.animate_x_change(self.example_x, run_time = 3)
def nudge_x(self):
lines, labels = self.line_group
def get_value_points():
return [
label[0].get_bottom()
for label in labels
]
starts = get_value_points()
self.animate_x_change(self.example_x + self.dx, run_time = 0)
ends = get_value_points()
self.animate_x_change(self.example_x, run_time = 0)
nudge_lines = VGroup()
braces = VGroup()
numbers = VGroup()
for start, end, line, label, config in zip(starts, ends, lines, labels, self.line_configs):
color = label[0].get_color()
nudge_line = Line(start, end)
nudge_line.set_stroke(color, width = 6)
brace = Brace(nudge_line, DOWN, buff = SMALL_BUFF)
2018-03-30 11:51:31 -07:00
brace.set_color(color)
2017-04-17 10:19:30 -07:00
func_label = config["func_label"]
if len(func_label) == 1:
text = "$d%s$"%func_label
else:
text = "$d(%s)$"%func_label
brace.text = brace.get_text(text, buff = SMALL_BUFF)
2018-03-30 11:51:31 -07:00
brace.text.set_color(color)
2017-04-17 10:19:30 -07:00
brace.add(brace.text)
line.add(nudge_line)
nudge_lines.add(nudge_line)
braces.add(brace)
numbers.add(line.numbers)
line.remove(*line.numbers)
dx_brace, dx_squared_brace, dsine_brace = braces
x_value = str(self.example_x)
x_value_label = TexMobject("=%s"%x_value)
x_value_label.next_to(labels[0][1], RIGHT)
dx_squared_value = TexMobject(
"= 2x\\,dx ", "\\\\ = 2(%s)dx"%x_value
)
dx_squared_value.shift(
dx_squared_brace.text.get_right()+MED_SMALL_BUFF*RIGHT - \
dx_squared_value[0].get_left()
)
dsine_value = TextMobject(
"$=\\cos(%s)$"%self.line_configs[1]["func_label"],
dx_squared_brace.text.get_tex_string()
)
dsine_value.next_to(dsine_brace.text)
less_than_zero = TexMobject("<0")
less_than_zero.next_to(dsine_brace.text)
all_x_squared_relevant_labels = VGroup(
dx_squared_brace, dsine_brace,
labels[1], labels[2],
dsine_value,
)
all_x_squared_relevant_labels.save_state()
self.play(FadeOut(numbers))
self.animate_x_change(
self.example_x + self.dx,
run_time = 1,
added_anims = it.chain(
[GrowFromCenter(dx_brace)],
2018-08-09 17:56:05 -07:00
list(map(ShowCreation, nudge_lines))
2017-04-17 10:19:30 -07:00
)
)
self.animate_x_change(self.example_x)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(Write(x_value_label))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(FocusOn(dx_squared_brace))
self.play(Write(dx_squared_brace))
self.wiggle_by_dx()
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for part in dx_squared_value:
self.play(Write(part))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(FadeOut(dx_squared_value))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
#Needs to be part of everything for the reconfiguraiton
dsine_brace.set_fill(opacity = 0)
dsine_value.set_fill(opacity = 0)
self.add(dsine_brace, dsine_value)
self.replace_x_squared_with_h()
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(dsine_brace.set_fill, None, 1)
self.discuss_dsine_sign(less_than_zero)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
dsine_value.set_fill(opacity = 1)
self.play(Write(dsine_value))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(
all_x_squared_relevant_labels.restore,
submobject_mode = "lagged_start",
lag_factor = 3,
run_time = 3,
)
self.__dict__.update(self.__class__.CONFIG)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for mob in dsine_value:
self.play(Indicate(mob))
2018-01-15 19:15:05 -08:00
self.wait()
2017-02-16 20:21:35 -08:00
2017-04-17 10:19:30 -07:00
two_x_dx = dx_squared_value[0]
dx_squared = dsine_value[1]
two_x_dx_copy = VGroup(*two_x_dx[1:]).copy()
self.play(FocusOn(two_x_dx))
self.play(Write(two_x_dx))
self.play(
two_x_dx_copy.move_to, dx_squared, LEFT,
dx_squared.next_to, dx_squared, UP,
run_time = 2
2017-02-16 20:21:35 -08:00
)
2017-04-17 10:19:30 -07:00
self.play(FadeOut(dx_squared))
for sublist in two_x_dx_copy[:2], two_x_dx_copy[2:]:
self.play(Indicate(VGroup(*sublist)))
2018-01-15 19:15:05 -08:00
self.wait()
self.wait(2)
2017-02-16 20:21:35 -08:00
2017-04-17 10:19:30 -07:00
self.final_derivative = dsine_value
def discuss_dsine_sign(self, less_than_zero):
self.wiggle_by_dx()
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for x in self.example_x+self.dx, self.example_x:
self.animate_x_change(x, run_time = 2)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
if less_than_zero not in self.get_mobjects():
self.play(Write(less_than_zero))
else:
self.play(FadeOut(less_than_zero))
def replace_x_squared_with_h(self):
new_config = copy.deepcopy(self.__class__.CONFIG)
new_config["line_configs"][1]["func_label"] = "h"
new_config["line_configs"][2]["func_label"] = "\\sin(h)"
self.transition_to_alt_config(
return_to_original_configuration = False,
**new_config
)
def give_example_of_meaning(self):
words = TextMobject("For example,")
expression = TexMobject("\\cos(1.5^2)\\cdot 2(1.5)\\,dx")
group = VGroup(words, expression)
2019-02-04 14:54:25 -08:00
group.arrange(DOWN, aligned_edge = LEFT)
2017-04-17 10:19:30 -07:00
group.scale(0.8)
group.to_edge(RIGHT)
arrow = Arrow(group.get_bottom(), self.final_derivative[0].get_top())
2018-08-09 17:56:05 -07:00
self.play(*list(map(FadeOut, [self.arrows, self.arrow_labels])))
2017-04-17 10:19:30 -07:00
self.play(FadeIn(group))
self.play(ShowCreation(arrow))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.wiggle_by_dx()
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
########
def wiggle_by_dx(self, **kwargs):
kwargs["run_time"] = kwargs.get("run_time", 1)
kwargs["rate_func"] = kwargs.get("rate_func", there_and_back)
target_x = self.line_group.x_val + self.dx
self.animate_x_change(target_x, **kwargs)
def animate_x_change(self, target_x, **kwargs):
#Assume fixed lines, only update labels
kwargs["run_time"] = kwargs.get("run_time", 2)
added_anims = kwargs.get("added_anims", [])
start_x = self.line_group.x_val
def update(line_group, alpha):
lines, labels = line_group
new_x = interpolate(start_x, target_x, alpha)
for line, label, config in zip(lines, labels, self.line_configs):
new_label = self.get_line_label(
line, new_x, **config
)
Transform(label, new_label).update(1)
line_group.x_val = new_x
self.play(
UpdateFromAlphaFunc(self.line_group, update),
*added_anims,
**kwargs
)
def get_line_group(self, x):
group = VGroup()
group.lines, group.labels = VGroup(), VGroup()
for line_config in self.line_configs:
number_line = self.get_number_line(**line_config)
label = self.get_line_label(number_line, x, **line_config)
group.lines.add(number_line)
group.labels.add(label)
group.add(group.lines, group.labels)
group.x_val = x
return group
def get_number_line(
self, center_y, **number_line_config
):
number_line = NumberLine(color = GREY, **number_line_config)
number_line.stretch_to_fit_width(self.line_width)
number_line.add_numbers()
number_line.shift(center_y*UP)
number_line.to_edge(LEFT, buff = LARGE_BUFF)
return number_line
def get_line_label(
self, number_line, x, func, func_label, triangle_color,
**spillover_kwargs
):
triangle = RegularPolygon(
n=3, start_angle = -np.pi/2,
fill_color = triangle_color,
fill_opacity = 0.75,
stroke_width = 0,
)
triangle.set_height(self.triangle_height)
2017-04-17 10:19:30 -07:00
triangle.move_to(
number_line.number_to_point(func(x)), DOWN
)
label_mob = TexMobject(func_label)
label_mob.next_to(triangle, UP, buff = SMALL_BUFF, aligned_edge = LEFT)
return VGroup(triangle, label_mob)
class GeneralizeChainRule(Scene):
2017-02-16 20:21:35 -08:00
def construct(self):
2017-04-17 10:19:30 -07:00
example = TexMobject(
"\\frac{d}{dx}", "\\sin(", "x^2", ")", "=",
"\\cos(", "x^2", ")", "\\,2x",
)
general = TexMobject(
"\\frac{d}{dx}", "g(", "h(x)", ")", "=",
"{dg \\over ", " dh}", "(", "h(x)", ")", "{dh \\over", " dx}", "(x)"
)
example.to_edge(UP, buff = LARGE_BUFF)
example.shift(RIGHT)
general.next_to(example, DOWN, buff = 1.5*LARGE_BUFF)
for mob in example, general:
2018-03-30 11:51:31 -07:00
mob.set_color(SINE_COLOR)
mob[0].set_color(WHITE)
2017-04-17 10:19:30 -07:00
for tex in "x^2", "2x", "(x)", "{dh", " dx}":
2018-03-30 11:51:31 -07:00
mob.set_color_by_tex(tex, X_SQUARED_COLOR, substring = True)
2017-04-17 10:19:30 -07:00
example_outer = VGroup(*example[1:4])
example_inner = example[2]
d_example_outer = VGroup(*example[5:8])
d_example_inner = example[6]
d_example_d_inner = example[8]
general_outer = VGroup(*general[1:4])
general_inner = general[2]
d_general_outer = VGroup(*general[5:10])
d_general_inner = general[8]
d_general_d_inner = VGroup(*general[10:13])
example_outer_brace = Brace(example_outer)
example_inner_brace = Brace(example_inner, UP, buff = SMALL_BUFF)
d_example_outer_brace = Brace(d_example_outer)
d_example_inner_brace = Brace(d_example_inner, buff = SMALL_BUFF)
d_example_d_inner_brace = Brace(d_example_d_inner, UP, buff = SMALL_BUFF)
general_outer_brace = Brace(general_outer)
general_inner_brace = Brace(general_inner, UP, buff = SMALL_BUFF)
d_general_outer_brace = Brace(d_general_outer)
d_general_inner_brace = Brace(d_general_inner, buff = SMALL_BUFF)
d_general_d_inner_brace = Brace(d_general_d_inner, UP, buff = SMALL_BUFF)
for brace in example_outer_brace, general_outer_brace:
brace.text = brace.get_text("Outer")
for brace in example_inner_brace, general_inner_brace:
brace.text = brace.get_text("Inner")
for brace in d_example_outer_brace, d_general_outer_brace:
brace.text = brace.get_text("d(Outer)")
brace.text.shift(SMALL_BUFF*LEFT)
for brace in d_example_d_inner_brace, d_general_d_inner_brace:
brace.text = brace.get_text("d(Inner)", buff = SMALL_BUFF)
#d(out)d(in) for example
self.add(example)
braces = VGroup(
example_outer_brace,
example_inner_brace,
d_example_outer_brace
)
for brace in braces:
self.play(GrowFromCenter(brace))
self.play(Write(brace.text, run_time = 1))
2018-01-15 19:15:05 -08:00
self.wait()
self.wait()
2017-04-17 10:19:30 -07:00
self.play(*it.chain(*[
2018-03-30 11:51:31 -07:00
[mob.scale_in_place, 1.2, mob.set_color, YELLOW]
for mob in (example_inner, d_example_inner)
2017-04-17 10:19:30 -07:00
]), rate_func = there_and_back)
self.play(Transform(
example_inner.copy(), d_example_inner,
path_arc = -np.pi/2,
remover = True
2017-02-16 20:21:35 -08:00
))
2018-01-15 19:15:05 -08:00
self.wait()
2017-02-16 20:21:35 -08:00
self.play(
2017-04-17 10:19:30 -07:00
GrowFromCenter(d_example_d_inner_brace),
Write(d_example_d_inner_brace.text)
2017-03-22 15:06:17 -07:00
)
2017-04-17 10:19:30 -07:00
self.play(Transform(
VGroup(*reversed(example_inner.copy())),
d_example_d_inner,
path_arc = -np.pi/2,
run_time = 2,
remover = True
))
2018-01-15 19:15:05 -08:00
self.wait()
2017-02-16 20:21:35 -08:00
2017-04-17 10:19:30 -07:00
#Generalize
2018-08-09 17:56:05 -07:00
self.play(*list(map(FadeIn, general[:5])))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(
Transform(example_outer_brace, general_outer_brace),
Transform(example_outer_brace.text, general_outer_brace.text),
Transform(example_inner_brace, general_inner_brace),
Transform(example_inner_brace.text, general_inner_brace.text),
2017-02-18 14:02:46 -08:00
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(
Transform(d_example_outer_brace, d_general_outer_brace),
Transform(d_example_outer_brace.text, d_general_outer_brace.text),
2017-02-18 14:02:46 -08:00
)
2017-04-17 10:19:30 -07:00
self.play(Write(d_general_outer))
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-04-17 10:19:30 -07:00
self.play(
Transform(d_example_d_inner_brace, d_general_d_inner_brace),
Transform(d_example_d_inner_brace.text, d_general_d_inner_brace.text),
2017-02-18 14:02:46 -08:00
)
2017-04-17 10:19:30 -07:00
self.play(Write(d_general_d_inner))
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-02-18 14:02:46 -08:00
2017-04-17 10:19:30 -07:00
#Name chain rule
name = TextMobject("``Chain rule''")
name.scale(1.2)
2018-03-30 11:51:31 -07:00
name.set_color(YELLOW)
2017-04-17 10:19:30 -07:00
name.to_corner(UP+LEFT)
self.play(Write(name))
2018-01-15 19:15:05 -08:00
self.wait()
2017-02-18 14:02:46 -08:00
2017-04-17 10:19:30 -07:00
#Point out dh bottom
morty = Mortimer().flip()
morty.to_corner(DOWN+LEFT)
d_general_outer_copy = d_general_outer.copy()
morty.set_fill(opacity = 0)
2017-02-18 14:02:46 -08:00
self.play(
2017-04-17 10:19:30 -07:00
morty.set_fill, None, 1,
morty.change_mode, "raise_left_hand",
morty.look, UP+LEFT,
d_general_outer_copy.next_to,
morty.get_corner(UP+LEFT), UP, MED_LARGE_BUFF,
d_general_outer_copy.shift_onto_screen
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
circle = Circle(color = YELLOW)
circle.replace(d_general_outer_copy[1])
circle.scale_in_place(1.4)
self.play(ShowCreation(circle))
self.play(Blink(morty))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
inner = d_general_outer_copy[3]
self.play(
morty.change_mode, "hooray",
morty.look_at, inner,
inner.shift, UP
2017-02-18 14:02:46 -08:00
)
2017-04-17 10:19:30 -07:00
self.play(inner.shift, DOWN)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(morty.change_mode, "pondering")
self.play(Blink(morty))
2018-01-15 19:15:05 -08:00
self.wait()
2018-08-09 17:56:05 -07:00
self.play(*list(map(FadeOut, [
2017-04-17 10:19:30 -07:00
d_general_outer_copy, inner, circle
2018-08-09 17:56:05 -07:00
])))
2017-04-17 10:19:30 -07:00
#Show cancelation
braces = [
d_example_d_inner_brace,
d_example_outer_brace,
example_inner_brace,
example_outer_brace,
]
texts = [brace.text for brace in braces]
2018-08-09 17:56:05 -07:00
self.play(*list(map(FadeOut, braces+texts)))
2017-04-17 10:19:30 -07:00
to_collapse = VGroup(VGroup(*general[7:10]), general[12])
dg_dh = VGroup(*general[5:7])
dh_dx = VGroup(*general[10:12])
to_collapse.generate_target()
2018-08-09 17:56:05 -07:00
points = VGroup(*list(map(VectorizedPoint,
2017-04-17 10:19:30 -07:00
[m.get_left() for m in to_collapse]
2018-08-09 17:56:05 -07:00
)))
2017-02-18 14:02:46 -08:00
self.play(
2017-04-17 10:19:30 -07:00
Transform(to_collapse, points),
dh_dx.next_to, dg_dh,
morty.look_at, dg_dh,
2017-02-18 14:02:46 -08:00
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
for mob in list(dg_dh)+list(dh_dx):
circle = Circle(color = YELLOW)
circle.replace(mob)
circle.scale_in_place(1.3)
self.play(ShowCreation(circle))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(FadeOut(circle))
strikes = VGroup()
for dh in dg_dh[1], dh_dx[0]:
strike = TexMobject("/")
strike.stretch(2, dim = 0)
strike.rotate(-np.pi/12)
strike.move_to(dh)
2018-03-30 11:51:31 -07:00
strike.set_color(RED)
2017-04-17 10:19:30 -07:00
strikes.add(strike)
self.play(Write(strikes))
self.play(morty.change_mode, "hooray")
equals_dg_dx = TexMobject("= \\frac{dg}{dx}")
equals_dg_dx.next_to(dh_dx)
self.play(Write(equals_dg_dx))
self.play(Blink(morty))
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-02-20 17:23:20 -08:00
2017-04-17 10:19:30 -07:00
##More than a notational trick
2017-02-20 17:23:20 -08:00
self.play(
2017-04-17 10:19:30 -07:00
PiCreatureSays(morty, """
This is more than a
notational trick
"""),
VGroup(
dg_dh, dh_dx, equals_dg_dx, strikes,
*general[:5]
).shift, DOWN,
FadeOut(example)
2017-02-20 17:23:20 -08:00
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(Blink(morty))
2018-01-15 19:15:05 -08:00
self.wait()
2017-02-18 14:02:46 -08:00
2017-04-17 10:19:30 -07:00
class WatchingVideo(PiCreatureScene):
def construct(self):
laptop = Laptop()
laptop.scale(2)
laptop.to_corner(UP+RIGHT)
randy = self.get_primary_pi_creature()
randy.move_to(laptop, DOWN+LEFT)
randy.shift(MED_SMALL_BUFF*UP)
randy.look_at(laptop.screen)
formulas = VGroup(*[
TexMobject("\\frac{d}{dx}\\left( %s \\right)"%s)
for s in [
"e^x \\sin(x)",
"\\sin(x) \\cdot \\frac{1}{\\cos(x)}",
"\\cos(3x)^2",
"e^x(x^2 + 3x + 2)",
]
])
2019-02-04 14:54:25 -08:00
formulas.arrange(
2017-04-17 10:19:30 -07:00
DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
2017-02-18 14:02:46 -08:00
)
2017-04-17 10:19:30 -07:00
formulas.next_to(randy, LEFT, buff = MED_LARGE_BUFF)
formulas.shift_onto_screen()
2017-04-17 10:19:30 -07:00
self.add(randy, laptop)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(randy.change_mode, "erm")
self.play(Blink(randy))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(randy.change_mode, "maybe")
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.play(Blink(randy))
for formula in formulas:
self.play(
Write(formula, run_time = 2),
randy.change_mode, "thinking"
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
def create_pi_creatures(self):
return [Randolph().shift(DOWN+RIGHT)]
2017-02-18 14:02:46 -08:00
class NextVideo(TeacherStudentsScene):
def construct(self):
series = VideoSeries()
series.to_edge(UP)
next_video = series[4]
2017-04-17 10:19:30 -07:00
pre_expression = TexMobject(
"x", "^2", "+", "y", "^2", "=", "1"
2017-02-18 14:02:46 -08:00
)
2017-04-17 10:19:30 -07:00
d_expression = TexMobject(
"2", "x", "\\,dx", "+", "2", "y", "\\,dy", "=", "0"
2017-02-18 14:02:46 -08:00
)
2017-04-17 10:19:30 -07:00
expression_to_d_expression_indices = [
1, 0, 0, 2, 4, 3, 3, 5, 6
]
expression = VGroup()
for i, j in enumerate(expression_to_d_expression_indices):
submob = pre_expression[j].copy()
if d_expression.expression_parts[i] == "2":
two = TexMobject("2")
two.replace(submob)
expression.add(two)
else:
expression.add(submob)
for mob in expression, d_expression:
mob.scale(1.2)
mob.next_to(
self.get_teacher().get_corner(UP+LEFT), UP,
buff = MED_LARGE_BUFF
)
mob.shift_onto_screen()
2017-03-22 15:06:17 -07:00
2017-04-17 10:19:30 -07:00
axes = Axes(x_min = -3, x_max = 3, color = GREY)
axes.add(Circle(color = YELLOW))
line = Line(np.sqrt(2)*UP, np.sqrt(2)*RIGHT)
line.scale_in_place(1.5)
axes.add(line)
axes.scale(0.5)
axes.next_to(d_expression, LEFT)
self.add(series)
self.play(
next_video.shift, 0.5*DOWN,
2018-03-30 11:51:31 -07:00
next_video.set_color, YELLOW,
2017-04-17 10:19:30 -07:00
self.get_teacher().change_mode, "raise_right_hand"
2017-02-18 14:02:46 -08:00
)
2018-01-15 19:15:05 -08:00
self.wait()
2017-02-20 17:23:20 -08:00
self.play(
2017-04-17 10:19:30 -07:00
Write(expression),
*[
ApplyMethod(pi.change_mode, "pondering")
for pi in self.get_students()
]
2017-02-20 17:23:20 -08:00
)
2017-04-17 10:19:30 -07:00
self.play(FadeIn(axes))
2018-01-15 19:15:05 -08:00
self.wait()
2017-04-17 10:19:30 -07:00
self.remove(expression)
self.play(Transform(expression, d_expression, path_arc = np.pi/2))
2018-01-15 19:15:05 -08:00
self.wait()
2017-03-22 15:06:17 -07:00
self.play(
2017-04-17 10:19:30 -07:00
Rotate(
line, np.pi/4,
about_point = axes.get_center(),
rate_func = wiggle,
run_time = 3
)
2017-03-22 15:06:17 -07:00
)
2018-01-15 19:15:05 -08:00
self.wait(2)
2017-02-18 14:02:46 -08:00
2017-04-17 10:19:30 -07:00
class Chapter4Thanks(PatreonThanks):
2017-02-18 14:02:46 -08:00
CONFIG = {
"specific_patrons" : [
"Ali Yahya",
"Meshal Alshammari",
"CrypticSwarm ",
"Ankit Agarwal",
"Yu Jun",
2017-04-17 10:19:30 -07:00
"Shelby Doolittle",
2017-02-18 14:02:46 -08:00
"Dave Nicponski",
"Damion Kistler",
"Juan Benet",
"Othman Alikhan",
"Justin Helps",
"Markus Persson",
"Dan Buchoff",
"Derek Dai",
"Joseph John Cox",
"Luc Ritchie",
"Nils Schneider",
"Mathew Bramson",
"Guido Gambardella",
"Jerry Ling",
"Mark Govea",
"Vecht",
"Shimin Kuang",
"Rish Kundalia",
"Achille Brighton",
"Kirk Werklund",
"Ripta Pasay",
"Felipe Diniz",
2017-04-29 18:23:00 -07:00
],
"patron_group_size" : 8,
2017-02-18 14:02:46 -08:00
}
2017-04-17 10:19:30 -07:00
class Thumbnail(IntroduceProductAsArea):
CONFIG = {
"default_x" : 0.8,
"dx" : 0.05
}
2017-02-20 17:23:20 -08:00
def construct(self):
2017-04-17 10:19:30 -07:00
self.x_slider = self.get_x_slider(self.default_x)
blg = self.box_label_group = self.get_box_label_group(
self.default_x
)
df_boxes = self.get_df_boxes()
df_boxes.space_out_submobjects(1.1)
df_boxes.move_to(blg[0], UP+LEFT)
blg[1][1].next_to(df_boxes[-1], RIGHT)
df_box_labels = self.get_df_box_labels(df_boxes)
blg.add(df_boxes, df_box_labels)
blg.set_height(FRAME_HEIGHT-2*MED_LARGE_BUFF)
2017-04-17 10:19:30 -07:00
blg.center()
self.add(blg)