Files
manim/3b1b_projects/old/eoc/chapter10.py

3676 lines
112 KiB
Python

from manimlib.imports import *
def derivative(func, x, n = 1, dx = 0.01):
samples = [func(x + (k - n/2)*dx) for k in range(n+1)]
while len(samples) > 1:
samples = [
(s_plus_dx - s)/dx
for s, s_plus_dx in zip(samples, samples[1:])
]
return samples[0]
def taylor_approximation(func, highest_term, center_point = 0):
derivatives = [
derivative(func, center_point, n = n)
for n in range(highest_term + 1)
]
coefficients = [
d/math.factorial(n)
for n, d in enumerate(derivatives)
]
return lambda x : sum([
c*((x-center_point)**n)
for n, c in enumerate(coefficients)
])
class Chapter10OpeningQuote(OpeningQuote):
CONFIG = {
"quote" : [
"For me, mathematics is a collection of ",
"examples", "; a ",
"theorem", " is a statement about a collection of ",
"examples", " and the purpose of proving ",
"theorems", " is to classify and explain the ",
"examples", "."
],
"quote_arg_separator" : "",
"highlighted_quote_terms" : {
"examples" : BLUE,
},
"author" : "John B. Conway",
"fade_in_kwargs" : {
"run_time" : 7,
}
}
class ExampleApproximation(GraphScene):
CONFIG = {
"function" : lambda x : np.exp(-x**2),
"function_tex" : "e^{-x^2}",
"function_color" : BLUE,
"order_sequence" : [0, 2, 4],
"center_point" : 0,
"approximation_terms" : ["1 ", "-x^2", "+\\frac{1}{2}x^4"],
"approximation_color" : GREEN,
"x_min" : -3,
"x_max" : 3,
"y_min" : -1,
"y_max" : 2,
"graph_origin" : DOWN + 2*LEFT,
}
def construct(self):
self.setup_axes()
func_graph = self.get_graph(
self.function,
self.function_color,
)
approx_graphs = [
self.get_graph(
taylor_approximation(self.function, n),
self.approximation_color
)
for n in self.order_sequence
]
near_text = TextMobject(
"Near %s $= %d$"%(
self.x_axis_label, self.center_point
)
)
near_text.to_corner(UP + RIGHT)
near_text.add_background_rectangle()
equation = TexMobject(
self.function_tex,
"\\approx",
*self.approximation_terms
)
equation.next_to(near_text, DOWN, MED_LARGE_BUFF)
equation.to_edge(RIGHT)
near_text.next_to(equation, UP, MED_LARGE_BUFF)
equation.set_color_by_tex(
self.function_tex, self.function_color,
substring = False
)
approx_terms = VGroup(*[
equation.get_part_by_tex(tex, substring = False)
for tex in self.approximation_terms
])
approx_terms.set_fill(
self.approximation_color,
opacity = 0,
)
equation.add_background_rectangle()
approx_graph = VectorizedPoint(
self.input_to_graph_point(self.center_point, func_graph)
)
self.play(
ShowCreation(func_graph, run_time = 2),
Animation(equation),
Animation(near_text),
)
for graph, term in zip(approx_graphs, approx_terms):
self.play(
Transform(approx_graph, graph, run_time = 2),
Animation(equation),
Animation(near_text),
term.set_fill, None, 1,
)
self.wait()
self.wait(2)
class ExampleApproximationWithSine(ExampleApproximation):
CONFIG = {
"function" : np.sin,
"function_tex" : "\\sin(x)",
"order_sequence" : [1, 3, 5],
"center_point" : 0,
"approximation_terms" : [
"x",
"-\\frac{1}{6}x^3",
"+\\frac{1}{120}x^5",
],
"approximation_color" : GREEN,
"x_min" : -2*np.pi,
"x_max" : 2*np.pi,
"x_tick_frequency" : np.pi/2,
"y_min" : -2,
"y_max" : 2,
"graph_origin" : DOWN + 2*LEFT,
}
class ExampleApproximationWithExp(ExampleApproximation):
CONFIG = {
"function" : np.exp,
"function_tex" : "e^x",
"order_sequence" : [1, 2, 3, 4],
"center_point" : 0,
"approximation_terms" : [
"1 + x",
"+\\frac{1}{2}x^2",
"+\\frac{1}{6}x^3",
"+\\frac{1}{24}x^4",
],
"approximation_color" : GREEN,
"x_min" : -3,
"x_max" : 4,
"y_min" : -1,
"y_max" : 10,
"graph_origin" : 2*DOWN + 3*LEFT,
}
class Pendulum(ReconfigurableScene):
CONFIG = {
"anchor_point" : 3*UP + 4*LEFT,
"radius" : 4,
"weight_radius" : 0.2,
"angle" : np.pi/6,
"approx_tex" : [
"\\approx 1 - ", "{\\theta", "^2", "\\over", "2}"
],
"leave_original_cosine" : False,
"perform_substitution" : True,
}
def construct(self):
self.draw_pendulum()
self.show_oscillation()
self.show_height()
self.get_angry_at_cosine()
self.substitute_approximation()
self.show_confusion()
def draw_pendulum(self):
pendulum = self.get_pendulum()
ceiling = self.get_ceiling()
self.add(ceiling)
self.play(ShowCreation(pendulum.line))
self.play(DrawBorderThenFill(pendulum.weight, run_time = 1))
self.pendulum = pendulum
def show_oscillation(self):
trajectory_dots = self.get_trajectory_dots()
kwargs = self.get_swing_kwargs()
self.play(
ShowCreation(
trajectory_dots,
rate_func=linear,
run_time = kwargs["run_time"]
),
Rotate(self.pendulum, -2*self.angle, **kwargs),
)
for m in 2, -2, 2:
self.play(Rotate(self.pendulum, m*self.angle, **kwargs))
self.wait()
def show_height(self):
v_line = self.get_v_line()
h_line = self.get_h_line()
radius_brace = self.get_radius_brace()
height_brace = self.get_height_brace()
height_tex = self.get_height_brace_tex(height_brace)
arc, theta = self.get_arc_and_theta()
height_tex_R = height_tex.get_part_by_tex("R")
height_tex_theta = height_tex.get_part_by_tex("\\theta")
to_write = VGroup(*[
part
for part in height_tex
if part not in [height_tex_R, height_tex_theta]
])
self.play(
ShowCreation(h_line),
GrowFromCenter(height_brace)
)
self.play(
ShowCreation(v_line),
ShowCreation(arc),
Write(theta),
)
self.play(
GrowFromCenter(radius_brace)
)
self.wait(2)
self.play(
Write(to_write),
ReplacementTransform(
radius_brace[-1].copy(),
height_tex_R
),
ReplacementTransform(
theta.copy(),
height_tex_theta
),
run_time = 2
)
self.wait(2)
self.arc = arc
self.theta = theta
self.height_tex_R = height_tex_R
self.cosine = VGroup(*[
height_tex.get_part_by_tex(tex)
for tex in ("cos", "theta", ")")
])
self.one_minus = VGroup(*[
height_tex.get_part_by_tex(tex)
for tex in ("\\big(1-", "\\big)")
])
def get_angry_at_cosine(self):
cosine = self.cosine
morty = Mortimer()
morty.to_corner(DOWN+RIGHT)
cosine.generate_target()
cosine.save_state()
cosine.target.next_to(morty, UP)
if self.leave_original_cosine:
cosine_copy = cosine.copy()
self.add(cosine_copy)
self.one_minus.add(cosine_copy)
self.play(FadeIn(morty))
self.play(
MoveToTarget(cosine),
morty.change, "angry", cosine.target,
)
self.wait()
self.play(Blink(morty))
self.wait()
self.morty = morty
def substitute_approximation(self):
morty = self.morty
cosine = self.cosine
cosine.generate_target()
cosine_approx = self.get_cosine_approx()
cosine_approx.next_to(cosine, UP+RIGHT)
cosine_approx.to_edge(RIGHT)
cosine.target.next_to(
cosine_approx, LEFT,
align_using_submobjects = True
)
kwargs = self.get_swing_kwargs()
self.play(
FadeIn(
cosine_approx,
run_time = 2,
lag_ratio = 0.5
),
MoveToTarget(cosine),
morty.change, "pondering", cosine_approx
)
self.wait()
if not self.perform_substitution:
return
self.play(
ApplyMethod(
cosine_approx.theta_squared_over_two.copy().next_to,
self.height_tex_R,
run_time = 2,
),
FadeOut(self.one_minus),
morty.look_at, self.height_tex_R,
)
self.play(morty.change, "thinking", self.height_tex_R)
self.transition_to_alt_config(
angle = np.pi/12,
transformation_kwargs = {"run_time" : 2},
)
def show_confusion(self):
randy = Randolph(color = BLUE_C)
randy.scale(0.8)
randy.next_to(self.cosine, DOWN+LEFT)
randy.to_edge(DOWN)
self.play(FadeIn(randy))
self.play(
randy.change, "confused", self.cosine
)
self.play(randy.look_at, self.height_tex_R)
self.wait()
self.play(randy.look_at, self.cosine)
self.play(Blink(randy))
self.wait()
#######
def get_pendulum(self):
line = Line(
self.anchor_point,
self.anchor_point + self.radius*DOWN,
color = WHITE
)
weight = Circle(
radius = self.weight_radius,
fill_color = GREY,
fill_opacity = 1,
stroke_width = 0,
)
weight.move_to(line.get_end())
result = VGroup(line, weight)
result.rotate(
self.angle,
about_point = self.anchor_point
)
result.line = line
result.weight = weight
return result
def get_ceiling(self):
line = Line(LEFT, RIGHT, color = GREY)
line.scale(FRAME_X_RADIUS)
line.move_to(self.anchor_point[1]*UP)
return line
def get_trajectory_dots(self, n_dots = 40, color = YELLOW):
arc_angle = np.pi/6
proportions = self.swing_rate_func(
np.linspace(0, 1, n_dots)
)
angles = -2*arc_angle*proportions
angle_to_point = lambda a : np.cos(a)*RIGHT + np.sin(a)*UP
dots = VGroup(*[
# Line(*map(angle_to_point, pair))
Dot(angle_to_point(angle), radius = 0.005)
for angle in angles
])
dots.set_color(color)
dots.scale(self.radius)
dots.rotate(-np.pi/2 + arc_angle)
dots.shift(self.anchor_point)
return dots
def get_v_line(self):
return DashedLine(
self.anchor_point,
self.anchor_point + self.radius*DOWN,
color = WHITE
)
def get_h_line(self, color = BLUE):
start = self.anchor_point + self.radius*DOWN
end = start + self.radius*np.sin(self.angle)*RIGHT
return Line(start, end, color = color)
def get_radius_brace(self):
v_line = self.get_v_line()
brace = Brace(v_line, RIGHT)
brace.rotate(self.angle, about_point = self.anchor_point)
brace.add(brace.get_text("$R$", buff = SMALL_BUFF))
return brace
def get_height_brace(self):
h_line = self.get_h_line()
height = (1 - np.cos(self.angle))*self.radius
line = Line(
h_line.get_end(),
h_line.get_end() + height*UP,
)
brace = Brace(line, RIGHT)
return brace
def get_height_brace_tex(self, brace):
tex_mob = TexMobject(
"R", "\\big(1-", "\\cos(", "\\theta", ")", "\\big)"
)
tex_mob.set_color_by_tex("theta", YELLOW)
tex_mob.next_to(brace, RIGHT)
return tex_mob
def get_arc_and_theta(self):
arc = Arc(
start_angle = -np.pi/2,
angle = self.angle,
color = YELLOW
)
theta = TexMobject("\\theta")
theta.set_color(YELLOW)
theta.next_to(
arc.point_from_proportion(0.5),
DOWN, SMALL_BUFF
)
for mob in arc, theta:
mob.shift(self.anchor_point)
return arc, theta
def get_cosine_approx(self):
approx = TexMobject(*self.approx_tex)
approx.set_color_by_tex("theta", YELLOW)
approx.theta_squared_over_two = VGroup(*approx[1:5])
return approx
def get_swing_kwargs(self):
return {
"about_point" : self.anchor_point,
"run_time" : 1.7,
"rate_func" : self.swing_rate_func,
}
def swing_rate_func(self, t):
return (1-np.cos(np.pi*t))/2.0
class PendulumWithBetterApprox(Pendulum):
CONFIG = {
"approx_tex" : [
"\\approx 1 - ", "{\\theta", "^2", "\\over", "2}",
"+", "{\\theta", "^4", "\\over", "24}"
],
"leave_original_cosine" : True,
"perform_substitution" : False,
}
def show_confusion(self):
pass
class ExampleApproximationWithCos(ExampleApproximationWithSine):
CONFIG = {
"function" : np.cos,
"function_tex" : "\\cos(\\theta)",
"order_sequence" : [0, 2],
"approximation_terms" : [
"1",
"-\\frac{1}{2} \\theta ^2",
],
"x_axis_label" : "$\\theta$",
"y_axis_label" : "",
"x_axis_width" : 13,
"graph_origin" : DOWN,
}
def construct(self):
ExampleApproximationWithSine.construct(self)
randy = Randolph(color = BLUE_C)
randy.to_corner(DOWN+LEFT)
high_graph = self.get_graph(lambda x : 4)
v_lines, alt_v_lines = [
VGroup(*[
self.get_vertical_line_to_graph(
u*dx, high_graph,
line_class = DashedLine,
color = YELLOW
)
for u in (-1, 1)
])
for dx in (0.01, 0.7)
]
self.play(*list(map(ShowCreation, v_lines)), run_time = 2)
self.play(Transform(
v_lines, alt_v_lines,
run_time = 2,
))
self.play(FadeIn(randy))
self.play(PiCreatureBubbleIntroduction(
randy, "How...?",
bubble_class = ThoughtBubble,
look_at_arg = self.graph_origin,
target_mode = "confused"
))
self.wait(2)
self.play(Blink(randy))
self.wait()
def setup_axes(self):
GraphScene.setup_axes(self)
x_val_label_pairs = [
(-np.pi, "-\\pi"),
(np.pi, "\\pi"),
(2*np.pi, "2\\pi"),
]
self.x_axis_labels = VGroup()
for x_val, label in x_val_label_pairs:
tex = TexMobject(label)
tex.next_to(self.coords_to_point(x_val, 0), DOWN)
self.add(tex)
self.x_axis_labels.add(tex)
class ConstructQuadraticApproximation(ExampleApproximationWithCos):
CONFIG = {
"x_axis_label" : "$x$",
"colors" : [BLUE, YELLOW, GREEN],
}
def construct(self):
self.setup_axes()
self.add_cosine_graph()
self.add_quadratic_graph()
self.introduce_quadratic_constants()
self.show_value_at_zero()
self.set_c0_to_one()
self.let_c1_and_c2_vary()
self.show_tangent_slope()
self.compute_cosine_derivative()
self.compute_polynomial_derivative()
self.let_c2_vary()
self.point_out_negative_concavity()
self.compute_cosine_second_derivative()
self.show_matching_curvature()
self.show_matching_tangent_lines()
self.compute_polynomial_second_derivative()
self.box_final_answer()
def add_cosine_graph(self):
cosine_label = TexMobject("\\cos(x)")
cosine_label.to_corner(UP+LEFT)
cosine_graph = self.get_graph(np.cos)
dot = Dot(color = WHITE)
dot.move_to(cosine_label)
for mob in cosine_label, cosine_graph:
mob.set_color(self.colors[0])
def update_dot(dot):
dot.move_to(cosine_graph.points[-1])
return dot
self.play(Write(cosine_label, run_time = 1))
self.play(dot.move_to, cosine_graph.points[0])
self.play(
ShowCreation(cosine_graph),
UpdateFromFunc(dot, update_dot),
run_time = 4
)
self.play(FadeOut(dot))
self.cosine_label = cosine_label
self.cosine_graph = cosine_graph
def add_quadratic_graph(self):
quadratic_graph = self.get_quadratic_graph()
self.play(ReplacementTransform(
self.cosine_graph.copy(),
quadratic_graph,
run_time = 3
))
self.quadratic_graph = quadratic_graph
def introduce_quadratic_constants(self):
quadratic_tex = self.get_quadratic_tex("c_0", "c_1", "c_2")
const_terms = quadratic_tex.get_parts_by_tex("c")
free_to_change = TextMobject("Free to change")
free_to_change.next_to(const_terms, DOWN, LARGE_BUFF)
arrows = VGroup(*[
Arrow(
free_to_change.get_top(),
const.get_bottom(),
tip_length = 0.75*Arrow.CONFIG["tip_length"],
color = const.get_color()
)
for const in const_terms
])
alt_consts_list = [
(0, -1, -0.25),
(1, -1, -0.25),
(1, 0, -0.25),
(),
]
self.play(FadeIn(
quadratic_tex,
run_time = 3,
lag_ratio = 0.5
))
self.play(
FadeIn(free_to_change),
*list(map(ShowCreation, arrows))
)
self.play(*[
ApplyMethod(
const.scale_in_place, 0.8,
run_time = 2,
rate_func = squish_rate_func(there_and_back, a, a + 0.75)
)
for const, a in zip(const_terms, np.linspace(0, 0.25, len(const_terms)))
])
for alt_consts in alt_consts_list:
self.change_quadratic_graph(
self.quadratic_graph, *alt_consts
)
self.wait()
self.quadratic_tex = quadratic_tex
self.free_to_change_group = VGroup(free_to_change, *arrows)
self.free_to_change_group.arrows = arrows
def show_value_at_zero(self):
arrow, x_equals_0 = ax0_group = self.get_arrow_x_equals_0_group()
ax0_group.next_to(
self.cosine_label, RIGHT,
align_using_submobjects = True
)
one = TexMobject("1")
one.next_to(arrow, RIGHT)
one.save_state()
one.move_to(self.cosine_label)
one.set_fill(opacity = 0)
v_line = self.get_vertical_line_to_graph(
0, self.cosine_graph,
line_class = DashedLine,
color = YELLOW
)
self.play(ShowCreation(v_line))
self.play(
ShowCreation(arrow),
Write(x_equals_0, run_time = 2)
)
self.play(one.restore)
self.wait()
self.v_line = v_line
self.equals_one_group = VGroup(arrow, x_equals_0, one)
def set_c0_to_one(self):
poly_at_zero = self.get_quadratic_tex(
"c_0", "c_1", "c_2", arg = "0"
)
poly_at_zero.next_to(self.quadratic_tex, DOWN)
equals_c0 = TexMobject("=", "c_0", "+0")
equals_c0.set_color_by_tex("c_0", self.colors[0])
equals_c0.next_to(
poly_at_zero.get_part_by_tex("="), DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
poly_group = VGroup(
equals_c0,
poly_at_zero,
self.quadratic_tex,
)
poly_group_target = VGroup(
TexMobject("=", "1", "+0").set_color_by_tex("1", self.colors[0]),
self.get_quadratic_tex("1", "c_1", "c_2", arg = "0"),
self.get_quadratic_tex("1", "c_1", "c_2"),
)
for start, target in zip(poly_group, poly_group_target):
target.move_to(start)
self.play(FadeOut(self.free_to_change_group))
self.play(ReplacementTransform(
self.quadratic_tex.copy(),
poly_at_zero
))
self.wait(2)
self.play(FadeIn(equals_c0))
self.wait(2)
self.play(Transform(
poly_group, poly_group_target,
run_time = 2,
lag_ratio = 0.5
))
self.wait(2)
self.play(*list(map(FadeOut, [poly_at_zero, equals_c0])))
self.free_to_change_group.remove(
self.free_to_change_group.arrows[0]
)
self.play(FadeIn(self.free_to_change_group))
def let_c1_and_c2_vary(self):
alt_consts_list = [
(1, 1, -0.25),
(1, -1, -0.25),
(1, -1, 0.25),
(1, 1, -0.1),
]
for alt_consts in alt_consts_list:
self.change_quadratic_graph(
self.quadratic_graph,
*alt_consts
)
self.wait()
def show_tangent_slope(self):
graph_point_at_zero = self.input_to_graph_point(
0, self.cosine_graph
)
tangent_line = self.get_tangent_line(0, self.cosine_graph)
self.play(ShowCreation(tangent_line))
self.change_quadratic_graph(
self.quadratic_graph, 1, 0, -0.1
)
self.wait()
self.change_quadratic_graph(
self.quadratic_graph, 1, 1, -0.1
)
self.wait(2)
self.change_quadratic_graph(
self.quadratic_graph, 1, 0, -0.1
)
self.wait(2)
self.tangent_line = tangent_line
def compute_cosine_derivative(self):
derivative, rhs = self.get_cosine_derivative()
self.play(FadeIn(
VGroup(derivative, *rhs[:2]),
run_time = 2,
lag_ratio = 0.5
))
self.wait(2)
self.play(Write(VGroup(*rhs[2:])), run_time = 2)
self.wait()
self.play(Rotate(
self.tangent_line, np.pi/12,
in_place = True,
run_time = 3,
rate_func = wiggle
))
self.wait()
def compute_polynomial_derivative(self):
derivative = self.get_quadratic_derivative("c_1", "c_2")
derivative_at_zero = self.get_quadratic_derivative(
"c_1", "c_2", arg = "0"
)
equals_c1 = TexMobject("=", "c_1", "+0")
equals_c1.next_to(
derivative_at_zero.get_part_by_tex("="), DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT,
)
equals_c1.set_color_by_tex("c_1", self.colors[1])
poly_group = VGroup(
equals_c1,
derivative,
self.quadratic_tex
)
poly_group_target = VGroup(
TexMobject("=", "0", "+0").set_color_by_tex(
"0", self.colors[1], substring = False
),
self.get_quadratic_derivative("0", "c_2", arg = "0"),
self.get_quadratic_tex("1", "0", "c_2")
)
for start, target in zip(poly_group, poly_group_target):
target.move_to(start)
self.play(FadeOut(self.free_to_change_group))
self.play(FadeIn(
derivative,
run_time = 3,
lag_ratio = 0.5
))
self.wait()
self.play(Transform(
derivative, derivative_at_zero,
run_time = 2,
lag_ratio = 0.5
))
self.wait(2)
self.play(Write(equals_c1))
self.wait(2)
self.play(Transform(
poly_group, poly_group_target,
run_time = 3,
lag_ratio = 0.5
))
self.wait(2)
self.play(*list(map(FadeOut, poly_group[:-1])))
self.free_to_change_group.remove(
self.free_to_change_group.arrows[1]
)
self.play(FadeIn(self.free_to_change_group))
def let_c2_vary(self):
alt_c2_values = [-1, -0.05, 1, -0.2]
for alt_c2 in alt_c2_values:
self.change_quadratic_graph(
self.quadratic_graph,
1, 0, alt_c2
)
self.wait()
def point_out_negative_concavity(self):
partial_cosine_graph = self.get_graph(
np.cos,
x_min = -1,
x_max = 1,
color = PINK
)
self.play(ShowCreation(partial_cosine_graph, run_time = 2))
self.wait()
for x, run_time in (-1, 2), (1, 4):
self.play(self.get_tangent_line_change_anim(
self.tangent_line, x, self.cosine_graph,
run_time = run_time
))
self.wait()
self.play(*list(map(FadeOut, [
partial_cosine_graph, self.tangent_line
])))
def compute_cosine_second_derivative(self):
second_deriv, rhs = self.get_cosine_second_derivative()
self.play(FadeIn(
VGroup(second_deriv, *rhs[1][:2]),
run_time = 2,
lag_ratio = 0.5
))
self.wait(3)
self.play(Write(VGroup(*rhs[1][2:]), run_time = 2))
self.wait()
def show_matching_curvature(self):
alt_consts_list = [
(1, 1, -0.2),
(1, 0, -0.2),
(1, 0, -0.5),
]
for alt_consts in alt_consts_list:
self.change_quadratic_graph(
self.quadratic_graph,
*alt_consts
)
self.wait()
def show_matching_tangent_lines(self):
graphs = [self.quadratic_graph, self.cosine_graph]
tangent_lines = [
self.get_tangent_line(0, graph, color = color)
for graph, color in zip(graphs, [WHITE, YELLOW])
]
tangent_change_anims = [
self.get_tangent_line_change_anim(
line, np.pi/2, graph,
run_time = 6,
rate_func = there_and_back,
)
for line, graph in zip(tangent_lines, graphs)
]
self.play(*list(map(ShowCreation, tangent_lines)))
self.play(*tangent_change_anims)
self.play(*list(map(FadeOut, tangent_lines)))
def compute_polynomial_second_derivative(self):
c2s = ["c_2", "\\text{\\tiny $\\left(-\\frac{1}{2}\\right)$}"]
derivs = [
self.get_quadratic_derivative("0", c2)
for c2 in c2s
]
second_derivs = [
TexMobject(
"{d^2 P \\over dx^2}", "(x)", "=", "2", c2
)
for c2 in c2s
]
for deriv, second_deriv in zip(derivs, second_derivs):
second_deriv[0].scale(
0.7, about_point = second_deriv[0].get_right()
)
second_deriv[-1].set_color(self.colors[-1])
second_deriv.next_to(
deriv, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
poly_group = VGroup(
second_derivs[0],
derivs[0],
self.quadratic_tex
)
poly_group_target = VGroup(
second_derivs[1],
derivs[1],
self.get_quadratic_tex("1", "0", c2s[1])
)
for tex_mob in poly_group_target:
tex_mob.get_part_by_tex(c2s[1]).shift(SMALL_BUFF*UP)
self.play(FadeOut(self.free_to_change_group))
self.play(FadeIn(derivs[0]))
self.wait(2)
self.play(Write(second_derivs[0]))
self.wait(2)
self.play(Transform(
poly_group, poly_group_target,
run_time = 3,
lag_ratio = 0.5
))
self.wait(3)
def box_final_answer(self):
box = Rectangle(stroke_color = PINK)
box.stretch_to_fit_width(
self.quadratic_tex.get_width() + MED_LARGE_BUFF
)
box.stretch_to_fit_height(
self.quadratic_tex.get_height() + MED_LARGE_BUFF
)
box.move_to(self.quadratic_tex)
self.play(ShowCreation(box, run_time = 2))
self.wait(2)
######
def change_quadratic_graph(self, graph, *args, **kwargs):
transformation_kwargs = {}
transformation_kwargs["run_time"] = kwargs.pop("run_time", 2)
transformation_kwargs["rate_func"] = kwargs.pop("rate_func", smooth)
new_graph = self.get_quadratic_graph(*args, **kwargs)
self.play(Transform(graph, new_graph, **transformation_kwargs))
graph.underlying_function = new_graph.underlying_function
def get_quadratic_graph(self, c0 = 1, c1 = 0, c2 = -0.5):
return self.get_graph(
lambda x : c0 + c1*x + c2*x**2,
color = self.colors[2]
)
def get_quadratic_tex(self, c0, c1, c2, arg = "x"):
tex_mob = TexMobject(
"P(", arg, ")", "=",
c0, "+", c1, arg, "+", c2, arg, "^2"
)
for tex, color in zip([c0, c1, c2], self.colors):
tex_mob.set_color_by_tex(tex, color)
tex_mob.to_corner(UP+RIGHT)
return tex_mob
def get_quadratic_derivative(self, c1, c2, arg = "x"):
result = TexMobject(
"{dP \\over dx}", "(", arg, ")", "=",
c1, "+", "2", c2, arg
)
result[0].scale(0.7, about_point = result[0].get_right())
for index, color in zip([5, 8], self.colors[1:]):
result[index].set_color(color)
if hasattr(self, "quadratic_tex"):
result.next_to(
self.quadratic_tex, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
return result
def get_arrow_x_equals_0_group(self):
arrow = Arrow(LEFT, RIGHT)
x_equals_0 = TexMobject("x = 0")
x_equals_0.scale(0.75)
x_equals_0.next_to(arrow.get_center(), UP, 2*SMALL_BUFF)
x_equals_0.shift(SMALL_BUFF*LEFT)
return VGroup(arrow, x_equals_0)
def get_tangent_line(self, x, graph, color = YELLOW):
tangent_line = Line(LEFT, RIGHT, color = color)
tangent_line.rotate(self.angle_of_tangent(x, graph))
tangent_line.scale(2)
tangent_line.move_to(self.input_to_graph_point(x, graph))
return tangent_line
def get_tangent_line_change_anim(self, tangent_line, new_x, graph, **kwargs):
start_x = self.x_axis.point_to_number(
tangent_line.get_center()
)
def update(tangent_line, alpha):
x = interpolate(start_x, new_x, alpha)
new_line = self.get_tangent_line(
x, graph, color = tangent_line.get_color()
)
Transform(tangent_line, new_line).update(1)
return tangent_line
return UpdateFromAlphaFunc(tangent_line, update, **kwargs)
def get_cosine_derivative(self):
if not hasattr(self, "cosine_label"):
self.cosine_label = TexMobject("\\cos(x)")
self.cosine_label.to_corner(UP+LEFT)
derivative = TexMobject(
"{d(", "\\cos", ")", "\\over", "dx}", "(0)",
)
derivative.set_color_by_tex("\\cos", self.colors[0])
derivative.scale(0.7)
derivative.next_to(
self.cosine_label, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
rhs = TexMobject("=", "-\\sin(0)", "=", "0")
rhs.set_color_by_tex("\\sin", self.colors[1])
rhs.scale(0.75)
rhs.next_to(
derivative, RIGHT,
align_using_submobjects = True
)
self.cosine_derivative = VGroup(derivative, rhs)
return self.cosine_derivative
def get_cosine_second_derivative(self):
if not hasattr(self, "cosine_derivative"):
self.get_cosine_derivative()
second_deriv = TexMobject(
"{d^2(", "\\cos", ")", "\\over", "dx^2}",
"(", "0", ")",
)
second_deriv.set_color_by_tex("cos", self.colors[0])
second_deriv.set_color_by_tex("-\\cos", self.colors[2])
second_deriv.scale(0.75)
second_deriv.add_background_rectangle()
second_deriv.next_to(
self.cosine_derivative, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
rhs = TexMobject("=", "-\\cos(0)", "=", "-1")
rhs.set_color_by_tex("cos", self.colors[2])
rhs.scale(0.8)
rhs.next_to(
second_deriv, RIGHT,
align_using_submobjects = True
)
rhs.add_background_rectangle()
self.cosine_second_derivative = VGroup(second_deriv, rhs)
return self.cosine_second_derivative
class ReflectOnQuadraticApproximation(TeacherStudentsScene):
def construct(self):
self.show_example_approximation()
# self.add_polynomial()
# self.show_c0()
# self.show_c1()
# self.show_c2()
def show_example_approximation(self):
approx_at_x, approx_at_point = [
TexMobject(
"\\cos(", s, ")", "\\approx",
"1 - \\frac{1}{2}", "(", s, ")", "^2"
).next_to(self.get_students(), UP, 2)
for s in ("x", "0.1",)
]
approx_rhs = TexMobject("=", "0.995")
approx_rhs.next_to(approx_at_point, RIGHT)
real_result = TexMobject(
"\\cos(", "0.1", ")", "=",
"%.7f\\dots"%np.cos(0.1)
)
real_result.shift(
approx_rhs.get_part_by_tex("=").get_center() -\
real_result.get_part_by_tex("=").get_center()
)
for mob in approx_at_point, real_result:
mob.set_color_by_tex("0.1", YELLOW)
real_result.set_fill(opacity = 0)
self.play(
Write(approx_at_x, run_time = 2),
self.teacher.change_mode, "raise_right_hand"
)
self.wait(2)
self.play(ReplacementTransform(
approx_at_x, approx_at_point,
))
self.wait()
self.play(Write(approx_rhs))
self.wait(2)
self.play(
real_result.shift, 1.5*DOWN,
real_result.set_fill, None, 1,
)
self.change_student_modes(*["hooray"]*3)
self.wait(2)
self.change_student_modes(
*["plain"]*3,
added_anims = list(map(FadeOut, [
approx_at_point, approx_rhs, real_result
])),
look_at_arg = approx_at_x
)
def add_polynomial(self):
polynomial = self.get_polynomial()
const_terms = polynomial.get_parts_by_tex("c")
self.play(
Write(polynomial),
self.teacher.change, "pondering"
)
self.wait(2)
self.play(*[
ApplyMethod(
const.shift, MED_LARGE_BUFF*UP,
run_time = 2,
rate_func = squish_rate_func(there_and_back, a, a+0.7)
)
for const, a in zip(const_terms, np.linspace(0, 0.3, len(const_terms)))
])
self.wait()
self.const_terms = const_terms
self.polynomial = polynomial
def show_c0(self):
c0 = self.polynomial.get_part_by_tex("c_0")
c0.save_state()
equation = TexMobject("P(0) = \\cos(0)")
equation.to_corner(UP+RIGHT)
new_polynomial = self.get_polynomial(c0 = "1")
self.play(c0.shift, UP)
self.play(Write(equation))
self.wait()
self.play(Transform(self.polynomial, new_polynomial))
self.play(FadeOut(equation))
def show_c1(self):
c1 = self.polynomial.get_part_by_tex("c_1")
c1.save_state()
equation = TexMobject(
"\\frac{dP}{dx}(0) = \\frac{d(\\cos)}{dx}(0)"
)
equation.to_corner(UP+RIGHT)
new_polynomial = self.get_polynomial(c0 = "1", c1 = "0")
self.play(c1.shift, UP)
self.play(Write(equation))
self.wait()
self.play(Transform(self.polynomial, new_polynomial))
self.wait()
self.play(FadeOut(equation))
def show_c2(self):
c2 = self.polynomial.get_part_by_tex("c_2")
c2.save_state()
equation = TexMobject(
"\\frac{d^2 P}{dx^2}(0) = \\frac{d^2(\\cos)}{dx^2}(0)"
)
equation.to_corner(UP+RIGHT)
alt_c2_tex = "\\text{\\tiny $\\left(-\\frac{1}{2}\\right)$}"
new_polynomial = self.get_polynomial(
c0 = "1", c1 = "0", c2 = alt_c2_tex
)
new_polynomial.get_part_by_tex(alt_c2_tex).shift(SMALL_BUFF*UP)
self.play(c2.shift, UP)
self.play(FadeIn(equation))
self.wait(2)
self.play(Transform(self.polynomial, new_polynomial))
self.wait(2)
self.play(FadeOut(equation))
#####
def get_polynomial(self, c0 = "c_0", c1 = "c_1", c2 = "c_2"):
polynomial = TexMobject(
"P(x) = ", c0, "+", c1, "x", "+", c2, "x^2"
)
colors = ConstructQuadraticApproximation.CONFIG["colors"]
for tex, color in zip([c0, c1, c2], colors):
polynomial.set_color_by_tex(tex, color, substring = False)
polynomial.next_to(self.teacher, UP, LARGE_BUFF)
polynomial.to_edge(RIGHT)
return polynomial
class ReflectionOnQuadraticSupplement(ConstructQuadraticApproximation):
def construct(self):
self.setup_axes()
self.add(self.get_graph(np.cos, color = self.colors[0]))
quadratic_graph = self.get_quadratic_graph()
self.add(quadratic_graph)
self.wait()
for c0 in 0, 2, 1:
self.change_quadratic_graph(
quadratic_graph,
c0 = c0
)
self.wait(2)
for c1 in 1, -1, 0:
self.change_quadratic_graph(
quadratic_graph,
c1 = c1
)
self.wait(2)
for c2 in -0.1, -1, -0.5:
self.change_quadratic_graph(
quadratic_graph,
c2 = c2
)
self.wait(2)
class SimilarityOfChangeBehavior(ConstructQuadraticApproximation):
def construct(self):
colors = [YELLOW, WHITE]
max_x = np.pi/2
self.setup_axes()
cosine_graph = self.get_graph(np.cos, color = self.colors[0])
quadratic_graph = self.get_quadratic_graph()
graphs = VGroup(cosine_graph, quadratic_graph)
dots = VGroup()
for graph, color in zip(graphs, colors):
dot = Dot(color = color)
dot.move_to(self.input_to_graph_point(0, graph))
dot.graph = graph
dots.add(dot)
def update_dot(dot, alpha):
x = interpolate(0, max_x, alpha)
dot.move_to(self.input_to_graph_point(x, dot.graph))
dot_anims = [
UpdateFromAlphaFunc(dot, update_dot, run_time = 3)
for dot in dots
]
tangent_lines = VGroup(*[
self.get_tangent_line(0, graph, color)
for graph, color in zip(graphs, colors)
])
tangent_line_movements = [
self.get_tangent_line_change_anim(
line, max_x, graph,
run_time = 5,
)
for line, graph in zip(tangent_lines, graphs)
]
self.add(cosine_graph, quadratic_graph)
self.play(FadeIn(dots))
self.play(*dot_anims)
self.play(
FadeIn(tangent_lines),
FadeOut(dots)
)
self.play(*tangent_line_movements + dot_anims, run_time = 6)
self.play(*list(map(FadeOut, [tangent_lines, dots])))
self.wait()
class MoreTerms(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"More terms!",
target_mode = "surprised",
)
self.change_student_modes(*["hooray"]*3)
self.wait(3)
class CubicAndQuarticApproximations(ConstructQuadraticApproximation):
CONFIG = {
"colors": [BLUE, YELLOW, GREEN, RED, MAROON_B],
}
def construct(self):
self.add_background()
self.take_third_derivative_of_cubic()
self.show_third_derivative_of_cosine()
self.set_c3_to_zero()
self.show_cubic_curves()
self.add_quartic_term()
self.show_fourth_derivative_of_cosine()
self.take_fourth_derivative_of_quartic()
self.solve_for_c4()
self.show_quartic_approximation()
def add_background(self):
self.setup_axes()
self.cosine_graph = self.get_graph(
np.cos, color = self.colors[0]
)
self.quadratic_graph = self.get_quadratic_graph()
self.big_rect = Rectangle(
height = FRAME_HEIGHT,
width = FRAME_WIDTH,
stroke_width = 0,
fill_color = BLACK,
fill_opacity = 0.5,
)
self.add(
self.cosine_graph, self.quadratic_graph,
self.big_rect
)
self.cosine_label = TexMobject("\\cos", "(0)", "=1")
self.cosine_label.set_color_by_tex("cos", self.colors[0])
self.cosine_label.scale(0.75)
self.cosine_label.to_corner(UP+LEFT)
self.add(self.cosine_label)
self.add(self.get_cosine_derivative())
self.add(self.get_cosine_second_derivative())
self.polynomial = TexMobject(
"P(x)=", "1", "-\\frac{1}{2}", "x^2"
)
self.polynomial.set_color_by_tex("1", self.colors[0])
self.polynomial.set_color_by_tex("-\\frac{1}{2}", self.colors[2])
self.polynomial.to_corner(UP+RIGHT)
self.polynomial.quadratic_part = VGroup(
*self.polynomial[1:]
)
self.add(self.polynomial)
def take_third_derivative_of_cubic(self):
polynomial = self.polynomial
plus_cubic_term = TexMobject("+\\,", "c_3", "x^3")
plus_cubic_term.next_to(polynomial, RIGHT)
plus_cubic_term.to_edge(RIGHT, buff = LARGE_BUFF)
plus_cubic_term.set_color_by_tex("c_3", self.colors[3])
plus_cubic_copy = plus_cubic_term.copy()
polynomial.generate_target()
polynomial.target.next_to(plus_cubic_term, LEFT)
self.play(FocusOn(polynomial))
self.play(
MoveToTarget(polynomial),
GrowFromCenter(plus_cubic_term)
)
self.wait()
brace = Brace(polynomial.quadratic_part, DOWN)
third_derivative = TexMobject(
"\\frac{d^3 P}{dx^3}(x) = ", "0"
)
third_derivative.shift(
brace.get_bottom() + MED_SMALL_BUFF*DOWN -\
third_derivative.get_part_by_tex("0").get_top()
)
self.play(Write(third_derivative[0]))
self.play(GrowFromCenter(brace))
self.play(ReplacementTransform(
polynomial.quadratic_part.copy(),
VGroup(third_derivative[1])
))
self.wait(2)
self.play(plus_cubic_copy.next_to, third_derivative, RIGHT)
derivative_term = self.take_derivatives_of_monomial(
VGroup(*plus_cubic_copy[1:])
)
third_derivative.add(plus_cubic_copy[0], derivative_term)
self.plus_cubic_term = plus_cubic_term
self.polynomial_third_derivative = third_derivative
self.polynomial_third_derivative_brace = brace
def show_third_derivative_of_cosine(self):
cosine_third_derivative = self.get_cosine_third_derivative()
dot = Dot(fill_opacity = 0.5)
dot.move_to(self.polynomial_third_derivative)
self.play(
dot.move_to, cosine_third_derivative,
dot.set_fill, None, 0
)
self.play(ReplacementTransform(
self.cosine_second_derivative.copy(),
cosine_third_derivative
))
self.wait(2)
dot.set_fill(opacity = 0.5)
self.play(
dot.move_to, self.polynomial_third_derivative.get_right(),
dot.set_fill, None, 0,
)
self.wait()
def set_c3_to_zero(self):
c3s = VGroup(
self.polynomial_third_derivative[-1][-1],
self.plus_cubic_term.get_part_by_tex("c_3")
)
zeros = VGroup(*[
TexMobject("0").move_to(c3)
for c3 in c3s
])
zeros.set_color(self.colors[3])
zeros.shift(SMALL_BUFF*UP)
zeros[0].shift(0.25*SMALL_BUFF*(UP+LEFT))
self.play(Transform(
c3s, zeros,
run_time = 2,
lag_ratio = 0.5
))
self.wait(2)
def show_cubic_curves(self):
real_graph = self.quadratic_graph
real_graph.save_state()
graph = real_graph.copy()
graph.save_state()
alt_graphs = [
self.get_graph(func, color = real_graph.get_color())
for func in [
lambda x : x*(x-1)*(x+1),
lambda x : 1 - 0.5*(x**2) + 0.2*(x**3)
]
]
self.play(FadeIn(graph))
real_graph.set_stroke(width = 0)
for alt_graph in alt_graphs:
self.play(Transform(graph, alt_graph, run_time = 2))
self.wait()
self.play(graph.restore, run_time = 2)
real_graph.restore()
self.play(FadeOut(graph))
def add_quartic_term(self):
polynomial = self.polynomial
plus_quartic_term = TexMobject("+\\,", "c_4", "x^4")
plus_quartic_term.next_to(polynomial, RIGHT)
plus_quartic_term.set_color_by_tex("c_4", self.colors[4])
self.play(*list(map(FadeOut, [
self.plus_cubic_term,
self.polynomial_third_derivative,
self.polynomial_third_derivative_brace,
])))
self.play(Write(plus_quartic_term))
self.wait()
self.plus_quartic_term = plus_quartic_term
def show_fourth_derivative_of_cosine(self):
cosine_fourth_derivative = self.get_cosine_fourth_derivative()
self.play(FocusOn(self.cosine_third_derivative))
self.play(ReplacementTransform(
self.cosine_third_derivative.copy(),
cosine_fourth_derivative
))
self.wait(3)
def take_fourth_derivative_of_quartic(self):
quartic_term = VGroup(*self.plus_quartic_term.copy()[1:])
fourth_deriv_lhs = TexMobject("{d^4 P \\over dx^4}(x)", "=")
fourth_deriv_lhs.next_to(
self.polynomial, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
alt_rhs = TexMobject("=", "24 \\cdot", "c_4")
alt_rhs.next_to(
fourth_deriv_lhs.get_part_by_tex("="), DOWN,
buff = LARGE_BUFF,
aligned_edge = LEFT
)
alt_rhs.set_color_by_tex("c_4", self.colors[4])
self.play(Write(fourth_deriv_lhs))
self.play(
quartic_term.next_to, fourth_deriv_lhs, RIGHT
)
self.wait()
fourth_deriv_rhs = self.take_derivatives_of_monomial(quartic_term)
self.wait()
self.play(Write(alt_rhs))
self.wait()
self.fourth_deriv_lhs = fourth_deriv_lhs
self.fourth_deriv_rhs = fourth_deriv_rhs
self.fourth_deriv_alt_rhs = alt_rhs
def solve_for_c4(self):
c4s = VGroup(
self.fourth_deriv_alt_rhs.get_part_by_tex("c_4"),
self.fourth_deriv_rhs[-1],
self.plus_quartic_term.get_part_by_tex("c_4")
)
fraction = TexMobject("\\text{\\small $\\frac{1}{24}$}")
fraction.set_color(self.colors[4])
fractions = VGroup(*[
fraction.copy().move_to(c4, LEFT)
for c4 in c4s
])
fractions.shift(SMALL_BUFF*UP)
x_to_4 = self.plus_quartic_term.get_part_by_tex("x^4")
x_to_4.generate_target()
x_to_4.target.shift(MED_SMALL_BUFF*RIGHT)
self.play(
Transform(
c4s, fractions,
run_time = 3,
lag_ratio = 0.5,
),
MoveToTarget(x_to_4, run_time = 2)
)
self.wait(3)
def show_quartic_approximation(self):
real_graph = self.quadratic_graph
graph = real_graph.copy()
quartic_graph = self.get_graph(
lambda x : 1 - (x**2)/2.0 + (x**4)/24.0,
color = graph.get_color(),
)
tex_mobs = VGroup(*[
self.polynomial,
self.fourth_deriv_rhs,
self.fourth_deriv_alt_rhs,
self.cosine_label,
self.cosine_derivative,
self.cosine_second_derivative,
self.cosine_third_derivative[1],
])
for tex_mob in tex_mobs:
tex_mob.add_to_back(BackgroundRectangle(tex_mob))
self.play(FadeIn(graph))
real_graph.set_stroke(width = 0)
self.play(
Transform(
graph, quartic_graph,
run_time = 3,
),
Animation(tex_mobs)
)
self.wait(3)
####
def take_derivatives_of_monomial(self, term, *added_anims):
"""
Must be a group of pure TexMobjects,
last part must be of the form x^n
"""
n = int(term[-1].get_tex_string()[-1])
curr_term = term
added_anims_iter = iter(added_anims)
for k in range(n, 0, -1):
exponent = curr_term[-1][-1]
exponent_copy = exponent.copy()
front_num = TexMobject("%d \\cdot"%k)
front_num.move_to(curr_term[0][0], LEFT)
new_monomial = TexMobject("x^%d"%(k-1))
new_monomial.replace(curr_term[-1])
Transform(curr_term[-1], new_monomial).update(1)
curr_term.generate_target()
curr_term.target.shift(
(front_num.get_width()+SMALL_BUFF)*RIGHT
)
curr_term[-1][-1].set_fill(opacity = 0)
possibly_added_anims = []
try:
possibly_added_anims.append(next(added_anims_iter))
except:
pass
self.play(
ApplyMethod(
exponent_copy.replace, front_num[0],
path_arc = np.pi,
),
Write(
front_num[1],
rate_func = squish_rate_func(smooth, 0.5, 1)
),
MoveToTarget(curr_term),
*possibly_added_anims,
run_time = 2
)
self.remove(exponent_copy)
self.add(front_num)
curr_term = VGroup(front_num, *curr_term)
self.wait()
self.play(FadeOut(curr_term[-1]))
return VGroup(*curr_term[:-1])
def get_cosine_third_derivative(self):
if not hasattr(self, "cosine_second_derivative"):
self.get_cosine_second_derivative()
third_deriv = TexMobject(
"{d^3(", "\\cos", ")", "\\over", "dx^3}",
"(", "0", ")",
)
third_deriv.set_color_by_tex("cos", self.colors[0])
third_deriv.set_color_by_tex("-\\cos", self.colors[3])
third_deriv.scale(0.75)
third_deriv.add_background_rectangle()
third_deriv.next_to(
self.cosine_second_derivative, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
rhs = TexMobject("=", "\\sin(0)", "=", "0")
rhs.set_color_by_tex("sin", self.colors[3])
rhs.scale(0.8)
rhs.next_to(
third_deriv, RIGHT,
align_using_submobjects = True
)
rhs.add_background_rectangle()
rhs.background_rectangle.scale_in_place(1.2)
self.cosine_third_derivative = VGroup(third_deriv, rhs)
return self.cosine_third_derivative
def get_cosine_fourth_derivative(self):
if not hasattr(self, "cosine_third_derivative"):
self.get_cosine_third_derivative()
fourth_deriv = TexMobject(
"{d^4(", "\\cos", ")", "\\over", "dx^4}",
"(", "0", ")",
)
fourth_deriv.set_color_by_tex("cos", self.colors[0])
fourth_deriv.scale(0.75)
fourth_deriv.add_background_rectangle()
fourth_deriv.next_to(
self.cosine_third_derivative, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
rhs = TexMobject("=", "\\cos(0)", "=", "1")
rhs.set_color_by_tex("cos", self.colors[4])
rhs.scale(0.8)
rhs.next_to(
fourth_deriv, RIGHT,
align_using_submobjects = True
)
rhs.add_background_rectangle()
rhs.background_rectangle.scale_in_place(1.2)
self.cosine_fourth_derivative = VGroup(fourth_deriv, rhs)
return self.cosine_fourth_derivative
class NoticeAFewThings(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"Notice a few things",
target_mode = "hesitant"
)
self.wait(3)
class FactorialTerms(CubicAndQuarticApproximations):
def construct(self):
lhs_list = [
TexMobject(
"{d%s"%s, "\\over", "dx%s}"%s, "(", "c_8", "x^8", ")="
)
for i in range(9)
for s in ["^%d"%i if i > 1 else ""]
]
for lhs in lhs_list:
lhs.set_color_by_tex("c_8", YELLOW)
lhs.next_to(ORIGIN, LEFT)
lhs_list[0].set_fill(opacity = 0)
added_anims = [
ReplacementTransform(
start_lhs, target_lhs,
rate_func = squish_rate_func(smooth, 0, 0.5)
)
for start_lhs, target_lhs in zip(lhs_list, lhs_list[1:])
]
term = TexMobject("c_8", "x^8")
term.next_to(lhs[-1], RIGHT)
term.set_color_by_tex("c_8", YELLOW)
self.add(term)
self.wait()
result = self.take_derivatives_of_monomial(term, *added_anims)
factorial_term = VGroup(*result[:-1])
brace = Brace(factorial_term)
eight_factorial = brace.get_text("$8!$")
coefficient = result[-1]
words = TextMobject(
"Set", "$c_8$",
"$ = \\frac{\\text{Desired derivative value}}{8!}"
)
words.set_color_by_tex("c_8", YELLOW)
words.shift(2*UP)
self.play(
GrowFromCenter(brace),
Write(eight_factorial)
)
self.play(
ReplacementTransform(
coefficient.copy(),
words.get_part_by_tex("c_8")
),
Write(words),
)
self.wait(2)
class HigherTermsDontMessUpLowerTerms(Scene):
CONFIG = {
"colors" : CubicAndQuarticApproximations.CONFIG["colors"][::2],
}
def construct(self):
self.add_polynomial()
self.show_second_derivative()
def add_polynomial(self):
c0_tex = "1"
c2_tex = "\\text{\\small $\\left(-\\frac{1}{2}\\right)$}"
c4_tex = "c_4"
polynomial = TexMobject(
"P(x) = ",
c0_tex, "+",
c2_tex, "x^2", "+",
c4_tex, "x^4",
)
polynomial.shift(2*LEFT + UP)
c0, c2, c4 = [
polynomial.get_part_by_tex(tex)
for tex in (c0_tex, c2_tex, c4_tex)
]
for term, color in zip([c0, c2, c4], self.colors):
term.set_color(color)
arrows = VGroup(*[
Arrow(
c4.get_top(), c.get_top(),
path_arc = arc,
color = c.get_color()
)
for c, arc in [(c2, 0.9*np.pi), (c0, np.pi)]
])
no_affect_words = TextMobject(
"Doesn't affect \\\\ previous terms"
)
no_affect_words.next_to(arrows, RIGHT)
no_affect_words.shift(MED_SMALL_BUFF*(UP+LEFT))
self.add(*polynomial[:-2])
self.wait()
self.play(Write(VGroup(*polynomial[-2:])))
self.play(
Write(no_affect_words),
ShowCreation(arrows),
run_time = 3
)
self.wait(2)
self.polynomial = polynomial
self.c0_tex = c0_tex
self.c2_tex = c2_tex
self.c4_tex = c4_tex
def show_second_derivative(self):
second_deriv = TexMobject(
"{d^2 P \\over dx^2}(", "0", ")", "=",
"2", self.c2_tex, "+",
"3 \\cdot 4", self.c4_tex, "(", "0", ")", "^2"
)
second_deriv.set_color_by_tex(self.c2_tex, self.colors[1])
second_deriv.set_color_by_tex(self.c4_tex, self.colors[2])
second_deriv.set_color_by_tex("0", YELLOW)
second_deriv.next_to(
self.polynomial, DOWN,
buff = MED_LARGE_BUFF,
aligned_edge = LEFT
)
higher_terms = VGroup(*second_deriv[-6:])
brace = Brace(higher_terms, DOWN)
equals_zero = brace.get_text("=0")
second_deriv.save_state()
second_deriv.move_to(self.polynomial, LEFT)
second_deriv.set_fill(opacity = 0)
self.play(second_deriv.restore)
self.wait()
self.play(GrowFromCenter(brace))
self.wait()
self.play(Write(equals_zero))
self.wait(3)
class EachTermControlsOneDerivative(Scene):
def construct(self):
colors = CubicAndQuarticApproximations.CONFIG["colors"]
polynomial = TexMobject(
"P(x) = ", "c_0", "+", "c_1", "x", *it.chain(*[
["+", "c_%d"%n, "x^%d"%n]
for n in range(2, 5)
])
)
consts = polynomial.get_parts_by_tex("c")
deriv_words = VGroup(*[
TextMobject("Controls \\\\ $%s(0)$"%tex)
for tex in [
"P",
"\\frac{dP}{dx}",
] + [
"\\frac{d^%d P}{dx^%d}"%(n, n)
for n in range(2, 5)
]
])
deriv_words.arrange(
RIGHT,
buff = LARGE_BUFF,
aligned_edge = UP
)
deriv_words.set_width(FRAME_WIDTH - MED_LARGE_BUFF)
deriv_words.to_edge(UP)
for const, deriv, color in zip(consts, deriv_words, colors):
for mob in const, deriv:
mob.set_color(color)
arrow = Arrow(
const.get_top(),
deriv.get_bottom(),
# buff = SMALL_BUFF,
color = color
)
deriv.arrow = arrow
self.add(polynomial)
for deriv in deriv_words:
self.play(
ShowCreation(deriv.arrow),
FadeIn(deriv)
)
self.wait()
class ApproximateNearNewPoint(CubicAndQuarticApproximations):
CONFIG = {
"target_approx_centers" : [np.pi/2, np.pi],
}
def construct(self):
self.setup_axes()
self.add_cosine_graph()
self.shift_approximation_center()
self.show_polynomials()
def add_cosine_graph(self):
self.cosine_graph = self.get_graph(
np.cos, self.colors[0]
)
self.add(self.cosine_graph)
def shift_approximation_center(self):
quartic_graph = self.get_quartic_approximation(0)
dot = Dot(color = YELLOW)
dot.move_to(self.coords_to_point(0, 1))
v_line = self.get_vertical_line_to_graph(
self.target_approx_centers[-1], self.cosine_graph,
line_class = DashedLine,
color = YELLOW
)
pi = self.x_axis_labels[1]
pi.add_background_rectangle()
self.play(
ReplacementTransform(
self.cosine_graph.copy(),
quartic_graph,
),
DrawBorderThenFill(dot, run_time = 1)
)
for target, rt in zip(self.target_approx_centers, [3, 4, 4]):
self.change_approximation_center(
quartic_graph, dot, target, run_time = rt
)
self.play(
ShowCreation(v_line),
Animation(pi)
)
self.wait()
def change_approximation_center(self, graph, dot, target, **kwargs):
start = self.x_axis.point_to_number(dot.get_center())
def update_quartic(graph, alpha):
new_a = interpolate(start, target, alpha)
new_graph = self.get_quartic_approximation(new_a)
Transform(graph, new_graph).update(1)
return graph
def update_dot(dot, alpha):
new_x = interpolate(start, target, alpha)
dot.move_to(self.input_to_graph_point(new_x, self.cosine_graph))
self.play(
UpdateFromAlphaFunc(graph, update_quartic),
UpdateFromAlphaFunc(dot, update_dot),
**kwargs
)
def show_polynomials(self):
poly_around_pi = self.get_polynomial("(x-\\pi)", "\\pi")
poly_around_pi.to_corner(UP+LEFT)
randy = Randolph()
randy.to_corner(DOWN+LEFT)
self.play(FadeIn(
poly_around_pi,
run_time = 4,
lag_ratio = 0.5
))
self.wait(2)
self.play(FadeIn(randy))
self.play(randy.change, "confused", poly_around_pi)
self.play(Blink(randy))
self.wait(2)
self.play(randy.change_mode, "happy")
self.wait(2)
###
def get_polynomial(self, arg, center_tex):
result = TexMobject(
"P_{%s}(x)"%center_tex, "=", "c_0", *it.chain(*[
["+", "c_%d"%d, "%s^%d"%(arg, d)]
for d in range(1, 5)
])
)
for d, color in enumerate(self.colors):
result.set_color_by_tex("c_%d"%d, color)
result.scale(0.85)
result.add_background_rectangle()
return result
def get_quartic_approximation(self, a):
coefficients = [
derivative(np.cos, a, n)
for n in range(5)
]
func = lambda x : sum([
(c/math.factorial(n))*(x - a)**n
for n, c in enumerate(coefficients)
])
return self.get_graph(func, color = GREEN)
class OnAPhilosophicalLevel(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"And on a \\\\ philosophical level",
run_time = 1
)
self.wait(3)
class TranslationOfInformation(CubicAndQuarticApproximations):
def construct(self):
self.add_background()
self.mention_information_exchange()
self.show_derivative_pattern()
self.show_polynomial()
self.name_taylor_polynomial()
self.draw_new_function_graph()
self.write_general_function_derivative()
self.replace_coefficients_in_generality()
self.walk_through_terms()
self.show_polynomial_around_a()
def add_background(self):
self.setup_axes()
self.cosine_graph = self.get_graph(
np.cos, color = self.colors[0]
)
self.add(self.cosine_graph)
def mention_information_exchange(self):
deriv_info = TextMobject(
"Derivative \\\\ information \\\\ at a point"
)
deriv_info.next_to(ORIGIN, LEFT, LARGE_BUFF)
deriv_info.to_edge(UP)
output_info = TextMobject(
"Output \\\\ information \\\\ near that point"
)
output_info.next_to(ORIGIN, RIGHT, LARGE_BUFF)
output_info.to_edge(UP)
arrow = Arrow(deriv_info, output_info)
center_v_line = self.get_vertical_line_to_graph(
0, self.cosine_graph,
line_class = DashedLine,
color = YELLOW
)
outer_v_lines = VGroup(*[
center_v_line.copy().shift(vect)
for vect in (LEFT, RIGHT)
])
outer_v_lines.set_color(GREEN)
dot = Dot(color = YELLOW)
dot.move_to(center_v_line.get_top())
dot.save_state()
dot.move_to(deriv_info)
dot.set_fill(opacity = 0)
quadratic_graph = self.get_quadratic_graph()
self.play(Write(deriv_info, run_time = 2))
self.play(dot.restore)
self.play(ShowCreation(center_v_line))
self.wait()
self.play(ShowCreation(arrow))
self.play(Write(output_info, run_time = 2))
self.play(ReplacementTransform(
VGroup(center_v_line).copy(),
outer_v_lines
))
self.play(ReplacementTransform(
self.cosine_graph.copy(),
quadratic_graph
), Animation(dot))
for x in -1, 1, 0:
start_x = self.x_axis.point_to_number(dot.get_center())
self.play(UpdateFromAlphaFunc(
dot,
lambda d, a : d.move_to(self.input_to_graph_point(
interpolate(start_x, x, a),
self.cosine_graph
)),
run_time = 2
))
self.wait()
self.play(*list(map(FadeOut, [
deriv_info, arrow, output_info, outer_v_lines
])))
self.quadratic_graph = quadratic_graph
self.v_line = center_v_line
self.dot = dot
def show_derivative_pattern(self):
derivs_at_x, derivs_at_zero = [
VGroup(*[
TexMobject(tex, "(", arg, ")")
for tex in [
"\\cos", "-\\sin",
"-\\cos", "\\sin", "\\cos"
]
])
for arg in ("x", "0")
]
arrows = VGroup(*[
Arrow(
UP, ORIGIN,
color = WHITE,
buff = 0,
tip_length = MED_SMALL_BUFF
)
for d in derivs_at_x
])
group = VGroup(*it.chain(*list(zip(
derivs_at_x,
arrows
))))
group.add(TexMobject("\\vdots"))
group.arrange(DOWN, buff = SMALL_BUFF)
group.set_height(FRAME_HEIGHT - MED_LARGE_BUFF)
group.to_edge(LEFT)
for dx, d0, color in zip(derivs_at_x, derivs_at_zero, self.colors):
for d in dx, d0:
d.set_color(color)
d0.replace(dx)
rhs_group = VGroup(*[
TexMobject("=", "%d"%d).scale(0.7).next_to(deriv, RIGHT)
for deriv, d in zip(derivs_at_zero, [1, 0, -1, 0, 1])
])
derivative_values = VGroup(*[
rhs[1] for rhs in rhs_group
])
for value, color in zip(derivative_values, self.colors):
value.set_color(color)
zeros = VGroup(*[
deriv.get_part_by_tex("0")
for deriv in derivs_at_zero
])
self.play(FadeIn(derivs_at_x[0]))
self.wait()
for start_d, arrow, target_d in zip(group[::2], group[1::2], group[2::2]):
self.play(
ReplacementTransform(
start_d.copy(), target_d
),
ShowCreation(arrow)
)
self.wait()
self.wait()
self.play(ReplacementTransform(
derivs_at_x, derivs_at_zero
))
self.wait()
self.play(*list(map(Write, rhs_group)))
self.wait()
for rhs in rhs_group:
self.play(Indicate(rhs[1]), color = WHITE)
self.wait()
self.play(*[
ReplacementTransform(
zero.copy(), self.dot,
run_time = 3,
rate_func = squish_rate_func(smooth, a, a+0.4)
)
for zero, a in zip(zeros, np.linspace(0, 0.6, len(zeros)))
])
self.wait()
self.cosine_derivative_group = VGroup(
derivs_at_zero, arrows, group[-1], rhs_group
)
self.derivative_values = derivative_values
def show_polynomial(self):
derivative_values = self.derivative_values.copy()
polynomial = self.get_polynomial("x", 1, 0, -1, 0, 1)
polynomial.to_corner(UP+RIGHT)
monomial = TexMobject("\\frac{1}{4!}", "x^4")
monomial = VGroup(VGroup(monomial[0]), monomial[1])
monomial.next_to(polynomial, DOWN, LARGE_BUFF)
self.play(*[
Transform(
dv, pc,
run_time = 2,
path_arc = np.pi/2
)
for dv, pc, a in zip(
derivative_values,
polynomial.coefficients,
np.linspace(0, 0.6, len(derivative_values))
)
])
self.play(
Write(polynomial, run_time = 5),
Animation(derivative_values)
)
self.remove(derivative_values)
self.wait(2)
to_fade = self.take_derivatives_of_monomial(monomial)
self.play(FadeOut(to_fade))
self.wait()
self.polynomial = polynomial
def name_taylor_polynomial(self):
brace = Brace(
VGroup(
self.polynomial.coefficients,
self.polynomial.factorials
),
DOWN
)
name = brace.get_text("``Taylor polynomial''")
name.shift(MED_SMALL_BUFF*RIGHT)
quartic_graph = self.get_graph(
lambda x : 1 - (x**2)/2.0 + (x**4)/24.0,
color = GREEN,
x_min = -3.2,
x_max = 3.2,
)
quartic_graph.set_color(self.colors[4])
self.play(GrowFromCenter(brace))
self.play(Write(name))
self.wait()
self.play(
Transform(
self.quadratic_graph, quartic_graph,
run_time = 2
),
Animation(self.dot)
)
self.wait(2)
self.taylor_name_group = VGroup(brace, name)
def draw_new_function_graph(self):
def func(x):
return (np.sin(x**2 + x)+0.5)*np.exp(-x**2)
graph = self.get_graph(
func, color = self.colors[0]
)
self.play(*list(map(FadeOut, [
self.cosine_derivative_group,
self.cosine_graph,
self.quadratic_graph,
self.v_line,
self.dot
])))
self.play(ShowCreation(graph))
self.graph = graph
def write_general_function_derivative(self):
derivs_at_x, derivs_at_zero, derivs_at_a = deriv_lists = [
VGroup(*[
TexMobject("\\text{$%s$}"%args[0], *args[1:])
for args in [
("f", "(", arg, ")"),
("\\frac{df}{dx}", "(", arg, ")"),
("\\frac{d^2 f}{dx^2}", "(", arg, ")"),
("\\frac{d^3 f}{dx^3}", "(", arg, ")"),
("\\frac{d^4 f}{dx^4}", "(", arg, ")"),
]
])
for arg in ("x", "0", "a")
]
derivs_at_x.arrange(DOWN, buff = MED_LARGE_BUFF)
derivs_at_x.set_height(FRAME_HEIGHT - MED_LARGE_BUFF)
derivs_at_x.to_edge(LEFT)
zeros = VGroup(*[
deriv.get_part_by_tex("0")
for deriv in derivs_at_zero
])
self.dot.move_to(self.input_to_graph_point(0, self.graph))
self.v_line.put_start_and_end_on(
self.graph_origin, self.dot.get_center()
)
for color, dx, d0, da in zip(self.colors, *deriv_lists):
for d in dx, d0, da:
d.set_color(color)
d.add_background_rectangle()
d0.replace(dx)
da.replace(dx)
self.play(FadeIn(derivs_at_x[0]))
self.wait()
for start, target in zip(derivs_at_x, derivs_at_x[1:]):
self.play(ReplacementTransform(
start.copy(), target
))
self.wait()
self.wait()
self.play(ReplacementTransform(
derivs_at_x, derivs_at_zero,
))
self.play(ReplacementTransform(
zeros.copy(), self.dot,
run_time = 2,
lag_ratio = 0.5
))
self.play(ShowCreation(self.v_line))
self.wait()
self.derivs_at_zero = derivs_at_zero
self.derivs_at_a = derivs_at_a
def replace_coefficients_in_generality(self):
new_polynomial = self.get_polynomial("x", *[
tex_mob.get_tex_string()
for tex_mob in self.derivs_at_zero[:-1]
])
new_polynomial.to_corner(UP+RIGHT)
polynomial_fourth_term = VGroup(
*self.polynomial[-7:-1]
)
self.polynomial.remove(*polynomial_fourth_term)
self.play(
ReplacementTransform(
self.polynomial, new_polynomial,
run_time = 2,
lag_ratio = 0.5
),
FadeOut(polynomial_fourth_term),
FadeOut(self.taylor_name_group),
)
self.polynomial = new_polynomial
self.wait(3)
def walk_through_terms(self):
func = self.graph.underlying_function
approx_graphs = [
self.get_graph(
taylor_approximation(func, n),
color = WHITE
)
for n in range(7)
]
for graph, color in zip(approx_graphs, self.colors):
graph.set_color(color)
left_mob = self.polynomial.coefficients[0]
right_mobs = list(self.polynomial.factorials)
right_mobs.append(self.polynomial[-1])
braces = [
Brace(
VGroup(left_mob, *right_mobs[:n]),
DOWN
)
for n in range(len(approx_graphs))
]
brace = braces[0]
brace.stretch_to_fit_width(MED_LARGE_BUFF)
approx_graph = approx_graphs[0]
self.polynomial.add_background_rectangle()
self.play(GrowFromCenter(brace))
self.play(ShowCreation(approx_graph))
self.wait()
for new_brace, new_graph in zip(braces[1:], approx_graphs[1:]):
self.play(Transform(brace, new_brace))
self.play(
Transform(approx_graph, new_graph, run_time = 2),
Animation(self.polynomial),
Animation(self.dot),
)
self.wait()
self.play(FadeOut(brace))
self.approx_graph = approx_graph
self.approx_order = len(approx_graphs) - 1
def show_polynomial_around_a(self):
new_polynomial = self.get_polynomial("(x-a)", *[
tex_mob.get_tex_string()
for tex_mob in self.derivs_at_a[:-2]
])
new_polynomial.to_corner(UP+RIGHT)
new_polynomial.add_background_rectangle()
polynomial_third_term = VGroup(
*self.polynomial[1][-7:-1]
)
self.polynomial[1].remove(*polynomial_third_term)
group = VGroup(self.approx_graph, self.dot, self.v_line)
def get_update_function(target_x):
def update(group, alpha):
graph, dot, line = group
start_x = self.x_axis.point_to_number(dot.get_center())
x = interpolate(start_x, target_x, alpha)
graph_point = self.input_to_graph_point(x, self.graph)
dot.move_to(graph_point)
line.put_start_and_end_on(
self.coords_to_point(x, 0),
graph_point,
)
new_approx_graph = self.get_graph(
taylor_approximation(
self.graph.underlying_function,
self.approx_order,
center_point = x
),
color = graph.get_color()
)
Transform(graph, new_approx_graph).update(1)
return VGroup(graph, dot, line)
return update
self.play(
UpdateFromAlphaFunc(
group, get_update_function(1), run_time = 2
),
Animation(self.polynomial),
Animation(polynomial_third_term)
)
self.wait()
self.play(Transform(
self.derivs_at_zero,
self.derivs_at_a
))
self.play(
Transform(self.polynomial, new_polynomial),
FadeOut(polynomial_third_term)
)
self.wait()
for x in -1, np.pi/6:
self.play(
UpdateFromAlphaFunc(
group, get_update_function(x),
),
Animation(self.polynomial),
run_time = 4,
)
self.wait()
#####
def get_polynomial(self, arg, *coefficients):
result = TexMobject(
"P(x) = ", str(coefficients[0]), *list(it.chain(*[
["+", str(c), "{%s"%arg, "^%d"%n, "\\over", "%d!}"%n]
for n, c in zip(it.count(1), coefficients[1:])
])) + [
"+ \\cdots"
]
)
result.scale(0.8)
coefs = VGroup(result[1], *result[3:-1:6])
for coef, color in zip(coefs, self.colors):
coef.set_color(color)
result.coefficients = coefs
result.factorials = VGroup(*result[7::6])
return result
class ThisIsAStandardFormula(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"You will see this \\\\ in your texts",
run_time = 1
)
self.change_student_modes(
*["sad"]*3,
look_at_arg = FRAME_Y_RADIUS*UP
)
self.wait(2)
class ExpPolynomial(TranslationOfInformation, ExampleApproximationWithExp):
CONFIG = {
"x_tick_frequency" : 1,
"x_leftmost_tick" : -3,
"graph_origin" : 2*(DOWN+LEFT),
"y_axis_label" : "",
}
def construct(self):
self.setup_axes()
self.add_graph()
self.show_derivatives()
self.show_polynomial()
self.walk_through_terms()
def add_graph(self):
graph = self.get_graph(np.exp)
e_to_x = self.get_graph_label(graph, "e^x")
self.play(
ShowCreation(graph),
Write(
e_to_x,
rate_func = squish_rate_func(smooth, 0.5, 1)
),
run_time = 2
)
self.wait()
self.graph = graph
self.e_to_x = e_to_x
def show_derivatives(self):
self.e_to_x.generate_target()
derivs_at_x, derivs_at_zero = [
VGroup(*[
TexMobject("e^%s"%s).set_color(c)
for c in self.colors
])
for s in ("x", "0")
]
derivs_at_x.submobjects[0] = self.e_to_x.target
arrows = VGroup(*[
Arrow(
UP, ORIGIN,
color = WHITE,
buff = SMALL_BUFF,
tip_length = 0.2,
)
for d in derivs_at_x
])
group = VGroup(*it.chain(*list(zip(
derivs_at_x,
arrows
))))
group.add(TexMobject("\\vdots"))
group.arrange(DOWN, buff = 2*SMALL_BUFF)
group.set_height(FRAME_HEIGHT - MED_LARGE_BUFF)
group.to_edge(LEFT)
for dx, d0 in zip(derivs_at_x, derivs_at_zero):
for d in dx, d0:
d.add_background_rectangle()
d0.replace(dx)
rhs_group = VGroup(*[
TexMobject("=", "1").scale(0.7).next_to(deriv, RIGHT)
for deriv in derivs_at_zero
])
derivative_values = VGroup(*[
rhs[1] for rhs in rhs_group
])
for value, color in zip(derivative_values, self.colors):
value.set_color(color)
for arrow in arrows:
d_dx = TexMobject("d/dx")
d_dx.scale(0.5)
d_dx.next_to(arrow, RIGHT, SMALL_BUFF)
d_dx.shift(SMALL_BUFF*UP)
arrow.add(d_dx)
self.play(MoveToTarget(self.e_to_x))
derivs_at_x.submobjects[0] = self.e_to_x
for start_d, arrow, target_d in zip(group[::2], group[1::2], group[2::2]):
self.play(
ReplacementTransform(
start_d.copy(), target_d
),
Write(arrow, run_time = 1)
)
self.wait()
self.wait()
self.play(ReplacementTransform(
derivs_at_x, derivs_at_zero
))
self.wait()
self.play(*list(map(Write, rhs_group)))
self.derivative_values = derivative_values
def show_polynomial(self):
derivative_values = self.derivative_values.copy()
polynomial = self.get_polynomial("x", 1, 1, 1, 1, 1)
polynomial.to_corner(UP+RIGHT)
##These are to make the walk_through_terms method work
self.polynomial = polynomial.copy()
self.dot = Dot(fill_opacity = 0)
###
polynomial.add_background_rectangle()
self.play(*[
Transform(
dv, pc,
run_time = 2,
path_arc = np.pi/2
)
for dv, pc in zip(
derivative_values,
polynomial.coefficients,
)
])
self.play(
Write(polynomial, run_time = 4),
Animation(derivative_values)
)
####
def setup_axes(self):
GraphScene.setup_axes(self)
class ShowSecondTerm(TeacherStudentsScene):
def construct(self):
colors = CubicAndQuarticApproximations.CONFIG["colors"]
polynomial = TexMobject(
"f(a)", "+",
"\\frac{df}{dx}(a)", "(x - a)", "+",
"\\frac{d^2 f}{dx^2}(a)", "(x - a)^2"
)
for tex, color in zip(["f(a)", "df", "d^2 f"], colors):
polynomial.set_color_by_tex(tex, color)
polynomial.next_to(self.teacher, UP+LEFT)
polynomial.shift(MED_LARGE_BUFF*UP)
second_term = VGroup(*polynomial[-2:])
box = Rectangle(color = colors[2])
box.replace(second_term, stretch = True)
box.stretch_in_place(1.1, 0)
box.stretch_in_place(1.2, 1)
words = TextMobject("Geometric view")
words.next_to(box, UP)
self.teacher_says(
"Now for \\\\ something fun!",
target_mode = "hooray"
)
self.wait(2)
self.play(
RemovePiCreatureBubble(
self.teacher,
target_mode = "raise_right_hand"
),
Write(polynomial)
)
self.play(
ShowCreation(box),
FadeIn(words),
)
self.change_student_modes(*["pondering"]*3)
self.wait(3)
class SecondTermIntuition(AreaIsDerivative):
CONFIG = {
"func" : lambda x : x*(x-1)*(x-2) + 2,
"num_rects" : 300,
"t_max" : 2.3,
"x_max" : 4,
"x_labeled_nums" : None,
"x_axis_label" : "",
"y_labeled_nums" : None,
"y_axis_label" : "",
"y_min" : -1,
"y_max" : 5,
"y_tick_frequency" : 1,
"variable_point_label" : "x",
"area_opacity" : 1,
"default_riemann_start_color" : BLUE_E,
"dx" : 0.15,
"skip_reconfiguration" : False,
}
def setup(self):
GraphScene.setup(self)
ReconfigurableScene.setup(self)
self.foreground_mobjects = []
def construct(self):
self.setup_axes()
self.introduce_area()
self.write_derivative()
self.nudge_end_point()
self.point_out_triangle()
self.relabel_start_and_end()
self.compute_triangle_area()
self.walk_through_taylor_terms()
def introduce_area(self):
graph = self.v_graph = self.get_graph(
self.func, color = WHITE,
)
self.foreground_mobjects.append(graph)
area = self.area = self.get_area(0, self.t_max)
func_name = TexMobject("f_{\\text{area}}(x)")
func_name.move_to(self.coords_to_point(0.6, 1))
self.foreground_mobjects.append(func_name)
self.add(graph, area, func_name)
self.add_T_label(self.t_max)
if not self.skip_animations:
for target in 1.6, 2.7, self.t_max:
self.change_area_bounds(
new_t_max = target,
run_time = 3,
)
self.__name__ = func_name
def write_derivative(self):
deriv = TexMobject("\\frac{df_{\\text{area}}}{dx}(x)")
deriv.next_to(
self.input_to_graph_point(2.7, self.v_graph),
RIGHT
)
deriv.shift_onto_screen()
self.play(ApplyWave(self.v_graph, direction = UP))
self.play(Write(deriv, run_time = 2))
self.wait()
self.deriv_label = deriv
def nudge_end_point(self):
dark_area = self.area.copy()
dark_area.set_fill(BLACK, opacity = 0.5)
curr_x = self.x_axis.point_to_number(self.area.get_right())
new_x = curr_x + self.dx
rect = Rectangle(
stroke_width = 0,
fill_color = YELLOW,
fill_opacity = 0.75
)
rect.replace(
VGroup(
VectorizedPoint(self.coords_to_point(new_x, 0)),
self.right_v_line,
),
stretch = True
)
dx_brace = Brace(rect, DOWN, buff = 0)
dx_label = dx_brace.get_text("$dx$", buff = SMALL_BUFF)
dx_label_group = VGroup(dx_label, dx_brace)
height_brace = Brace(rect, LEFT, buff = SMALL_BUFF)
self.change_area_bounds(new_t_max = new_x)
self.play(
FadeIn(dark_area),
*list(map(Animation, self.foreground_mobjects))
)
self.play(
FadeOut(self.T_label_group),
FadeIn(dx_label_group),
FadeIn(rect),
FadeIn(height_brace)
)
self.wait()
if not self.skip_reconfiguration:
self.transition_to_alt_config(
dx = self.dx/10.0,
run_time = 3,
)
self.play(FadeOut(height_brace))
self.dx_label_group = dx_label_group
self.rect = rect
self.dark_area = dark_area
def point_out_triangle(self):
triangle = Polygon(LEFT, ORIGIN, UP)
triangle.set_stroke(width = 0)
triangle.set_fill(MAROON_B, opacity = 1)
triangle.replace(
Line(
self.rect.get_corner(UP+LEFT),
self.right_v_line.get_top()
),
stretch = True
)
circle = Circle(color = RED)
circle.set_height(triangle.get_height())
circle.replace(triangle, dim_to_match = 1)
circle.scale_in_place(1.3)
self.play(DrawBorderThenFill(triangle))
self.play(ShowCreation(circle))
self.play(FadeOut(circle))
self.triangle = triangle
def relabel_start_and_end(self):
dx_label, dx_brace = self.dx_label_group
x_minus_a = TexMobject("(x-a)")
x_minus_a.scale(0.7)
x_minus_a.move_to(dx_label)
labels = VGroup()
arrows = VGroup()
for vect, tex in (LEFT, "a"), (RIGHT, "x"):
point = self.rect.get_corner(DOWN+vect)
label = TexMobject(tex)
label.next_to(point, DOWN+vect)
label.shift(LARGE_BUFF*vect)
arrow = Arrow(
label.get_corner(UP-vect),
point,
buff = SMALL_BUFF,
tip_length = 0.2,
color = WHITE
)
labels.add(label)
arrows.add(arrow)
for label, arrow in zip(labels, arrows):
self.play(
Write(label),
ShowCreation(arrow)
)
self.wait()
self.wait()
self.play(ReplacementTransform(
dx_label, x_minus_a
))
self.wait()
self.x_minus_a = x_minus_a
def compute_triangle_area(self):
triangle = self.triangle.copy()
tex_scale_factor = 0.7
base_line = Line(*[
triangle.get_corner(DOWN+vect)
for vect in (LEFT, RIGHT)
])
base_line.set_color(RED)
base_label = TextMobject("Base = ", "$(x-a)$")
base_label.scale(tex_scale_factor)
base_label.next_to(base_line, DOWN+RIGHT, MED_LARGE_BUFF)
base_label.shift(SMALL_BUFF*UP)
base_term = base_label[1].copy()
base_arrow = Arrow(
base_label.get_left(),
base_line.get_center(),
buff = SMALL_BUFF,
color = base_line.get_color(),
tip_length = 0.2
)
height_brace = Brace(triangle, RIGHT, buff = SMALL_BUFF)
height_labels = [
TexMobject("\\text{Height} = ", s, "(x-a)")
for s in [
"(\\text{Slope})",
"\\frac{d^2 f_{\\text{area}}}{dx^2}(a)"
]
]
for label in height_labels:
label.scale(tex_scale_factor)
label.next_to(height_brace, RIGHT)
height_term = VGroup(*height_labels[1][1:]).copy()
self.play(
FadeIn(base_label),
ShowCreation(base_arrow),
ShowCreation(base_line)
)
self.wait(2)
self.play(
GrowFromCenter(height_brace),
Write(height_labels[0])
)
self.wait(2)
self.play(ReplacementTransform(*height_labels))
self.wait(2)
#Show area formula
equals_half = TexMobject("=\\frac{1}{2}")
equals_half.scale(tex_scale_factor)
group = VGroup(triangle, equals_half, height_term, base_term)
group.generate_target()
group.target.arrange(RIGHT, buff = SMALL_BUFF)
group.target[-1].next_to(
group.target[-2], RIGHT,
buff = SMALL_BUFF,
align_using_submobjects = True
)
group.target[1].shift(0.02*DOWN)
group.target.to_corner(UP+RIGHT)
exp_2 = TexMobject("2").scale(0.8*tex_scale_factor)
exp_2.next_to(
group.target[-2], UP+RIGHT,
buff = 0,
align_using_submobjects = True
)
equals_half.scale(0.1)
equals_half.move_to(triangle)
equals_half.set_fill(opacity = 0)
self.play(
FadeOut(self.deriv_label),
MoveToTarget(group, run_time = 2)
)
self.wait(2)
self.play(Transform(
group[-1], exp_2
))
self.wait(2)
def walk_through_taylor_terms(self):
mini_area, mini_rect, mini_triangle = [
mob.copy()
for mob in (self.dark_area, self.rect, self.triangle)
]
mini_area.set_fill(BLUE_E, opacity = 1)
mini_area.set_height(1)
mini_rect.set_height(1)
mini_triangle.set_height(0.5)
geometric_taylor = VGroup(
TexMobject("f(x) \\approx "), mini_area,
TexMobject("+"), mini_rect,
TexMobject("+"), mini_triangle,
)
geometric_taylor.arrange(
RIGHT, buff = MED_SMALL_BUFF
)
geometric_taylor.to_corner(UP+LEFT)
analytic_taylor = TexMobject(
"f(x) \\approx", "f(a)", "+",
"\\frac{df}{dx}(a)(x-a)", "+",
"\\frac{1}{2}\\frac{d^2 f}{dx^2}(a)(x-a)^2"
)
analytic_taylor.set_color_by_tex("f(a)", BLUE)
analytic_taylor.set_color_by_tex("df", YELLOW)
analytic_taylor.set_color_by_tex("d^2 f", MAROON_B)
analytic_taylor.scale(0.7)
analytic_taylor.next_to(
geometric_taylor, DOWN,
aligned_edge = LEFT
)
for part in analytic_taylor:
part.add_to_back(BackgroundRectangle(part))
new_func_name = TexMobject("f_{\\text{area}}(a)")
new_func_name.replace(self.__name__)
self.play(FadeIn(
geometric_taylor,
run_time = 2,
lag_ratio = 0.5
))
self.wait()
self.play(
FadeIn(VGroup(*analytic_taylor[:3])),
self.dark_area.set_fill, BLUE_E, 1,
Transform(self.__name__, new_func_name)
)
self.wait()
self.play(
self.rect.scale_in_place, 0.5,
rate_func = there_and_back
)
self.play(FadeIn(VGroup(*analytic_taylor[3:5])))
self.wait(2)
self.play(
self.triangle.scale_in_place, 0.5,
rate_func = there_and_back
)
self.play(FadeIn(VGroup(*analytic_taylor[5:])))
self.wait(3)
class EachTermHasMeaning(TeacherStudentsScene):
def construct(self):
self.get_pi_creatures().scale_in_place(0.8).shift(UP)
self.teacher_says(
"Each term \\\\ has meaning!",
target_mode = "hooray",
bubble_kwargs = {"height" : 3, "width" : 4}
)
self.change_student_modes(
*["thinking"]*3,
look_at_arg = 4*UP
)
self.wait(3)
class AskAboutInfiniteSum(TeacherStudentsScene):
def construct(self):
self.ask_question()
self.name_taylor_series()
self.be_careful()
def ask_question(self):
big_rect = Rectangle(
width = FRAME_WIDTH,
height = FRAME_HEIGHT,
stroke_width = 0,
fill_color = BLACK,
fill_opacity = 0.7,
)
randy = self.get_students()[1]
series = TexMobject(
"\\cos(x)", "\\approx",
"1 - \\frac{x^2}{2!} + \\frac{x^4}{4!}",
" - \\frac{x^6}{6!}",
"+\\cdots"
)
series.next_to(randy, UP, 2)
series.shift_onto_screen()
rhs = VGroup(*series[2:])
arrow = Arrow(rhs.get_left(), rhs.get_right())
arrow.next_to(rhs, UP)
words = TextMobject("Add infinitely many")
words.next_to(arrow, UP)
self.teacher_says(
"We could call \\\\ it an end here"
)
self.change_student_modes(*["erm"]*3)
self.wait(3)
self.play(
RemovePiCreatureBubble(self.teacher),
self.get_students()[0].change_mode, "plain",
self.get_students()[2].change_mode, "plain",
FadeIn(big_rect),
randy.change_mode, "pondering"
)
crowd = VGroup(*self.get_pi_creatures())
crowd.remove(randy)
self.crowd_copy = crowd.copy()
self.remove(crowd)
self.add(self.crowd_copy, big_rect, randy)
self.play(Write(series))
self.play(
ShowCreation(arrow),
Write(words)
)
self.wait(3)
self.arrow = arrow
self.words = words
self.series = series
self.randy = randy
def name_taylor_series(self):
series_def = TextMobject(
"Infinite sum $\\Leftrightarrow$ series"
)
taylor_series = TextMobject("Taylor series")
for mob in series_def, taylor_series:
mob.move_to(self.words)
brace = Brace(self.series.get_part_by_tex("4!"), DOWN)
taylor_polynomial = brace.get_text("Taylor polynomial")
self.play(ReplacementTransform(
self.words, series_def
))
self.wait()
self.play(
GrowFromCenter(brace),
Write(taylor_polynomial)
)
self.wait(2)
self.play(
series_def.scale, 0.7,
series_def.to_corner, UP+RIGHT,
FadeIn(taylor_series)
)
self.play(self.randy.change, "thinking", taylor_series)
self.wait()
def be_careful(self):
self.play(FadeIn(self.teacher))
self.remove(self.crowd_copy[0])
self.teacher_says(
"Be careful",
bubble_kwargs = {
"width" : 3,
"height" : 2
},
added_anims = [self.randy.change, "hesitant"]
)
self.wait(2)
self.play(self.randy.change, "confused", self.series)
self.wait(3)
class ConvergenceExample(Scene):
def construct(self):
max_shown_power = 6
max_computed_power = 13
series = TexMobject(*list(it.chain(*[
["\\frac{1}{%d}"%(3**n), "+"]
for n in range(1, max_shown_power)
])) + ["\\cdots"])
series_nums = [3**(-n) for n in range(1, max_computed_power)]
partial_sums = np.cumsum(series_nums)
braces = self.get_partial_sum_braces(series, partial_sums)
convergence_words = TextMobject("``Converges'' to $\\frac{1}{2}$")
convergence_words.next_to(series, UP, LARGE_BUFF)
convergence_words.set_color(YELLOW)
rhs = TexMobject("= \\frac{1}{2}")
rhs.next_to(series, RIGHT)
rhs.set_color(BLUE)
brace = braces[0]
self.add(series, brace)
for i, new_brace in enumerate(braces[1:]):
self.play(Transform(brace, new_brace))
if i == 4:
self.play(FadeIn(convergence_words))
else:
self.wait()
self.play(
FadeOut(brace),
Write(rhs)
)
self.wait(2)
def get_partial_sum_braces(self, series, partial_sums):
braces = [
Brace(VGroup(*series[:n]))
for n in range(1, len(series)-1, 2)
]
last_brace = braces[-1]
braces += [
braces[-1].copy().stretch_in_place(
1 + 0.1 + 0.02*(n+1), dim = 0,
).move_to(last_brace, LEFT)
for n in range(len(partial_sums) - len(braces))
]
for brace, partial_sum in zip(braces, partial_sums):
number = brace.get_text("%.7f"%partial_sum)
number.set_color(YELLOW)
brace.add(number)
return braces
class ExpConvergenceExample(ConvergenceExample):
def construct(self):
e_to_x, series_with_x = x_group = self.get_series("x")
x_group.to_edge(UP)
e_to_1, series_with_1 = one_group = self.get_series("1")
terms = [1./math.factorial(n) for n in range(11)]
partial_sums = np.cumsum(terms)
braces = self.get_partial_sum_braces(series_with_1, partial_sums)
brace = braces[1]
for lhs, s in (e_to_x, "x"), (e_to_1, "1"):
new_lhs = TexMobject("e^%s"%s, "=")
new_lhs.move_to(lhs, RIGHT)
lhs.target = new_lhs
self.add(x_group)
self.wait()
self.play(ReplacementTransform(x_group.copy(), one_group))
self.play(FadeIn(brace))
self.wait()
for new_brace in braces[2:]:
self.play(Transform(brace, new_brace))
self.wait()
self.wait()
self.play(MoveToTarget(e_to_1))
self.wait(2)
def get_series(self, arg, n_terms = 5):
series = TexMobject("1", "+", *list(it.chain(*[
["\\frac{%s^%d}{%d!}"%(arg, n, n), "+"]
for n in range(1, n_terms+1)
])) + ["\\cdots"])
colors = list(CubicAndQuarticApproximations.CONFIG["colors"])
colors += [BLUE_C]
for term, color in zip(series[::2], colors):
term.set_color(color)
lhs = TexMobject("e^%s"%arg, "\\rightarrow")
lhs.arrange(RIGHT, buff = SMALL_BUFF)
group = VGroup(lhs, series)
group.arrange(RIGHT, buff = SMALL_BUFF)
return group
class ExpGraphConvergence(ExpPolynomial, ExpConvergenceExample):
CONFIG = {
"example_input" : 2,
"graph_origin" : 3*DOWN + LEFT,
"n_iterations" : 8,
"y_max" : 20,
"num_graph_anchor_points" : 50,
"func" : np.exp,
}
def construct(self):
self.setup_axes()
self.add_series()
approx_graphs = self.get_approx_graphs()
graph = self.get_graph(self.func, color = self.colors[0])
v_line = self.get_vertical_line_to_graph(
self.example_input, graph,
line_class = DashedLine,
color = YELLOW
)
dot = Dot(color = YELLOW)
dot.to_corner(UP+LEFT)
equals = TexMobject("=")
equals.replace(self.arrow)
equals.scale_in_place(0.8)
brace = self.braces[1]
approx_graph = approx_graphs[1]
x = self.example_input
self.add(graph, self.series)
self.wait()
self.play(dot.move_to, self.coords_to_point(x, 0))
self.play(
dot.move_to, self.input_to_graph_point(x, graph),
ShowCreation(v_line)
)
self.wait()
self.play(
GrowFromCenter(brace),
ShowCreation(approx_graph)
)
self.wait()
for new_brace, new_graph in zip(self.braces[2:], approx_graphs[2:]):
self.play(
Transform(brace, new_brace),
Transform(approx_graph, new_graph),
Animation(self.series),
)
self.wait()
self.play(FocusOn(equals))
self.play(Transform(self.arrow, equals))
self.wait(2)
def add_series(self):
series_group = self.get_series("x")
e_to_x, series = series_group
series_group.scale(0.8)
series_group.to_corner(UP+LEFT)
braces = self.get_partial_sum_braces(
series, np.zeros(self.n_iterations)
)
for brace in braces:
brace.remove(brace[-1])
series.add_background_rectangle()
self.add(series_group)
self.braces = braces
self.series = series
self.arrow = e_to_x[1]
def get_approx_graphs(self):
def get_nth_approximation(n):
return lambda x : sum([
float(x**k)/math.factorial(k)
for k in range(n+1)
])
approx_graphs = [
self.get_graph(get_nth_approximation(n))
for n in range(self.n_iterations)
]
colors = it.chain(self.colors, it.repeat(WHITE))
for approx_graph, color in zip(approx_graphs, colors):
approx_graph.set_color(color)
dot = Dot(color = WHITE)
dot.move_to(self.input_to_graph_point(
self.example_input, approx_graph
))
approx_graph.add(dot)
return approx_graphs
class SecondExpGraphConvergence(ExpGraphConvergence):
CONFIG = {
"example_input" : 3,
"n_iterations" : 12,
}
class BoundedRadiusOfConvergence(CubicAndQuarticApproximations):
CONFIG = {
"num_graph_anchor_points" : 100,
}
def construct(self):
self.setup_axes()
func = lambda x : (np.sin(x**2 + x)+0.5)*(np.log(x+1.01)+1)*np.exp(-x)
graph = self.get_graph(
func, color = self.colors[0],
x_min = -0.99,
x_max = self.x_max,
)
v_line = self.get_vertical_line_to_graph(
0, graph,
line_class = DashedLine,
color = YELLOW
)
dot = Dot(color = YELLOW).move_to(v_line.get_top())
two_graph = self.get_graph(lambda x : 2)
outer_v_lines = VGroup(*[
DashedLine(
self.coords_to_point(x, -2),
self.coords_to_point(x, 2),
color = WHITE
)
for x in (-1, 1)
])
colors = list(self.colors) + [GREEN, MAROON_B, PINK]
approx_graphs = [
self.get_graph(
taylor_approximation(func, n),
color = color
)
for n, color in enumerate(colors)
]
approx_graph = approx_graphs[1]
self.add(graph, v_line, dot)
self.play(ReplacementTransform(
VGroup(v_line.copy()), outer_v_lines
))
self.play(
ShowCreation(approx_graph),
Animation(dot)
)
self.wait()
for new_graph in approx_graphs[2:]:
self.play(
Transform(approx_graph, new_graph),
Animation(dot)
)
self.wait()
self.wait()
class RadiusOfConvergenceForLnX(ExpGraphConvergence):
CONFIG = {
"x_min" : -1,
"x_leftmost_tick" : None,
"x_max" : 5,
"y_min" : -2,
"y_max" : 3,
"graph_origin" : DOWN+2*LEFT,
"func" : np.log,
"num_graph_anchor_points" : 100,
"initial_n_iterations" : 7,
"n_iterations" : 11,
"convergent_example" : 1.5,
"divergent_example" : 2.5,
}
def construct(self):
self.add_graph()
self.add_series()
self.show_bounds()
self.show_converging_point()
self.show_diverging_point()
self.write_divergence()
self.write_radius_of_convergence()
def add_graph(self):
self.setup_axes()
self.graph = self.get_graph(
self.func,
x_min = 0.01
)
self.add(self.graph)
def add_series(self):
series = TexMobject(
"\\ln(x) \\rightarrow",
"(x-1)", "-",
"\\frac{(x-1)^2}{2}", "+",
"\\frac{(x-1)^3}{3}", "-",
"\\frac{(x-1)^4}{4}", "+",
"\\cdots"
)
lhs = VGroup(*series[1:])
series.add_background_rectangle()
series.scale(0.8)
series.to_corner(UP+LEFT)
for n in range(4):
lhs[2*n].set_color(self.colors[n+1])
self.braces = self.get_partial_sum_braces(
lhs, np.zeros(self.n_iterations)
)
for brace in self.braces:
brace.remove(brace[-1])
self.play(FadeIn(
series,
run_time = 3,
lag_ratio = 0.5
))
self.wait()
self.series = series
self.foreground_mobjects = [series]
def show_bounds(self):
dot = Dot(fill_opacity = 0)
dot.move_to(self.series)
v_lines = [
DashedLine(*[
self.coords_to_point(x, y)
for y in (-2, 2)
])
for x in (0, 1, 2)
]
outer_v_lines = VGroup(*v_lines[::2])
center_v_line = VGroup(v_lines[1])
input_v_line = Line(*[
self.coords_to_point(self.convergent_example, y)
for y in (-4, 3)
])
input_v_line.set_stroke(WHITE, width = 2)
self.play(
dot.move_to, self.coords_to_point(1, 0),
dot.set_fill, YELLOW, 1,
)
self.wait()
self.play(
GrowFromCenter(center_v_line),
Animation(dot)
)
self.play(Transform(center_v_line, outer_v_lines))
self.foreground_mobjects.append(dot)
def show_converging_point(self):
approx_graphs = [
self.get_graph(
taylor_approximation(self.func, n, 1),
color = WHITE
)
for n in range(1, self.n_iterations+1)
]
colors = it.chain(
self.colors[1:],
[GREEN, MAROON_B],
it.repeat(PINK)
)
for graph, color in zip(approx_graphs, colors):
graph.set_color(color)
for graph in approx_graphs:
dot = Dot(color = WHITE)
dot.move_to(self.input_to_graph_point(
self.convergent_example, graph
))
graph.dot = dot
graph.add(dot)
approx_graph = approx_graphs[0].deepcopy()
approx_dot = approx_graph.dot
brace = self.braces[0].copy()
self.play(*it.chain(
list(map(FadeIn, [approx_graph, brace])),
list(map(Animation, self.foreground_mobjects))
))
self.wait()
new_graphs = approx_graphs[1:self.initial_n_iterations]
for new_graph, new_brace in zip(new_graphs, self.braces[1:]):
self.play(
Transform(approx_graph, new_graph),
Transform(brace, new_brace),
*list(map(Animation, self.foreground_mobjects))
)
self.wait()
approx_graph.remove(approx_dot)
self.play(
approx_dot.move_to, self.coords_to_point(self.divergent_example, 0),
*it.chain(
list(map(FadeOut, [approx_graph, brace])),
list(map(Animation, self.foreground_mobjects))
)
)
self.wait()
self.approx_graphs = approx_graphs
self.approx_dot = approx_dot
def show_diverging_point(self):
for graph in self.approx_graphs:
graph.dot.move_to(self.input_to_graph_point(
self.divergent_example, graph
))
approx_graph = self.approx_graphs[0].deepcopy()
brace = self.braces[0].copy()
self.play(
ReplacementTransform(
self.approx_dot, approx_graph.dot
),
FadeIn(approx_graph[0]),
FadeIn(brace),
*list(map(Animation, self.foreground_mobjects))
)
new_graphs = self.approx_graphs[1:self.initial_n_iterations]
for new_graph, new_brace in zip(self.approx_graphs[1:], self.braces[1:]):
self.play(
Transform(approx_graph, new_graph),
Transform(brace, new_brace),
*list(map(Animation, self.foreground_mobjects))
)
self.wait()
self.approx_dot = approx_graph.dot
self.approx_graph = approx_graph
def write_divergence(self):
word = TextMobject("``Diverges''")
word.next_to(self.approx_dot, RIGHT, LARGE_BUFF)
word.shift(MED_SMALL_BUFF*DOWN)
word.add_background_rectangle()
arrow = Arrow(
word.get_left(), self.approx_dot,
buff = SMALL_BUFF,
color = WHITE
)
self.play(
Write(word),
ShowCreation(arrow)
)
self.wait()
new_graphs = self.approx_graphs[self.initial_n_iterations:]
for new_graph in new_graphs:
self.play(
Transform(self.approx_graph, new_graph),
*list(map(Animation, self.foreground_mobjects))
)
self.wait()
def write_radius_of_convergence(self):
line = Line(*[
self.coords_to_point(x, 0)
for x in (1, 2)
])
line.set_color(YELLOW)
brace = Brace(line, DOWN)
words = brace.get_text("``Radius of convergence''")
words.add_background_rectangle()
self.play(
GrowFromCenter(brace),
ShowCreation(line)
)
self.wait()
self.play(Write(words))
self.wait(3)
class MoreToBeSaid(TeacherStudentsScene):
CONFIG = {
"seconds_to_blink" : 4,
}
def construct(self):
words = TextMobject(
"Lagrange error bounds, ",
"convergence tests, ",
"$\\dots$"
)
words[0].set_color(BLUE)
words[1].set_color(GREEN)
words.to_edge(UP)
fade_rect = FullScreenFadeRectangle()
rect = Rectangle(height = 9, width = 16)
rect.set_height(FRAME_Y_RADIUS)
rect.to_corner(UP+RIGHT)
randy = self.get_students()[1]
self.teacher_says(
"There's still \\\\ more to learn!",
target_mode = "surprised",
bubble_kwargs = {"height" : 3, "width" : 4}
)
for word in words:
self.play(FadeIn(word))
self.wait()
self.teacher_says(
"About everything",
)
self.change_student_modes(*["pondering"]*3)
self.wait()
self.remove()
self.pi_creatures = []##Hack
self.play(
RemovePiCreatureBubble(self.teacher),
FadeOut(words),
FadeIn(fade_rect),
randy.change, "happy", rect
)
self.pi_creatures = [randy]
self.play(ShowCreation(rect))
self.wait(4)
class Chapter10Thanks(PatreonThanks):
CONFIG = {
"specific_patrons" : [
"Ali Yahya",
"CrypticSwarm",
"Kaustuv DeBiswas",
"Kathryn Schmiedicke",
"Karan Bhargava",
"Ankit Agarwal",
"Yu Jun",
"Dave Nicponski",
"Damion Kistler",
"Juan Benet",
"Othman Alikhan",
"Markus Persson",
"Joseph John Cox",
"Dan Buchoff",
"Derek Dai",
"Luc Ritchie",
"Ahmad Bamieh",
"Mark Govea",
"Zac Wentzell",
"Robert Teed",
"Jason Hise",
"Meshal Alshammari",
"Bernd Sing",
"Nils Schneider",
"James Thornton",
"Mustafa Mahdi",
"Jonathan Eppele",
"Mathew Bramson",
"Jerry Ling",
"Vecht",
"Shimin Kuang",
"Rish Kundalia",
"Achille Brighton",
"Ripta Pasay",
],
}
class Thumbnail(ExampleApproximationWithSine):
CONFIG = {
"graph_origin" : DOWN,
"x_axis_label" : "",
"y_axis_label" : "",
"x_axis_width" : 14,
"graph_stroke_width" : 8,
}
def construct(self):
self.setup_axes()
cos_graph = self.get_graph(np.cos)
cos_graph.set_stroke(BLUE, self.graph_stroke_width)
quad_graph = self.get_graph(taylor_approximation(np.cos, 2))
quad_graph.set_stroke(GREEN, self.graph_stroke_width)
quartic = self.get_graph(taylor_approximation(np.cos, 4))
quartic.set_stroke(PINK, self.graph_stroke_width)
self.add(cos_graph, quad_graph, quartic)
title = TextMobject("Taylor Series")
title.set_width(1.5*FRAME_X_RADIUS)
title.add_background_rectangle()
title.to_edge(UP)
self.add(title)