mirror of
https://github.com/3b1b/manim.git
synced 2025-07-28 20:43:56 +08:00
2775 lines
83 KiB
Python
2775 lines
83 KiB
Python
import scipy
|
|
from manimlib.imports import *
|
|
from old_projects.eoc.chapter1 import Thumbnail as Chapter1Thumbnail
|
|
from old_projects.eoc.chapter2 import Car, MoveCar, ShowSpeedometer, \
|
|
IncrementNumber, GraphCarTrajectory, SecantLineToTangentLine, \
|
|
VELOCITY_COLOR, TIME_COLOR, DISTANCE_COLOR
|
|
|
|
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.wait(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.wait(2)
|
|
self.play(
|
|
Write(formula),
|
|
self.pi_creature.change_mode, "confused"
|
|
)
|
|
self.wait()
|
|
|
|
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.set_color_by_tex("h", GREEN, substring = False)
|
|
result.set_color_by_tex("d\\theta", GREEN)
|
|
|
|
result.set_width(FRAME_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.set_color_by_tex("v", VELOCITY_COLOR)
|
|
formula.next_to(self.teacher.get_corner(UP+LEFT), UP, MED_LARGE_BUFF)
|
|
|
|
self.play(FadeIn(series, lag_ratio = 0.5))
|
|
self.play(
|
|
this_video.shift, this_video.get_height()*DOWN/2,
|
|
this_video.set_color, YELLOW,
|
|
self.teacher.change_mode, "raise_right_hand",
|
|
)
|
|
self.play(Write(VGroup(integral, v_t, dt)))
|
|
self.change_student_modes(*["erm"]*3)
|
|
self.wait()
|
|
self.play(Write(VGroup(deriv, equals, v_T)), )
|
|
self.change_student_modes(*["confused"]*3)
|
|
self.wait(3)
|
|
self.play(
|
|
this_video.restore,
|
|
next_video.shift, next_video.get_height()*DOWN/2,
|
|
next_video.set_color, 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.wait(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(*list(map(Dot, [self.point_A, self.point_B])))
|
|
line = Line(*dots, buff = 0)
|
|
line.set_color(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.wait()
|
|
|
|
#Show speedometer
|
|
self.introduce_added_mobjects()
|
|
self.play(ShowCreation(square))
|
|
self.wait()
|
|
|
|
#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.wait()
|
|
|
|
#Ask about distance
|
|
self.play(*list(map(ShowCreation, dots)))
|
|
self.play(ShowCreation(line))
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
Write(brace_text)
|
|
)
|
|
self.wait(2)
|
|
|
|
class GraphDistanceVsTime(GraphCarTrajectory):
|
|
CONFIG = {
|
|
"y_min" : 0,
|
|
"y_max" : 100,
|
|
"y_axis_height" : 6,
|
|
"y_tick_frequency" : 10,
|
|
"y_labeled_nums" : list(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" : list(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" : list(range(1, 9)),
|
|
"x_axis_label" : "$t$",
|
|
"y_min" : 0,
|
|
"y_max" : 25,
|
|
"y_axis_height" : 6,
|
|
"y_tick_frequency" : 5,
|
|
"y_labeled_nums" : list(range(5, 30, 5)),
|
|
"y_axis_label" : "Velocity in $\\frac{\\text{meters}}{\\text{second}}$",
|
|
"num_graph_anchor_points" : 50,
|
|
}
|
|
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,
|
|
lag_ratio = 0.5,
|
|
rate_func=linear,
|
|
))
|
|
|
|
self.speedometer = speedometer
|
|
|
|
def plot_points(self):
|
|
times = list(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.set_color(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=linear
|
|
),
|
|
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.wait()
|
|
|
|
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.wait()
|
|
|
|
##
|
|
|
|
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.set_color_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):
|
|
CONFIG = {
|
|
"title" : "Chapter 2: The paradox of the derivative",
|
|
}
|
|
def construct(self):
|
|
title = TextMobject(self.title)
|
|
title.to_edge(UP)
|
|
rect = Rectangle(width = 16, height = 9, color = WHITE)
|
|
rect.set_height(1.5*FRAME_Y_RADIUS)
|
|
rect.next_to(title, DOWN)
|
|
|
|
self.add(title)
|
|
self.play(ShowCreation(rect))
|
|
self.wait(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.set_color_by_tex("ds", DISTANCE_COLOR)
|
|
ds_dt.set_color_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.wait()
|
|
|
|
def write_antiderivative(self):
|
|
randy = Randolph()
|
|
randy.to_corner(DOWN+LEFT)
|
|
randy.shift(2*RIGHT)
|
|
words = TexMobject(
|
|
"{d(", "???", ") \\over \\,", "dt}", "=", "t(8-t)"
|
|
)
|
|
words.set_color_by_tex("t(8-t)", VELOCITY_COLOR)
|
|
words.set_color_by_tex("???", DISTANCE_COLOR)
|
|
words.set_color_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.wait()
|
|
|
|
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, antiderivative = self.get_arc_labels(arcs)
|
|
group = VGroup(functions, arcs, derivative, antiderivative)
|
|
|
|
self.add(functions, top_arc, derivative)
|
|
self.wait()
|
|
self.play(
|
|
ShowCreation(bottom_arc),
|
|
Write(antiderivative),
|
|
self.pi_creature.change_mode, "raise_right_hand"
|
|
)
|
|
self.wait(2)
|
|
for pair in reversed(list(zip(functions, alt_functions))):
|
|
self.play(
|
|
Transform(*pair),
|
|
self.pi_creature.change_mode, "pondering"
|
|
)
|
|
self.wait(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.wait()
|
|
|
|
def get_functions(self, left_tex, right_tex):
|
|
left = TexMobject(left_tex)
|
|
left.shift(2*LEFT)
|
|
left.set_color(DISTANCE_COLOR)
|
|
right = TexMobject(right_tex)
|
|
right.shift(2*RIGHT)
|
|
right.set_color(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.set_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.set_color(MAROON_B)
|
|
|
|
return arcs
|
|
|
|
def get_arc_labels(self, arcs):
|
|
top_arc, bottom_arc = arcs
|
|
derivative = TextMobject("Derivative")
|
|
derivative.next_to(top_arc, UP)
|
|
antiderivative = TextMobject("``Antiderivative''")
|
|
antiderivative.next_to(bottom_arc, DOWN)
|
|
antiderivative.set_color(bottom_arc.get_color())
|
|
|
|
return VGroup(derivative, antiderivative)
|
|
|
|
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,
|
|
lag_ratio = 0.5
|
|
))
|
|
self.wait()
|
|
|
|
class ConstantVelocityCar(Scene):
|
|
def construct(self):
|
|
car = Car()
|
|
car.move_to(5*LEFT + 3*DOWN)
|
|
|
|
self.add(car)
|
|
self.wait()
|
|
self.play(MoveCar(
|
|
car, 7*RIGHT+3*DOWN,
|
|
run_time = 5,
|
|
rate_func=linear,
|
|
))
|
|
self.wait()
|
|
|
|
class ConstantVelocityPlot(PlotVelocity):
|
|
CONFIG = {
|
|
"x_axis_label" : "Time",
|
|
"units_of_area_color" : BLUE_E,
|
|
}
|
|
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=linear, run_time = 3))
|
|
self.wait()
|
|
|
|
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.set_color(VELOCITY_COLOR)
|
|
t_label = top_brace.get_text(
|
|
"8 seconds"
|
|
)
|
|
t_label.set_color(TIME_COLOR)
|
|
|
|
s_label = TexMobject("10", "\\times", "8", "\\text{ meters}")
|
|
s_label.set_color_by_tex("10", VELOCITY_COLOR)
|
|
s_label.set_color_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.wait(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.set_color, YELLOW,
|
|
*list(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.wait()
|
|
self.play(Blink(randy))
|
|
self.wait()
|
|
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.copy()
|
|
for axis in (self.x_axis, self.y_axis)
|
|
])
|
|
lines.set_color(TIME_COLOR)
|
|
square = Square(
|
|
stroke_color = BLACK,
|
|
stroke_width = 1,
|
|
fill_color = self.units_of_area_color,
|
|
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)
|
|
])
|
|
|
|
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:
|
|
self.play(
|
|
FadeClass(
|
|
units_of_area,
|
|
lag_ratio = 0.5,
|
|
run_time = 3
|
|
),
|
|
Animation(self.s_label),
|
|
self.randy.look_at, self.area_rect
|
|
)
|
|
self.play(Blink(self.randy))
|
|
self.wait()
|
|
|
|
class PiecewiseConstantCar(Scene):
|
|
def construct(self):
|
|
car = Car()
|
|
start_point = 5*LEFT
|
|
car.move_to(start_point)
|
|
|
|
self.add(car)
|
|
self.wait()
|
|
for shift in 2, 6, 12:
|
|
car.randy.rotate_in_place(np.pi/8)
|
|
anim = MoveCar(
|
|
car, start_point+shift*RIGHT,
|
|
rate_func=linear
|
|
)
|
|
|
|
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.wait()
|
|
|
|
class PiecewiseConstantPlot(PlotVelocity):
|
|
CONFIG = {
|
|
"y_axis_label" : "",
|
|
"min_graph_proportion" : 0.1,
|
|
"max_graph_proportion" : 0.8,
|
|
"num_riemann_approximations" : 7,
|
|
"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()
|
|
self.label_integral()
|
|
|
|
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.wait()
|
|
self.play(FadeOut(group))
|
|
|
|
def show_piecewise_constant_graph(self):
|
|
pw_constant_graph = self.get_pw_constant_graph()
|
|
alt_lines = [
|
|
line.copy().set_color(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).set_color(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(*list(map(MoveToTarget, faders)))
|
|
self.play(ShowCreation(pw_constant_graph, run_time = 2))
|
|
self.wait()
|
|
self.play(ShowCreation(line))
|
|
self.wait()
|
|
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.wait(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.wait()
|
|
self.play(
|
|
ReplacementTransform(
|
|
flat_rects, rects,
|
|
run_time = 2,
|
|
lag_ratio = 0.5,
|
|
),
|
|
Animation(right_brace)
|
|
)
|
|
self.play(*list(map(FadeOut, [top_brace, right_brace])))
|
|
self.wait()
|
|
|
|
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:]:
|
|
self.transform_between_riemann_rects(rects, new_rects)
|
|
self.wait()
|
|
|
|
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.set_color_by_tex("dt", YELLOW)
|
|
|
|
self.play(ReplacementTransform(
|
|
rects, target_rects,
|
|
run_time = 2,
|
|
lag_ratio = 0.5
|
|
))
|
|
rects.restore()
|
|
self.wait()
|
|
self.play(
|
|
ShowCreation(ticks),
|
|
FadeOut(self.x_axis.numbers)
|
|
)
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
Write(dt_label)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(
|
|
example_text,
|
|
run_time = 2,
|
|
lag_ratio = 0.5,
|
|
),
|
|
ReplacementTransform(
|
|
dt_label.copy(),
|
|
example_text.get_part_by_tex("dt")
|
|
)
|
|
)
|
|
self.wait()
|
|
|
|
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.wait()
|
|
for label in t_labels:
|
|
self.play(FadeIn(label))
|
|
self.wait()
|
|
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.wait()
|
|
self.wait()
|
|
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.wait()
|
|
self.play(FadeOut(t_label_copy))
|
|
self.wait()
|
|
|
|
self.play(ShowCreation(circle))
|
|
self.play(ShowCreation(rect_top))
|
|
self.play(FadeOut(circle))
|
|
rect.add(rect_top)
|
|
self.wait()
|
|
for x in range(2):
|
|
self.play(
|
|
rect.stretch_to_fit_height, v_lines[1].get_height(),
|
|
rect.move_to, rect.get_bottom(), DOWN,
|
|
Animation(v_lines),
|
|
run_time = 4,
|
|
rate_func = there_and_back
|
|
)
|
|
|
|
self.play(*list(map(FadeOut, [
|
|
group[1]
|
|
for group in (v_lines, h_lines, height_labels)
|
|
])))
|
|
self.play(
|
|
v_lines[0].set_color, RED,
|
|
rate_func = there_and_back,
|
|
)
|
|
self.wait()
|
|
|
|
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.wait(2)
|
|
self.play(*list(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:20]
|
|
|
|
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)
|
|
]
|
|
self.play(*anims)
|
|
self.wait()
|
|
|
|
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 = list(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.wait()
|
|
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.wait()
|
|
|
|
for bound in bounds:
|
|
self.play(Write(bound))
|
|
self.wait()
|
|
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
|
|
)
|
|
self.play(ApplyWave(self.ticks, direction = UP))
|
|
self.wait()
|
|
|
|
for mob, tex in (self.v_t, "v(t)"), (self.dt_label, "dt"):
|
|
self.play(ReplacementTransform(
|
|
mob.copy().set_color(YELLOW),
|
|
integral.get_part_by_tex(tex),
|
|
run_time = 2
|
|
))
|
|
self.wait()
|
|
|
|
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()
|
|
|
|
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.set_color, YELLOW
|
|
)
|
|
self.play(Blink(morty))
|
|
self.play(
|
|
ReplacementTransform(
|
|
dt_copy.copy(), int_dt,
|
|
run_time = 2
|
|
),
|
|
morty.look_at, int_dt
|
|
)
|
|
self.wait(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.wait()
|
|
|
|
#Shrink dt just a bit
|
|
self.play(
|
|
morty.change_mode, "pondering",
|
|
rects.set_fill, None, 0.75,
|
|
*list(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,
|
|
lag_ratio = 0.5
|
|
),
|
|
Transform(
|
|
self.ticks, self.get_ticks(next_rects),
|
|
run_time = 2,
|
|
lag_ratio = 0.5,
|
|
),
|
|
)
|
|
self.rects = rects = next_rects
|
|
self.wait()
|
|
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.wait()
|
|
|
|
self.morty = morty
|
|
|
|
def what_does_sum_approach(self):
|
|
morty = self.morty
|
|
rects = self.rects
|
|
|
|
cross = TexMobject("\\times")
|
|
cross.replace(self.sum_word, stretch = True)
|
|
cross.set_color(RED)
|
|
brace = Brace(self.integral, DOWN)
|
|
dt_to_0 = brace.get_text("$dt \\to 0$")
|
|
|
|
distance_words = TextMobject(
|
|
"Area", "= Distance traveled"
|
|
)
|
|
distance_words.next_to(rects, UP)
|
|
arrow = Arrow(
|
|
distance_words[0].get_bottom(),
|
|
rects.get_center(),
|
|
color = WHITE
|
|
)
|
|
|
|
self.play(PiCreatureSays(
|
|
morty, "Why not $\\Sigma$?",
|
|
target_mode = "sassy"
|
|
))
|
|
self.play(Blink(morty))
|
|
self.wait()
|
|
self.play(Write(cross))
|
|
self.wait()
|
|
self.play(
|
|
RemovePiCreatureBubble(morty, target_mode = "plain"),
|
|
*list(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,
|
|
lag_ratio = 0.5
|
|
),
|
|
morty.look_at, rects,
|
|
)
|
|
self.wait()
|
|
|
|
self.play(
|
|
Write(distance_words),
|
|
ShowCreation(arrow),
|
|
morty.change_mode, "pondering",
|
|
morty.look_at, distance_words,
|
|
)
|
|
self.wait()
|
|
self.play(Blink(morty))
|
|
self.wait()
|
|
|
|
self.area_arrow = arrow
|
|
|
|
def label_integral(self):
|
|
words = TextMobject("``Integral of $v(t)$''")
|
|
words.to_edge(UP)
|
|
arrow = Arrow(
|
|
words.get_right(),
|
|
self.integral.get_left()
|
|
)
|
|
|
|
self.play(Indicate(self.integral))
|
|
self.play(Write(words, run_time = 2))
|
|
self.play(ShowCreation(arrow))
|
|
self.wait()
|
|
self.play(*[
|
|
ApplyFunction(
|
|
lambda r : r.shift(0.2*UP).set_fill(None, 1),
|
|
rect,
|
|
run_time = 3,
|
|
rate_func = squish_rate_func(
|
|
there_and_back,
|
|
alpha, alpha+0.2,
|
|
)
|
|
)
|
|
for rect, alpha in zip(
|
|
self.rects,
|
|
np.linspace(0, 0.8, len(self.rects))
|
|
)
|
|
]+[
|
|
Animation(self.area_arrow),
|
|
self.morty.change_mode, "happy",
|
|
self.morty.look_at, self.rects,
|
|
])
|
|
self.wait()
|
|
|
|
#####
|
|
|
|
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.set_color(self.v_graph.get_color())
|
|
result.add(line)
|
|
return result
|
|
|
|
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.set_color(YELLOW)
|
|
return ticks
|
|
|
|
class DontKnowHowToHandleNonConstant(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.play(*[
|
|
ApplyMethod(pi.change, "maybe", UP)
|
|
for pi in self.get_pi_creatures()
|
|
])
|
|
self.wait(3)
|
|
|
|
class CarJourneyApproximation(Scene):
|
|
CONFIG = {
|
|
"n_jumps" : 5,
|
|
"bottom_words" : "Approximated motion (5 jumps)",
|
|
}
|
|
def construct(self):
|
|
points = [5*LEFT + v for v in (UP, 2*DOWN)]
|
|
cars = [Car().move_to(point) for point in points]
|
|
h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS)
|
|
words = [
|
|
TextMobject("Real motion (smooth)").shift(3*UP),
|
|
TextMobject(self.bottom_words).shift(0.5*DOWN),
|
|
]
|
|
words[1].set_color(GREEN)
|
|
|
|
|
|
self.add(h_line, *cars + words)
|
|
self.wait()
|
|
self.play(*[
|
|
MoveCar(
|
|
car, point+10*RIGHT,
|
|
run_time = 5,
|
|
rate_func = rf
|
|
)
|
|
for car, point, rf in zip(cars, points, [
|
|
s_rate_func,
|
|
self.get_approximated_rate_func(self.n_jumps)
|
|
])
|
|
])
|
|
self.wait()
|
|
|
|
def get_approximated_rate_func(self, n):
|
|
new_v_rate_func = lambda t : v_rate_func(np.floor(t*n)/n)
|
|
max_integral, err = scipy.integrate.quad(
|
|
v_rate_func, 0, 1
|
|
)
|
|
def result(t):
|
|
integral, err = scipy.integrate.quad(new_v_rate_func, 0, t)
|
|
return integral/max_integral
|
|
return result
|
|
|
|
class LessWrongCarJourneyApproximation(CarJourneyApproximation):
|
|
CONFIG = {
|
|
"n_jumps" : 20,
|
|
"bottom_words" : "Better approximation (20 jumps)",
|
|
}
|
|
|
|
class TellMeThatsNotSurprising(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.teacher_says(
|
|
"Tell me that's \\\\ not surprising!",
|
|
target_mode = "hooray",
|
|
run_time = 1
|
|
)
|
|
self.wait(3)
|
|
|
|
class HowDoesThisHelp(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.student_says(
|
|
"How does this help\\textinterrobang",
|
|
target_mode = "angry",
|
|
run_time = 1
|
|
)
|
|
self.change_student_modes(
|
|
"confused", "angry", "confused",
|
|
)
|
|
self.wait(2)
|
|
self.teacher_says(
|
|
"You're right.",
|
|
target_mode = "shruggie",
|
|
run_time = 1
|
|
)
|
|
self.change_student_modes(*["sassy"]*3)
|
|
self.wait(2)
|
|
|
|
class AreaUnderACurve(GraphScene):
|
|
CONFIG = {
|
|
"y_max" : 4,
|
|
"y_min" : 0,
|
|
"num_iterations" : 7
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
graph = self.get_graph(self.func)
|
|
rect_list = self.get_riemann_rectangles_list(
|
|
graph, self.num_iterations
|
|
)
|
|
VGroup(*rect_list).set_fill(opacity = 0.8)
|
|
rects = rect_list[0]
|
|
|
|
self.play(ShowCreation(graph))
|
|
self.play(Write(rects))
|
|
for new_rects in 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,
|
|
lag_ratio = 0.5
|
|
))
|
|
self.wait()
|
|
|
|
|
|
def func(self, x):
|
|
return np.sin(x) + 1
|
|
|
|
class AltAreaUnderCurve(AreaUnderACurve):
|
|
CONFIG = {
|
|
"graph_origin" : 2*DOWN,
|
|
"x_min" : -3,
|
|
"x_max" : 3,
|
|
"x_axis_width" : 12,
|
|
"y_max" : 2,
|
|
"y_axis_height" : 4,
|
|
}
|
|
def func(self, x):
|
|
return np.exp(-x**2)
|
|
|
|
class Chapter1Wrapper(Chapter2Wrapper):
|
|
CONFIG = {
|
|
"title" : "Essence of calculus, chapter 1",
|
|
}
|
|
|
|
class AreaIsDerivative(PlotVelocity, ReconfigurableScene):
|
|
CONFIG = {
|
|
"y_axis_label" : "",
|
|
"num_rects" : 400,
|
|
"dT" : 0.25,
|
|
"variable_point_label" : "T",
|
|
"area_opacity" : 0.8,
|
|
}
|
|
def setup(self):
|
|
PlotVelocity.setup(self)
|
|
ReconfigurableScene.setup(self)
|
|
self.setup_axes()
|
|
self.add(*self.get_v_graph_and_label())
|
|
self.x_axis_label_mob.shift(MED_LARGE_BUFF*DOWN)
|
|
self.v_graph_label.shift(MED_LARGE_BUFF*DOWN)
|
|
self.foreground_mobjects = []
|
|
|
|
def construct(self):
|
|
self.introduce_variable_area()
|
|
self.write_integral()
|
|
self.nudge_input()
|
|
self.show_rectangle_approximation()
|
|
|
|
def introduce_variable_area(self):
|
|
area = self.area = self.get_area(0, 6)
|
|
x_nums = self.x_axis.numbers
|
|
|
|
self.play(Write(area, run_time = 2))
|
|
self.play(FadeOut(self.x_axis.numbers))
|
|
self.add_T_label(6)
|
|
self.change_area_bounds(
|
|
new_t_max = 4,
|
|
rate_func = there_and_back,
|
|
run_time = 2
|
|
)
|
|
self.wait()
|
|
|
|
def write_integral(self):
|
|
integral = TexMobject("\\int", "^T", "_0", "v(t)", "\\,dt")
|
|
integral.to_corner(UP+RIGHT)
|
|
integral.shift(2*LEFT)
|
|
top_T = integral.get_part_by_tex("T")
|
|
moving_T = self.T_label_group[0]
|
|
|
|
s_T = TexMobject("s(T)", "= ")
|
|
s_T.set_color_by_tex("s", DISTANCE_COLOR)
|
|
s_T.next_to(integral, LEFT)
|
|
|
|
int_arrow, s_arrow = [
|
|
Arrow(
|
|
mob.get_left(), self.area.get_center(),
|
|
color = WHITE
|
|
)
|
|
for mob in (integral, s_T)
|
|
]
|
|
|
|
distance_word = TextMobject("Distance")
|
|
distance_word.move_to(self.area)
|
|
|
|
self.play(Write(integral))
|
|
self.play(ShowCreation(int_arrow))
|
|
self.foreground_mobjects.append(int_arrow)
|
|
self.wait()
|
|
self.change_area_bounds(
|
|
new_t_max = 8,
|
|
rate_func = there_and_back,
|
|
run_time = 3,
|
|
)
|
|
self.play(Indicate(top_T))
|
|
self.play(ReplacementTransform(
|
|
top_T.copy(), moving_T
|
|
))
|
|
self.change_area_bounds(
|
|
new_t_max = 3,
|
|
rate_func = there_and_back,
|
|
run_time = 3
|
|
)
|
|
self.wait()
|
|
self.play(Write(distance_word, run_time = 2))
|
|
self.play(
|
|
ReplacementTransform(int_arrow, s_arrow),
|
|
FadeIn(s_T)
|
|
)
|
|
self.wait()
|
|
self.play(FadeOut(distance_word))
|
|
self.change_area_bounds(new_t_max = 0, run_time = 2)
|
|
self.change_area_bounds(
|
|
new_t_max = 8,
|
|
rate_func=linear,
|
|
run_time = 7.9,
|
|
)
|
|
self.wait()
|
|
self.change_area_bounds(new_t_max = 5)
|
|
self.wait()
|
|
|
|
def nudge_input(self):
|
|
dark_area = self.area.copy()
|
|
dark_area.set_fill(BLACK, opacity = 0.5)
|
|
curr_T = self.x_axis.point_to_number(self.area.get_right())
|
|
new_T = curr_T + self.dT
|
|
|
|
rect = Rectangle(
|
|
stroke_width = 0,
|
|
fill_color = YELLOW,
|
|
fill_opacity = 0.75
|
|
)
|
|
rect.replace(
|
|
VGroup(
|
|
VectorizedPoint(self.coords_to_point(new_T, 0)),
|
|
self.right_v_line,
|
|
),
|
|
stretch = True
|
|
)
|
|
|
|
dT_brace = Brace(rect, DOWN, buff = 0)
|
|
dT_label = dT_brace.get_text("$dT$", buff = SMALL_BUFF)
|
|
dT_label_group = VGroup(dT_label, dT_brace)
|
|
|
|
ds_label = TexMobject("ds")
|
|
ds_label.next_to(rect, RIGHT, LARGE_BUFF, UP)
|
|
ds_label.set_color(DISTANCE_COLOR)
|
|
ds_arrow = Arrow(ds_label.get_left(), rect.get_left())
|
|
ds_arrow.set_color(WHITE)
|
|
|
|
v_brace = Brace(rect, LEFT, buff = SMALL_BUFF)
|
|
v_T_label = v_brace.get_text("$v(T)$", buff = SMALL_BUFF)
|
|
|
|
self.change_area_bounds(new_t_max = new_T)
|
|
self.play(
|
|
FadeIn(dark_area),
|
|
*list(map(Animation, self.foreground_mobjects))
|
|
)
|
|
self.play(
|
|
FadeOut(self.T_label_group),
|
|
FadeIn(dT_label_group)
|
|
)
|
|
self.wait()
|
|
self.play(Write(ds_label))
|
|
self.play(ShowCreation(ds_arrow))
|
|
self.wait(2)
|
|
self.play(GrowFromCenter(v_brace))
|
|
self.play(ReplacementTransform(
|
|
self.v_graph_label.get_part_by_tex("v").copy(),
|
|
v_T_label,
|
|
run_time = 2
|
|
))
|
|
self.wait()
|
|
self.play(Indicate(dT_label))
|
|
self.wait()
|
|
|
|
self.rect = rect
|
|
self.dT_label_group = dT_label_group
|
|
self.v_T_label_group = VGroup(v_T_label, v_brace)
|
|
self.dark_area = dark_area
|
|
self.ds_label = ds_label
|
|
self.ds_arrow = ds_arrow
|
|
|
|
def show_rectangle_approximation(self):
|
|
formula1 = TexMobject("ds", "=", "v(T)", "dT")
|
|
formula2 = TexMobject("{ds", "\\over\\,", "dT}", "=", "v(T)")
|
|
for formula in formula1, formula2:
|
|
formula.next_to(self.v_graph_label, UP, LARGE_BUFF)
|
|
formula.set_color_by_tex("ds", DISTANCE_COLOR)
|
|
|
|
self.play(
|
|
DrawBorderThenFill(self.rect),
|
|
Animation(self.ds_arrow)
|
|
)
|
|
self.wait()
|
|
self.play(*[
|
|
ReplacementTransform(
|
|
mob, formula1.get_part_by_tex(tex),
|
|
run_time = 2
|
|
)
|
|
for mob, tex in [
|
|
(self.ds_label, "ds"),
|
|
(self.ds_arrow, "="),
|
|
(self.v_T_label_group[0].copy(), "v(T)"),
|
|
(self.dT_label_group[0].copy(), "dT"),
|
|
]
|
|
])
|
|
self.wait()
|
|
self.transition_to_alt_config(
|
|
dT = self.dT/5.0,
|
|
transformation_kwargs = {"run_time" : 2},
|
|
)
|
|
self.wait()
|
|
self.play(*[
|
|
ReplacementTransform(
|
|
formula1.get_part_by_tex(tex),
|
|
formula2.get_part_by_tex(tex),
|
|
)
|
|
for tex in ("ds", "=", "v(T)", "dT")
|
|
] + [
|
|
Write(formula2.get_part_by_tex("over"))
|
|
])
|
|
self.wait()
|
|
|
|
|
|
####
|
|
|
|
def add_T_label(self, x_val, **kwargs):
|
|
triangle = RegularPolygon(n=3, start_angle = np.pi/2)
|
|
triangle.set_height(MED_SMALL_BUFF)
|
|
triangle.move_to(self.coords_to_point(x_val, 0), UP)
|
|
triangle.set_fill(WHITE, 1)
|
|
triangle.set_stroke(width = 0)
|
|
T_label = TexMobject(self.variable_point_label)
|
|
T_label.next_to(triangle, DOWN)
|
|
v_line = self.get_vertical_line_to_graph(
|
|
x_val, self.v_graph,
|
|
color = YELLOW
|
|
)
|
|
|
|
self.play(
|
|
DrawBorderThenFill(triangle),
|
|
ShowCreation(v_line),
|
|
Write(T_label, run_time = 1),
|
|
**kwargs
|
|
)
|
|
|
|
self.T_label_group = VGroup(T_label, triangle)
|
|
self.right_v_line = v_line
|
|
|
|
def get_area(self, t_min, t_max):
|
|
numerator = max(t_max - t_min, 0.01)
|
|
dx = float(numerator) / self.num_rects
|
|
return self.get_riemann_rectangles(
|
|
self.v_graph,
|
|
x_min = t_min,
|
|
x_max = t_max,
|
|
dx = dx,
|
|
stroke_width = 0,
|
|
).set_fill(opacity = self.area_opacity)
|
|
|
|
def change_area_bounds(self, new_t_min = None, new_t_max = None, **kwargs):
|
|
curr_t_min = self.x_axis.point_to_number(self.area.get_left())
|
|
curr_t_max = self.x_axis.point_to_number(self.area.get_right())
|
|
if new_t_min is None:
|
|
new_t_min = curr_t_min
|
|
if new_t_max is None:
|
|
new_t_max = curr_t_max
|
|
|
|
group = VGroup(self.area, self.right_v_line, self.T_label_group)
|
|
def update_group(group, alpha):
|
|
area, v_line, T_label = group
|
|
t_min = interpolate(curr_t_min, new_t_min, alpha)
|
|
t_max = interpolate(curr_t_max, new_t_max, alpha)
|
|
new_area = self.get_area(t_min, t_max)
|
|
new_v_line = self.get_vertical_line_to_graph(
|
|
t_max, self.v_graph
|
|
)
|
|
new_v_line.set_color(v_line.get_color())
|
|
T_label.move_to(new_v_line.get_bottom(), UP)
|
|
|
|
#Fade close to 0
|
|
T_label[0].set_fill(opacity = min(1, t_max))
|
|
|
|
Transform(area, new_area).update(1)
|
|
Transform(v_line, new_v_line).update(1)
|
|
return group
|
|
|
|
self.play(
|
|
UpdateFromAlphaFunc(group, update_group),
|
|
*list(map(Animation, self.foreground_mobjects)),
|
|
**kwargs
|
|
)
|
|
|
|
class DirectInterpretationOfDsDt(TeacherStudentsScene):
|
|
def construct(self):
|
|
equation = TexMobject("{ds", "\\over\\,", "dT}", "(T)", "=", "v(T)")
|
|
ds, over, dt, of_T, equals, v = equation
|
|
equation.next_to(self.get_pi_creatures(), UP, LARGE_BUFF)
|
|
equation.shift(RIGHT)
|
|
v.set_color(VELOCITY_COLOR)
|
|
|
|
s_words = TextMobject("Tiny change in", "distance")
|
|
s_words.next_to(ds, UP+LEFT, LARGE_BUFF)
|
|
s_words.shift_onto_screen()
|
|
s_arrow = Arrow(s_words[1].get_bottom(), ds.get_left())
|
|
s_words.add(s_arrow)
|
|
s_words.set_color(DISTANCE_COLOR)
|
|
|
|
t_words = TextMobject("Tiny change in", "time")
|
|
t_words.next_to(dt, DOWN+LEFT)
|
|
t_words.to_edge(LEFT)
|
|
t_arrow = Arrow(t_words[1].get_top(), dt.get_left())
|
|
t_words.add(t_arrow)
|
|
t_words.set_color(TIME_COLOR)
|
|
|
|
self.add(ds, over, dt, of_T)
|
|
for words, part in (s_words, ds), (t_words, dt):
|
|
self.play(
|
|
FadeIn(
|
|
words,
|
|
run_time = 2,
|
|
lag_ratio = 0.5,
|
|
),
|
|
self.students[1].change_mode, "raise_right_hand"
|
|
)
|
|
self.play(part.set_color, words.get_color())
|
|
self.wait()
|
|
self.play(Write(VGroup(equals, v)))
|
|
self.change_student_modes(*["pondering"]*3)
|
|
self.wait(3)
|
|
|
|
class FindAntiderivative(Antiderivative):
|
|
def construct(self):
|
|
self.introduce()
|
|
self.first_part()
|
|
self.second_part()
|
|
self.combine()
|
|
self.add_plus_C()
|
|
|
|
def introduce(self):
|
|
q_marks, rhs = functions = self.get_functions("???", "t(8-t)")
|
|
expanded_rhs = TexMobject("8t - t^2")
|
|
expanded_rhs.move_to(rhs, LEFT)
|
|
expanded_rhs.set_color(rhs.get_color())
|
|
self.v_part1 = VGroup(*expanded_rhs[:2])
|
|
self.v_part2 = VGroup(*expanded_rhs[2:])
|
|
for part in self.v_part1, self.v_part2:
|
|
part.save_state()
|
|
|
|
top_arc, bottom_arc = arcs = self.get_arcs(functions)
|
|
derivative, antiderivative = words = self.get_arc_labels(arcs)
|
|
|
|
self.add(functions)
|
|
self.play(*list(map(ShowCreation, arcs)))
|
|
for word in words:
|
|
self.play(FadeIn(word, lag_ratio = 0.5))
|
|
self.wait()
|
|
self.change_mode("confused")
|
|
self.wait(2)
|
|
self.play(*[
|
|
ReplacementTransform(
|
|
rhs[i], expanded_rhs[j],
|
|
run_time = 2,
|
|
path_arc = np.pi
|
|
)
|
|
for i, j in enumerate([1, 4, 0, 2, 3, 4])
|
|
]+[
|
|
self.pi_creature.change_mode, "hesitant"
|
|
])
|
|
self.wait()
|
|
|
|
self.q_marks = q_marks
|
|
self.arcs = arcs
|
|
self.words = words
|
|
|
|
def first_part(self):
|
|
four_t_squared, two_t = self.get_functions("4t^2", "2t")
|
|
four = four_t_squared[0]
|
|
four.shift(UP)
|
|
four.set_fill(opacity = 0)
|
|
t_squared = VGroup(*four_t_squared[1:])
|
|
two_t.move_to(self.v_part1, LEFT)
|
|
|
|
self.play(self.v_part2.to_corner, UP+RIGHT)
|
|
self.play(
|
|
self.pi_creature.change, "plain", self.v_part1
|
|
)
|
|
self.play(ApplyWave(
|
|
self.q_marks,
|
|
direction = UP,
|
|
amplitude = SMALL_BUFF
|
|
))
|
|
self.wait(2)
|
|
self.play(
|
|
FadeOut(self.q_marks),
|
|
FadeIn(t_squared),
|
|
self.v_part1.shift, DOWN+RIGHT,
|
|
)
|
|
self.play(*[
|
|
ReplacementTransform(
|
|
t_squared[i].copy(), two_t[1-i],
|
|
run_time = 2,
|
|
path_arc = -np.pi/6.
|
|
)
|
|
for i in (0, 1)
|
|
])
|
|
self.change_mode("thinking")
|
|
self.wait()
|
|
self.play(four.set_fill, YELLOW, 1)
|
|
self.play(four.shift, DOWN)
|
|
self.play(FadeOut(two_t))
|
|
self.play(self.v_part1.restore)
|
|
self.play(four.set_color, DISTANCE_COLOR)
|
|
self.wait(2)
|
|
|
|
self.s_part1 = four_t_squared
|
|
|
|
def second_part(self):
|
|
self.arcs_copy = self.arcs.copy()
|
|
self.words_copy = self.words.copy()
|
|
part1_group = VGroup(
|
|
self.s_part1, self.v_part1,
|
|
self.arcs_copy, self.words_copy
|
|
)
|
|
|
|
neg_third_t_cubed, three_t_squared = self.get_functions(
|
|
"- \\frac{1}{3} t^3", "3t^2"
|
|
)
|
|
three_t_squared.move_to(self.v_part1, LEFT)
|
|
neg = neg_third_t_cubed[0]
|
|
third = VGroup(*neg_third_t_cubed[1:4])
|
|
t_cubed = VGroup(*neg_third_t_cubed[4:])
|
|
three = three_t_squared[0]
|
|
t_squared = VGroup(*three_t_squared[1:])
|
|
|
|
self.play(
|
|
part1_group.scale, 0.5,
|
|
part1_group.to_corner, UP+LEFT,
|
|
self.pi_creature.change_mode, "plain"
|
|
)
|
|
self.play(
|
|
self.v_part2.restore,
|
|
self.v_part2.shift, LEFT
|
|
)
|
|
self.play(FadeIn(self.q_marks))
|
|
self.wait()
|
|
|
|
self.play(
|
|
FadeOut(self.q_marks),
|
|
FadeIn(t_cubed),
|
|
self.v_part2.shift, DOWN+RIGHT
|
|
)
|
|
self.play(*[
|
|
ReplacementTransform(
|
|
t_cubed[i].copy(), three_t_squared[j],
|
|
path_arc = -np.pi/6,
|
|
run_time = 2,
|
|
)
|
|
for i, j in [(0, 1), (1, 0), (1, 2)]
|
|
])
|
|
self.wait()
|
|
self.play(FadeIn(third))
|
|
self.play(FadeOut(three))
|
|
self.wait(2)
|
|
self.play(Write(neg))
|
|
self.play(
|
|
FadeOut(t_squared),
|
|
self.v_part2.shift, UP+LEFT
|
|
)
|
|
self.wait(2)
|
|
|
|
self.s_part2 = neg_third_t_cubed
|
|
|
|
def combine(self):
|
|
self.play(
|
|
self.v_part1.restore,
|
|
self.v_part2.restore,
|
|
self.s_part1.scale, 2,
|
|
self.s_part1.next_to, self.s_part2, LEFT,
|
|
FadeOut(self.arcs_copy),
|
|
FadeOut(self.words_copy),
|
|
run_time = 2,
|
|
)
|
|
self.change_mode("happy")
|
|
self.wait(2)
|
|
|
|
def add_plus_C(self):
|
|
s_group = VGroup(self.s_part1, self.s_part2)
|
|
plus_Cs = [
|
|
TexMobject("+%d"%d)
|
|
for d in range(1, 8)
|
|
]
|
|
for plus_C in plus_Cs:
|
|
plus_C.set_color(YELLOW)
|
|
plus_C.move_to(s_group, RIGHT)
|
|
plus_C = plus_Cs[0]
|
|
|
|
self.change_mode("sassy")
|
|
self.wait()
|
|
self.play(
|
|
s_group.next_to, plus_C.copy(), LEFT,
|
|
GrowFromCenter(plus_C),
|
|
)
|
|
self.wait()
|
|
for new_plus_C in plus_Cs[1:]:
|
|
self.play(Transform(plus_C, new_plus_C))
|
|
self.wait()
|
|
|
|
class GraphSPlusC(GraphDistanceVsTime):
|
|
CONFIG = {
|
|
"y_axis_label" : "Distance"
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
graph = self.get_graph(
|
|
s_func,
|
|
color = DISTANCE_COLOR,
|
|
x_min = 0,
|
|
x_max = 8,
|
|
)
|
|
tangent = self.get_secant_slope_group(
|
|
6, graph, dx = 0.01
|
|
).secant_line
|
|
v_line = self.get_vertical_line_to_graph(
|
|
6, graph, line_class = DashedLine
|
|
)
|
|
v_line.scale_in_place(2)
|
|
v_line.set_color(WHITE)
|
|
graph_label, plus_C = full_label = TexMobject(
|
|
"s(t) = 4t^2 - \\frac{1}{3}t^3", "+C"
|
|
)
|
|
plus_C.set_color(YELLOW)
|
|
full_label.next_to(graph.points[-1], DOWN)
|
|
full_label.to_edge(RIGHT)
|
|
|
|
self.play(ShowCreation(graph))
|
|
self.play(FadeIn(graph_label))
|
|
self.wait()
|
|
self.play(
|
|
graph.shift, UP,
|
|
run_time = 2,
|
|
rate_func = there_and_back
|
|
)
|
|
self.play(ShowCreation(tangent))
|
|
graph.add(tangent)
|
|
self.play(ShowCreation(v_line))
|
|
self.play(
|
|
graph.shift, 2*DOWN,
|
|
run_time = 4,
|
|
rate_func = there_and_back,
|
|
)
|
|
self.play(Write(plus_C))
|
|
self.play(
|
|
graph.shift, 2*UP,
|
|
rate_func = there_and_back,
|
|
run_time = 4,
|
|
)
|
|
self.wait()
|
|
|
|
class LowerBound(AreaIsDerivative):
|
|
CONFIG = {
|
|
"graph_origin" : 2.5*DOWN + 6*LEFT
|
|
}
|
|
|
|
def construct(self):
|
|
self.add_integral_and_area()
|
|
self.mention_lower_bound()
|
|
self.drag_right_endpoint_to_zero()
|
|
self.write_antiderivative_difference()
|
|
self.show_alternate_antiderivative_difference()
|
|
self.add_constant_to_antiderivative()
|
|
|
|
def add_integral_and_area(self):
|
|
self.area = self.get_area(0, 6)
|
|
self.integral = self.get_integral("0", "T")
|
|
self.remove(self.x_axis.numbers)
|
|
self.add(self.area, self.integral)
|
|
self.add_T_label(6, run_time = 0)
|
|
|
|
def mention_lower_bound(self):
|
|
lower_bound = self.integral.get_part_by_tex("0")
|
|
circle = Circle(color = YELLOW)
|
|
circle.replace(lower_bound)
|
|
circle.scale_in_place(3)
|
|
zero_label = lower_bound.copy()
|
|
|
|
self.play(ShowCreation(circle))
|
|
self.play(Indicate(lower_bound))
|
|
self.play(
|
|
zero_label.scale, 1.5,
|
|
zero_label.next_to, self.graph_origin, DOWN, MED_LARGE_BUFF,
|
|
FadeOut(circle)
|
|
)
|
|
self.wait()
|
|
|
|
self.zero_label = zero_label
|
|
|
|
def drag_right_endpoint_to_zero(self):
|
|
zero_integral = self.get_integral("0", "0")
|
|
zero_integral[1].set_color(YELLOW)
|
|
zero_int_bounds = list(reversed(
|
|
zero_integral.get_parts_by_tex("0")
|
|
))
|
|
for bound in zero_int_bounds:
|
|
circle = Circle(color = YELLOW)
|
|
circle.replace(bound)
|
|
circle.scale_in_place(3)
|
|
bound.circle = circle
|
|
self.integral.save_state()
|
|
equals_zero = TexMobject("=0")
|
|
equals_zero.next_to(zero_integral, RIGHT)
|
|
equals_zero.set_color(GREEN)
|
|
|
|
self.change_area_bounds(0, 0, run_time = 3)
|
|
self.play(ReplacementTransform(
|
|
self.zero_label.copy(), equals_zero
|
|
))
|
|
self.play(Transform(self.integral, zero_integral))
|
|
self.wait(2)
|
|
for bound in zero_int_bounds:
|
|
self.play(ShowCreation(bound.circle))
|
|
self.play(FadeOut(bound.circle))
|
|
self.play(*[
|
|
ReplacementTransform(
|
|
bound.copy(), VGroup(equals_zero[1])
|
|
)
|
|
for bound in zero_int_bounds
|
|
])
|
|
self.wait(2)
|
|
self.change_area_bounds(0, 5)
|
|
self.play(
|
|
self.integral.restore,
|
|
FadeOut(equals_zero)
|
|
)
|
|
|
|
self.zero_integral = zero_integral
|
|
|
|
def write_antiderivative_difference(self):
|
|
antideriv_diff = self.get_antiderivative_difference("0", "T")
|
|
equals, at_T, minus, at_zero = antideriv_diff
|
|
antideriv_diff_at_eight = self.get_antiderivative_difference("0", "8")
|
|
at_eight = antideriv_diff_at_eight.left_part
|
|
integral_at_eight = self.get_integral("0", "8")
|
|
|
|
for part in at_T, at_zero, at_eight:
|
|
part.brace = Brace(part, DOWN, buff = SMALL_BUFF)
|
|
part.brace.save_state()
|
|
|
|
antideriv_text = at_T.brace.get_text("Antiderivative", buff = SMALL_BUFF)
|
|
antideriv_text.set_color(MAROON_B)
|
|
value_at_eight = at_eight.brace.get_text(
|
|
"%.2f"%s_func(8)
|
|
)
|
|
happens_to_be_zero = at_zero.brace.get_text("""
|
|
Happens to
|
|
equal 0
|
|
""")
|
|
|
|
big_brace = Brace(VGroup(at_T, at_zero))
|
|
cancel_text = big_brace.get_text("Cancels when $T=0$")
|
|
|
|
self.play(*list(map(Write, [equals, at_T])))
|
|
self.play(
|
|
GrowFromCenter(at_T.brace),
|
|
Write(antideriv_text, run_time = 2)
|
|
)
|
|
self.change_area_bounds(0, 5.5, rate_func = there_and_back)
|
|
self.wait()
|
|
self.play(
|
|
ReplacementTransform(at_T.copy(), at_zero),
|
|
Write(minus)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
ReplacementTransform(at_T.brace, big_brace),
|
|
ReplacementTransform(antideriv_text, cancel_text)
|
|
)
|
|
self.change_area_bounds(0, 0, run_time = 4)
|
|
self.wait()
|
|
self.play(
|
|
ReplacementTransform(big_brace, at_zero.brace),
|
|
ReplacementTransform(cancel_text, happens_to_be_zero),
|
|
)
|
|
self.wait(2)
|
|
self.change_area_bounds(0, 8, run_time = 2)
|
|
self.play(
|
|
Transform(self.integral, integral_at_eight),
|
|
Transform(antideriv_diff, antideriv_diff_at_eight),
|
|
MaintainPositionRelativeTo(at_zero.brace, at_zero),
|
|
MaintainPositionRelativeTo(happens_to_be_zero, at_zero.brace),
|
|
)
|
|
self.play(
|
|
GrowFromCenter(at_eight.brace),
|
|
Write(value_at_eight)
|
|
)
|
|
self.wait(2)
|
|
self.play(*list(map(FadeOut, [
|
|
at_eight.brace, value_at_eight,
|
|
at_zero.brace, happens_to_be_zero,
|
|
])))
|
|
|
|
self.antideriv_diff = antideriv_diff
|
|
|
|
def show_alternate_antiderivative_difference(self):
|
|
new_integral = self.get_integral("1", "7")
|
|
new_antideriv_diff = self.get_antiderivative_difference("1", "7")
|
|
numbers = [
|
|
TexMobject("%d"%d).next_to(
|
|
self.coords_to_point(d, 0),
|
|
DOWN, MED_LARGE_BUFF
|
|
)
|
|
for d in (1, 7)
|
|
]
|
|
tex_mobs = [new_integral]+new_antideriv_diff[1::2]+numbers
|
|
for tex_mob in tex_mobs:
|
|
tex_mob.set_color_by_tex("1", RED)
|
|
tex_mob.set_color_by_tex("7", GREEN)
|
|
tex_mob.set_color_by_tex("\\frac{1}{3}", WHITE)
|
|
|
|
self.change_area_bounds(1, 7, run_time = 2)
|
|
self.play(
|
|
self.T_label_group[0].set_fill, None, 0,
|
|
*list(map(FadeIn, numbers))
|
|
)
|
|
self.play(
|
|
Transform(self.integral, new_integral),
|
|
Transform(self.antideriv_diff, new_antideriv_diff),
|
|
)
|
|
self.wait(3)
|
|
for part in self.antideriv_diff[1::2]:
|
|
self.play(Indicate(part, scale_factor = 1.1))
|
|
self.wait()
|
|
|
|
def add_constant_to_antiderivative(self):
|
|
antideriv_diff = self.antideriv_diff
|
|
plus_fives = VGroup(*[TexMobject("+5") for i in range(2)])
|
|
plus_fives.set_color(YELLOW)
|
|
for five, part in zip(plus_fives, antideriv_diff[1::2]):
|
|
five.next_to(part, DOWN)
|
|
group = VGroup(
|
|
plus_fives[0],
|
|
antideriv_diff[2].copy(),
|
|
plus_fives[1]
|
|
)
|
|
|
|
self.play(Write(plus_fives, run_time = 2))
|
|
self.wait(2)
|
|
self.play(
|
|
group.arrange,
|
|
group.next_to, antideriv_diff, DOWN, MED_LARGE_BUFF
|
|
)
|
|
self.wait()
|
|
self.play(FadeOut(group, run_time = 2))
|
|
self.wait()
|
|
|
|
#####
|
|
|
|
def get_integral(self, lower_bound, upper_bound):
|
|
result = TexMobject(
|
|
"\\int", "^"+upper_bound, "_"+lower_bound,
|
|
"t(8-t)", "\\,dt"
|
|
)
|
|
result.next_to(self.graph_origin, RIGHT, MED_LARGE_BUFF)
|
|
result.to_edge(UP)
|
|
return result
|
|
|
|
def get_antiderivative_difference(self, lower_bound, upper_bound):
|
|
strings = []
|
|
for bound in upper_bound, lower_bound:
|
|
try:
|
|
d = int(bound)
|
|
strings.append("(%d)"%d)
|
|
except:
|
|
strings.append(bound)
|
|
parts = []
|
|
for s in strings:
|
|
part = TexMobject(
|
|
"\\left(",
|
|
"4", s, "^2", "-", "\\frac{1}{3}", s, "^3"
|
|
"\\right))"
|
|
)
|
|
part.set_color_by_tex(s, YELLOW, substring = False)
|
|
parts.append(part)
|
|
result = VGroup(
|
|
TexMobject("="), parts[0],
|
|
TexMobject("-"), parts[1],
|
|
)
|
|
result.left_part, result.right_part = parts
|
|
result.arrange(RIGHT)
|
|
result.scale(0.9)
|
|
result.next_to(self.integral, RIGHT)
|
|
return result
|
|
|
|
class FundamentalTheorem(GraphScene):
|
|
CONFIG = {
|
|
"lower_bound" : 1,
|
|
"upper_bound" : 7,
|
|
"lower_bound_color" : RED,
|
|
"upper_bound_color" : GREEN,
|
|
"n_riemann_iterations" : 6,
|
|
}
|
|
|
|
def construct(self):
|
|
self.add_graph_and_integral()
|
|
self.show_f_dx_sum()
|
|
self.show_rects_approaching_area()
|
|
self.write_antiderivative()
|
|
self.write_fundamental_theorem_of_calculus()
|
|
self.show_integral_considering_continuum()
|
|
self.show_antiderivative_considering_bounds()
|
|
|
|
def add_graph_and_integral(self):
|
|
self.setup_axes()
|
|
integral = TexMobject("\\int", "^b", "_a", "f(x)", "\\,dx")
|
|
integral.next_to(ORIGIN, LEFT)
|
|
integral.to_edge(UP)
|
|
integral.set_color_by_tex("a", self.lower_bound_color)
|
|
integral.set_color_by_tex("b", self.upper_bound_color)
|
|
graph = self.get_graph(
|
|
lambda x : -0.01*x*(x-3)*(x-6)*(x-12) + 3,
|
|
)
|
|
self.add(integral, graph)
|
|
self.graph = graph
|
|
self.integral = integral
|
|
|
|
self.bound_labels = VGroup()
|
|
self.v_lines = VGroup()
|
|
for bound, tex in (self.lower_bound, "a"), (self.upper_bound, "b"):
|
|
label = integral.get_part_by_tex(tex).copy()
|
|
label.scale(1.5)
|
|
label.next_to(self.coords_to_point(bound, 0), DOWN)
|
|
v_line = self.get_vertical_line_to_graph(
|
|
bound, graph, color = label.get_color()
|
|
)
|
|
|
|
self.bound_labels.add(label)
|
|
self.v_lines.add(v_line)
|
|
self.add(label, v_line)
|
|
|
|
def show_f_dx_sum(self):
|
|
kwargs = {
|
|
"x_min" : self.lower_bound,
|
|
"x_max" : self.upper_bound,
|
|
"fill_opacity" : 0.75,
|
|
"stroke_width" : 0.25,
|
|
}
|
|
low_opacity = 0.25
|
|
start_rect_index = 3
|
|
num_shown_sum_steps = 5
|
|
last_rect_index = start_rect_index + num_shown_sum_steps + 1
|
|
|
|
self.rect_list = self.get_riemann_rectangles_list(
|
|
self.graph, self.n_riemann_iterations, **kwargs
|
|
)
|
|
rects = self.rects = self.rect_list[0]
|
|
rects.save_state()
|
|
|
|
start_rect = rects[start_rect_index]
|
|
f_brace = Brace(start_rect, LEFT, buff = 0)
|
|
dx_brace = Brace(start_rect, DOWN, buff = 0)
|
|
f_brace.label = f_brace.get_text("$f(x)$")
|
|
dx_brace.label = dx_brace.get_text("$dx$")
|
|
|
|
flat_rects = self.get_riemann_rectangles(
|
|
self.get_graph(lambda x : 0), dx = 0.5, **kwargs
|
|
)
|
|
|
|
self.transform_between_riemann_rects(
|
|
flat_rects, rects,
|
|
replace_mobject_with_target_in_scene = True,
|
|
)
|
|
self.play(*[
|
|
ApplyMethod(
|
|
rect.set_fill, None,
|
|
1 if rect is start_rect else low_opacity
|
|
)
|
|
for rect in rects
|
|
])
|
|
self.play(*it.chain(
|
|
list(map(GrowFromCenter, [f_brace, dx_brace])),
|
|
list(map(Write, [f_brace.label, dx_brace.label])),
|
|
))
|
|
self.wait()
|
|
for i in range(start_rect_index+1, last_rect_index):
|
|
self.play(
|
|
rects[i-1].set_fill, None, low_opacity,
|
|
rects[i].set_fill, None, 1,
|
|
f_brace.set_height, rects[i].get_height(),
|
|
f_brace.next_to, rects[i], LEFT, 0,
|
|
dx_brace.next_to, rects[i], DOWN, 0,
|
|
*[
|
|
MaintainPositionRelativeTo(brace.label, brace)
|
|
for brace in (f_brace, dx_brace)
|
|
]
|
|
)
|
|
self.wait()
|
|
self.play(*it.chain(
|
|
list(map(FadeOut, [
|
|
f_brace, dx_brace,
|
|
f_brace.label, dx_brace.label
|
|
])),
|
|
[rects.set_fill, None, kwargs["fill_opacity"]]
|
|
))
|
|
|
|
def show_rects_approaching_area(self):
|
|
for new_rects in self.rect_list:
|
|
self.transform_between_riemann_rects(
|
|
self.rects, new_rects
|
|
)
|
|
|
|
def write_antiderivative(self):
|
|
deriv = TexMobject(
|
|
"{d", "F", "\\over\\,", "dx}", "(x)", "=", "f(x)"
|
|
)
|
|
deriv_F = deriv.get_part_by_tex("F")
|
|
deriv.next_to(self.integral, DOWN, MED_LARGE_BUFF)
|
|
rhs = TexMobject(*"=F(b)-F(a)")
|
|
rhs.set_color_by_tex("a", self.lower_bound_color)
|
|
rhs.set_color_by_tex("b", self.upper_bound_color)
|
|
rhs.next_to(self.integral, RIGHT)
|
|
|
|
self.play(Write(deriv))
|
|
self.wait(2)
|
|
self.play(*it.chain(
|
|
[
|
|
ReplacementTransform(deriv_F.copy(), part)
|
|
for part in rhs.get_parts_by_tex("F")
|
|
],
|
|
[
|
|
Write(VGroup(*rhs.get_parts_by_tex(tex)))
|
|
for tex in "=()-"
|
|
]
|
|
))
|
|
for tex in "b", "a":
|
|
self.play(ReplacementTransform(
|
|
self.integral.get_part_by_tex(tex).copy(),
|
|
rhs.get_part_by_tex(tex)
|
|
))
|
|
self.wait()
|
|
self.wait(2)
|
|
|
|
self.deriv = deriv
|
|
self.rhs = rhs
|
|
|
|
def write_fundamental_theorem_of_calculus(self):
|
|
words = TextMobject("""
|
|
Fundamental
|
|
theorem of
|
|
calculus
|
|
""")
|
|
words.to_edge(RIGHT)
|
|
|
|
self.play(Write(words))
|
|
self.wait()
|
|
|
|
def show_integral_considering_continuum(self):
|
|
self.play(*[
|
|
ApplyMethod(mob.set_fill, None, 0.2)
|
|
for mob in (self.deriv, self.rhs)
|
|
])
|
|
self.play(
|
|
self.rects.restore,
|
|
run_time = 3,
|
|
rate_func = there_and_back
|
|
)
|
|
self.wait()
|
|
for x in range(2):
|
|
self.play(*[
|
|
ApplyFunction(
|
|
lambda m : m.shift(MED_SMALL_BUFF*UP).set_fill(opacity = 1),
|
|
rect,
|
|
run_time = 3,
|
|
rate_func = squish_rate_func(
|
|
there_and_back,
|
|
alpha, alpha+0.2
|
|
)
|
|
)
|
|
for rect, alpha in zip(
|
|
self.rects,
|
|
np.linspace(0, 0.8, len(self.rects))
|
|
)
|
|
])
|
|
self.wait()
|
|
|
|
def show_antiderivative_considering_bounds(self):
|
|
self.play(
|
|
self.integral.set_fill, None, 0.5,
|
|
self.deriv.set_fill, None, 1,
|
|
self.rhs.set_fill, None, 1,
|
|
)
|
|
for label, line in reversed(list(zip(self.bound_labels, self.v_lines))):
|
|
new_line = line.copy().set_color(YELLOW)
|
|
label.save_state()
|
|
self.play(label.set_color, YELLOW)
|
|
self.play(ShowCreation(new_line))
|
|
self.play(ShowCreation(line))
|
|
self.remove(new_line)
|
|
self.play(label.restore)
|
|
self.wait()
|
|
self.play(self.integral.set_fill, None, 1)
|
|
self.wait(3)
|
|
|
|
class LetsRecap(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.teacher_says(
|
|
"Let's recap",
|
|
target_mode = "hesitant",
|
|
)
|
|
self.change_student_modes(*["happy"]*3)
|
|
self.wait(3)
|
|
|
|
class NegativeArea(GraphScene):
|
|
CONFIG = {
|
|
"x_axis_label" : "Time",
|
|
"y_axis_label" : "Velocity",
|
|
"graph_origin" : 1.5*DOWN + 5*LEFT,
|
|
"y_min" : -3,
|
|
"y_max" : 7,
|
|
"small_dx" : 0.01,
|
|
"sample_input" : 5,
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
self.add_graph_and_area()
|
|
self.write_negative_area()
|
|
self.show_negative_point()
|
|
self.show_car_going_backwards()
|
|
self.write_v_dt()
|
|
self.show_rectangle()
|
|
self.write_signed_area()
|
|
|
|
def add_graph_and_area(self):
|
|
graph = self.get_graph(
|
|
lambda x : -0.02*(x+1)*(x-3)*(x-7)*(x-10),
|
|
x_min = 0,
|
|
x_max = 8,
|
|
color = VELOCITY_COLOR
|
|
)
|
|
area = self.get_riemann_rectangles(
|
|
graph,
|
|
x_min = 0,
|
|
x_max = 8,
|
|
dx = self.small_dx,
|
|
start_color = BLUE_D,
|
|
end_color = BLUE_D,
|
|
fill_opacity = 0.75,
|
|
stroke_width = 0,
|
|
)
|
|
|
|
self .play(
|
|
ShowCreation(graph),
|
|
FadeIn(
|
|
area,
|
|
run_time = 2,
|
|
lag_ratio = 0.5,
|
|
)
|
|
)
|
|
|
|
self.graph = graph
|
|
self.area = area
|
|
|
|
def write_negative_area(self):
|
|
words = TextMobject("Negative area")
|
|
words.set_color(RED)
|
|
words.next_to(
|
|
self.coords_to_point(7, -2),
|
|
RIGHT,
|
|
)
|
|
arrow = Arrow(words, self.coords_to_point(
|
|
self.sample_input, -1,
|
|
))
|
|
|
|
self.play(
|
|
Write(words, run_time = 2),
|
|
ShowCreation(arrow)
|
|
)
|
|
self.wait(2)
|
|
self.play(*list(map(FadeOut, [self.area, arrow])))
|
|
|
|
self.negative_area_words = words
|
|
|
|
def show_negative_point(self):
|
|
v_line = self.get_vertical_line_to_graph(
|
|
self.sample_input, self.graph,
|
|
color = RED
|
|
)
|
|
self.play(ShowCreation(v_line))
|
|
self.wait()
|
|
self.v_line = v_line
|
|
|
|
def show_car_going_backwards(self):
|
|
car = Car()
|
|
start_point = 3*RIGHT + 2*UP
|
|
end_point = start_point + LEFT
|
|
nudged_end_point = end_point + MED_SMALL_BUFF*LEFT
|
|
car.move_to(start_point)
|
|
arrow = Arrow(RIGHT, LEFT, color = RED)
|
|
arrow.next_to(car, UP+LEFT)
|
|
arrow.shift(MED_LARGE_BUFF*RIGHT)
|
|
|
|
self.play(FadeIn(car))
|
|
self.play(ShowCreation(arrow))
|
|
self.play(MoveCar(
|
|
car, end_point,
|
|
moving_forward = False,
|
|
run_time = 3
|
|
))
|
|
self.wait()
|
|
ghost_car = car.copy().fade()
|
|
right_nose_line = self.get_car_nose_line(car)
|
|
self.play(ShowCreation(right_nose_line))
|
|
self.add(ghost_car)
|
|
self.play(MoveCar(
|
|
car, nudged_end_point,
|
|
moving_forward = False
|
|
))
|
|
left_nose_line = self.get_car_nose_line(car)
|
|
self.play(ShowCreation(left_nose_line))
|
|
|
|
self.nose_lines = VGroup(left_nose_line, right_nose_line)
|
|
self.car = car
|
|
self.ghost_car = ghost_car
|
|
|
|
def write_v_dt(self):
|
|
brace = Brace(self.nose_lines, DOWN, buff = 0)
|
|
equation = TexMobject("ds", "=", "v(t)", "dt")
|
|
equation.next_to(brace, DOWN, SMALL_BUFF, LEFT)
|
|
equation.set_color_by_tex("ds", DISTANCE_COLOR)
|
|
equation.set_color_by_tex("dt", TIME_COLOR)
|
|
|
|
negative = TextMobject("Negative")
|
|
negative.set_color(RED)
|
|
negative.next_to(equation.get_corner(UP+RIGHT), UP, LARGE_BUFF)
|
|
ds_arrow, v_arrow = arrows = VGroup(*[
|
|
Arrow(
|
|
negative.get_bottom(),
|
|
equation.get_part_by_tex(tex).get_top(),
|
|
color = RED,
|
|
)
|
|
for tex in ("ds", "v(t)")
|
|
])
|
|
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
Write(equation)
|
|
)
|
|
self.wait()
|
|
self.play(FadeIn(negative))
|
|
self.play(ShowCreation(v_arrow))
|
|
self.wait(2)
|
|
self.play(ReplacementTransform(
|
|
v_arrow.copy(),
|
|
ds_arrow
|
|
))
|
|
self.wait(2)
|
|
|
|
self.ds_equation = equation
|
|
self.negative_word = negative
|
|
self.negative_word_arrows = arrows
|
|
|
|
def show_rectangle(self):
|
|
rect_list = self.get_riemann_rectangles_list(
|
|
self.graph, x_min = 0, x_max = 8,
|
|
n_iterations = 6,
|
|
start_color = BLUE_D,
|
|
end_color = BLUE_D,
|
|
fill_opacity = 0.75,
|
|
)
|
|
rects = rect_list[0]
|
|
rect = rects[len(rects)*self.sample_input//8]
|
|
|
|
dt_brace = Brace(rect, UP, buff = 0)
|
|
v_brace = Brace(rect, LEFT, buff = 0)
|
|
dt_label = dt_brace.get_text("$dt$", buff = SMALL_BUFF)
|
|
dt_label.set_color(YELLOW)
|
|
v_label = v_brace.get_text("$v(t)$", buff = SMALL_BUFF)
|
|
v_label.add_background_rectangle()
|
|
|
|
self.play(FadeOut(self.v_line), FadeIn(rect))
|
|
self.play(
|
|
GrowFromCenter(dt_brace),
|
|
GrowFromCenter(v_brace),
|
|
Write(dt_label),
|
|
Write(v_label),
|
|
)
|
|
self.wait(2)
|
|
self.play(*it.chain(
|
|
[FadeIn(r) for r in rects if r is not rect],
|
|
list(map(FadeOut, [
|
|
dt_brace, v_brace, dt_label, v_label
|
|
]))
|
|
))
|
|
self.wait()
|
|
for new_rects in rect_list[1:]:
|
|
self.transform_between_riemann_rects(rects, new_rects)
|
|
self.wait()
|
|
|
|
def write_signed_area(self):
|
|
words = TextMobject("``Signed area''")
|
|
words.next_to(self.coords_to_point(self.sample_input, 0), UP)
|
|
symbols = VGroup(*[
|
|
TexMobject(sym).move_to(self.coords_to_point(*coords))
|
|
for sym, coords in [
|
|
("+", (1, 2)),
|
|
("-", (5, -1)),
|
|
("+", (7.6, 0.5)),
|
|
]
|
|
])
|
|
self.play(Write(words))
|
|
self.play(Write(symbols))
|
|
self.wait()
|
|
|
|
####
|
|
|
|
def get_car_nose_line(self, car):
|
|
line = DashedLine(car.get_top(), car.get_bottom())
|
|
line.move_to(car.get_right())
|
|
return line
|
|
|
|
class NextVideo(TeacherStudentsScene):
|
|
def construct(self):
|
|
series = VideoSeries()
|
|
series.to_edge(UP)
|
|
next_video = series[8]
|
|
integral = TexMobject("\\int")
|
|
integral.next_to(next_video, DOWN, LARGE_BUFF)
|
|
|
|
self.play(FadeIn(series, lag_ratio = 0.5))
|
|
self.play(
|
|
next_video.set_color, YELLOW,
|
|
next_video.shift, next_video.get_height()*DOWN/2,
|
|
self.teacher.change_mode, "raise_right_hand"
|
|
)
|
|
self.play(Write(integral))
|
|
self.wait(5)
|
|
|
|
class Chapter8PatreonThanks(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",
|
|
"Dan Buchoff",
|
|
"Derek Dai",
|
|
"Joseph John Cox",
|
|
"Luc Ritchie",
|
|
"Robert Teed",
|
|
"Jason Hise",
|
|
"Meshal Alshammari",
|
|
"Bernd Sing",
|
|
"Nils Schneider",
|
|
"James Thornton",
|
|
"Mustafa Mahdi",
|
|
"Jonathan Eppele",
|
|
"Mathew Bramson",
|
|
"Jerry Ling",
|
|
"Mark Govea",
|
|
"Vecht",
|
|
"Shimin Kuang",
|
|
"Rish Kundalia",
|
|
"Achille Brighton",
|
|
"Ripta Pasay",
|
|
]
|
|
}
|
|
|
|
class Thumbnail(Chapter1Thumbnail):
|
|
CONFIG = {
|
|
"x_axis_label" : "",
|
|
"y_axis_label" : "",
|
|
"graph_origin" : 1.5*DOWN + 4*LEFT,
|
|
"y_axis_height" : 5,
|
|
"x_max" : 5,
|
|
"x_axis_width" : 11,
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
self.remove(*self.x_axis.numbers)
|
|
self.remove(*self.y_axis.numbers)
|
|
graph = self.get_graph(self.func)
|
|
rects = self.get_riemann_rectangles(
|
|
graph,
|
|
x_min = 0,
|
|
x_max = 4,
|
|
dx = 0.25,
|
|
)
|
|
words = TextMobject("Integrals")
|
|
words.set_width(8)
|
|
words.to_edge(UP)
|
|
|
|
self.add(graph, rects, words)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|