3b1b-manim/eoc/chapter8.py

1357 lines
40 KiB
Python
Raw Normal View History

2017-04-12 09:06:04 -07:00
from helpers import *
from mobject.tex_mobject import TexMobject
from mobject import Mobject
from mobject.image_mobject import ImageMobject
from mobject.vectorized_mobject import *
from animation.animation import Animation
from animation.transform import *
from animation.simple_animations import *
from animation.playground import *
from topics.geometry import *
from topics.characters import *
from topics.functions import *
from topics.fractals import *
from topics.number_line import *
from topics.combinatorics import *
from topics.numerals import *
from topics.three_dimensions import *
from topics.objects import *
from scene import Scene
from scene.zoomed_scene import ZoomedScene
from scene.reconfigurable_scene import ReconfigurableScene
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
from eoc.graph_scene import GraphScene
from eoc.chapter2 import Car, MoveCar, ShowSpeedometer, \
IncrementNumber, GraphCarTrajectory, SecantLineToTangentLine, \
VELOCITY_COLOR, TIME_COLOR, DISTANCE_COLOR
from topics.common_scenes import OpeningQuote, PatreonThanks
def v_rate_func(t):
return 4*t - 4*(t**2)
def s_rate_func(t):
return 3*(t**2) - 2*(t**3)
def v_func(t):
return t*(8-t)
def s_func(t):
return 4*t**2 - (t**3)/3.
class Chapter8OpeningQuote(OpeningQuote, PiCreatureScene):
CONFIG = {
"quote" : [
" One should never try to prove anything that \\\\ is not ",
"almost obvious", ". "
],
"quote_arg_separator" : "",
"highlighted_quote_terms" : {
"almost obvious" : BLUE,
},
"author" : "Alexander Grothendieck"
}
def construct(self):
self.remove(self.pi_creature)
OpeningQuote.construct(self)
words_copy = self.quote.get_part_by_tex("obvious").copy()
author = self.author
author.save_state()
formula = self.get_formula()
formula.next_to(author, DOWN, MED_LARGE_BUFF)
formula.to_edge(LEFT)
self.revert_to_original_skipping_status()
self.play(FadeIn(self.pi_creature))
self.play(
author.next_to, self.pi_creature.get_corner(UP+LEFT), UP,
self.pi_creature.change_mode, "raise_right_hand"
)
self.dither(3)
self.play(
author.restore,
self.pi_creature.change_mode, "plain"
)
self.play(
words_copy.next_to, self.pi_creature,
LEFT, MED_SMALL_BUFF, UP,
self.pi_creature.change_mode, "thinking"
)
self.dither(2)
self.play(
Write(formula),
self.pi_creature.change_mode, "confused"
)
self.dither()
def get_formula(self):
result = TexMobject(
"{d(\\sin(\\theta)) \\over \\,", "d\\theta}", "=",
"\\lim_{", "h", " \\to 0}",
"{\\sin(\\theta+", "h", ") - \\sin(\\theta) \\over", " h}", "=",
"\\lim_{", "h", " \\to 0}",
"{\\big[ \\sin(\\theta)\\cos(", "h", ") + ",
"\\sin(", "h", ")\\cos(\\theta)\\big] - \\sin(\\theta) \\over", "h}",
"= \\dots"
)
result.highlight_by_tex("h", GREEN, substring = False)
result.highlight_by_tex("d\\theta", GREEN)
result.scale_to_fit_width(2*SPACE_WIDTH - 2*MED_SMALL_BUFF)
return result
class ThisVideo(TeacherStudentsScene):
def construct(self):
series = VideoSeries()
series.to_edge(UP)
this_video = series[7]
this_video.save_state()
next_video = series[8]
deriv, integral, v_t, dt, equals, v_T = formula = TexMobject(
"\\frac{d}{dT}",
"\\int_0^T", "v(t)", "\\,dt",
"=", "v(T)"
)
formula.highlight_by_tex("v", VELOCITY_COLOR)
formula.next_to(self.teacher.get_corner(UP+LEFT), UP, MED_LARGE_BUFF)
self.play(FadeIn(series, submobject_mode = "lagged_start"))
self.play(
this_video.shift, this_video.get_height()*DOWN/2,
this_video.highlight, YELLOW,
self.teacher.change_mode, "raise_right_hand",
)
self.play(Write(VGroup(integral, v_t, dt)))
self.change_student_modes(*["erm"]*3)
self.dither()
self.play(Write(VGroup(deriv, equals, v_T)), )
self.change_student_modes(*["confused"]*3)
self.dither(3)
self.play(
this_video.restore,
next_video.shift, next_video.get_height()*DOWN/2,
next_video.highlight, YELLOW,
integral[0].copy().next_to, next_video, DOWN, MED_LARGE_BUFF,
FadeOut(formula),
*it.chain(*[
[pi.change_mode, "plain", pi.look_at, next_video]
for pi in self.pi_creatures
])
)
self.dither(2)
class InCarRestrictedView(ShowSpeedometer):
CONFIG = {
"speedometer_title_text" : "Your view",
}
def construct(self):
car = Car()
car.move_to(self.point_A)
self.car = car
car.randy.save_state()
Transform(car.randy, Randolph()).update(1)
car.randy.next_to(car, RIGHT, MED_LARGE_BUFF)
car.randy.look_at(car)
window = car[1][6].copy()
window.is_subpath = False
window.set_fill(BLACK, opacity = 0.75)
window.set_stroke(width = 0)
square = Square(stroke_color = WHITE)
square.replace(VGroup(self.speedometer, self.speedometer_title))
square.scale_in_place(1.5)
square.pointwise_become_partial(square, 0.25, 0.75)
time_label = TextMobject("Time (in seconds):", "0")
time_label.shift(2*UP)
dots = VGroup(*map(Dot, [self.point_A, self.point_B]))
line = Line(*dots, buff = 0)
line.highlight(DISTANCE_COLOR)
brace = Brace(line, DOWN)
brace_text = brace.get_text("Distance traveled?")
#Sit in car
self.add(car)
self.play(Blink(car.randy))
self.play(car.randy.restore, Animation(car))
self.play(ShowCreation(window, run_time = 2))
self.dither()
#Show speedometer
self.introduce_added_mobjects()
self.play(ShowCreation(square))
self.dither()
#Travel
self.play(FadeIn(time_label))
self.play(
MoveCar(car, self.point_B, rate_func = s_rate_func),
IncrementNumber(time_label[1], run_time = 8),
MaintainPositionRelativeTo(window, car),
*self.get_added_movement_anims(
rate_func = v_rate_func,
radians = -(16.0/70)*4*np.pi/3
),
run_time = 8
)
eight = TexMobject("8").move_to(time_label[1])
self.play(Transform(
time_label[1], eight,
rate_func = squish_rate_func(smooth, 0, 0.5)
))
self.dither()
#Ask about distance
self.play(*map(ShowCreation, dots))
self.play(ShowCreation(line))
self.play(
GrowFromCenter(brace),
Write(brace_text)
)
self.dither(2)
class GraphDistanceVsTime(GraphCarTrajectory):
CONFIG = {
"y_min" : 0,
"y_max" : 100,
"y_axis_height" : 6,
"y_tick_frequency" : 10,
"y_labeled_nums" : range(10, 100, 10),
"y_axis_label" : "Distance (in meters)",
"x_min" : -1,
"x_max" : 9,
"x_axis_width" : 9,
"x_tick_frequency" : 1,
"x_leftmost_tick" : None, #Change if different from x_min
"x_labeled_nums" : range(1, 9),
"x_axis_label" : "$t$",
"time_of_journey" : 8,
"care_movement_rate_func" : s_rate_func,
"num_graph_anchor_points" : 100
}
def construct(self):
self.setup_axes()
graph = self.get_graph(
s_func,
color = DISTANCE_COLOR,
x_min = 0,
x_max = 8,
)
origin = self.coords_to_point(0, 0)
graph_label = self.get_graph_label(
graph, "s(t)", color = DISTANCE_COLOR
)
self.introduce_graph(graph, origin)
class PlotVelocity(GraphScene):
CONFIG = {
"x_min" : -1,
"x_max" : 9,
"x_axis_width" : 9,
"x_tick_frequency" : 1,
"x_labeled_nums" : range(1, 9),
"x_axis_label" : "$t$",
"y_min" : 0,
"y_max" : 25,
"y_axis_height" : 6,
"y_tick_frequency" : 5,
"y_labeled_nums" : range(5, 30, 5),
"y_axis_label" : "Velocity in $\\frac{\\text{meters}}{\\text{second}}$",
}
def construct(self):
self.setup_axes()
self.add_speedometer()
self.plot_points()
self.draw_curve()
def add_speedometer(self):
speedometer = Speedometer()
speedometer.next_to(self.y_axis_label_mob, RIGHT, LARGE_BUFF)
speedometer.to_edge(UP)
self.play(DrawBorderThenFill(
speedometer,
submobject_mode = "lagged_start",
rate_func = None,
))
self.speedometer = speedometer
def plot_points(self):
times = range(0, 9)
points = [
self.coords_to_point(t, v_func(t))
for t in times
]
dots = VGroup(*[Dot(p, radius = 0.07) for p in points])
dots.highlight(VELOCITY_COLOR)
pre_dots = VGroup()
dot_intro_anims = []
for time, dot in zip(times, dots):
pre_dot = dot.copy()
self.speedometer.move_needle_to_velocity(v_func(time))
pre_dot.move_to(self.speedometer.get_needle_tip())
pre_dot.set_fill(opacity = 0)
pre_dots.add(pre_dot)
dot_intro_anims += [
ApplyMethod(
pre_dot.set_fill, YELLOW, 1,
run_time = 0.1,
),
ReplacementTransform(
pre_dot, dot,
run_time = 0.9,
)
]
self.speedometer.move_needle_to_velocity(0)
self.play(
Succession(
*dot_intro_anims, rate_func = None
),
ApplyMethod(
self.speedometer.move_needle_to_velocity,
v_func(4),
rate_func = squish_rate_func(
lambda t : 1-v_rate_func(t),
0, 0.95,
)
),
run_time = 5
)
self.dither()
def draw_curve(self):
graph, label = self.get_v_graph_and_label()
self.revert_to_original_skipping_status()
self.play(ShowCreation(graph, run_time = 3))
self.play(Write(graph_label))
self.dither()
##
def get_v_graph_and_label(self):
graph = self.get_graph(
v_func,
x_min = 0,
x_max = 8,
color = VELOCITY_COLOR
)
graph_label = TexMobject("v(t)", "=t(8-t)")
graph_label.highlight_by_tex("v(t)", VELOCITY_COLOR)
graph_label.next_to(
graph.point_from_proportion(7./8.),
UP+RIGHT
)
self.v_graph = graph
self.v_graph_label = graph_label
return graph, graph_label
class Chapter2Wrapper(Scene):
def construct(self):
title = TextMobject("Chapter 2: The paradox of the derivative")
title.to_edge(UP)
rect = Rectangle(width = 16, height = 9, color = WHITE)
rect.scale_to_fit_height(1.5*SPACE_HEIGHT)
rect.next_to(title, DOWN)
self.add(title)
self.play(ShowCreation(rect))
self.dither(3)
class GivenDistanceWhatIsVelocity(GraphCarTrajectory):
def construct(self):
self.force_skipping()
self.setup_axes()
graph = self.graph_sigmoid_trajectory_function()
origin = self.coords_to_point(0, 0)
self.introduce_graph(graph, origin)
self.comment_on_slope(graph, origin)
self.revert_to_original_skipping_status()
self.show_velocity_graph()
class DerivativeOfDistance(SecantLineToTangentLine):
def construct(self):
self.setup_axes()
self.remove(self.y_axis_label_mob, self.x_axis_label_mob)
self.add_derivative_definition(self.y_axis_label_mob)
self.add_graph()
self.draw_axes()
self.show_tangent_line()
class AskAboutAntiderivative(PlotVelocity):
def construct(self):
self.setup_axes()
self.add_v_graph()
self.write_s_formula()
self.write_antiderivative()
def add_v_graph(self):
graph, label = self.get_v_graph_and_label()
self.play(ShowCreation(graph))
self.play(Write(label))
self.graph = graph
self.graph_label = label
def write_s_formula(self):
ds_dt = TexMobject("ds", "\\over\\,", "dt")
ds_dt.highlight_by_tex("ds", DISTANCE_COLOR)
ds_dt.highlight_by_tex("dt", TIME_COLOR)
ds_dt.next_to(self.graph_label, UP, LARGE_BUFF)
v_t = self.graph_label.get_part_by_tex("v(t)")
arrow = Arrow(
ds_dt.get_bottom(), v_t.get_top(),
color = WHITE,
)
self.play(
Write(ds_dt, run_time = 2),
ShowCreation(arrow)
)
self.dither()
def write_antiderivative(self):
randy = Randolph()
randy.to_corner(DOWN+LEFT)
randy.shift(2*RIGHT)
words = TexMobject(
"{d(", "???", ") \\over \\,", "dt}", "=", "t(8-t)"
)
words.highlight_by_tex("t(8-t)", VELOCITY_COLOR)
words.highlight_by_tex("???", DISTANCE_COLOR)
words.highlight_by_tex("dt", TIME_COLOR)
words.scale(0.7)
self.play(FadeIn(randy))
self.play(PiCreatureSays(
randy, words,
target_mode = "confused",
bubble_kwargs = {"height" : 3, "width" : 4},
))
self.play(Blink(randy))
self.dither()
class Antiderivative(PiCreatureScene):
def construct(self):
functions = self.get_functions("t^2", "2t")
alt_functions = self.get_functions("???", "t(8-t)")
top_arc, bottom_arc = arcs = self.get_arcs(functions)
derivative = TextMobject("Derivative")
derivative.next_to(top_arc, UP)
antiderivative = TextMobject("``Antiderivative''")
antiderivative.next_to(bottom_arc, DOWN)
antiderivative.highlight(bottom_arc.get_color())
group = VGroup(functions, arcs, derivative, antiderivative)
self.add(functions, top_arc, derivative)
self.dither()
self.play(
ShowCreation(bottom_arc),
Write(antiderivative),
self.pi_creature.change_mode, "raise_right_hand"
)
self.dither(2)
for pair in reversed(zip(functions, alt_functions)):
self.play(
Transform(*pair),
self.pi_creature.change_mode, "pondering"
)
self.dither(2)
self.pi_creature_says(
"But first!",
target_mode = "surprised",
look_at_arg = 50*OUT,
added_anims = [group.to_edge, LEFT],
run_time = 1,
)
self.dither()
def get_functions(self, left_tex, right_tex):
left = TexMobject(left_tex)
left.shift(2*LEFT)
left.highlight(DISTANCE_COLOR)
right = TexMobject(right_tex)
right.shift(2*RIGHT)
right.highlight(VELOCITY_COLOR)
result = VGroup(left, right)
result.shift(UP)
return result
def get_arcs(self, functions):
f1, f2 = functions
top_line = Line(f1.get_corner(UP+RIGHT), f2.get_corner(UP+LEFT))
bottom_line = Line(f1.get_corner(DOWN+RIGHT), f2.get_corner(DOWN+LEFT))
top_arc = Arc(start_angle = 5*np.pi/6, angle = -2*np.pi/3)
bottom_arc = top_arc.copy()
bottom_arc.rotate(np.pi)
arcs = VGroup(top_arc, bottom_arc)
arcs.scale_to_fit_width(top_line.get_width())
for arc in arcs:
arc.add_tip()
top_arc.next_to(top_line, UP)
bottom_arc.next_to(bottom_line, DOWN)
bottom_arc.highlight(MAROON_B)
return arcs
class AreaUnderVGraph(PlotVelocity):
def construct(self):
self.setup_axes()
self.add(*self.get_v_graph_and_label())
self.show_rects()
def show_rects(self):
rect_list = self.get_riemann_rectangles_list(
self.v_graph, 7,
max_dx = 1.0,
x_min = 0,
x_max = 8,
)
flat_graph = self.get_graph(lambda t : 0)
rects = self.get_riemann_rectangles(
flat_graph, x_min = 0, x_max = 8, dx = 1.0
)
for new_rects in rect_list:
new_rects.set_fill(opacity = 0.8)
rects.align_submobjects(new_rects)
for alt_rect in rects[::2]:
alt_rect.set_fill(opacity = 0)
self.play(Transform(
rects, new_rects,
run_time = 2,
submobject_mode = "lagged_start"
))
self.dither()
class ConstantVelocityCar(Scene):
def construct(self):
car = Car()
car.scale(2)
car.move_to(3*LEFT + 3*DOWN)
self.add(car)
self.dither()
self.play(MoveCar(
car, 6*RIGHT+3*DOWN,
run_time = 5,
rate_func = None,
))
self.dither()
class ConstantVelocityPlot(PlotVelocity):
CONFIG = {
"x_axis_label" : "Time"
}
def construct(self):
self.setup_axes()
self.x_axis_label_mob.shift(DOWN)
self.draw_graph()
self.show_product()
self.comment_on_area_wierdness()
self.note_units()
def draw_graph(self):
graph = self.get_graph(
lambda t : 10,
x_min = 0,
x_max = 8,
color = VELOCITY_COLOR
)
self.play(ShowCreation(graph, rate_func = None, run_time = 3))
self.dither()
self.graph = graph
def show_product(self):
rect = Rectangle(
stroke_width = 0,
fill_color = DISTANCE_COLOR,
fill_opacity = 0.5
)
rect.replace(
VGroup(self.graph, VectorizedPoint(self.graph_origin)),
stretch = True
)
right_brace = Brace(rect, RIGHT)
top_brace = Brace(rect, UP)
v_label = right_brace.get_text(
"$10 \\frac{\\text{meters}}{\\text{second}}$",
)
v_label.highlight(VELOCITY_COLOR)
t_label = top_brace.get_text(
"8 seconds"
)
t_label.highlight(TIME_COLOR)
s_label = TexMobject("10", "\\times", "8", "\\text{ meters}")
s_label.highlight_by_tex("10", VELOCITY_COLOR)
s_label.highlight_by_tex("8", TIME_COLOR)
s_label.move_to(rect)
self.play(
GrowFromCenter(right_brace),
Write(v_label),
)
self.play(
GrowFromCenter(top_brace),
Write(t_label),
)
self.play(
FadeIn(rect),
Write(s_label),
Animation(self.graph)
)
self.dither(2)
self.area_rect = rect
self.s_label = s_label
def comment_on_area_wierdness(self):
randy = Randolph()
randy.to_corner(DOWN+LEFT)
bubble = randy.get_bubble(
"Distance \\\\ is area?",
bubble_class = ThoughtBubble,
height = 3,
width = 4,
fill_opacity = 1,
)
bubble.content.scale_in_place(0.8)
bubble.content.shift(SMALL_BUFF*UP)
VGroup(bubble[-1], bubble.content).shift(1.5*LEFT)
self.play(FadeIn(randy))
self.play(randy.change_mode, "pondering")
self.play(
self.area_rect.highlight, YELLOW,
*map(Animation, self.get_mobjects()),
rate_func = there_and_back
)
self.play(Blink(randy))
self.play(
randy.change_mode, "confused",
randy.look_at, randy.bubble,
ShowCreation(bubble),
Write(bubble.content),
)
self.dither()
self.play(Blink(randy))
self.dither()
self.play(
randy.change_mode, "pondering",
FadeOut(bubble),
FadeOut(bubble.content),
)
self.randy = randy
def note_units(self):
x_line, y_line = lines = VGroup(*[
axis.main_line.copy()
for axis in self.x_axis, self.y_axis
])
lines.highlight(TIME_COLOR)
square = Square(
stroke_color = BLACK,
stroke_width = 1,
fill_color = PINK,
fill_opacity = 1,
)
square.replace(
VGroup(*[
VectorizedPoint(self.coords_to_point(i, i))
for i in 0, 1
]),
stretch = True
)
units_of_area = VGroup(*[
square.copy().move_to(
self.coords_to_point(x, y),
DOWN+LEFT
)
for x in range(8)
for y in range(10)
])
2017-04-12 09:06:04 -07:00
self.play(ShowCreation(x_line))
self.play(Indicate(self.x_axis_label_mob))
self.play(FadeOut(x_line))
self.play(
ShowCreation(y_line),
self.randy.look_at, self.y_axis_label_mob
)
self.play(Indicate(self.y_axis_label_mob))
self.play(FadeOut(y_line))
for FadeClass in FadeIn, FadeOut:
2017-04-12 09:06:04 -07:00
self.play(
FadeClass(
units_of_area,
submobject_mode = "lagged_start",
run_time = 3
2017-04-12 09:06:04 -07:00
),
Animation(self.s_label),
self.randy.look_at, self.area_rect
)
self.play(Blink(self.randy))
self.dither()
class PiecewiseConstantCar(Scene):
def construct(self):
car = Car()
start_point = 5*LEFT
car.move_to(start_point)
self.add(car)
self.dither()
for shift in 2, 6, 12:
car.randy.rotate_in_place(np.pi/8)
anim = MoveCar(
car, start_point+shift*RIGHT,
rate_func = None
)
anim.target_mobject[0].rotate_in_place(-np.pi/8)
# for mob in anim.starting_mobject, anim.mobject:
# mob.randy.rotate_in_place(np.pi/6)
self.play(anim)
self.dither()
class PiecewiseConstantPlot(PlotVelocity):
CONFIG = {
"y_axis_label" : "",
"min_graph_proportion" : 0.1,
"max_graph_proportion" : 0.8,
"num_riemann_approximations" : 7, ##TODO
"riemann_rect_fill_opacity" : 0.75,
"tick_size" : 0.2,
}
def construct(self):
self.setup_graph()
self.always_changing()
self.show_piecewise_constant_graph()
self.compute_distance_on_each_interval()
self.approximate_original_curve()
self.revert_to_specific_approximation()
self.show_specific_rectangle()
self.show_v_dt_for_all_rectangles()
self.write_integral_symbol()
self.roles_of_dt()
self.what_does_sum_approach()
def setup_graph(self):
self.setup_axes()
self.add(*self.get_v_graph_and_label())
def always_changing(self):
dot = Dot()
arrow = Arrow(LEFT, RIGHT)
words = TextMobject("Always changing")
group = VGroup(dot, arrow, words)
def update_group(group, alpha):
dot, arrow, words = group
prop = interpolate(
self.min_graph_proportion,
self.max_graph_proportion,
alpha
)
graph_point = self.v_graph.point_from_proportion(prop)
dot.move_to(graph_point)
x_val = self.x_axis.point_to_number(graph_point)
angle = self.angle_of_tangent(x_val, self.v_graph)
angle += np.pi/2
vect = rotate_vector(RIGHT, angle)
arrow.rotate(angle - arrow.get_angle() + np.pi)
arrow.shift(
graph_point + MED_SMALL_BUFF*vect - arrow.get_end()
)
words.next_to(arrow.get_start(), UP)
return group
update_group(group, 0)
self.play(
Write(words),
ShowCreation(arrow),
DrawBorderThenFill(dot),
run_time = 1
)
self.play(UpdateFromAlphaFunc(
group, update_group,
rate_func = there_and_back,
run_time = 5
))
self.dither()
self.play(FadeOut(group))
def show_piecewise_constant_graph(self):
pw_constant_graph = self.get_pw_constant_graph()
alt_lines = [
line.copy().highlight(YELLOW)
for line in pw_constant_graph[:4]
]
for line in alt_lines:
line.start_dot = Dot(line.get_start())
line.end_dot = Dot(line.get_end())
VGroup(line.start_dot, line.end_dot).highlight(line.get_color())
line = alt_lines[0]
faders = [self.v_graph, self.v_graph_label]
for mob in faders:
mob.save_state()
mob.generate_target()
mob.target.fade(0.7)
self.play(*map(MoveToTarget, faders))
self.play(ShowCreation(pw_constant_graph, run_time = 2))
self.dither()
self.play(ShowCreation(line))
self.dither()
for new_line in alt_lines[1:]:
for mob in line.end_dot, new_line.start_dot, new_line:
self.play(Transform(
line, mob,
run_time = 1./3
))
self.remove(line)
self.add(new_line)
self.dither(2)
line = new_line
self.play(FadeOut(line))
self.pw_constant_graph = pw_constant_graph
def compute_distance_on_each_interval(self):
rect_list = self.get_riemann_rectangles_list(
self.v_graph, self.num_riemann_approximations,
max_dx = 1,
x_min = 0,
x_max = 8,
)
for rects in rect_list:
rects.set_fill(opacity = self.riemann_rect_fill_opacity)
flat_rects = self.get_riemann_rectangles(
self.get_graph(lambda t : 0),
x_min = 0, x_max = 8, dx = 1
)
rects = rect_list[0]
rect = rects[1]
flat_rects.submobjects[1] = rect.copy()
right_brace = Brace(rect, RIGHT)
top_brace = Brace(rect, UP)
right_brace.label = right_brace.get_text("$7\\frac{\\text{m}}{\\text{s}}$")
top_brace.label = top_brace.get_text("$1$s")
self.play(FadeIn(rect))
for brace in right_brace, top_brace:
self.play(
GrowFromCenter(brace),
Write(brace.label, run_time = 1),
)
brace.add(brace.label)
self.dither()
self.play(
ReplacementTransform(
flat_rects, rects,
run_time = 2,
submobject_mode = "lagged_start",
),
Animation(right_brace)
)
self.play(*map(FadeOut, [top_brace, right_brace]))
self.dither()
self.rects = rects
self.rect_list = rect_list
def approximate_original_curve(self):
rects = self.rects
self.play(
FadeOut(self.pw_constant_graph),
*[
m.restore
for m in self.v_graph, self.v_graph_label
]+[Animation(self.rects)]
)
for new_rects in self.rect_list[1:]:
rects.align_submobjects(new_rects)
for every_other_rect in rects[::2]:
every_other_rect.set_fill(opacity = 0)
self.play(Transform(
rects, new_rects,
run_time = 2,
submobject_mode = "lagged_start"
))
self.dither()
def revert_to_specific_approximation(self):
rects = self.rects
rects.save_state()
target_rects = self.rect_list[2]
target_rects.set_fill(opacity = 1)
ticks = self.get_ticks(target_rects)
tick_pair = VGroup(*ticks[4:6])
brace = Brace(tick_pair, DOWN, buff = 0)
dt_label = brace.get_text("$dt$", buff = SMALL_BUFF)
example_text = TextMobject(
"For example, \\\\",
"$dt$", "$=0.25$"
)
example_text.to_corner(UP+RIGHT)
example_text.highlight_by_tex("dt", YELLOW)
self.play(ReplacementTransform(
rects, target_rects,
run_time = 2,
submobject_mode = "lagged_start"
))
rects.restore()
self.dither()
self.play(
ShowCreation(ticks),
FadeOut(self.x_axis.numbers)
)
self.play(
GrowFromCenter(brace),
Write(dt_label)
)
self.dither()
self.play(
FadeIn(
example_text,
run_time = 2,
submobject_mode = "lagged_start",
),
ReplacementTransform(
dt_label.copy(),
example_text.get_part_by_tex("dt")
)
)
self.dither()
self.rects = rects = target_rects
self.ticks = ticks
self.dt_brace = brace
self.dt_label = dt_label
self.dt_example_text = example_text
def show_specific_rectangle(self):
rects = self.rects
rect = rects[4].copy()
rect_top = Line(
rect.get_corner(UP+LEFT),
rect.get_corner(UP+RIGHT),
color = self.v_graph.get_color()
)
t_vals = [1, 1.25]
t_labels = VGroup(*[
TexMobject("t=%s"%str(t))
for t in t_vals
])
t_labels.scale(0.7)
t_labels.next_to(rect, DOWN)
for vect, label in zip([LEFT, RIGHT], t_labels):
label.shift(1.5*vect)
label.add(Arrow(
label.get_edge_center(-vect),
rect.get_corner(DOWN+vect),
buff = SMALL_BUFF,
tip_length = 0.15,
color = WHITE
))
v_lines = VGroup()
h_lines = VGroup()
height_labels = VGroup()
for t in t_vals:
v_line = self.get_vertical_line_to_graph(
t, self.v_graph,
color = YELLOW
)
y_axis_point = self.graph_origin[0]*RIGHT
y_axis_point += v_line.get_end()[1]*UP
h_line = DashedLine(v_line.get_end(), y_axis_point)
label = TexMobject("%.1f"%v_func(t))
label.scale(0.5)
label.next_to(h_line, LEFT, SMALL_BUFF)
v_lines.add(v_line)
h_lines.add(h_line)
height_labels.add(label)
circle = Circle(radius = 0.25, color = WHITE)
circle.move_to(rect.get_top())
self.play(
rects.set_fill, None, 0.25,
Animation(rect)
)
self.dither()
for label in t_labels:
self.play(FadeIn(label))
self.dither()
for v_line, h_line, label in zip(v_lines, h_lines, height_labels):
self.play(ShowCreation(v_line))
self.play(ShowCreation(h_line))
self.play(Write(label, run_time = 1))
self.dither()
self.dither()
t_label_copy = t_labels[0].copy()
self.play(
t_label_copy.scale, 1./0.7,
t_label_copy.next_to, self.v_graph_label, DOWN+LEFT, 0
)
self.dither()
self.play(FadeOut(t_label_copy))
self.dither()
self.play(ShowCreation(circle))
self.play(ShowCreation(rect_top))
self.play(FadeOut(circle))
rect.add(rect_top)
self.dither()
for x in range(2):
self.play(
rect.scale_to_fit_height, v_lines[1].get_height(),
rect.move_to, rect.get_bottom(), DOWN,
run_time = 4,
rate_func = there_and_back
)
self.play(*map(FadeOut, [
group[1]
for group in v_lines, h_lines, height_labels
]))
self.play(
v_lines[0].highlight, RED,
rate_func = there_and_back,
)
self.dither()
area = TextMobject(
"7$\\frac{\\text{m}}{\\text{s}}$",
"$\\times$",
"0.25s",
"=",
"1.75m"
)
area.next_to(rect, RIGHT, LARGE_BUFF)
arrow = Arrow(
area.get_left(), rect.get_center(),
buff = 0,
color = WHITE
)
area.shift(SMALL_BUFF*RIGHT)
self.play(
Write(area),
ShowCreation(arrow)
)
self.dither(2)
self.play(*map(FadeOut, [
area, arrow,
v_lines[0], h_lines[0], height_labels[0],
rect, t_labels
]))
def show_v_dt_for_all_rectangles(self):
dt_brace_group = VGroup(self.dt_brace, self.dt_label)
rects_subset = self.rects[10:15]
last_rect = None
for rect in rects_subset:
brace = Brace(rect, LEFT, buff = 0)
v_t = TexMobject("v(t)")
v_t.next_to(brace, LEFT, SMALL_BUFF)
anims = [
rect.set_fill, None, 1,
dt_brace_group.next_to, rect, DOWN, SMALL_BUFF
]
if last_rect is not None:
anims += [
last_rect.set_fill, None, 0.25,
ReplacementTransform(last_brace, brace),
ReplacementTransform(last_v_t, v_t),
]
else:
anims += [
GrowFromCenter(brace),
Write(v_t)
2017-04-12 09:06:04 -07:00
]
self.play(*anims)
self.dither()
last_rect = rect
last_brace = brace
last_v_t = v_t
self.v_t = last_v_t
self.v_t_brace = last_brace
def write_integral_symbol(self):
integral = TexMobject(
"\\int", "^8", "_0", "v(t)", "\\,dt"
)
integral.to_corner(UP+RIGHT)
int_copy = integral.get_part_by_tex("int").copy()
bounds = map(integral.get_part_by_tex, ["0", "8"])
sum_word = TextMobject("``Sum''")
sum_word.next_to(integral, DOWN, MED_LARGE_BUFF, LEFT)
alt_sum_word = sum_word.copy()
int_symbol = TexMobject("\\int")
int_symbol.replace(alt_sum_word[1], dim_to_match = 1)
alt_sum_word.submobjects[1] = int_symbol
self.play(FadeOut(self.dt_example_text))
self.play(Write(integral.get_part_by_tex("int")))
self.dither()
self.play(Transform(int_copy, int_symbol))
self.play(Write(alt_sum_word), Animation(int_copy))
self.remove(int_copy)
self.play(ReplacementTransform(alt_sum_word, sum_word))
self.dither()
for bound in bounds:
self.play(Write(bound))
self.dither()
for bound, num in zip(bounds, [0, 8]):
bound_copy = bound.copy()
point = self.coords_to_point(num, 0)
self.play(
bound_copy.scale, 1.5,
bound_copy.next_to, point, DOWN, MED_LARGE_BUFF
2017-04-12 09:06:04 -07:00
)
self.play(ApplyWave(self.ticks, direction = UP))
self.dither()
for mob, tex in (self.v_t, "v(t)"), (self.dt_label, "dt"):
self.play(ReplacementTransform(
mob.copy().highlight(YELLOW),
integral.get_part_by_tex(tex),
run_time = 2
))
2017-04-12 09:06:04 -07:00
self.dither()
self.integral = integral
self.sum_word = sum_word
def roles_of_dt(self):
rects = self.rects
next_rects = self.rect_list[3]
morty = Mortimer().flip()
morty.to_corner(DOWN+LEFT)
int_dt = self.integral.get_part_by_tex("dt")
dt_copy = int_dt.copy()
2017-04-12 09:06:04 -07:00
self.play(FadeIn(morty))
self.play(
morty.change_mode, "raise_right_hand",
morty.look, UP+RIGHT,
dt_copy.next_to, morty.get_corner(UP+RIGHT), UP,
dt_copy.highlight, YELLOW
)
self.play(Blink(morty))
self.play(
ReplacementTransform(
dt_copy.copy(), int_dt,
run_time = 2
),
morty.look_at, int_dt
)
self.dither(2)
self.play(
ReplacementTransform(dt_copy.copy(), self.dt_label),
morty.look_at, self.dt_label
)
self.play(*[
ApplyMethod(
tick.shift, tick.get_height()*UP/2,
run_time = 2,
rate_func = squish_rate_func(
there_and_back,
alpha, alpha+0.2,
)
)
for tick, alpha in zip(
self.ticks,
np.linspace(0, 0.8, len(self.ticks))
)
])
self.dither()
2017-04-12 09:06:04 -07:00
#Shrink dt just a bit
self.play(
morty.change_mode, "pondering",
rects.set_fill, None, 0.75,
*map(FadeOut, [
dt_copy, self.v_t, self.v_t_brace
])
)
rects.align_submobjects(next_rects)
for every_other_rect in rects[::2]:
every_other_rect.set_fill(opacity = 0)
self.play(
self.dt_brace.stretch, 0.5, 0,
self.dt_brace.move_to, self.dt_brace, LEFT,
ReplacementTransform(
rects, next_rects,
run_time = 2,
submobject_mode = "lagged_start"
),
Transform(
self.ticks, self.get_ticks(next_rects),
run_time = 2,
submobject_mode = "lagged_start",
),
)
self.rects = rects = next_rects
self.dither()
self.play(Blink(morty))
self.play(*[
ApplyFunction(
lambda r : r.shift(0.2*UP).set_fill(None, 1),
rect,
run_time = 2,
rate_func = squish_rate_func(
there_and_back,
alpha, alpha+0.2,
)
)
for rect, alpha in zip(
rects,
np.linspace(0, 0.8, len(rects))
)
]+[
morty.change_mode, "thinking",
])
self.dither()
2017-04-12 09:06:04 -07:00
self.morty = morty
2017-04-12 09:06:04 -07:00
def what_does_sum_approach(self):
morty = self.morty
rects = self.rects
2017-04-12 09:06:04 -07:00
cross = TexMobject("\\times")
cross.replace(self.sum_word, stretch = True)
cross.highlight(RED)
brace = Brace(self.integral, DOWN)
dt_to_0 = brace.get_text("$dt \\to 0$")
2017-04-12 09:06:04 -07:00
self.play(PiCreatureSays(
morty, "Why not $\\Sigma$?",
target_mode = "sassy"
))
self.play(Blink(morty))
self.dither()
self.play(Write(cross))
self.dither()
self.play(
RemovePiCreatureBubble(morty, target_mode = "plain"),
*map(FadeOut, [
cross, self.sum_word, self.ticks,
self.dt_brace, self.dt_label,
])
)
self.play(FadeIn(brace), FadeIn(dt_to_0))
for new_rects in self.rect_list[4:]:
rects.align_submobjects(new_rects)
for every_other_rect in rects[::2]:
every_other_rect.set_fill(opacity = 0)
self.play(
Transform(
rects, new_rects,
run_time = 2,
submobject_mode = "lagged_start"
),
morty.look_at, rects,
)
self.dither()
#####
def get_pw_constant_graph(self):
result = VGroup()
for left_x in range(8):
xs = [left_x, left_x+1]
y = self.v_graph.underlying_function(left_x)
line = Line(*[
self.coords_to_point(x, y)
for x in xs
])
line.highlight(self.v_graph.get_color())
result.add(line)
return result
2017-04-12 09:06:04 -07:00
def get_ticks(self, rects):
ticks = VGroup(*[
Line(
point+self.tick_size*UP/2,
point+self.tick_size*DOWN/2
)
for t in np.linspace(0, 8, len(rects)+1)
for point in [self.coords_to_point(t, 0)]
])
ticks.highlight(YELLOW)
return ticks
2017-04-12 09:06:04 -07:00
class CarJourneyApproximations(Scene):
def construct(self):
pass
2017-04-12 09:06:04 -07:00