mirror of
https://github.com/3b1b/manim.git
synced 2025-07-28 12:32:36 +08:00
2169 lines
64 KiB
Python
2169 lines
64 KiB
Python
import scipy
|
|
import fractions
|
|
|
|
from manimlib.imports import *
|
|
|
|
class Chapter9OpeningQuote(OpeningQuote):
|
|
CONFIG = {
|
|
"quote" : [
|
|
"We often hear that mathematics consists mainly of",
|
|
"proving theorems.",
|
|
"Is a writer's job mainly that of\\\\",
|
|
"writing sentences?"
|
|
],
|
|
"highlighted_quote_terms" : {
|
|
"proving theorems." : MAROON_B,
|
|
"writing sentences?" : MAROON_B,
|
|
},
|
|
"author" : "Gian-Carlo Rota",
|
|
}
|
|
|
|
class AverageOfContinuousVariable(GraphScene):
|
|
CONFIG = {
|
|
"bounds" : [1, 7],
|
|
"bound_colors" : [RED, GREEN],
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
graph = self.get_graph(
|
|
lambda x : 0.1*x*(x-3)*(x-6) + 4
|
|
)
|
|
graph_label = self.get_graph_label(graph, "f(x)")
|
|
boundary_lines = self.get_vertical_lines_to_graph(
|
|
graph, *self.bounds, num_lines = 2,
|
|
line_class = DashedLine
|
|
)
|
|
for line, color in zip(boundary_lines, self.bound_colors):
|
|
line.set_color(color)
|
|
v_line = self.get_vertical_line_to_graph(
|
|
self.bounds[0], graph, color = YELLOW,
|
|
)
|
|
|
|
question = TextMobject(
|
|
"What is the average \\\\ value of $f(x)$?"
|
|
)
|
|
question.next_to(boundary_lines, UP)
|
|
|
|
self.play(ShowCreation(graph), Write(graph_label))
|
|
self.play(ShowCreation(boundary_lines))
|
|
self.play(FadeIn(
|
|
question,
|
|
run_time = 2,
|
|
lag_ratio = 0.5,
|
|
))
|
|
self.play(ShowCreation(v_line))
|
|
for bound in reversed(self.bounds):
|
|
self.play(self.get_v_line_change_anim(
|
|
v_line, graph, bound,
|
|
run_time = 3,
|
|
))
|
|
self.wait()
|
|
self.wait()
|
|
|
|
def get_v_line_change_anim(self, v_line, graph, target_x, **kwargs):
|
|
start_x = self.x_axis.point_to_number(v_line.get_bottom())
|
|
def update(v_line, alpha):
|
|
new_x = interpolate(start_x, target_x, alpha)
|
|
v_line.put_start_and_end_on(
|
|
self.coords_to_point(new_x, 0),
|
|
self.input_to_graph_point(new_x, graph)
|
|
)
|
|
return v_line
|
|
return UpdateFromAlphaFunc(v_line, update, **kwargs)
|
|
|
|
class ThisVideo(TeacherStudentsScene):
|
|
def construct(self):
|
|
series = VideoSeries()
|
|
series.to_edge(UP)
|
|
this_video = series[8]
|
|
|
|
self.play(FadeIn(series, lag_ratio = 0.5))
|
|
self.teacher_says(
|
|
"A new view of \\\\ the fundamental theorem",
|
|
bubble_kwargs = {"height" : 3},
|
|
added_anims = [
|
|
this_video.shift, this_video.get_height()*DOWN/2,
|
|
this_video.set_color, YELLOW,
|
|
]
|
|
)
|
|
self.change_student_modes(*["pondering"]*3)
|
|
self.wait(3)
|
|
|
|
class AverageOfSineStart(AverageOfContinuousVariable):
|
|
CONFIG = {
|
|
"y_min" : -2,
|
|
"y_max" : 2,
|
|
"x_min" : -1,
|
|
"x_max" : 2.5*np.pi,
|
|
"x_leftmost_tick" : 0,
|
|
"x_tick_frequency" : np.pi/4,
|
|
"x_axis_width" : 12,
|
|
"graph_origin" : 5*LEFT,
|
|
"x_label_scale_val" : 0.75,
|
|
"func" : np.sin,
|
|
"graph_color" : BLUE,
|
|
"bounds" : [0, np.pi],
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
self.add_graph()
|
|
self.ask_about_average()
|
|
|
|
def add_graph(self, run_time = 1):
|
|
graph = self.get_graph(self.func, color = self.graph_color)
|
|
graph_label = self.get_graph_label(
|
|
graph, "\\sin(x)",
|
|
direction = UP
|
|
)
|
|
self.play(
|
|
ShowCreation(graph),
|
|
Write(graph_label),
|
|
run_time = run_time
|
|
)
|
|
|
|
self.graph = graph
|
|
self.graph_label = graph_label
|
|
|
|
def ask_about_average(self):
|
|
half_period_graph = self.get_graph_portion_between_bounds()
|
|
question = TextMobject("Average height?")
|
|
question.to_edge(UP)
|
|
arrow = Arrow(question.get_bottom(), half_period_graph.get_top())
|
|
midpoint = np.mean(self.bounds)
|
|
v_line = self.get_vertical_line_to_graph(
|
|
midpoint, self.graph,
|
|
line_class = DashedLine,
|
|
color = WHITE
|
|
)
|
|
|
|
self.play(FadeIn(half_period_graph))
|
|
self.play(
|
|
Write(question, run_time = 2),
|
|
ShowCreation(arrow)
|
|
)
|
|
self.play(ShowCreation(v_line))
|
|
for bound in self.bounds + [midpoint]:
|
|
self.play(self.get_v_line_change_anim(
|
|
v_line, self.graph, bound,
|
|
run_time = 3
|
|
))
|
|
|
|
#########
|
|
|
|
def get_graph_portion_between_bounds(self):
|
|
self.graph_portion_between_bounds = self.get_graph(
|
|
self.func,
|
|
x_min = self.bounds[0],
|
|
x_max = self.bounds[1],
|
|
color = YELLOW
|
|
)
|
|
return self.graph_portion_between_bounds
|
|
|
|
def setup_axes(self):
|
|
GraphScene.setup_axes(self)
|
|
self.add_x_axis_labels()
|
|
|
|
def add_x_axis_labels(self):
|
|
labels_and_x_values = [
|
|
("\\pi/2", np.pi/2),
|
|
("\\pi", np.pi),
|
|
("3\\pi/2", 3*np.pi/2),
|
|
("2\\pi", 2*np.pi),
|
|
]
|
|
self.x_axis_labels = VGroup()
|
|
for label, x in labels_and_x_values:
|
|
tex_mob = TexMobject(label)
|
|
tex_mob.scale(self.x_label_scale_val)
|
|
tex_mob.move_to(
|
|
self.coords_to_point(x, -3*self.x_axis.tick_size),
|
|
)
|
|
self.add(tex_mob)
|
|
self.x_axis_labels.add(tex_mob)
|
|
|
|
class LengthOfDayGraph(GraphScene):
|
|
CONFIG = {
|
|
"x_min" : 0,
|
|
"x_max" : 365,
|
|
"x_axis_width" : 12,
|
|
"x_tick_frequency" : 25,
|
|
"x_labeled_nums" : list(range(50, 365, 50)),
|
|
"x_axis_label" : "Days since March 21",
|
|
"y_min" : 0,
|
|
"y_max" : 16,
|
|
"y_axis_height" : 6,
|
|
"y_tick_frequency" : 1,
|
|
"y_labeled_nums" : list(range(2, 15, 2)),
|
|
"y_axis_label" : "Hours of daylight",
|
|
"graph_origin" : 6*LEFT + 3*DOWN,
|
|
"camera_class" : ThreeDCamera,
|
|
"camera_config" : {
|
|
"shading_factor" : 1,
|
|
}
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
self.add_graph()
|
|
self.show_solar_pannel()
|
|
self.set_color_summer_months()
|
|
self.mention_constants()
|
|
|
|
def add_graph(self):
|
|
x_label = self.x_axis_label_mob
|
|
y_label = self.y_axis_label_mob
|
|
|
|
graph = self.get_graph(
|
|
lambda x : 2.7*np.sin((2*np.pi)*x/365 ) + 12.4,
|
|
color = GREEN,
|
|
)
|
|
graph_label = TexMobject("2.7\\sin(2\\pi x/365) + 12.4")
|
|
graph_label.to_corner(UP+RIGHT).shift(LEFT)
|
|
VGroup(*graph_label[3:6]).set_color(graph.get_color())
|
|
graph_label[9].set_color(YELLOW)
|
|
|
|
self.remove(x_label, y_label)
|
|
for label in y_label, x_label:
|
|
self.play(FadeIn(
|
|
label,
|
|
run_time = 2,
|
|
lag_ratio = 0.5
|
|
))
|
|
self.play(
|
|
ShowCreation(graph, rate_func=linear),
|
|
FadeIn(
|
|
graph_label,
|
|
rate_func = squish_rate_func(smooth, 0.5, 1),
|
|
lag_ratio = 0.5
|
|
),
|
|
run_time = 3,
|
|
)
|
|
self.wait()
|
|
|
|
self.graph = graph
|
|
self.graph_label = graph_label
|
|
|
|
def show_solar_pannel(self):
|
|
randy = Randolph()
|
|
randy.to_edge(DOWN)
|
|
panel = ThreeDMobject(*[
|
|
Rectangle(
|
|
height = 0.7, width = 0.25,
|
|
fill_color = DARK_GREY,
|
|
fill_opacity = 1,
|
|
stroke_width = 1,
|
|
stroke_color = GREY,
|
|
)
|
|
for x in range(6)
|
|
])
|
|
panel.arrange(RIGHT, buff = SMALL_BUFF)
|
|
panel.center()
|
|
panels = ThreeDMobject(panel, panel.copy(), panel.copy())
|
|
panels.arrange(DOWN)
|
|
panels.rotate(4*np.pi/12, DOWN)
|
|
panels.rotate(-np.pi/6, OUT)
|
|
side_vect = RIGHT
|
|
side_vect = rotate_vector(side_vect, 4*np.pi/12, DOWN)
|
|
side_vect = rotate_vector(side_vect, -np.pi/3, OUT)
|
|
panels.next_to(randy.get_corner(UP+RIGHT), RIGHT)
|
|
|
|
self.play(FadeIn(randy))
|
|
self.play(
|
|
randy.change, "thinking", panels.get_right(),
|
|
FadeIn(
|
|
panels,
|
|
run_time = 2,
|
|
lag_ratio = 0.5
|
|
)
|
|
)
|
|
for angle in -np.pi/4, np.pi/4:
|
|
self.play(*[
|
|
Rotate(
|
|
panel, angle,
|
|
axis = side_vect,
|
|
in_place = True,
|
|
run_time = 2,
|
|
rate_func = squish_rate_func(smooth, a, a+0.8)
|
|
)
|
|
for panel, a in zip(panels, np.linspace(0, 0.2, len(panels)))
|
|
])
|
|
self.play(Blink(randy))
|
|
self.play(*list(map(FadeOut, [randy, panels])))
|
|
|
|
def set_color_summer_months(self):
|
|
summer_rect = Rectangle()
|
|
summer_rect.set_stroke(width = 0)
|
|
summer_rect.set_fill(YELLOW, opacity = 0.25)
|
|
summer_rect.replace(Line(
|
|
self.graph_origin,
|
|
self.coords_to_point(365/2, 15.5)
|
|
), stretch = True)
|
|
|
|
winter_rect = Rectangle()
|
|
winter_rect.set_stroke(width = 0)
|
|
winter_rect.set_fill(BLUE, opacity = 0.25)
|
|
winter_rect.replace(Line(
|
|
self.coords_to_point(365/2, 15.5),
|
|
self.coords_to_point(365, 0),
|
|
), stretch = True)
|
|
|
|
|
|
summer_words, winter_words = [
|
|
TextMobject("%s \\\\ months"%s).move_to(rect)
|
|
for s, rect in [
|
|
("Summer", summer_rect),
|
|
("Winter", winter_rect),
|
|
]
|
|
]
|
|
|
|
for rect, words in (summer_rect, summer_words), (winter_rect, winter_words):
|
|
self.play(
|
|
FadeIn(rect),
|
|
Write(words, run_time = 2)
|
|
)
|
|
self.wait()
|
|
|
|
def mention_constants(self):
|
|
#2.7\\sin(2\\pi t/365) + 12.4
|
|
constants = VGroup(*[
|
|
VGroup(*self.graph_label[i:j])
|
|
for i, j in [(0, 3), (7, 9), (11, 14), (16, 20)]
|
|
])
|
|
|
|
self.play(*[
|
|
ApplyFunction(
|
|
lambda c : c.scale_in_place(0.9).shift(SMALL_BUFF*DOWN).set_color(RED),
|
|
constant,
|
|
run_time = 3,
|
|
rate_func = squish_rate_func(there_and_back, a, a+0.7)
|
|
)
|
|
for constant, a in zip(
|
|
constants,
|
|
np.linspace(0, 0.3, len(constants))
|
|
)
|
|
])
|
|
self.wait()
|
|
|
|
|
|
#####
|
|
|
|
class AskAboutAverageOfContinuousVariables(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.student_says(
|
|
"The average \\dots of a \\\\ continuous thing?",
|
|
target_mode = "sassy",
|
|
)
|
|
self.change_student_modes("confused", "sassy", "confused")
|
|
self.play(self.teacher.change_mode, "happy")
|
|
self.wait(2)
|
|
|
|
class AverageOfFiniteSet(Scene):
|
|
CONFIG = {
|
|
"lengths" : [1, 4, 2, 5]
|
|
}
|
|
def construct(self):
|
|
lengths = self.lengths
|
|
lines = VGroup(*[
|
|
Line(ORIGIN, length*RIGHT)
|
|
for length in lengths
|
|
])
|
|
colors = Color(BLUE).range_to(RED, len(lengths))
|
|
lines.set_color_by_gradient(*colors)
|
|
lines.arrange(RIGHT)
|
|
lines.generate_target()
|
|
lines.target.arrange(RIGHT, buff = 0)
|
|
for mob in lines, lines.target:
|
|
mob.shift(UP)
|
|
brace = Brace(lines.target, UP)
|
|
|
|
labels = VGroup(*[
|
|
TexMobject(str(d)).next_to(line, UP).set_color(line.get_color())
|
|
for d, line in zip(lengths, lines)
|
|
])
|
|
plusses = [TexMobject("+") for x in range(len(lengths)-1)]
|
|
symbols = VGroup(*
|
|
plusses + [TexMobject("=")]
|
|
)
|
|
symbols.set_fill(opacity = 0)
|
|
|
|
labels.generate_target()
|
|
symbols.generate_target()
|
|
symbols.target.set_fill(opacity = 1)
|
|
sum_eq = VGroup(*it.chain(*list(zip(labels.target, symbols.target))))
|
|
sum_eq.arrange(RIGHT)
|
|
sum_eq.next_to(brace, UP)
|
|
|
|
sum_mob = TexMobject(str(sum(lengths)))
|
|
sum_mob.next_to(sum_eq, RIGHT)
|
|
|
|
dividing_lines = VGroup(*[
|
|
DashedLine(p + MED_SMALL_BUFF*UP, p + MED_LARGE_BUFF*DOWN)
|
|
for alpha in np.linspace(0, 1, len(lengths)+1)
|
|
for p in [interpolate(
|
|
lines.target.get_left(),
|
|
lines.target.get_right(),
|
|
alpha
|
|
)]
|
|
])
|
|
|
|
lower_braces = VGroup(*[
|
|
Brace(VGroup(*dividing_lines[i:i+2]), DOWN)
|
|
for i in range(len(lengths))
|
|
])
|
|
averages = VGroup(*[
|
|
lb.get_text("$%d/%d$"%(sum(lengths), len(lengths)))
|
|
for lb in lower_braces
|
|
])
|
|
circle = Circle(color = YELLOW)
|
|
circle.replace(averages[1], stretch = True)
|
|
circle.scale_in_place(1.5)
|
|
|
|
self.add(lines)
|
|
self.play(FadeIn(
|
|
labels,
|
|
lag_ratio = 0.5,
|
|
run_time = 3
|
|
))
|
|
self.wait()
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
*list(map(MoveToTarget, [lines, labels, symbols])),
|
|
run_time = 2
|
|
)
|
|
self.play(Write(sum_mob))
|
|
self.wait()
|
|
self.play(ShowCreation(dividing_lines, run_time = 2))
|
|
self.play(*it.chain(
|
|
list(map(Write, averages)),
|
|
list(map(GrowFromCenter, lower_braces))
|
|
))
|
|
self.play(ShowCreation(circle))
|
|
self.wait(2)
|
|
|
|
class TryToAddInfinitelyManyPoints(AverageOfSineStart):
|
|
CONFIG = {
|
|
"max_denominator" : 40,
|
|
}
|
|
def construct(self):
|
|
self.add_graph()
|
|
self.try_to_add_infinitely_many_values()
|
|
self.show_continuum()
|
|
self.mention_integral()
|
|
|
|
def add_graph(self):
|
|
self.setup_axes()
|
|
AverageOfSineStart.add_graph(self, run_time = 0)
|
|
self.add(self.get_graph_portion_between_bounds())
|
|
self.graph_label.to_edge(RIGHT)
|
|
self.graph_label.shift(DOWN)
|
|
|
|
def try_to_add_infinitely_many_values(self):
|
|
v_lines = VGroup(*[
|
|
self.get_vertical_line_to_graph(
|
|
numerator*np.pi/denominator, self.graph,
|
|
color = YELLOW,
|
|
stroke_width = 6./denominator
|
|
)
|
|
for denominator in range(self.max_denominator)
|
|
for numerator in range(1, denominator)
|
|
if fractions.gcd(numerator, denominator) == 1
|
|
])
|
|
ghost_lines = v_lines.copy().set_stroke(GREY)
|
|
|
|
v_lines.generate_target()
|
|
start_lines = VGroup(*v_lines.target[:15])
|
|
end_lines = VGroup(*v_lines.target[15:])
|
|
|
|
plusses = VGroup(*[TexMobject("+") for x in start_lines])
|
|
sum_eq = VGroup(*it.chain(*list(zip(start_lines, plusses))))
|
|
sum_eq.add(*end_lines)
|
|
sum_eq.arrange(RIGHT)
|
|
sum_eq.next_to(v_lines[0], UP, aligned_edge = LEFT)
|
|
sum_eq.to_edge(UP, buff = MED_SMALL_BUFF)
|
|
|
|
h_line = Line(LEFT, RIGHT)
|
|
h_line.set_width(start_lines.get_width())
|
|
h_line.set_color(WHITE)
|
|
h_line.next_to(sum_eq, DOWN, aligned_edge = LEFT)
|
|
|
|
infinity = TexMobject("\\infty")
|
|
infinity.next_to(h_line, DOWN)
|
|
|
|
self.play(ShowCreation(
|
|
v_lines,
|
|
run_time = 3,
|
|
))
|
|
self.add(ghost_lines, v_lines)
|
|
self.wait(2)
|
|
self.play(
|
|
MoveToTarget(
|
|
v_lines,
|
|
run_time = 3,
|
|
lag_ratio = 0.5
|
|
),
|
|
Write(plusses)
|
|
)
|
|
self.play(ShowCreation(h_line))
|
|
self.play(Write(infinity))
|
|
self.wait()
|
|
|
|
def show_continuum(self):
|
|
arrow = Arrow(ORIGIN, UP+LEFT)
|
|
input_range = Line(*[
|
|
self.coords_to_point(bound, 0)
|
|
for bound in self.bounds
|
|
])
|
|
VGroup(arrow, input_range).set_color(RED)
|
|
|
|
self.play(FadeIn(arrow))
|
|
self.play(
|
|
arrow.next_to, input_range.get_start(),
|
|
DOWN+RIGHT, SMALL_BUFF
|
|
)
|
|
self.play(
|
|
arrow.next_to, input_range.copy().get_end(),
|
|
DOWN+RIGHT, SMALL_BUFF,
|
|
ShowCreation(input_range),
|
|
run_time = 3,
|
|
)
|
|
self.play(
|
|
arrow.next_to, input_range.get_start(),
|
|
DOWN+RIGHT, SMALL_BUFF,
|
|
run_time = 3
|
|
)
|
|
self.play(FadeOut(arrow))
|
|
self.wait()
|
|
|
|
def mention_integral(self):
|
|
randy = Randolph()
|
|
randy.to_edge(DOWN)
|
|
randy.shift(3*LEFT)
|
|
|
|
self.play(FadeIn(randy))
|
|
self.play(PiCreatureBubbleIntroduction(
|
|
randy, "Use an integral!",
|
|
bubble_class = ThoughtBubble,
|
|
target_mode = "hooray"
|
|
))
|
|
self.play(Blink(randy))
|
|
curr_bubble = randy.bubble
|
|
new_bubble = randy.get_bubble("Somehow...")
|
|
self.play(
|
|
Transform(curr_bubble, new_bubble),
|
|
Transform(curr_bubble.content, new_bubble.content),
|
|
randy.change_mode, "shruggie",
|
|
)
|
|
self.play(Blink(randy))
|
|
self.wait()
|
|
|
|
class FiniteSample(TryToAddInfinitelyManyPoints):
|
|
CONFIG = {
|
|
"dx" : 0.1,
|
|
"graph_origin" : 6*LEFT + 0.5*DOWN,
|
|
}
|
|
def construct(self):
|
|
self.add_graph()
|
|
self.show_finite_sample()
|
|
|
|
def show_finite_sample(self):
|
|
v_lines = self.get_sample_lines(dx = self.dx)
|
|
summed_v_lines = v_lines.copy()
|
|
plusses = VGroup(*[
|
|
TexMobject("+").scale(0.75)
|
|
for l in v_lines
|
|
])
|
|
numerator = VGroup(*it.chain(*list(zip(summed_v_lines, plusses))))
|
|
for group in numerator, plusses:
|
|
group.remove(plusses[-1])
|
|
numerator.arrange(
|
|
RIGHT,
|
|
buff = SMALL_BUFF,
|
|
aligned_edge = DOWN
|
|
)
|
|
# numerator.set_width(FRAME_X_RADIUS)
|
|
numerator.scale(0.5)
|
|
numerator.move_to(self.coords_to_point(3*np.pi/2, 0))
|
|
numerator.to_edge(UP)
|
|
frac_line = TexMobject("\\over \\,")
|
|
frac_line.stretch_to_fit_width(numerator.get_width())
|
|
frac_line.next_to(numerator, DOWN)
|
|
denominator = TextMobject("(Num. samples)")
|
|
denominator.next_to(frac_line, DOWN)
|
|
|
|
self.play(ShowCreation(v_lines, run_time = 3))
|
|
self.wait()
|
|
self.play(
|
|
ReplacementTransform(
|
|
v_lines.copy(),
|
|
summed_v_lines,
|
|
run_time = 3,
|
|
lag_ratio = 0.5
|
|
),
|
|
Write(
|
|
plusses,
|
|
rate_func = squish_rate_func(smooth, 0.3, 1)
|
|
)
|
|
)
|
|
self.play(Write(frac_line, run_time = 1))
|
|
self.play(Write(denominator))
|
|
self.wait()
|
|
|
|
self.plusses = plusses
|
|
self.average = VGroup(numerator, frac_line, denominator)
|
|
self.v_lines = v_lines
|
|
|
|
###
|
|
|
|
def get_sample_lines(self, dx, color = YELLOW, stroke_width = 2):
|
|
return VGroup(*[
|
|
self.get_vertical_line_to_graph(
|
|
x, self.graph,
|
|
color = color,
|
|
stroke_width = stroke_width,
|
|
)
|
|
for x in np.arange(
|
|
self.bounds[0]+dx,
|
|
self.bounds[1],
|
|
dx
|
|
)
|
|
])
|
|
|
|
class FiniteSampleWithMoreSamplePoints(FiniteSample):
|
|
CONFIG = {
|
|
"dx" : 0.05
|
|
}
|
|
|
|
class FeelsRelatedToAnIntegral(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.student_says(
|
|
"Seems integral-ish...",
|
|
target_mode = "maybe"
|
|
)
|
|
self.play(self.teacher.change_mode, "happy")
|
|
self.wait(2)
|
|
|
|
class IntegralOfSine(FiniteSample):
|
|
CONFIG = {
|
|
"thin_dx" : 0.01,
|
|
"rect_opacity" : 0.75,
|
|
}
|
|
def construct(self):
|
|
self.force_skipping()
|
|
FiniteSample.construct(self)
|
|
self.remove(self.y_axis_label_mob)
|
|
self.remove(*self.x_axis_labels[::2])
|
|
self.revert_to_original_skipping_status()
|
|
|
|
self.put_average_in_corner()
|
|
self.write_integral()
|
|
self.show_riemann_rectangles()
|
|
self.let_dx_approach_zero()
|
|
self.bring_back_average()
|
|
self.distribute_dx()
|
|
self.let_dx_approach_zero(restore = False)
|
|
self.write_area_over_width()
|
|
self.show_moving_v_line()
|
|
|
|
def put_average_in_corner(self):
|
|
self.average.save_state()
|
|
self.plusses.set_stroke(width = 0.5)
|
|
self.play(
|
|
self.average.scale, 0.75,
|
|
self.average.to_corner, DOWN+RIGHT,
|
|
)
|
|
|
|
def write_integral(self):
|
|
integral = TexMobject("\\int_0^\\pi", "\\sin(x)", "\\,dx")
|
|
integral.move_to(self.graph_portion_between_bounds)
|
|
integral.to_edge(UP)
|
|
|
|
self.play(Write(integral))
|
|
self.wait(2)
|
|
|
|
self.integral = integral
|
|
|
|
def show_riemann_rectangles(self):
|
|
kwargs = {
|
|
"dx" : self.dx,
|
|
"x_min" : self.bounds[0],
|
|
"x_max" : self.bounds[1],
|
|
"fill_opacity" : self.rect_opacity,
|
|
}
|
|
rects = self.get_riemann_rectangles(self.graph, **kwargs)
|
|
rects.set_stroke(YELLOW, width = 1)
|
|
flat_rects = self.get_riemann_rectangles(
|
|
self.get_graph(lambda x : 0),
|
|
**kwargs
|
|
)
|
|
thin_kwargs = dict(kwargs)
|
|
thin_kwargs["dx"] = self.thin_dx
|
|
thin_kwargs["stroke_width"] = 0
|
|
self.thin_rects = self.get_riemann_rectangles(
|
|
self.graph,
|
|
**thin_kwargs
|
|
)
|
|
|
|
|
|
start_index = 20
|
|
end_index = start_index + 5
|
|
low_opacity = 0.5
|
|
high_opacity = 1
|
|
|
|
start_rect = rects[start_index]
|
|
side_brace = Brace(start_rect, LEFT, buff = SMALL_BUFF)
|
|
bottom_brace = Brace(start_rect, DOWN, buff = SMALL_BUFF)
|
|
sin_x = TexMobject("\\sin(x)")
|
|
sin_x.next_to(side_brace, LEFT, SMALL_BUFF)
|
|
dx = bottom_brace.get_text("$dx$", buff = SMALL_BUFF)
|
|
|
|
self.transform_between_riemann_rects(
|
|
flat_rects, rects,
|
|
replace_mobject_with_target_in_scene = True,
|
|
)
|
|
self.remove(self.v_lines)
|
|
self.wait()
|
|
|
|
rects.save_state()
|
|
self.play(*it.chain(
|
|
[
|
|
ApplyMethod(
|
|
rect.set_style_data, BLACK, 1,
|
|
None, #Fill color
|
|
high_opacity if rect is start_rect else low_opacity
|
|
)
|
|
for rect in rects
|
|
],
|
|
list(map(GrowFromCenter, [side_brace, bottom_brace])),
|
|
list(map(Write, [sin_x, dx])),
|
|
))
|
|
self.wait()
|
|
for i in range(start_index+1, end_index):
|
|
self.play(
|
|
rects[i-1].set_fill, None, low_opacity,
|
|
rects[i].set_fill, None, high_opacity,
|
|
side_brace.set_height, rects[i].get_height(),
|
|
side_brace.next_to, rects[i], LEFT, SMALL_BUFF,
|
|
bottom_brace.next_to, rects[i], DOWN, SMALL_BUFF,
|
|
MaintainPositionRelativeTo(sin_x, side_brace),
|
|
MaintainPositionRelativeTo(dx, bottom_brace),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
rects.restore,
|
|
*list(map(FadeOut, [sin_x, dx, side_brace, bottom_brace]))
|
|
)
|
|
|
|
self.rects = rects
|
|
self.dx_brace = bottom_brace
|
|
self.dx_label = dx
|
|
|
|
def let_dx_approach_zero(self, restore = True):
|
|
start_state = self.rects.copy()
|
|
self.transform_between_riemann_rects(
|
|
self.rects, self.thin_rects,
|
|
run_time = 3
|
|
)
|
|
self.wait(2)
|
|
if restore:
|
|
self.transform_between_riemann_rects(
|
|
self.rects, start_state.copy(),
|
|
run_time = 2,
|
|
)
|
|
self.remove(self.rects)
|
|
self.rects = start_state
|
|
self.rects.set_fill(opacity = 1)
|
|
self.play(
|
|
self.rects.set_fill, None,
|
|
self.rect_opacity,
|
|
)
|
|
self.wait()
|
|
|
|
def bring_back_average(self):
|
|
num_samples = self.average[-1]
|
|
|
|
example_dx = TexMobject("0.1")
|
|
example_dx.move_to(self.dx_label)
|
|
|
|
input_range = Line(*[
|
|
self.coords_to_point(bound, 0)
|
|
for bound in self.bounds
|
|
])
|
|
input_range.set_color(RED)
|
|
|
|
#Bring back average
|
|
self.play(
|
|
self.average.restore,
|
|
self.average.center,
|
|
self.average.to_edge, UP,
|
|
self.integral.to_edge, DOWN,
|
|
run_time = 2
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
Write(self.dx_brace),
|
|
Write(self.dx_label),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeOut(self.dx_label),
|
|
FadeIn(example_dx)
|
|
)
|
|
self.play(Indicate(example_dx))
|
|
self.wait()
|
|
self.play(ShowCreation(input_range))
|
|
self.play(FadeOut(input_range))
|
|
self.wait()
|
|
|
|
#Ask how many there are
|
|
num_samples_copy = num_samples.copy()
|
|
v_lines = self.v_lines
|
|
self.play(*[
|
|
ApplyFunction(
|
|
lambda l : l.shift(0.5*UP).set_color(GREEN),
|
|
line,
|
|
rate_func = squish_rate_func(
|
|
there_and_back, a, a+0.3
|
|
),
|
|
run_time = 3,
|
|
)
|
|
for line, a in zip(
|
|
self.v_lines,
|
|
np.linspace(0, 0.7, len(self.v_lines))
|
|
)
|
|
] + [
|
|
num_samples_copy.set_color, GREEN
|
|
])
|
|
self.play(FadeOut(v_lines))
|
|
self.wait()
|
|
|
|
#Count number of samples
|
|
num_samples_copy.generate_target()
|
|
num_samples_copy.target.shift(DOWN + 0.5*LEFT)
|
|
rhs = TexMobject("\\approx", "\\pi", "/", "0.1")
|
|
rhs.next_to(num_samples_copy.target, RIGHT)
|
|
self.play(
|
|
MoveToTarget(num_samples_copy),
|
|
Write(rhs.get_part_by_tex("approx")),
|
|
)
|
|
self.play(ShowCreation(input_range))
|
|
self.play(ReplacementTransform(
|
|
self.x_axis_labels[1].copy(),
|
|
rhs.get_part_by_tex("pi")
|
|
))
|
|
self.play(FadeOut(input_range))
|
|
self.play(
|
|
ReplacementTransform(
|
|
example_dx.copy(),
|
|
rhs.get_part_by_tex("0.1")
|
|
),
|
|
Write(rhs.get_part_by_tex("/"))
|
|
)
|
|
self.wait(2)
|
|
|
|
#Substitute number of samples
|
|
self.play(ReplacementTransform(
|
|
example_dx, self.dx_label
|
|
))
|
|
dx = rhs.get_part_by_tex("0.1")
|
|
self.play(Transform(
|
|
dx, TexMobject("dx").move_to(dx)
|
|
))
|
|
self.wait(2)
|
|
approx = rhs.get_part_by_tex("approx")
|
|
rhs.remove(approx)
|
|
self.play(
|
|
FadeOut(num_samples),
|
|
FadeOut(num_samples_copy),
|
|
FadeOut(approx),
|
|
rhs.next_to, self.average[1], DOWN
|
|
)
|
|
self.wait()
|
|
|
|
self.pi_over_dx = rhs
|
|
|
|
def distribute_dx(self):
|
|
numerator, frac_line, denominator = self.average
|
|
pi, over, dx = self.pi_over_dx
|
|
integral = self.integral
|
|
|
|
dx.generate_target()
|
|
lp, rp = parens = TexMobject("()")
|
|
parens.set_height(numerator.get_height())
|
|
lp.next_to(numerator, LEFT)
|
|
rp.next_to(numerator, RIGHT)
|
|
dx.target.next_to(rp, RIGHT)
|
|
|
|
self.play(
|
|
MoveToTarget(dx, path_arc = np.pi/2),
|
|
Write(parens),
|
|
frac_line.stretch_to_fit_width,
|
|
parens.get_width() + dx.get_width(),
|
|
frac_line.shift, dx.get_width()*RIGHT/2,
|
|
FadeOut(over)
|
|
)
|
|
self.wait(2)
|
|
|
|
average = VGroup(parens, numerator, dx, frac_line, pi)
|
|
integral.generate_target()
|
|
over_pi = TexMobject("\\frac{\\phantom{\\int \\sin(x)\\dx}}{\\pi}")
|
|
integral.target.set_width(over_pi.get_width())
|
|
integral.target.next_to(over_pi, UP)
|
|
integral_over_pi = VGroup(integral.target, over_pi)
|
|
integral_over_pi.to_corner(UP+RIGHT)
|
|
arrow = Arrow(LEFT, RIGHT)
|
|
arrow.next_to(integral.target, LEFT)
|
|
|
|
self.play(
|
|
average.scale, 0.9,
|
|
average.next_to, arrow, LEFT,
|
|
average.shift_onto_screen,
|
|
ShowCreation(arrow),
|
|
Write(over_pi),
|
|
MoveToTarget(integral, run_time = 2)
|
|
)
|
|
self.wait(2)
|
|
self.play(*list(map(FadeOut, [self.dx_label, self.dx_brace])))
|
|
|
|
self.integral_over_pi = VGroup(integral, over_pi)
|
|
self.average = average
|
|
self.average_arrow = arrow
|
|
|
|
def write_area_over_width(self):
|
|
self.play(
|
|
self.integral_over_pi.shift, 2*LEFT,
|
|
*list(map(FadeOut, [self.average, self.average_arrow]))
|
|
)
|
|
|
|
average_height = TextMobject("Average height = ")
|
|
area_over_width = TexMobject(
|
|
"{\\text{Area}", "\\over\\,", "\\text{Width}}", "="
|
|
)
|
|
area_over_width.get_part_by_tex("Area").set_color_by_gradient(
|
|
BLUE, GREEN
|
|
)
|
|
area_over_width.next_to(self.integral_over_pi[1][0], LEFT)
|
|
average_height.next_to(area_over_width, LEFT)
|
|
|
|
self.play(*list(map(FadeIn, [average_height, area_over_width])))
|
|
self.wait()
|
|
|
|
def show_moving_v_line(self):
|
|
mean = np.mean(self.bounds)
|
|
v_line = self.get_vertical_line_to_graph(
|
|
mean, self.graph,
|
|
line_class = DashedLine,
|
|
color = WHITE,
|
|
)
|
|
self.play(ShowCreation(v_line))
|
|
for count in range(2):
|
|
for x in self.bounds + [mean]:
|
|
self.play(self.get_v_line_change_anim(
|
|
v_line, self.graph, x,
|
|
run_time = 3
|
|
))
|
|
|
|
class Approx31(Scene):
|
|
def construct(self):
|
|
tex = TexMobject("\\approx 31")
|
|
tex.set_width(FRAME_WIDTH - LARGE_BUFF)
|
|
tex.to_edge(LEFT)
|
|
self.play(Write(tex))
|
|
self.wait(3)
|
|
|
|
class LetsSolveThis(TeacherStudentsScene):
|
|
def construct(self):
|
|
expression = TexMobject(
|
|
"{\\int_0^\\pi ", " \\sin(x)", "\\,dx \\over \\pi}"
|
|
)
|
|
expression.to_corner(UP+LEFT)
|
|
question = TextMobject(
|
|
"What's the antiderivative \\\\ of",
|
|
"$\\sin(x)$",
|
|
"?"
|
|
)
|
|
for tex_mob in expression, question:
|
|
tex_mob.set_color_by_tex("sin", BLUE)
|
|
self.add(expression)
|
|
|
|
self.teacher_says("Let's compute it.")
|
|
self.wait()
|
|
self.student_thinks(question)
|
|
self.wait(2)
|
|
|
|
class Antiderivative(AverageOfSineStart):
|
|
CONFIG = {
|
|
"antideriv_color" : GREEN,
|
|
"deriv_color" : BLUE,
|
|
"riemann_rect_dx" : 0.01,
|
|
"y_axis_label" : "",
|
|
"graph_origin" : 4*LEFT + DOWN,
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
self.add_x_axis_labels()
|
|
self.negate_derivative_of_cosine()
|
|
self.walk_through_slopes()
|
|
self.apply_ftoc()
|
|
self.show_difference_in_antiderivative()
|
|
self.comment_on_area()
|
|
self.divide_by_pi()
|
|
self.set_color_antiderivative_fraction()
|
|
self.show_slope()
|
|
self.bring_back_derivative()
|
|
self.show_tangent_slope()
|
|
|
|
def add_x_axis_labels(self):
|
|
AverageOfSineStart.add_x_axis_labels(self)
|
|
self.remove(*self.x_axis_labels[::2])
|
|
|
|
def negate_derivative_of_cosine(self):
|
|
cos, neg_cos, sin, neg_sin = graphs = [
|
|
self.get_graph(func)
|
|
for func in [
|
|
np.cos,
|
|
lambda x : -np.cos(x),
|
|
np.sin,
|
|
lambda x : -np.sin(x),
|
|
]
|
|
]
|
|
VGroup(cos, neg_cos).set_color(self.antideriv_color)
|
|
VGroup(sin, neg_sin).set_color(self.deriv_color)
|
|
labels = ["\\cos(x)", "-\\cos(x)", "\\sin(x)", "-\\sin(x)"]
|
|
x_vals = [2*np.pi, 2*np.pi, 5*np.pi/2, 5*np.pi/2]
|
|
vects = [UP, DOWN, UP, DOWN]
|
|
for graph, label, x_val, vect in zip(graphs, labels, x_vals, vects):
|
|
graph.label = self.get_graph_label(
|
|
graph, label,
|
|
x_val = x_val,
|
|
direction = vect,
|
|
buff = SMALL_BUFF
|
|
)
|
|
|
|
derivs = []
|
|
for F, f in ("\\cos", "-\\sin"), ("-\\cos", "\\sin"):
|
|
deriv = TexMobject(
|
|
"{d(", F, ")", "\\over\\,", "dx}", "(x)",
|
|
"=", f, "(x)"
|
|
)
|
|
deriv.set_color_by_tex(F, self.antideriv_color)
|
|
deriv.set_color_by_tex(f, self.deriv_color)
|
|
deriv.to_edge(UP)
|
|
derivs.append(deriv)
|
|
cos_deriv, neg_cos_deriv = derivs
|
|
|
|
self.add(cos_deriv)
|
|
for graph in cos, neg_sin:
|
|
self.play(
|
|
ShowCreation(graph, rate_func = smooth),
|
|
Write(
|
|
graph.label,
|
|
rate_func = squish_rate_func(smooth, 0.3, 1)
|
|
),
|
|
run_time = 2
|
|
)
|
|
self.wait()
|
|
self.wait()
|
|
self.play(*[
|
|
ReplacementTransform(*pair)
|
|
for pair in [
|
|
(derivs),
|
|
(cos, neg_cos),
|
|
(cos.label, neg_cos.label),
|
|
(neg_sin, sin),
|
|
(neg_sin.label, sin.label),
|
|
]
|
|
])
|
|
self.wait(2)
|
|
|
|
self.neg_cos = neg_cos
|
|
self.sin = sin
|
|
self.deriv = neg_cos_deriv
|
|
|
|
def walk_through_slopes(self):
|
|
neg_cos = self.neg_cos
|
|
sin = self.sin
|
|
|
|
faders = sin, sin.label
|
|
for mob in faders:
|
|
mob.save_state()
|
|
sin_copy = self.get_graph(
|
|
np.sin,
|
|
x_min = 0,
|
|
x_max = 2*np.pi,
|
|
color = BLUE,
|
|
)
|
|
v_line = self.get_vertical_line_to_graph(
|
|
0, neg_cos,
|
|
line_class = DashedLine,
|
|
color = WHITE
|
|
)
|
|
|
|
ss_group = self.get_secant_slope_group(
|
|
0, neg_cos,
|
|
dx = 0.001,
|
|
secant_line_color = YELLOW
|
|
)
|
|
def quad_smooth(t):
|
|
return 0.25*(np.floor(4*t) + smooth((4*t) % 1))
|
|
|
|
self.play(*[
|
|
ApplyMethod(m.fade, 0.6)
|
|
for m in faders
|
|
])
|
|
self.wait()
|
|
self.play(*list(map(ShowCreation, ss_group)), run_time = 2)
|
|
kwargs = {
|
|
"run_time" : 20,
|
|
"rate_func" : quad_smooth,
|
|
}
|
|
v_line_anim = self.get_v_line_change_anim(
|
|
v_line, sin_copy, 2*np.pi,
|
|
**kwargs
|
|
)
|
|
self.animate_secant_slope_group_change(
|
|
ss_group,
|
|
target_x = 2*np.pi,
|
|
added_anims = [
|
|
ShowCreation(sin_copy, **kwargs),
|
|
v_line_anim
|
|
],
|
|
**kwargs
|
|
)
|
|
self.play(
|
|
*list(map(FadeOut, [ss_group, v_line, sin_copy]))
|
|
)
|
|
self.wait()
|
|
|
|
self.ss_group = ss_group
|
|
|
|
def apply_ftoc(self):
|
|
deriv = self.deriv
|
|
integral = TexMobject(
|
|
"\\int", "^\\pi", "_0", "\\sin(x)", "\\,dx"
|
|
)
|
|
rhs = TexMobject(
|
|
"=", "\\big(", "-\\cos", "(", "\\pi", ")", "\\big)",
|
|
"-", "\\big(", "-\\cos", "(", "0", ")", "\\big)",
|
|
)
|
|
rhs.next_to(integral, RIGHT)
|
|
equation = VGroup(integral, rhs)
|
|
equation.to_corner(UP+RIGHT, buff = MED_SMALL_BUFF)
|
|
(start_pi, end_pi), (start_zero, end_zero) = start_end_pairs = [
|
|
[
|
|
m.get_part_by_tex(tex)
|
|
for m in (integral, rhs)
|
|
]
|
|
for tex in ("\\pi", "0")
|
|
]
|
|
|
|
for tex_mob in integral, rhs:
|
|
tex_mob.set_color_by_tex("sin", self.deriv_color)
|
|
tex_mob.set_color_by_tex("cos", self.antideriv_color)
|
|
tex_mob.set_color_by_tex("0", YELLOW)
|
|
tex_mob.set_color_by_tex("\\pi", YELLOW)
|
|
|
|
self.play(
|
|
Write(integral),
|
|
self.deriv.scale, 0.5,
|
|
self.deriv.center,
|
|
self.deriv.to_edge, LEFT, MED_SMALL_BUFF,
|
|
self.deriv.shift, UP,
|
|
)
|
|
self.wait()
|
|
|
|
self.play(FadeIn(
|
|
VGroup(*[part for part in rhs if part not in [end_pi, end_zero]]),
|
|
lag_ratio = 0.5,
|
|
run_time = 2,
|
|
))
|
|
self.wait()
|
|
for start, end in start_end_pairs:
|
|
self.play(ReplacementTransform(
|
|
start.copy(), end,
|
|
path_arc = np.pi/6,
|
|
run_time = 2
|
|
))
|
|
self.wait()
|
|
|
|
self.integral = integral
|
|
self.rhs = rhs
|
|
|
|
def show_difference_in_antiderivative(self):
|
|
pi_point, zero_point = points = [
|
|
self.input_to_graph_point(x, self.neg_cos)
|
|
for x in reversed(self.bounds)
|
|
]
|
|
interim_point = pi_point[0]*RIGHT + zero_point[1]*UP
|
|
pi_dot, zero_dot = dots = [
|
|
Dot(point, color = YELLOW)
|
|
for point in points
|
|
]
|
|
v_line = DashedLine(pi_point, interim_point)
|
|
h_line = DashedLine(interim_point, zero_point)
|
|
v_line_brace = Brace(v_line, RIGHT)
|
|
two_height_label = v_line_brace.get_text(
|
|
"$2$", buff = SMALL_BUFF
|
|
)
|
|
two_height_label.add_background_rectangle()
|
|
|
|
pi = self.x_axis_labels[1]
|
|
#Horrible hack
|
|
black_pi = pi.copy().set_color(BLACK)
|
|
self.add(black_pi, pi)
|
|
|
|
cos_tex = self.rhs.get_part_by_tex("cos")
|
|
|
|
self.play(ReplacementTransform(
|
|
cos_tex.copy(), pi_dot
|
|
))
|
|
self.wait()
|
|
moving_dot = pi_dot.copy()
|
|
self.play(
|
|
ShowCreation(v_line),
|
|
# Animation(pi),
|
|
pi.shift, 0.8*pi.get_width()*(LEFT+UP),
|
|
moving_dot.move_to, interim_point,
|
|
)
|
|
self.play(
|
|
ShowCreation(h_line),
|
|
ReplacementTransform(moving_dot, zero_dot)
|
|
)
|
|
self.play(GrowFromCenter(v_line_brace))
|
|
self.wait(2)
|
|
self.play(Write(two_height_label))
|
|
self.wait(2)
|
|
|
|
self.v_line = v_line
|
|
self.h_line = h_line
|
|
self.pi_dot = pi_dot
|
|
self.zero_dot = zero_dot
|
|
self.v_line_brace = v_line_brace
|
|
self.two_height_label = two_height_label
|
|
|
|
def comment_on_area(self):
|
|
rects = self.get_riemann_rectangles(
|
|
self.sin,
|
|
dx = self.riemann_rect_dx,
|
|
stroke_width = 0,
|
|
fill_opacity = 0.7,
|
|
x_min = self.bounds[0],
|
|
x_max = self.bounds[1],
|
|
)
|
|
area_two = TexMobject("2").replace(
|
|
self.two_height_label
|
|
)
|
|
|
|
self.play(Write(rects))
|
|
self.wait()
|
|
self.play(area_two.move_to, rects)
|
|
self.wait(2)
|
|
|
|
self.rects = rects
|
|
self.area_two = area_two
|
|
|
|
def divide_by_pi(self):
|
|
integral = self.integral
|
|
rhs = self.rhs
|
|
equals = rhs[0]
|
|
rhs_without_eq = VGroup(*rhs[1:])
|
|
frac_lines = VGroup(*[
|
|
TexMobject("\\over\\,").stretch_to_fit_width(
|
|
mob.get_width()
|
|
).move_to(mob)
|
|
for mob in (integral, rhs_without_eq)
|
|
])
|
|
frac_lines.shift(
|
|
(integral.get_height()/2 + SMALL_BUFF)*DOWN
|
|
)
|
|
pi_minus_zeros = VGroup(*[
|
|
TexMobject("\\pi", "-", "0").next_to(line, DOWN)
|
|
for line in frac_lines
|
|
])
|
|
for tex_mob in pi_minus_zeros:
|
|
for tex in "pi", "0":
|
|
tex_mob.set_color_by_tex(tex, YELLOW)
|
|
|
|
answer = TexMobject(" = \\frac{2}{\\pi}")
|
|
answer.next_to(
|
|
frac_lines, RIGHT,
|
|
align_using_submobjects = True
|
|
)
|
|
answer.shift_onto_screen()
|
|
|
|
self.play(
|
|
equals.next_to, frac_lines[0].copy(), RIGHT,
|
|
rhs_without_eq.next_to, frac_lines[1].copy(), UP,
|
|
*list(map(Write, frac_lines))
|
|
)
|
|
self.play(*[
|
|
ReplacementTransform(
|
|
integral.get_part_by_tex(tex).copy(),
|
|
pi_minus_zeros[0].get_part_by_tex(tex)
|
|
)
|
|
for tex in ("\\pi","0")
|
|
] + [
|
|
Write(pi_minus_zeros[0].get_part_by_tex("-"))
|
|
])
|
|
self.play(*[
|
|
ReplacementTransform(
|
|
rhs.get_part_by_tex(
|
|
tex, substring = False
|
|
).copy(),
|
|
pi_minus_zeros[1].get_part_by_tex(tex)
|
|
)
|
|
for tex in ("\\pi", "-", "0")
|
|
])
|
|
self.wait(2)
|
|
|
|
full_equation = VGroup(
|
|
integral, frac_lines, rhs, pi_minus_zeros
|
|
)
|
|
background_rect = BackgroundRectangle(full_equation, fill_opacity = 1)
|
|
background_rect.stretch_in_place(1.2, dim = 1)
|
|
full_equation.add_to_back(background_rect)
|
|
self.play(
|
|
full_equation.shift,
|
|
(answer.get_width()+MED_LARGE_BUFF)*LEFT
|
|
)
|
|
self.play(Write(answer))
|
|
self.wait()
|
|
|
|
self.antiderivative_fraction = VGroup(
|
|
rhs_without_eq,
|
|
frac_lines[1],
|
|
pi_minus_zeros[1]
|
|
)
|
|
self.integral_fraction = VGroup(
|
|
integral,
|
|
frac_lines[0],
|
|
pi_minus_zeros[0],
|
|
equals
|
|
)
|
|
|
|
def set_color_antiderivative_fraction(self):
|
|
fraction = self.antiderivative_fraction
|
|
big_rect = Rectangle(
|
|
stroke_width = 0,
|
|
fill_color = BLACK,
|
|
fill_opacity = 0.75,
|
|
)
|
|
big_rect.set_width(FRAME_WIDTH)
|
|
big_rect.set_height(FRAME_HEIGHT)
|
|
morty = Mortimer()
|
|
morty.to_corner(DOWN+RIGHT)
|
|
|
|
self.play(
|
|
FadeIn(big_rect),
|
|
FadeIn(morty),
|
|
Animation(fraction)
|
|
)
|
|
self.play(morty.change, "raise_right_hand", fraction)
|
|
self.play(Blink(morty))
|
|
self.wait(2)
|
|
self.play(
|
|
FadeOut(big_rect),
|
|
FadeOut(morty),
|
|
Animation(fraction)
|
|
)
|
|
|
|
def show_slope(self):
|
|
line = Line(
|
|
self.zero_dot.get_center(),
|
|
self.pi_dot.get_center(),
|
|
)
|
|
line.set_color(RED)
|
|
line.scale_in_place(1.2)
|
|
|
|
new_v_line = self.v_line.copy().set_color(RED)
|
|
new_h_line = self.h_line.copy().set_color(RED)
|
|
|
|
pi = TexMobject("\\pi")
|
|
pi.next_to(self.h_line, DOWN)
|
|
|
|
self.play(
|
|
FadeOut(self.rects),
|
|
FadeOut(self.area_two)
|
|
)
|
|
self.play(ShowCreation(new_v_line))
|
|
self.play(
|
|
ShowCreation(new_h_line),
|
|
Write(pi)
|
|
)
|
|
self.wait()
|
|
self.play(ShowCreation(line, run_time = 2))
|
|
self.wait()
|
|
|
|
def bring_back_derivative(self):
|
|
self.play(
|
|
FadeOut(self.integral_fraction),
|
|
self.deriv.scale, 1.7,
|
|
self.deriv.to_corner, UP+LEFT, MED_LARGE_BUFF,
|
|
self.deriv.shift, MED_SMALL_BUFF*DOWN,
|
|
)
|
|
self.wait()
|
|
|
|
def show_tangent_slope(self):
|
|
ss_group = self.get_secant_slope_group(
|
|
0, self.neg_cos,
|
|
dx = 0.001,
|
|
secant_line_color = YELLOW,
|
|
secant_line_length = 4,
|
|
)
|
|
|
|
self.play(*list(map(ShowCreation, ss_group)), run_time = 2)
|
|
for count in range(2):
|
|
for x in reversed(self.bounds):
|
|
self.animate_secant_slope_group_change(
|
|
ss_group,
|
|
target_x = x,
|
|
run_time = 6,
|
|
)
|
|
|
|
class GeneralAverage(AverageOfContinuousVariable):
|
|
CONFIG = {
|
|
"bounds" : [1, 6],
|
|
"bound_colors" : [GREEN, RED],
|
|
"graph_origin" : 5*LEFT + 2*DOWN,
|
|
"num_rect_iterations" : 4,
|
|
"max_dx" : 0.25,
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
self.add_graph()
|
|
self.ask_about_average()
|
|
self.show_signed_area()
|
|
self.put_area_away()
|
|
self.show_finite_sample()
|
|
self.show_improving_samples()
|
|
|
|
def add_graph(self):
|
|
graph = self.get_graph(self.func)
|
|
graph_label = self.get_graph_label(graph, "f(x)")
|
|
v_lines = VGroup(*[
|
|
self.get_vertical_line_to_graph(
|
|
x, graph, line_class = DashedLine
|
|
)
|
|
for x in self.bounds
|
|
])
|
|
for line, color in zip(v_lines, self.bound_colors):
|
|
line.set_color(color)
|
|
labels = list(map(TexMobject, "ab"))
|
|
for line, label in zip(v_lines, labels):
|
|
vect = line.get_start()-line.get_end()
|
|
label.next_to(line, vect/get_norm(vect))
|
|
label.set_color(line.get_color())
|
|
|
|
self.y_axis_label_mob.shift(0.7*LEFT)
|
|
|
|
self.play(
|
|
ShowCreation(graph),
|
|
Write(
|
|
graph_label,
|
|
rate_func = squish_rate_func(smooth, 0.5, 1)
|
|
),
|
|
run_time = 2
|
|
)
|
|
for line, label in zip(v_lines, labels):
|
|
self.play(
|
|
Write(label),
|
|
ShowCreation(line)
|
|
)
|
|
self.wait()
|
|
|
|
self.graph = graph
|
|
self.graph_label = graph_label
|
|
self.bounds_labels = labels
|
|
self.bound_lines = v_lines
|
|
|
|
def ask_about_average(self):
|
|
v_line = self.get_vertical_line_to_graph(
|
|
self.bounds[0], self.graph,
|
|
line_class = DashedLine,
|
|
color = WHITE
|
|
)
|
|
average = TextMobject("Average = ")
|
|
fraction = TexMobject(
|
|
"{\\displaystyle \\int", "^b", "_a", "f(x)", "\\,dx",
|
|
"\\over", "b", "-", "a}"
|
|
)
|
|
for color, tex in zip(self.bound_colors, "ab"):
|
|
fraction.set_color_by_tex(tex, color)
|
|
fraction.set_color_by_tex("displaystyle", WHITE)
|
|
integral = VGroup(*fraction[:5])
|
|
denominator = VGroup(*fraction[5:])
|
|
average.next_to(fraction.get_part_by_tex("over"), LEFT)
|
|
group = VGroup(average, fraction)
|
|
group.center().to_edge(UP).shift(LEFT)
|
|
|
|
self.count = 0
|
|
def next_v_line_anim():
|
|
target = self.bounds[0] if self.count%2 == 1 else self.bounds[1]
|
|
self.count += 1
|
|
return self.get_v_line_change_anim(
|
|
v_line, self.graph, target,
|
|
run_time = 4,
|
|
)
|
|
|
|
self.play(
|
|
next_v_line_anim(),
|
|
Write(average, run_time = 2),
|
|
)
|
|
self.play(
|
|
next_v_line_anim(),
|
|
Write(
|
|
VGroup(*[
|
|
fraction.get_part_by_tex(tex)
|
|
for tex in ("int", "f(x)", "dx", "over")
|
|
]),
|
|
rate_func = squish_rate_func(smooth, 0.25, 0.75),
|
|
run_time = 4
|
|
),
|
|
*[
|
|
ReplacementTransform(
|
|
label.copy(),
|
|
fraction.get_part_by_tex(tex, substring = False),
|
|
run_time = 2
|
|
)
|
|
for label, tex in zip(
|
|
self.bounds_labels,
|
|
["_a", "^b"]
|
|
)
|
|
]
|
|
)
|
|
self.play(
|
|
next_v_line_anim(),
|
|
Write(
|
|
fraction.get_part_by_tex("-"),
|
|
run_time = 4,
|
|
rate_func = squish_rate_func(smooth, 0.5, 0.75),
|
|
),
|
|
*[
|
|
ReplacementTransform(
|
|
label.copy(),
|
|
fraction.get_part_by_tex(tex, substring = False),
|
|
run_time = 4,
|
|
rate_func = squish_rate_func(smooth, 0.25, 0.75)
|
|
)
|
|
for label, tex in zip(
|
|
self.bounds_labels,
|
|
["a}", "b"]
|
|
)
|
|
]
|
|
|
|
)
|
|
self.play(next_v_line_anim())
|
|
self.play(FadeOut(v_line))
|
|
|
|
self.average_expression = VGroup(average, fraction)
|
|
|
|
def show_signed_area(self):
|
|
rect_list = self.get_riemann_rectangles_list(
|
|
self.graph,
|
|
self.num_rect_iterations,
|
|
max_dx = self.max_dx,
|
|
x_min = self.bounds[0],
|
|
x_max = self.bounds[1],
|
|
end_color = BLUE,
|
|
fill_opacity = 0.75,
|
|
stroke_width = 0.25,
|
|
)
|
|
rects = rect_list[0]
|
|
plus = TexMobject("+")
|
|
plus.move_to(self.coords_to_point(2, 2))
|
|
minus = TexMobject("-")
|
|
minus.move_to(self.coords_to_point(5.24, -1))
|
|
|
|
self.play(FadeIn(
|
|
rects,
|
|
run_time = 2,
|
|
lag_ratio = 0.5
|
|
))
|
|
for new_rects in rect_list[1:]:
|
|
self.transform_between_riemann_rects(rects, new_rects)
|
|
self.play(Write(plus))
|
|
self.play(Write(minus))
|
|
self.wait(2)
|
|
|
|
self.area = VGroup(rects, plus, minus)
|
|
|
|
def put_area_away(self):
|
|
self.play(
|
|
FadeOut(self.area),
|
|
self.average_expression.scale, 0.75,
|
|
self.average_expression.to_corner, DOWN+RIGHT,
|
|
)
|
|
self.wait()
|
|
|
|
def show_finite_sample(self):
|
|
v_lines = self.get_vertical_lines_to_graph(
|
|
self.graph,
|
|
x_min = self.bounds[0],
|
|
x_max = self.bounds[1],
|
|
color = GREEN
|
|
)
|
|
for line in v_lines:
|
|
if self.y_axis.point_to_number(line.get_end()) < 0:
|
|
line.set_color(RED)
|
|
line.save_state()
|
|
|
|
line_pair = VGroup(*v_lines[6:8])
|
|
brace = Brace(line_pair, DOWN)
|
|
dx = brace.get_text("$dx$")
|
|
|
|
num_samples = TextMobject("Num. samples")
|
|
approx = TexMobject("\\approx")
|
|
rhs = TexMobject("{b", "-", "a", "\\over", "dx}")
|
|
for tex, color in zip("ab", self.bound_colors):
|
|
rhs.set_color_by_tex(tex, color)
|
|
expression = VGroup(num_samples, approx, rhs)
|
|
expression.arrange(RIGHT)
|
|
expression.next_to(self.y_axis, RIGHT)
|
|
rhs_copy = rhs.copy()
|
|
|
|
f_brace = Brace(line_pair, LEFT, buff = 0)
|
|
f_x = f_brace.get_text("$f(x)$")
|
|
add_up_f_over = TexMobject("\\text{Add up $f(x)$}", "\\over")
|
|
add_up_f_over.next_to(num_samples, UP)
|
|
add_up_f_over.to_edge(UP)
|
|
|
|
|
|
self.play(ShowCreation(v_lines, run_time = 2))
|
|
self.play(*list(map(Write, [brace, dx])))
|
|
self.wait()
|
|
self.play(Write(VGroup(num_samples, approx, *rhs[:-1])))
|
|
self.play(ReplacementTransform(
|
|
dx.copy(), rhs.get_part_by_tex("dx")
|
|
))
|
|
self.wait(2)
|
|
|
|
self.play(
|
|
FadeIn(add_up_f_over),
|
|
*[
|
|
ApplyFunction(
|
|
lambda m : m.fade().set_stroke(width = 2),
|
|
v_line
|
|
)
|
|
for v_line in v_lines
|
|
]
|
|
)
|
|
self.play(*[
|
|
ApplyFunction(
|
|
lambda m : m.restore().set_stroke(width = 5),
|
|
v_line,
|
|
run_time = 3,
|
|
rate_func = squish_rate_func(
|
|
there_and_back, a, a+0.2
|
|
)
|
|
)
|
|
for v_line, a in zip(v_lines, np.linspace(0, 0.8, len(v_lines)))
|
|
])
|
|
self.play(*[vl.restore for vl in v_lines])
|
|
self.play(rhs_copy.next_to, add_up_f_over, DOWN)
|
|
self.wait(2)
|
|
frac_line = add_up_f_over[1]
|
|
self.play(
|
|
FadeOut(rhs_copy.get_part_by_tex("over")),
|
|
rhs_copy.get_part_by_tex("dx").next_to,
|
|
add_up_f_over[0], RIGHT, SMALL_BUFF,
|
|
frac_line.scale_about_point, 1.2, frac_line.get_left(),
|
|
frac_line.stretch_to_fit_height, frac_line.get_height(),
|
|
)
|
|
rhs_copy.remove(rhs_copy.get_part_by_tex("over"))
|
|
self.wait(2)
|
|
|
|
int_fraction = self.average_expression[1].copy()
|
|
int_fraction.generate_target()
|
|
int_fraction.target.next_to(add_up_f_over, RIGHT, LARGE_BUFF)
|
|
int_fraction.target.shift_onto_screen()
|
|
double_arrow = TexMobject("\\Leftrightarrow")
|
|
double_arrow.next_to(
|
|
int_fraction.target.get_part_by_tex("over"), LEFT
|
|
)
|
|
|
|
self.play(
|
|
MoveToTarget(int_fraction),
|
|
VGroup(add_up_f_over, rhs_copy).shift, 0.4*DOWN
|
|
)
|
|
self.play(Write(double_arrow))
|
|
self.play(*list(map(FadeOut, [
|
|
dx, brace, num_samples, approx, rhs
|
|
])))
|
|
self.wait()
|
|
|
|
self.v_lines = v_lines
|
|
|
|
def show_improving_samples(self):
|
|
stroke_width = self.v_lines[0].get_stroke_width()
|
|
new_v_lines_list = [
|
|
self.get_vertical_lines_to_graph(
|
|
self.graph,
|
|
x_min = self.bounds[0],
|
|
x_max = self.bounds[1],
|
|
num_lines = len(self.v_lines)*(2**n),
|
|
color = GREEN,
|
|
stroke_width = float(stroke_width)/n
|
|
)
|
|
for n in range(1, 4)
|
|
]
|
|
for new_v_lines in new_v_lines_list:
|
|
for line in new_v_lines:
|
|
if self.y_axis.point_to_number(line.get_end()) < 0:
|
|
line.set_color(RED)
|
|
|
|
for new_v_lines in new_v_lines_list:
|
|
self.play(Transform(
|
|
self.v_lines, new_v_lines,
|
|
run_time = 2,
|
|
lag_ratio = 0.5
|
|
))
|
|
self.wait()
|
|
|
|
####
|
|
|
|
def func(self, x):
|
|
return 0.09*(x+1)*(x-4)*(x-8)
|
|
|
|
class GeneralAntiderivative(GeneralAverage):
|
|
def construct(self):
|
|
self.force_skipping()
|
|
self.setup_axes()
|
|
self.add_graph()
|
|
self.revert_to_original_skipping_status()
|
|
|
|
self.fade_existing_graph()
|
|
self.add_fraction()
|
|
self.add_antiderivative_graph()
|
|
self.show_average_in_terms_of_F()
|
|
self.draw_slope()
|
|
self.show_tangent_line_slopes()
|
|
|
|
def fade_existing_graph(self):
|
|
self.graph.fade(0.3)
|
|
self.graph_label.fade(0.3)
|
|
self.bound_lines.fade(0.3)
|
|
|
|
def add_fraction(self):
|
|
fraction = TexMobject(
|
|
"{\\displaystyle \\int", "^b", "_a", "f(x)", "\\,dx",
|
|
"\\over", "b", "-", "a}"
|
|
)
|
|
for tex, color in zip("ab", self.bound_colors):
|
|
fraction.set_color_by_tex(tex, color)
|
|
fraction.set_color_by_tex("display", WHITE)
|
|
|
|
fraction.scale(0.8)
|
|
fraction.next_to(self.y_axis, RIGHT)
|
|
fraction.to_edge(UP, buff = MED_SMALL_BUFF)
|
|
self.add(fraction)
|
|
|
|
self.fraction = fraction
|
|
|
|
def add_antiderivative_graph(self):
|
|
x_max = 9.7
|
|
antideriv_graph = self.get_graph(
|
|
lambda x : scipy.integrate.quad(
|
|
self.graph.underlying_function,
|
|
1, x
|
|
)[0],
|
|
color = YELLOW,
|
|
x_max = x_max,
|
|
)
|
|
antideriv_graph_label = self.get_graph_label(
|
|
antideriv_graph, "F(x)",
|
|
x_val = x_max
|
|
)
|
|
|
|
deriv = TexMobject(
|
|
"{dF", "\\over", "dx}", "(x)", "=", "f(x)"
|
|
)
|
|
deriv.set_color_by_tex("dF", antideriv_graph.get_color())
|
|
deriv.set_color_by_tex("f(x)", BLUE)
|
|
deriv.next_to(
|
|
antideriv_graph_label, DOWN, MED_LARGE_BUFF, LEFT
|
|
)
|
|
|
|
self.play(
|
|
ShowCreation(antideriv_graph),
|
|
Write(
|
|
antideriv_graph_label,
|
|
rate_func = squish_rate_func(smooth, 0.5, 1)
|
|
),
|
|
run_time = 2,
|
|
)
|
|
self.wait()
|
|
self.play(Write(deriv))
|
|
self.wait()
|
|
|
|
self.antideriv_graph = antideriv_graph
|
|
|
|
def show_average_in_terms_of_F(self):
|
|
new_fraction = TexMobject(
|
|
"=",
|
|
"{F", "(", "b", ")", "-", "F", "(", "a", ")",
|
|
"\\over",
|
|
"b", "-", "a}"
|
|
)
|
|
for tex, color in zip("abF", self.bound_colors+[YELLOW]):
|
|
new_fraction.set_color_by_tex(tex, color)
|
|
new_fraction.next_to(
|
|
self.fraction.get_part_by_tex("over"), RIGHT,
|
|
align_using_submobjects = True
|
|
)
|
|
|
|
to_write = VGroup(*it.chain(*[
|
|
new_fraction.get_parts_by_tex(tex)
|
|
for tex in "=F()-"
|
|
]))
|
|
to_write.remove(new_fraction.get_parts_by_tex("-")[-1])
|
|
|
|
numerator = VGroup(*new_fraction[1:10])
|
|
denominator = VGroup(*new_fraction[-3:])
|
|
|
|
self.play(Write(to_write))
|
|
self.play(*[
|
|
ReplacementTransform(
|
|
label.copy(),
|
|
new_fraction.get_part_by_tex(tex),
|
|
run_time = 2,
|
|
rate_func = squish_rate_func(smooth, a, a+0.7)
|
|
)
|
|
for label, tex, a in zip(
|
|
self.bounds_labels, "ab", [0, 0.3]
|
|
)
|
|
])
|
|
self.wait()
|
|
|
|
self.show_change_in_height(numerator.copy())
|
|
self.shift_antideriv_graph_up_and_down()
|
|
self.play(Write(VGroup(*new_fraction[-4:])))
|
|
self.wait()
|
|
|
|
h_line_brace = Brace(self.h_line, DOWN)
|
|
denominator_copy = denominator.copy()
|
|
a_label = self.bounds_labels[0]
|
|
self.play(
|
|
GrowFromCenter(h_line_brace),
|
|
a_label.shift, 0.7*a_label.get_width()*LEFT,
|
|
a_label.shift, 2.2*a_label.get_height()*UP,
|
|
)
|
|
self.play(
|
|
denominator_copy.next_to, h_line_brace,
|
|
DOWN, SMALL_BUFF
|
|
)
|
|
self.wait(3)
|
|
|
|
def show_change_in_height(self, numerator):
|
|
numerator.add_to_back(BackgroundRectangle(numerator))
|
|
a_point, b_point = points = [
|
|
self.input_to_graph_point(x, self.antideriv_graph)
|
|
for x in self.bounds
|
|
]
|
|
interim_point = b_point[0]*RIGHT + a_point[1]*UP
|
|
|
|
v_line = Line(b_point, interim_point)
|
|
h_line = Line(interim_point, a_point)
|
|
VGroup(v_line, h_line).set_color(WHITE)
|
|
brace = Brace(v_line, RIGHT, buff = SMALL_BUFF)
|
|
|
|
graph_within_bounds = self.get_graph(
|
|
self.antideriv_graph.underlying_function,
|
|
x_min = self.bounds[0],
|
|
x_max = self.bounds[1],
|
|
color = self.antideriv_graph.get_color()
|
|
)
|
|
|
|
b_label = self.bounds_labels[1]
|
|
self.play(
|
|
self.antideriv_graph.fade, 0.7,
|
|
Animation(graph_within_bounds)
|
|
)
|
|
self.play(
|
|
ShowCreation(v_line),
|
|
b_label.shift, b_label.get_width()*RIGHT,
|
|
b_label.shift, 1.75*b_label.get_height()*DOWN,
|
|
)
|
|
self.play(ShowCreation(h_line))
|
|
self.play(
|
|
numerator.scale, 0.75,
|
|
numerator.next_to, brace.copy(), RIGHT, SMALL_BUFF,
|
|
GrowFromCenter(brace),
|
|
)
|
|
self.wait(2)
|
|
|
|
self.antideriv_graph.add(
|
|
graph_within_bounds, v_line, h_line, numerator, brace
|
|
)
|
|
self.h_line = h_line
|
|
self.graph_points_at_bounds = points
|
|
|
|
def shift_antideriv_graph_up_and_down(self):
|
|
for vect in 2*UP, 3*DOWN, UP:
|
|
self.play(
|
|
self.antideriv_graph.shift, vect,
|
|
run_time = 2
|
|
)
|
|
self.wait()
|
|
|
|
def draw_slope(self):
|
|
line = Line(*self.graph_points_at_bounds)
|
|
line.set_color(PINK)
|
|
line.scale_in_place(1.3)
|
|
|
|
self.play(ShowCreation(line, run_time = 2))
|
|
self.wait()
|
|
|
|
def show_tangent_line_slopes(self):
|
|
ss_group = self.get_secant_slope_group(
|
|
x = self.bounds[0],
|
|
graph = self.antideriv_graph,
|
|
dx = 0.001,
|
|
secant_line_color = BLUE,
|
|
secant_line_length = 2,
|
|
)
|
|
|
|
self.play(*list(map(ShowCreation, ss_group)))
|
|
for x in range(2):
|
|
for bound in reversed(self.bounds):
|
|
self.animate_secant_slope_group_change(
|
|
ss_group,
|
|
target_x = bound,
|
|
run_time = 5,
|
|
)
|
|
|
|
class LastVideoWrapper(Scene):
|
|
def construct(self):
|
|
title = TextMobject("Chapter 8: Integrals")
|
|
title.to_edge(UP)
|
|
rect = Rectangle(height = 9, width = 16)
|
|
rect.set_stroke(WHITE)
|
|
rect.set_height(1.5*FRAME_Y_RADIUS)
|
|
rect.next_to(title, DOWN)
|
|
|
|
self.play(Write(title), ShowCreation(rect))
|
|
self.wait(5)
|
|
|
|
class ASecondIntegralSensation(TeacherStudentsScene):
|
|
def construct(self):
|
|
finite_average = TexMobject("{1+5+4+2 \\over 4}")
|
|
numbers = VGroup(*finite_average[0:7:2])
|
|
plusses = VGroup(*finite_average[1:7:2])
|
|
denominator = VGroup(*finite_average[7:])
|
|
finite_average.to_corner(UP+LEFT)
|
|
finite_average.to_edge(LEFT)
|
|
|
|
continuum = UnitInterval(
|
|
color = GREY,
|
|
unit_size = 6
|
|
)
|
|
continuum.next_to(finite_average, RIGHT, 2)
|
|
line = Line(continuum.get_left(), continuum.get_right())
|
|
line.set_color(YELLOW)
|
|
arrow = Arrow(DOWN+RIGHT, ORIGIN)
|
|
arrow.next_to(line.get_start(), DOWN+RIGHT, SMALL_BUFF)
|
|
|
|
sigma_to_integral = TexMobject(
|
|
"\\sum \\Leftrightarrow \\int"
|
|
)
|
|
sigma_to_integral.next_to(
|
|
self.teacher.get_corner(UP+LEFT), UP, MED_LARGE_BUFF
|
|
)
|
|
|
|
self.teacher_says(
|
|
"A second integral \\\\ sensation"
|
|
)
|
|
self.change_student_modes(*["erm"]*3)
|
|
self.wait()
|
|
self.play(
|
|
Write(numbers),
|
|
RemovePiCreatureBubble(self.teacher),
|
|
)
|
|
self.change_student_modes(
|
|
*["pondering"]*3,
|
|
look_at_arg = numbers
|
|
)
|
|
self.play(Write(plusses))
|
|
self.wait()
|
|
self.play(Write(denominator))
|
|
self.wait()
|
|
|
|
self.change_student_modes(
|
|
*["confused"]*3,
|
|
look_at_arg = continuum,
|
|
added_anims = [Write(continuum, run_time = 2)]
|
|
)
|
|
self.play(ShowCreation(arrow))
|
|
arrow.save_state()
|
|
self.play(
|
|
arrow.next_to, line.copy().get_end(), DOWN+RIGHT, SMALL_BUFF,
|
|
ShowCreation(line),
|
|
run_time = 2
|
|
)
|
|
self.play(*list(map(FadeOut, [arrow])))
|
|
self.wait(2)
|
|
self.change_student_modes(
|
|
*["pondering"]*3,
|
|
look_at_arg = sigma_to_integral,
|
|
added_anims = [
|
|
Write(sigma_to_integral),
|
|
self.teacher.change_mode, "raise_right_hand"
|
|
]
|
|
)
|
|
self.wait(3)
|
|
|
|
class Chapter9PatreonThanks(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",
|
|
"Zac Wentzell",
|
|
"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(GraphScene):
|
|
CONFIG = {
|
|
"x_min" : -0.2,
|
|
"x_max" : 3.5,
|
|
"x_leftmost_tick" : 0,
|
|
"x_tick_frequency" : np.pi/4,
|
|
"x_axis_label" : "",
|
|
"y_min" : -0.75,
|
|
"y_max" : 0.75,
|
|
"y_axis_height" : 4.5,
|
|
"y_tick_frequency" : 0.25,
|
|
"y_axis_label" : ""
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
self.remove(self.axes)
|
|
|
|
sine = self.get_graph(np.sin)
|
|
rects = self.get_riemann_rectangles(
|
|
sine,
|
|
x_min = 0,
|
|
x_max = np.pi,
|
|
dx = 0.01,
|
|
stroke_width = 0,
|
|
)
|
|
sine.add_to_back(rects)
|
|
sine.add(self.axes.copy())
|
|
sine.to_corner(UP+LEFT, buff = SMALL_BUFF)
|
|
sine.scale(0.9)
|
|
|
|
area = TextMobject("Area")
|
|
area.scale(3)
|
|
area.move_to(rects)
|
|
|
|
cosine = self.get_graph(lambda x : -np.cos(x))
|
|
cosine.set_stroke(GREEN, 8)
|
|
line = self.get_secant_slope_group(
|
|
0.75*np.pi, cosine,
|
|
dx = 0.01
|
|
).secant_line
|
|
line.set_stroke(PINK, 7)
|
|
cosine.add(line)
|
|
cosine.add(self.axes.copy())
|
|
cosine.scale(0.7)
|
|
cosine.to_corner(DOWN+RIGHT, buff = MED_SMALL_BUFF)
|
|
|
|
slope = TextMobject("Slope")
|
|
slope.scale(3)
|
|
# slope.next_to(cosine, LEFT, buff = 0)
|
|
# slope.to_edge(DOWN)
|
|
slope.to_corner(DOWN+RIGHT)
|
|
|
|
double_arrow = DoubleArrow(
|
|
area.get_bottom(),
|
|
slope.get_left(),
|
|
color = YELLOW,
|
|
tip_length = 0.75,
|
|
buff = MED_LARGE_BUFF
|
|
)
|
|
double_arrow.set_stroke(width = 18)
|
|
|
|
triangle = Polygon(
|
|
ORIGIN, UP, UP+RIGHT,
|
|
stroke_width = 0,
|
|
fill_color = BLUE_E,
|
|
fill_opacity = 0.5,
|
|
)
|
|
triangle.stretch_to_fit_width(FRAME_WIDTH)
|
|
triangle.stretch_to_fit_height(FRAME_HEIGHT)
|
|
triangle.to_corner(UP+LEFT, buff = 0)
|
|
|
|
alt_triangle = triangle.copy()
|
|
alt_triangle.rotate(np.pi)
|
|
alt_triangle.set_fill(BLACK, 1)
|
|
|
|
self.add(
|
|
triangle, sine, area,
|
|
alt_triangle, cosine, slope,
|
|
double_arrow,
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|