mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
2061 lines
63 KiB
Python
2061 lines
63 KiB
Python
from big_ol_pile_of_manim_imports import *
|
|
from old_projects.eoc.chapter4 import ThreeLinesChainRule
|
|
|
|
class ExpFootnoteOpeningQuote(OpeningQuote):
|
|
CONFIG = {
|
|
"quote" : [
|
|
"Who has not been amazed to learn that the function",
|
|
"$y = e^x$,", "like a phoenix rising again from its own",
|
|
"ashes, is its own derivative?",
|
|
],
|
|
"highlighted_quote_terms" : {
|
|
"$y = e^x$" : MAROON_B
|
|
},
|
|
"author" : "Francois le Lionnais"
|
|
}
|
|
|
|
class LastVideo(TeacherStudentsScene):
|
|
def construct(self):
|
|
series = VideoSeries()
|
|
series.to_edge(UP)
|
|
last_video = series[2]
|
|
last_video.save_state()
|
|
this_video = series[3]
|
|
|
|
known_formulas = VGroup(*list(map(TexMobject, [
|
|
"\\frac{d(x^n)}{dx} = nx^{n-1}",
|
|
"\\frac{d(\\sin(x))}{dx} = \\cos(x)",
|
|
])))
|
|
known_formulas.arrange(
|
|
DOWN, buff = MED_LARGE_BUFF,
|
|
)
|
|
known_formulas.set_height(2.5)
|
|
exp_question = TexMobject("2^x", ", 7^x, ", "e^x", " ???")
|
|
|
|
last_video_brace = Brace(last_video)
|
|
known_formulas.next_to(last_video_brace, DOWN)
|
|
known_formulas.shift(MED_LARGE_BUFF*LEFT)
|
|
last_video_brace.save_state()
|
|
last_video_brace.shift(3*LEFT)
|
|
last_video_brace.set_fill(opacity = 0)
|
|
|
|
self.add(series)
|
|
self.play(
|
|
last_video_brace.restore,
|
|
last_video.set_color, YELLOW,
|
|
self.get_teacher().change_mode, "raise_right_hand",
|
|
)
|
|
self.play(Write(known_formulas))
|
|
self.wait()
|
|
self.student_says(
|
|
exp_question, student_index = 1,
|
|
added_anims = [self.get_teacher().change_mode, "pondering"]
|
|
)
|
|
self.wait(3)
|
|
e_to_x = exp_question.get_part_by_tex("e^x")
|
|
self.play(
|
|
self.teacher.change_mode, "raise_right_hand",
|
|
e_to_x.scale, 1.5,
|
|
e_to_x.set_color, YELLOW,
|
|
e_to_x.next_to, self.teacher.get_corner(UP+LEFT), UP
|
|
)
|
|
self.wait(2)
|
|
|
|
class PopulationSizeGraphVsPopulationMassGraph(Scene):
|
|
def construct(self):
|
|
pass
|
|
|
|
class DoublingPopulation(PiCreatureScene):
|
|
CONFIG = {
|
|
"time_color" : YELLOW,
|
|
"pi_creature_grid_dimensions" : (8, 8),
|
|
"pi_creature_grid_height" : 6,
|
|
}
|
|
|
|
def construct(self):
|
|
self.remove(self.get_pi_creatures())
|
|
self.introduce_expression()
|
|
self.introduce_pi_creatures()
|
|
self.count_through_days()
|
|
self.ask_about_dM_dt()
|
|
self.growth_per_day()
|
|
self.relate_growth_rate_to_pop_size()
|
|
|
|
def introduce_expression(self):
|
|
f_x = TexMobject("f(x)", "=", "2^x")
|
|
f_t = TexMobject("f(t)", "=", "2^t")
|
|
P_t = TexMobject("P(t)", "=", "2^t")
|
|
M_t = TexMobject("M(t)", "=", "2^t")
|
|
functions = VGroup(f_x, f_t, P_t, M_t)
|
|
for function in functions:
|
|
function.scale(1.2)
|
|
function.to_corner(UP+LEFT)
|
|
for function in functions[1:]:
|
|
for i, j in (0, 2), (2, 1):
|
|
function[i][j].set_color(self.time_color)
|
|
|
|
t_expression = TexMobject("t", "=", "\\text{Time (in days)}")
|
|
t_expression.to_corner(UP+RIGHT)
|
|
t_expression[0].set_color(self.time_color)
|
|
|
|
pop_brace, mass_brace = [
|
|
Brace(function[0], DOWN)
|
|
for function in (P_t, M_t)
|
|
]
|
|
for brace, word in (pop_brace, "size"), (mass_brace, "mass"):
|
|
text = brace.get_text("Population %s"%word)
|
|
text.to_edge(LEFT)
|
|
brace.text = text
|
|
|
|
self.play(Write(f_x))
|
|
self.wait()
|
|
self.play(
|
|
Transform(f_x, f_t),
|
|
FadeIn(
|
|
t_expression,
|
|
run_time = 2,
|
|
lag_ratio = 0.5
|
|
)
|
|
)
|
|
self.play(Transform(f_x, P_t))
|
|
self.play(
|
|
GrowFromCenter(pop_brace),
|
|
Write(pop_brace.text, run_time = 2)
|
|
)
|
|
self.wait(2)
|
|
|
|
self.function = f_x
|
|
self.pop_brace = pop_brace
|
|
self.t_expression = t_expression
|
|
self.mass_function = M_t
|
|
self.mass_brace = mass_brace
|
|
|
|
def introduce_pi_creatures(self):
|
|
creatures = self.get_pi_creatures()
|
|
total_num_days = self.get_num_days()
|
|
num_start_days = 4
|
|
|
|
self.reset()
|
|
for x in range(num_start_days):
|
|
self.let_one_day_pass()
|
|
self.wait()
|
|
self.play(
|
|
Transform(self.function, self.mass_function),
|
|
Transform(self.pop_brace, self.mass_brace),
|
|
Transform(self.pop_brace.text, self.mass_brace.text),
|
|
)
|
|
self.wait()
|
|
for x in range(total_num_days-num_start_days):
|
|
self.let_one_day_pass()
|
|
self.wait()
|
|
self.joint_blink(shuffle = False)
|
|
self.wait()
|
|
|
|
def count_through_days(self):
|
|
self.reset()
|
|
brace = self.get_population_size_descriptor()
|
|
days_to_let_pass = 3
|
|
|
|
self.play(GrowFromCenter(brace))
|
|
self.wait()
|
|
for x in range(days_to_let_pass):
|
|
self.let_one_day_pass()
|
|
new_brace = self.get_population_size_descriptor()
|
|
self.play(Transform(brace, new_brace))
|
|
self.wait()
|
|
|
|
self.population_size_descriptor = brace
|
|
|
|
def ask_about_dM_dt(self):
|
|
dM_dt_question = TexMobject("{dM", "\\over dt}", "=", "???")
|
|
dM, dt, equals, q_marks = dM_dt_question
|
|
dM_dt_question.next_to(self.function, DOWN, buff = LARGE_BUFF)
|
|
dM_dt_question.to_edge(LEFT)
|
|
|
|
self.play(
|
|
FadeOut(self.pop_brace),
|
|
FadeOut(self.pop_brace.text),
|
|
Write(dM_dt_question)
|
|
)
|
|
self.wait(3)
|
|
for mob in dM, dt:
|
|
self.play(Indicate(mob))
|
|
self.wait()
|
|
|
|
self.dM_dt_question = dM_dt_question
|
|
|
|
def growth_per_day(self):
|
|
day_to_day, frac = self.get_from_day_to_day_label()
|
|
|
|
self.play(
|
|
FadeOut(self.dM_dt_question),
|
|
FadeOut(self.population_size_descriptor),
|
|
FadeIn(day_to_day)
|
|
)
|
|
rect = self.let_day_pass_and_highlight_new_creatures(frac)
|
|
|
|
for x in range(2):
|
|
new_day_to_day, new_frac = self.get_from_day_to_day_label()
|
|
self.play(*list(map(FadeOut, [rect, frac])))
|
|
frac = new_frac
|
|
self.play(Transform(day_to_day, new_day_to_day))
|
|
rect = self.let_day_pass_and_highlight_new_creatures(frac)
|
|
self.play(*list(map(FadeOut, [rect, frac, day_to_day])))
|
|
|
|
def let_day_pass_and_highlight_new_creatures(self, frac):
|
|
num_new_creatures = 2**self.get_curr_day()
|
|
|
|
self.let_one_day_pass()
|
|
new_creatures = VGroup(
|
|
*self.get_on_screen_pi_creatures()[-num_new_creatures:]
|
|
)
|
|
rect = Rectangle(
|
|
color = GREEN,
|
|
fill_color = BLUE,
|
|
fill_opacity = 0.3,
|
|
)
|
|
rect.replace(new_creatures, stretch = True)
|
|
rect.stretch_to_fit_height(rect.get_height()+MED_SMALL_BUFF)
|
|
rect.stretch_to_fit_width(rect.get_width()+MED_SMALL_BUFF)
|
|
self.play(DrawBorderThenFill(rect))
|
|
self.play(Write(frac))
|
|
self.wait()
|
|
return rect
|
|
|
|
def relate_growth_rate_to_pop_size(self):
|
|
false_deriv = TexMobject(
|
|
"{d(2^t) ", "\\over dt}", "= 2^t"
|
|
)
|
|
difference_eq = TexMobject(
|
|
"{ {2^{t+1} - 2^t} \\over", "1}", "= 2^t"
|
|
)
|
|
real_deriv = TexMobject(
|
|
"{ {2^{t+dt} - 2^t} \\over", "dt}", "= \\, ???"
|
|
)
|
|
VGroup(
|
|
false_deriv[0][3],
|
|
false_deriv[2][-1],
|
|
difference_eq[0][1],
|
|
difference_eq[0][-2],
|
|
difference_eq[2][-1],
|
|
difference_eq[2][-1],
|
|
real_deriv[0][1],
|
|
real_deriv[0][-2],
|
|
).set_color(YELLOW)
|
|
VGroup(
|
|
difference_eq[0][3],
|
|
difference_eq[1][-1],
|
|
real_deriv[0][3],
|
|
real_deriv[0][4],
|
|
real_deriv[1][-2],
|
|
real_deriv[1][-1],
|
|
).set_color(GREEN)
|
|
|
|
expressions = [false_deriv, difference_eq, real_deriv]
|
|
text_arg_list = [
|
|
("Tempting", "...",),
|
|
("Rate of change", "\\\\ over one full day"),
|
|
("Rate of change", "\\\\ in a small time"),
|
|
]
|
|
for expression, text_args in zip(expressions, text_arg_list):
|
|
expression.next_to(
|
|
self.function, DOWN,
|
|
buff = LARGE_BUFF,
|
|
aligned_edge = LEFT,
|
|
)
|
|
expression.brace = Brace(expression, DOWN)
|
|
expression.brace_text = expression.brace.get_text(*text_args)
|
|
|
|
time = self.t_expression[-1]
|
|
new_time = TexMobject("3")
|
|
new_time.move_to(time, LEFT)
|
|
|
|
fading_creatures = VGroup(*self.get_on_screen_pi_creatures()[8:])
|
|
|
|
|
|
self.play(*list(map(FadeIn, [
|
|
false_deriv, false_deriv.brace, false_deriv.brace_text
|
|
])))
|
|
self.wait()
|
|
self.play(
|
|
Transform(time, new_time),
|
|
FadeOut(fading_creatures)
|
|
)
|
|
self.wait()
|
|
for x in range(3):
|
|
self.let_one_day_pass(run_time = 2)
|
|
self.wait(2)
|
|
|
|
for expression in difference_eq, real_deriv:
|
|
expression.brace_text[1].set_color(GREEN)
|
|
self.play(
|
|
Transform(false_deriv, expression),
|
|
Transform(false_deriv.brace, expression.brace),
|
|
Transform(false_deriv.brace_text, expression.brace_text),
|
|
)
|
|
self.wait(3)
|
|
self.reset()
|
|
for x in range(self.get_num_days()):
|
|
self.let_one_day_pass()
|
|
self.wait()
|
|
|
|
rect = Rectangle(color = YELLOW)
|
|
rect.replace(real_deriv)
|
|
rect.stretch_to_fit_width(rect.get_width()+MED_SMALL_BUFF)
|
|
rect.stretch_to_fit_height(rect.get_height()+MED_SMALL_BUFF)
|
|
self.play(*list(map(FadeOut, [
|
|
false_deriv.brace, false_deriv.brace_text
|
|
])))
|
|
self.play(ShowCreation(rect))
|
|
self.play(*[
|
|
ApplyFunction(
|
|
lambda pi : pi.change_mode("pondering").look_at(real_deriv),
|
|
pi,
|
|
run_time = 2,
|
|
rate_func = squish_rate_func(smooth, a, a+0.5)
|
|
)
|
|
for pi in self.get_pi_creatures()
|
|
for a in [0.5*random.random()]
|
|
])
|
|
self.wait(3)
|
|
|
|
###########
|
|
|
|
def create_pi_creatures(self):
|
|
width, height = self.pi_creature_grid_dimensions
|
|
creature_array = VGroup(*[
|
|
VGroup(*[
|
|
PiCreature(mode = "plain")
|
|
for y in range(height)
|
|
]).arrange(UP, buff = MED_LARGE_BUFF)
|
|
for x in range(width)
|
|
]).arrange(RIGHT, buff = MED_LARGE_BUFF)
|
|
creatures = VGroup(*it.chain(*creature_array))
|
|
creatures.set_height(self.pi_creature_grid_height)
|
|
creatures.to_corner(DOWN+RIGHT)
|
|
|
|
colors = color_gradient([BLUE, GREEN, GREY_BROWN], len(creatures))
|
|
random.shuffle(colors)
|
|
for creature, color in zip(creatures, colors):
|
|
creature.set_color(color)
|
|
|
|
return creatures
|
|
|
|
def reset(self):
|
|
time = self.t_expression[-1]
|
|
faders = [time] + list(self.get_on_screen_pi_creatures())
|
|
new_time = TexMobject("0")
|
|
new_time.next_to(self.t_expression[-2], RIGHT)
|
|
first_creature = self.get_pi_creatures()[0]
|
|
|
|
self.play(*list(map(FadeOut, faders)))
|
|
self.play(*list(map(FadeIn, [first_creature, new_time])))
|
|
self.t_expression.submobjects[-1] = new_time
|
|
|
|
def let_one_day_pass(self, run_time = 2):
|
|
all_creatures = self.get_pi_creatures()
|
|
on_screen_creatures = self.get_on_screen_pi_creatures()
|
|
low_i = len(on_screen_creatures)
|
|
high_i = min(2*low_i, len(all_creatures))
|
|
new_creatures = VGroup(*all_creatures[low_i:high_i])
|
|
|
|
to_children_anims = []
|
|
growing_anims = []
|
|
for old_pi, pi in zip(on_screen_creatures, new_creatures):
|
|
pi.save_state()
|
|
child = pi.copy()
|
|
child.scale(0.25, about_point = child.get_bottom())
|
|
child.eyes.scale(1.5, about_point = child.eyes.get_bottom())
|
|
pi.move_to(old_pi)
|
|
pi.set_fill(opacity = 0)
|
|
|
|
index = list(new_creatures).index(pi)
|
|
prop = float(index)/len(new_creatures)
|
|
alpha = np.clip(len(new_creatures)/8.0, 0, 0.5)
|
|
rate_func = squish_rate_func(
|
|
smooth, alpha*prop, alpha*prop+(1-alpha)
|
|
)
|
|
|
|
to_child_anim = Transform(pi, child, rate_func = rate_func)
|
|
to_child_anim.update(1)
|
|
growing_anim = ApplyMethod(pi.restore, rate_func = rate_func)
|
|
to_child_anim.update(0)
|
|
|
|
to_children_anims.append(to_child_anim)
|
|
growing_anims.append(growing_anim)
|
|
|
|
time = self.t_expression[-1]
|
|
total_new_creatures = len(on_screen_creatures) + len(new_creatures)
|
|
new_time = TexMobject(str(int(np.log2(total_new_creatures))))
|
|
new_time.move_to(time, LEFT)
|
|
|
|
growing_anims.append(Transform(time, new_time))
|
|
|
|
self.play(*to_children_anims, run_time = run_time/2.0)
|
|
self.play(*growing_anims, run_time = run_time/2.0)
|
|
|
|
def get_num_pi_creatures_on_screen(self):
|
|
mobjects = self.get_mobjects()
|
|
return sum([
|
|
pi in mobjects for pi in self.get_pi_creatures()
|
|
])
|
|
|
|
def get_population_size_descriptor(self):
|
|
on_screen_creatures = self.get_on_screen_pi_creatures()
|
|
brace = Brace(on_screen_creatures, LEFT)
|
|
n = len(on_screen_creatures)
|
|
label = brace.get_text(
|
|
"$2^%d$"%int(np.log2(n)),
|
|
"$=%d$"%n,
|
|
)
|
|
brace.add(label)
|
|
return brace
|
|
|
|
def get_num_days(self):
|
|
x, y = self.pi_creature_grid_dimensions
|
|
return int(np.log2(x*y))
|
|
|
|
def get_curr_day(self):
|
|
return int(np.log2(len(self.get_on_screen_pi_creatures())))
|
|
|
|
def get_from_day_to_day_label(self):
|
|
curr_day = self.get_curr_day()
|
|
top_words = TextMobject(
|
|
"From day", str(curr_day),
|
|
"to", str(curr_day+1), ":"
|
|
)
|
|
top_words.set_width(4)
|
|
top_words.next_to(
|
|
self.function, DOWN,
|
|
buff = MED_LARGE_BUFF,
|
|
aligned_edge = LEFT,
|
|
)
|
|
top_words[1].set_color(GREEN)
|
|
|
|
bottom_words = TexMobject(
|
|
str(2**curr_day),
|
|
"\\text{ creatures}", "\\over {1 \\text{ day}}"
|
|
)
|
|
bottom_words[0].set_color(GREEN)
|
|
bottom_words.next_to(top_words, DOWN, buff = MED_LARGE_BUFF)
|
|
|
|
return top_words, bottom_words
|
|
|
|
class GraphOfTwoToT(GraphScene):
|
|
CONFIG = {
|
|
"x_axis_label" : "$t$",
|
|
"y_axis_label" : "$M$",
|
|
"x_labeled_nums" : list(range(1, 7)),
|
|
"y_labeled_nums" : list(range(8, 40, 8)),
|
|
"x_max" : 6,
|
|
"y_min" : 0,
|
|
"y_max" : 32,
|
|
"y_tick_frequency" : 2,
|
|
"graph_origin" : 2.5*DOWN + 5*LEFT,
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
example_t = 3
|
|
graph = self.get_graph(lambda t : 2**t, color = BLUE_C)
|
|
self.graph = graph
|
|
graph_label = self.get_graph_label(
|
|
graph, "M(t) = 2^t",
|
|
direction = LEFT,
|
|
)
|
|
label_group = self.get_label_group(example_t)
|
|
v_line, brace, height_label, ss_group, slope_label = label_group
|
|
self.animate_secant_slope_group_change(
|
|
ss_group,
|
|
target_dx = 1,
|
|
run_time = 0
|
|
)
|
|
self.remove(ss_group)
|
|
|
|
#Draw graph and revert to tangent
|
|
self.play(ShowCreation(graph))
|
|
self.play(Write(graph_label))
|
|
self.wait()
|
|
self.play(Write(ss_group))
|
|
self.wait()
|
|
for target_dx in 0.01, 1, 0.01:
|
|
self.animate_secant_slope_group_change(
|
|
ss_group,
|
|
target_dx = target_dx
|
|
)
|
|
self.wait()
|
|
|
|
#Mark up with values
|
|
|
|
self.play(ShowCreation(v_line))
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
Write(height_label, run_time = 1)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(
|
|
slope_label,
|
|
run_time = 4,
|
|
lag_ratio = 0.5
|
|
),
|
|
ReplacementTransform(
|
|
height_label.copy(),
|
|
slope_label.get_part_by_tex("2^")
|
|
)
|
|
)
|
|
self.wait()
|
|
|
|
#Vary value
|
|
threes = VGroup(height_label[1], slope_label[2][1])
|
|
ts = VGroup(*[
|
|
TexMobject("t").set_color(YELLOW).scale(0.75).move_to(three)
|
|
for three in threes
|
|
])
|
|
self.play(Transform(threes, ts))
|
|
|
|
alt_example_t = example_t+1
|
|
def update_label_group(group, alpha):
|
|
t = interpolate(example_t, alt_example_t, alpha)
|
|
new_group = self.get_label_group(t)
|
|
Transform(group, new_group).update(1)
|
|
for t, three in zip(ts, threes):
|
|
t.move_to(three)
|
|
Transform(threes, ts).update(1)
|
|
return group
|
|
|
|
self.play(UpdateFromAlphaFunc(
|
|
label_group, update_label_group,
|
|
run_time = 3,
|
|
))
|
|
self.play(UpdateFromAlphaFunc(
|
|
label_group, update_label_group,
|
|
run_time = 3,
|
|
rate_func = lambda t : 1 - 1.5*smooth(t)
|
|
))
|
|
|
|
def get_label_group(self, t):
|
|
graph = self.graph
|
|
|
|
v_line = self.get_vertical_line_to_graph(
|
|
t, graph,
|
|
color = YELLOW,
|
|
)
|
|
brace = Brace(v_line, RIGHT)
|
|
height_label = brace.get_text("$2^%d$"%t)
|
|
|
|
ss_group = self.get_secant_slope_group(
|
|
t, graph, dx = 0.01,
|
|
df_label = "dM",
|
|
dx_label = "dt",
|
|
dx_line_color = GREEN,
|
|
secant_line_color = RED,
|
|
)
|
|
slope_label = TexMobject(
|
|
"\\text{Slope}", "=",
|
|
"2^%d"%t,
|
|
"(%.7f\\dots)"%np.log(2)
|
|
)
|
|
slope_label.next_to(
|
|
ss_group.secant_line.point_from_proportion(0.65),
|
|
DOWN+RIGHT,
|
|
buff = 0
|
|
)
|
|
slope_label.set_color_by_tex("Slope", RED)
|
|
return VGroup(
|
|
v_line, brace, height_label,
|
|
ss_group, slope_label
|
|
)
|
|
|
|
class SimpleGraphOfTwoToT(GraphOfTwoToT):
|
|
CONFIG = {
|
|
"x_axis_label" : "",
|
|
"y_axis_label" : "",
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
func = lambda t : 2**t
|
|
graph = self.get_graph(func)
|
|
line_pairs = VGroup()
|
|
for x in 1, 2, 3, 4, 5:
|
|
point = self.coords_to_point(x, func(x))
|
|
x_axis_point = self.coords_to_point(x, 0)
|
|
y_axis_point = self.coords_to_point(0, func(x))
|
|
line_pairs.add(VGroup(
|
|
DashedLine(x_axis_point, point),
|
|
DashedLine(y_axis_point, point),
|
|
))
|
|
|
|
|
|
self.play(ShowCreation(graph, run_time = 2))
|
|
for pair in line_pairs:
|
|
self.play(ShowCreation(pair))
|
|
self.wait()
|
|
|
|
class FakeDiagram(TeacherStudentsScene):
|
|
def construct(self):
|
|
gs = GraphScene(skip_animations = True)
|
|
gs.setup_axes()
|
|
background_graph, foreground_graph = graphs = VGroup(*[
|
|
gs.get_graph(
|
|
lambda t : np.log(2)*2**t,
|
|
x_min = -8,
|
|
x_max = 2 + dx
|
|
)
|
|
for dx in (0.25, 0)
|
|
])
|
|
for graph in graphs:
|
|
end_point = graph.points[-1]
|
|
axis_point = end_point[0]*RIGHT + gs.graph_origin[1]*UP
|
|
for alpha in np.linspace(0, 1, 20):
|
|
point = interpolate(axis_point, graph.points[0], alpha)
|
|
graph.add_line_to(point)
|
|
graph.set_stroke(width = 1)
|
|
graph.set_fill(opacity = 1)
|
|
graph.set_color(BLUE_D)
|
|
background_graph.set_color(YELLOW)
|
|
background_graph.set_stroke(width = 0.5)
|
|
|
|
graphs.next_to(self.teacher, UP+LEFT, LARGE_BUFF)
|
|
two_to_t = TexMobject("2^t")
|
|
two_to_t.next_to(
|
|
foreground_graph.get_corner(DOWN+RIGHT), UP+LEFT
|
|
)
|
|
corner_line = Line(*[
|
|
graph.get_corner(DOWN+RIGHT)
|
|
for graph in graphs
|
|
])
|
|
dt_brace = Brace(corner_line, DOWN, buff = SMALL_BUFF)
|
|
dt = dt_brace.get_text("$dt$")
|
|
|
|
side_brace = Brace(graphs, RIGHT, buff = SMALL_BUFF)
|
|
deriv = side_brace.get_text("$\\frac{d(2^t)}{dt}$")
|
|
|
|
circle = Circle(color = RED)
|
|
circle.replace(deriv, stretch = True)
|
|
circle.scale_in_place(1.5)
|
|
|
|
words = TextMobject("Not a real explanation")
|
|
words.to_edge(UP)
|
|
arrow = Arrow(words.get_bottom(), two_to_t.get_corner(UP+LEFT))
|
|
arrow.set_color(WHITE)
|
|
|
|
diagram = VGroup(
|
|
graphs, two_to_t, dt_brace, dt,
|
|
side_brace, deriv, circle,
|
|
words, arrow
|
|
)
|
|
|
|
self.play(self.teacher.change_mode, "raise_right_hand")
|
|
self.play(
|
|
Animation(VectorizedPoint(graphs.get_right())),
|
|
DrawBorderThenFill(foreground_graph),
|
|
Write(two_to_t)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
ReplacementTransform(
|
|
foreground_graph.copy(),
|
|
background_graph,
|
|
),
|
|
Animation(foreground_graph),
|
|
Animation(two_to_t),
|
|
GrowFromCenter(dt_brace),
|
|
Write(dt)
|
|
)
|
|
self.play(GrowFromCenter(side_brace))
|
|
self.play(Write(deriv, run_time = 2))
|
|
self.wait()
|
|
|
|
self.play(
|
|
ShowCreation(circle),
|
|
self.teacher.change_mode, "hooray"
|
|
)
|
|
self.change_student_modes(*["confused"]*3)
|
|
self.play(
|
|
Write(words),
|
|
ShowCreation(arrow),
|
|
self.teacher.change_mode, "shruggie"
|
|
)
|
|
self.wait(3)
|
|
self.play(
|
|
FadeOut(diagram),
|
|
*[
|
|
ApplyMethod(pi.change_mode, "plain")
|
|
for pi in self.get_pi_creatures()
|
|
]
|
|
)
|
|
self.teacher_says(
|
|
"More numerical \\\\ than visual..."
|
|
)
|
|
self.wait(2)
|
|
|
|
self.diagram = diagram
|
|
|
|
class AnalyzeExponentRatio(PiCreatureScene):
|
|
CONFIG = {
|
|
"base" : 2,
|
|
"base_str" : "2",
|
|
}
|
|
def construct(self):
|
|
base_str = self.base_str
|
|
|
|
func_def = TexMobject("M(", "t", ")", "= ", "%s^"%base_str, "t")
|
|
func_def.to_corner(UP+LEFT)
|
|
self.add(func_def)
|
|
|
|
ratio = TexMobject(
|
|
"{ {%s^"%base_str, "{t", "+", "dt}", "-",
|
|
"%s^"%base_str, "t}",
|
|
"\\over \\,", "dt}"
|
|
)
|
|
ratio.shift(UP+LEFT)
|
|
|
|
lhs = TexMobject("{dM", "\\over \\,", "dt}", "(", "t", ")", "=")
|
|
lhs.next_to(ratio, LEFT)
|
|
|
|
|
|
two_to_t_plus_dt = VGroup(*ratio[:4])
|
|
two_to_t = VGroup(*ratio[5:7])
|
|
two_to_t_two_to_dt = TexMobject(
|
|
"%s^"%base_str, "t",
|
|
"%s^"%base_str, "{dt}"
|
|
)
|
|
two_to_t_two_to_dt.move_to(two_to_t_plus_dt, DOWN+LEFT)
|
|
exp_prop_brace = Brace(two_to_t_two_to_dt, UP)
|
|
|
|
one = TexMobject("1")
|
|
one.move_to(ratio[5], DOWN)
|
|
lp, rp = parens = TexMobject("()")
|
|
parens.stretch(1.3, 1)
|
|
parens.set_height(ratio.get_height())
|
|
lp.next_to(ratio, LEFT, buff = 0)
|
|
rp.next_to(ratio, RIGHT, buff = 0)
|
|
|
|
extracted_two_to_t = TexMobject("%s^"%base_str, "t")
|
|
extracted_two_to_t.next_to(lp, LEFT, buff = SMALL_BUFF)
|
|
|
|
expressions = [
|
|
ratio, two_to_t_two_to_dt,
|
|
extracted_two_to_t, lhs, func_def
|
|
]
|
|
for expression in expressions:
|
|
expression.set_color_by_tex("t", YELLOW)
|
|
expression.set_color_by_tex("dt", GREEN)
|
|
|
|
#Apply exponential property
|
|
self.play(
|
|
Write(ratio), Write(lhs),
|
|
self.pi_creature.change_mode, "raise_right_hand"
|
|
)
|
|
self.wait(2)
|
|
self.play(
|
|
two_to_t_plus_dt.next_to, exp_prop_brace, UP,
|
|
self.pi_creature.change_mode, "pondering"
|
|
)
|
|
self.play(
|
|
ReplacementTransform(
|
|
two_to_t_plus_dt.copy(), two_to_t_two_to_dt,
|
|
run_time = 2,
|
|
path_arc = np.pi,
|
|
),
|
|
FadeIn(exp_prop_brace)
|
|
)
|
|
self.wait(2)
|
|
|
|
#Talk about exponential property
|
|
add_exp_rect, mult_rect = rects = [
|
|
Rectangle(
|
|
stroke_color = BLUE,
|
|
stroke_width = 2,
|
|
).replace(mob).scale_in_place(1.1)
|
|
for mob in [
|
|
VGroup(*two_to_t_plus_dt[1:]),
|
|
two_to_t_two_to_dt
|
|
]
|
|
]
|
|
words = VGroup(*[
|
|
TextMobject(s, " ideas")
|
|
for s in ("Additive", "Multiplicative")
|
|
])
|
|
words[0].move_to(words[1], LEFT)
|
|
words.set_color(BLUE)
|
|
words.next_to(two_to_t_plus_dt, RIGHT, buff = 1.5*LARGE_BUFF)
|
|
arrows = VGroup(*[
|
|
Arrow(word.get_left(), rect, color = words.get_color())
|
|
for word, rect in zip(words, rects)
|
|
])
|
|
|
|
self.play(ShowCreation(add_exp_rect))
|
|
self.wait()
|
|
self.play(ReplacementTransform(
|
|
add_exp_rect.copy(), mult_rect
|
|
))
|
|
self.wait()
|
|
self.change_mode("happy")
|
|
self.play(Write(words[0], run_time = 2))
|
|
self.play(ShowCreation(arrows[0]))
|
|
self.wait()
|
|
self.play(
|
|
Transform(*words),
|
|
Transform(*arrows),
|
|
)
|
|
self.wait(2)
|
|
self.play(*list(map(FadeOut, [
|
|
words[0], arrows[0], add_exp_rect, mult_rect,
|
|
two_to_t_plus_dt, exp_prop_brace,
|
|
])))
|
|
|
|
#Factor out 2^t
|
|
self.play(*[
|
|
FadeIn(
|
|
mob,
|
|
run_time = 2,
|
|
rate_func = squish_rate_func(smooth, 0.5, 1)
|
|
)
|
|
for mob in (one, lp, rp)
|
|
] + [
|
|
ReplacementTransform(
|
|
mob, extracted_two_to_t,
|
|
path_arc = np.pi/2,
|
|
run_time = 2,
|
|
)
|
|
for mob in (two_to_t, VGroup(*two_to_t_two_to_dt[:2]))
|
|
] + [
|
|
lhs.next_to, extracted_two_to_t, LEFT
|
|
])
|
|
self.change_mode("pondering")
|
|
shifter = VGroup(ratio[4], one, *two_to_t_two_to_dt[2:])
|
|
stretcher = VGroup(lp, ratio[7], rp)
|
|
self.play(
|
|
shifter.next_to, ratio[7], UP,
|
|
stretcher.stretch_in_place, 0.9, 0
|
|
)
|
|
self.wait(2)
|
|
|
|
#Ask about dt -> 0
|
|
brace = Brace(VGroup(extracted_two_to_t, ratio), DOWN)
|
|
alt_brace = Brace(parens, DOWN)
|
|
dt_to_zero = TexMobject("dt", "\\to 0")
|
|
dt_to_zero.set_color_by_tex("dt", GREEN)
|
|
dt_to_zero.next_to(brace, DOWN)
|
|
|
|
self.play(GrowFromCenter(brace))
|
|
self.play(Write(dt_to_zero))
|
|
self.wait(2)
|
|
|
|
#Who cares
|
|
randy = Randolph()
|
|
randy.scale(0.7)
|
|
randy.to_edge(DOWN)
|
|
|
|
self.play(
|
|
FadeIn(randy),
|
|
self.pi_creature.change_mode, "plain",
|
|
)
|
|
self.play(PiCreatureSays(
|
|
randy, "Who cares?",
|
|
bubble_kwargs = {"direction" : LEFT},
|
|
target_mode = "angry",
|
|
))
|
|
self.wait(2)
|
|
self.play(
|
|
RemovePiCreatureBubble(randy),
|
|
FadeOut(randy),
|
|
self.pi_creature.change_mode, "hooray",
|
|
self.pi_creature.look_at, parens
|
|
)
|
|
self.play(
|
|
Transform(brace, alt_brace),
|
|
dt_to_zero.next_to, alt_brace, DOWN
|
|
)
|
|
self.wait()
|
|
|
|
#Highlight separation
|
|
rects = [
|
|
Rectangle(
|
|
stroke_color = color,
|
|
stroke_width = 2,
|
|
).replace(mob, stretch = True).scale_in_place(1.1)
|
|
for mob, color in [
|
|
(VGroup(parens, dt_to_zero), GREEN),
|
|
(extracted_two_to_t, YELLOW),
|
|
]
|
|
]
|
|
self.play(ShowCreation(rects[0]))
|
|
self.wait(2)
|
|
self.play(ReplacementTransform(rects[0].copy(), rects[1]))
|
|
self.change_mode("happy")
|
|
self.wait()
|
|
self.play(*list(map(FadeOut, rects)))
|
|
|
|
#Plug in specific values
|
|
static_constant = self.try_specific_dt_values()
|
|
constant = static_constant.copy()
|
|
|
|
#Replace with actual constant
|
|
limit_term = VGroup(
|
|
brace, dt_to_zero, ratio[4], one, rects[0],
|
|
*ratio[7:]+two_to_t_two_to_dt[2:]
|
|
)
|
|
self.play(FadeIn(rects[0]))
|
|
self.play(limit_term.to_corner, DOWN+LEFT)
|
|
self.play(
|
|
lp.stretch, 0.5, 1,
|
|
lp.stretch, 0.8, 0,
|
|
lp.next_to, extracted_two_to_t[0], RIGHT,
|
|
rp.stretch, 0.5, 1,
|
|
rp.stretch, 0.8, 0,
|
|
rp.next_to, lp, RIGHT, SMALL_BUFF,
|
|
rp.shift, constant.get_width()*RIGHT,
|
|
constant.next_to, extracted_two_to_t[0], RIGHT, MED_LARGE_BUFF
|
|
)
|
|
self.wait()
|
|
self.change_mode("confused")
|
|
self.wait()
|
|
|
|
#Indicate distinction between dt group and t group again
|
|
for mob in limit_term, extracted_two_to_t:
|
|
self.play(FocusOn(mob))
|
|
self.play(Indicate(mob))
|
|
self.wait()
|
|
|
|
#hold_final_value
|
|
derivative = VGroup(
|
|
lhs, extracted_two_to_t, parens, constant
|
|
)
|
|
func_def_rhs = VGroup(*func_def[-2:]).copy()
|
|
func_lp, func_rp = func_parens = TexMobject("()")
|
|
func_parens.set_fill(opacity = 0)
|
|
func_lp.next_to(func_def_rhs[0], LEFT, buff = 0)
|
|
func_rp.next_to(func_lp, RIGHT, buff = func_def_rhs.get_width())
|
|
func_def_rhs.add(func_parens)
|
|
M = lhs[0][1]
|
|
|
|
self.play(
|
|
FadeOut(M),
|
|
func_def_rhs.move_to, M, LEFT,
|
|
func_def_rhs.set_fill, None, 1,
|
|
)
|
|
lhs[0].submobjects[1] = func_def_rhs
|
|
self.wait()
|
|
self.play(
|
|
derivative.next_to, self.pi_creature, UP,
|
|
derivative.to_edge, RIGHT,
|
|
self.pi_creature.change_mode, "raise_right_hand"
|
|
)
|
|
self.wait(2)
|
|
for mob in extracted_two_to_t, constant:
|
|
self.play(Indicate(mob))
|
|
self.wait()
|
|
self.wait(2)
|
|
|
|
def try_specific_dt_values(self):
|
|
expressions = []
|
|
for num_zeros in [1, 2, 4, 7]:
|
|
dt_str = "0." + num_zeros*"0" + "1"
|
|
dt_num = float(dt_str)
|
|
output_num = (self.base**dt_num - 1) / dt_num
|
|
output_str = "%.7f\\dots"%output_num
|
|
|
|
expression = TexMobject(
|
|
"{%s^"%self.base_str, "{%s}"%dt_str, "-1",
|
|
"\\over \\,", "%s}"%dt_str,
|
|
"=", output_str
|
|
)
|
|
expression.set_color_by_tex(dt_str, GREEN)
|
|
expression.set_color_by_tex(output_str, BLUE)
|
|
expression.to_corner(UP+RIGHT)
|
|
expressions.append(expression)
|
|
|
|
curr_expression = expressions[0]
|
|
self.play(
|
|
Write(curr_expression),
|
|
self.pi_creature.change_mode, "pondering"
|
|
)
|
|
self.wait(2)
|
|
for expression in expressions[1:]:
|
|
self.play(Transform(curr_expression, expression))
|
|
self.wait(2)
|
|
return curr_expression[-1]
|
|
|
|
class ExponentRatioWithThree(AnalyzeExponentRatio):
|
|
CONFIG = {
|
|
"base" : 3,
|
|
"base_str" : "3",
|
|
}
|
|
|
|
class ExponentRatioWithSeven(AnalyzeExponentRatio):
|
|
CONFIG = {
|
|
"base" : 7,
|
|
"base_str" : "7",
|
|
}
|
|
|
|
class ExponentRatioWithEight(AnalyzeExponentRatio):
|
|
CONFIG = {
|
|
"base" : 8,
|
|
"base_str" : "8",
|
|
}
|
|
|
|
class ExponentRatioWithE(AnalyzeExponentRatio):
|
|
CONFIG = {
|
|
"base" : np.exp(1),
|
|
"base_str" : "e",
|
|
}
|
|
|
|
class CompareTwoConstantToEightConstant(PiCreatureScene):
|
|
def construct(self):
|
|
two_deriv, eight_deriv = derivs = VGroup(*[
|
|
self.get_derivative_expression(base)
|
|
for base in (2, 8)
|
|
])
|
|
|
|
derivs.arrange(
|
|
DOWN, buff = 1.5, aligned_edge = LEFT
|
|
)
|
|
derivs.to_edge(LEFT, LARGE_BUFF).shift(UP)
|
|
arrow = Arrow(*[deriv[-2] for deriv in derivs])
|
|
times_three = TexMobject("\\times 3")
|
|
times_three.next_to(arrow, RIGHT)
|
|
|
|
why = TextMobject("Why?")
|
|
why.next_to(self.pi_creature, UP, MED_LARGE_BUFF)
|
|
|
|
self.add(eight_deriv)
|
|
self.wait()
|
|
self.play(ReplacementTransform(
|
|
eight_deriv.copy(),
|
|
two_deriv
|
|
))
|
|
self.wait()
|
|
self.play(ShowCreation(arrow))
|
|
self.play(
|
|
Write(times_three),
|
|
self.pi_creature.change_mode, "thinking"
|
|
)
|
|
self.wait(3)
|
|
|
|
self.play(
|
|
Animation(derivs),
|
|
Write(why),
|
|
self.pi_creature.change, "confused", derivs
|
|
)
|
|
self.wait()
|
|
for deriv in derivs:
|
|
for index in -5, -2:
|
|
self.play(Indicate(deriv[index]))
|
|
self.wait()
|
|
self.wait(2)
|
|
|
|
def get_derivative_expression(self, base):
|
|
base_str = str(base)
|
|
const_str = "%.4f\\dots"%np.log(base)
|
|
result = TexMobject(
|
|
"{d(", base_str, "^t", ")", "\\over", "dt}",
|
|
"=", base_str, "^t", "(", const_str, ")"
|
|
)
|
|
tex_color_paris = [
|
|
("t", YELLOW),
|
|
("dt", GREEN),
|
|
(const_str, BLUE)
|
|
]
|
|
for tex, color in tex_color_paris:
|
|
result.set_color_by_tex(tex, color)
|
|
return result
|
|
|
|
def create_pi_creature(self):
|
|
self.pi_creature = Randolph().flip()
|
|
self.pi_creature.to_edge(DOWN).shift(3*RIGHT)
|
|
return self.pi_creature
|
|
|
|
class AskAboutConstantOne(TeacherStudentsScene):
|
|
def construct(self):
|
|
note = TexMobject(
|
|
"{ d(a^", "t", ")", "\\over \\,", "dt}",
|
|
"=", "a^", "t", "(\\text{Some constant})"
|
|
)
|
|
note.set_color_by_tex("t", YELLOW)
|
|
note.set_color_by_tex("dt", GREEN)
|
|
note.set_color_by_tex("constant", BLUE)
|
|
note.to_corner(UP+LEFT)
|
|
self.add(note)
|
|
|
|
self.student_says(
|
|
"Is there a base where\\\\",
|
|
"that constant is 1?"
|
|
)
|
|
self.change_student_modes(
|
|
"pondering", "raise_right_hand", "thinking",
|
|
# look_at_arg = self.get_students()[1].bubble
|
|
)
|
|
self.wait(2)
|
|
self.play(FadeOut(note[-1], run_time = 3))
|
|
self.wait()
|
|
|
|
self.teacher_says(
|
|
"There is!\\\\",
|
|
"$e = 2.71828\\dots$",
|
|
target_mode = "hooray"
|
|
)
|
|
self.change_student_modes(*["confused"]*3)
|
|
self.wait(3)
|
|
|
|
class WhyPi(PiCreatureScene):
|
|
def construct(self):
|
|
circle = Circle(radius = 1, color = MAROON_B)
|
|
circle.rotate(np.pi/2)
|
|
circle.to_edge(UP)
|
|
ghost_circle = circle.copy()
|
|
ghost_circle.set_stroke(width = 1)
|
|
diam = Line(circle.get_left(), circle.get_right())
|
|
diam.set_color(YELLOW)
|
|
one = TexMobject("1")
|
|
one.next_to(diam, UP)
|
|
circum = diam.copy()
|
|
circum.set_color(circle.get_color())
|
|
circum.scale(np.pi)
|
|
circum.next_to(circle, DOWN, LARGE_BUFF)
|
|
circum.insert_n_curves(circle.get_num_curves()-2)
|
|
circum.make_jagged()
|
|
pi = TexMobject("\\pi")
|
|
pi.next_to(circum, UP)
|
|
why = TextMobject("Why?")
|
|
why.next_to(self.pi_creature, UP, MED_LARGE_BUFF)
|
|
|
|
self.add(ghost_circle, circle, diam, one)
|
|
self.wait()
|
|
self.play(Transform(circle, circum, run_time = 2))
|
|
self.play(
|
|
Write(pi),
|
|
Write(why),
|
|
self.pi_creature.change_mode, "confused",
|
|
)
|
|
self.wait(3)
|
|
|
|
|
|
#######
|
|
|
|
def create_pi_creature(self):
|
|
self.pi_creature = Randolph()
|
|
self.pi_creature.to_corner(DOWN+LEFT)
|
|
return self.pi_creature
|
|
|
|
class GraphOfExp(GraphScene):
|
|
CONFIG = {
|
|
"x_min" : -3,
|
|
"x_max" : 3,
|
|
"x_tick_frequency" : 1,
|
|
"x_axis_label" : "t",
|
|
"x_labeled_nums" : list(range(-3, 4)),
|
|
"x_axis_width" : 11,
|
|
"graph_origin" : 2*DOWN + LEFT,
|
|
"example_inputs" : [1, 2],
|
|
"small_dx" : 0.01,
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
self.show_slopes()
|
|
|
|
def show_slopes(self):
|
|
graph = self.get_graph(np.exp)
|
|
graph_label = self.get_graph_label(
|
|
graph, "e^t", direction = LEFT
|
|
)
|
|
graph_label.shift(MED_SMALL_BUFF*LEFT)
|
|
|
|
start_input, target_input = self.example_inputs
|
|
ss_group = self.get_secant_slope_group(
|
|
start_input, graph,
|
|
dx = self.small_dx,
|
|
dx_label = "dt",
|
|
df_label = "d(e^t)",
|
|
secant_line_color = YELLOW,
|
|
)
|
|
v_lines = [
|
|
self.get_vertical_line_to_graph(
|
|
x, graph,
|
|
color = WHITE,
|
|
)
|
|
for x in self.example_inputs
|
|
]
|
|
height_labels = [
|
|
TexMobject("e^%d"%x).next_to(vl, RIGHT, SMALL_BUFF)
|
|
for vl, x in zip(v_lines, self.example_inputs)
|
|
]
|
|
slope_labels = [
|
|
TextMobject(
|
|
"Slope = $e^%d$"%x
|
|
).next_to(vl.get_top(), UP+RIGHT).shift(0.7*RIGHT/x)
|
|
for vl, x in zip(v_lines, self.example_inputs)
|
|
]
|
|
|
|
self.play(
|
|
ShowCreation(graph, run_time = 2),
|
|
Write(
|
|
graph_label,
|
|
rate_func = squish_rate_func(smooth, 0.5, 1),
|
|
)
|
|
)
|
|
self.wait()
|
|
self.play(*list(map(ShowCreation, ss_group)))
|
|
self.play(Write(slope_labels[0]))
|
|
self.play(ShowCreation(v_lines[0]))
|
|
self.play(Write(height_labels[0]))
|
|
self.wait(2)
|
|
self.animate_secant_slope_group_change(
|
|
ss_group,
|
|
target_x = target_input,
|
|
run_time = 2,
|
|
added_anims = [
|
|
Transform(
|
|
*pair,
|
|
path_arc = np.pi/6,
|
|
run_time = 2
|
|
)
|
|
for pair in [
|
|
slope_labels,
|
|
v_lines,
|
|
height_labels,
|
|
]
|
|
]
|
|
)
|
|
self.wait(2)
|
|
|
|
self.graph = graph
|
|
self.ss_group = ss_group
|
|
|
|
class Chapter4Wrapper(Scene):
|
|
def construct(self):
|
|
title = TextMobject("Chapter 4 chain rule intuition")
|
|
title.to_edge(UP)
|
|
rect = Rectangle(width = 16, height = 9)
|
|
rect.set_height(1.5*FRAME_Y_RADIUS)
|
|
rect.next_to(title, DOWN)
|
|
|
|
self.add(title)
|
|
self.play(ShowCreation(rect))
|
|
self.wait(3)
|
|
|
|
class ApplyChainRule(TeacherStudentsScene):
|
|
def construct(self):
|
|
deriv_equation = TexMobject(
|
|
"{d(", "e^", "{3", "t}", ")", "\\over", "dt}",
|
|
"=", "3", "e^", "{3", "t}",
|
|
)
|
|
deriv_equation.next_to(self.teacher, UP+LEFT)
|
|
deriv_equation.shift(UP)
|
|
deriv_equation.set_color_by_tex("3", BLUE)
|
|
deriv = VGroup(*deriv_equation[:7])
|
|
exponent = VGroup(*deriv_equation[-2:])
|
|
circle = Circle(color = YELLOW)
|
|
circle.replace(exponent, stretch = True)
|
|
circle.scale_in_place(1.5)
|
|
|
|
self.teacher_says("Think of the \\\\ chain rule")
|
|
self.change_student_modes(*["pondering"]*3)
|
|
self.play(
|
|
Write(deriv),
|
|
RemovePiCreatureBubble(
|
|
self.teacher,
|
|
target_mode = "raise_right_hand"
|
|
),
|
|
)
|
|
self.wait(2)
|
|
self.play(*[
|
|
Transform(
|
|
*deriv_equation.get_parts_by_tex(
|
|
tex, substring = False
|
|
).copy()[:2],
|
|
path_arc = -np.pi,
|
|
run_time = 2
|
|
)
|
|
for tex in ("e^", "{3", "t}")
|
|
] + [
|
|
Write(deriv_equation.get_part_by_tex("="))
|
|
])
|
|
self.play(self.teacher.change_mode, "happy")
|
|
self.wait()
|
|
self.play(ShowCreation(circle))
|
|
self.play(Transform(
|
|
*deriv_equation.get_parts_by_tex("3").copy()[-1:-3:-1]
|
|
))
|
|
self.play(FadeOut(circle))
|
|
self.wait(3)
|
|
|
|
class ChainRuleIntuition(ThreeLinesChainRule):
|
|
CONFIG = {
|
|
"line_configs" : [
|
|
{
|
|
"func" : lambda t : t,
|
|
"func_label" : "t",
|
|
"triangle_color" : WHITE,
|
|
"center_y" : 3,
|
|
"x_min" : 0,
|
|
"x_max" : 3,
|
|
"numbers_to_show" : list(range(4)),
|
|
"numbers_with_elongated_ticks" : list(range(4)),
|
|
"tick_frequency" : 1,
|
|
},
|
|
{
|
|
"func" : lambda t : 3*t,
|
|
"func_label" : "3t",
|
|
"triangle_color" : GREEN,
|
|
"center_y" : 0.5,
|
|
"x_min" : 0,
|
|
"x_max" : 3,
|
|
"numbers_to_show" : list(range(0, 4)),
|
|
"numbers_with_elongated_ticks" : list(range(4)),
|
|
"tick_frequency" : 1,
|
|
},
|
|
{
|
|
"func" : lambda t : np.exp(3*t),
|
|
"func_label" : "e^{3t}",
|
|
"triangle_color" : BLUE,
|
|
"center_y" : -2,
|
|
"x_min" : 0,
|
|
"x_max" : 10,
|
|
"numbers_to_show" : list(range(0, 11, 3)),
|
|
"numbers_with_elongated_ticks" : list(range(11)),
|
|
"tick_frequency" : 1,
|
|
},
|
|
],
|
|
"example_x" : 0.4,
|
|
"start_x" : 0.4,
|
|
"max_x" : 0.6,
|
|
"min_x" : 0.2,
|
|
}
|
|
def construct(self):
|
|
self.introduce_line_group()
|
|
self.nudge_x()
|
|
|
|
def nudge_x(self):
|
|
lines, labels = self.line_group
|
|
def get_value_points():
|
|
return [
|
|
label[0].get_bottom()
|
|
for label in labels
|
|
]
|
|
starts = get_value_points()
|
|
self.animate_x_change(self.example_x + self.dx, run_time = 0)
|
|
ends = get_value_points()
|
|
self.animate_x_change(self.example_x, run_time = 0)
|
|
|
|
nudge_lines = VGroup()
|
|
braces = VGroup()
|
|
numbers = VGroup()
|
|
for start, end, line, label, config in zip(starts, ends, lines, labels, self.line_configs):
|
|
color = label[0].get_color()
|
|
nudge_line = Line(start, end)
|
|
nudge_line.set_stroke(color, width = 6)
|
|
brace = Brace(nudge_line, DOWN, buff = SMALL_BUFF)
|
|
brace.set_color(color)
|
|
func_label = config["func_label"]
|
|
if len(func_label) == 1:
|
|
text = "$d%s$"%func_label
|
|
else:
|
|
text = "$d(%s)$"%func_label
|
|
brace.text = brace.get_text(text, buff = SMALL_BUFF)
|
|
brace.text.set_color(color)
|
|
brace.add(brace.text)
|
|
|
|
line.add(nudge_line)
|
|
nudge_lines.add(nudge_line)
|
|
braces.add(brace)
|
|
numbers.add(line.numbers)
|
|
line.remove(*line.numbers)
|
|
dt_brace, d3t_brace, dexp3t_brace = braces
|
|
|
|
self.play(*list(map(FadeIn, [nudge_lines, braces])))
|
|
self.wait()
|
|
for count in range(3):
|
|
for dx in self.dx, 0:
|
|
self.animate_x_change(
|
|
self.example_x + dx,
|
|
run_time = 2
|
|
)
|
|
self.wait()
|
|
|
|
class WhyNaturalLogOf2ShowsUp(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.add_e_to_the_three_t()
|
|
self.show_e_to_log_2()
|
|
|
|
def add_e_to_the_three_t(self):
|
|
exp_c = self.get_exp_C("c")
|
|
exp_c.next_to(self.teacher, UP+LEFT)
|
|
|
|
self.play(
|
|
FadeIn(
|
|
exp_c,
|
|
run_time = 2,
|
|
lag_ratio = 0.5
|
|
),
|
|
self.teacher.change, "raise_right_hand"
|
|
)
|
|
self.wait()
|
|
self.look_at(4*LEFT + UP)
|
|
self.wait(3)
|
|
|
|
self.exp_c = exp_c
|
|
|
|
def show_e_to_log_2(self):
|
|
equation = TexMobject(
|
|
"2", "^t", "= e^", "{\\ln(2)", "t}"
|
|
)
|
|
equation.move_to(self.exp_c)
|
|
t_group = equation.get_parts_by_tex("t")
|
|
non_t_group = VGroup(*equation)
|
|
non_t_group.remove(*t_group)
|
|
|
|
log_words = TextMobject("``$e$ to the ", "\\emph{what}", "equals 2?''")
|
|
log_words.set_color_by_tex("what", BLUE)
|
|
log_words.next_to(equation, UP+LEFT)
|
|
log_words_arrow = Arrow(
|
|
log_words.get_right(),
|
|
equation.get_part_by_tex("ln(2)").get_corner(UP+LEFT),
|
|
color = BLUE,
|
|
)
|
|
|
|
derivative = TexMobject(
|
|
"\\ln(2)", "2", "^t", "=", "\\ln(2)", "e^", "{\\ln(2)", "t}"
|
|
)
|
|
derivative.move_to(equation)
|
|
for tex_mob in equation, derivative:
|
|
tex_mob.set_color_by_tex("ln(2)", BLUE)
|
|
tex_mob.set_color_by_tex("t", YELLOW)
|
|
derivative_arrow = Arrow(1.5*UP, ORIGIN, buff = 0)
|
|
derivative_arrow.set_color(WHITE)
|
|
derivative_arrow.next_to(
|
|
derivative.get_parts_by_tex("="), UP
|
|
)
|
|
derivative_symbol = TextMobject("Derivative")
|
|
derivative_symbol.next_to(derivative_arrow, RIGHT)
|
|
|
|
self.play(
|
|
Write(non_t_group),
|
|
self.exp_c.next_to, equation, LEFT, 2*LARGE_BUFF,
|
|
self.exp_c.to_edge, UP,
|
|
)
|
|
self.change_student_modes("confused", "sassy", "erm")
|
|
self.play(
|
|
Write(log_words),
|
|
ShowCreation(
|
|
log_words_arrow,
|
|
run_time = 2,
|
|
rate_func = squish_rate_func(smooth, 0.5, 1)
|
|
)
|
|
)
|
|
self.change_student_modes(
|
|
*["pondering"]*3,
|
|
look_at_arg = log_words
|
|
)
|
|
self.wait(2)
|
|
|
|
t_group.save_state()
|
|
t_group.shift(UP)
|
|
t_group.set_fill(opacity = 0)
|
|
self.play(
|
|
ApplyMethod(
|
|
t_group.restore,
|
|
run_time = 2,
|
|
lag_ratio = 0.5,
|
|
),
|
|
self.teacher.change_mode, "speaking"
|
|
)
|
|
self.wait(2)
|
|
self.play(FocusOn(self.exp_c))
|
|
self.play(Indicate(self.exp_c, scale_factor = 1.05))
|
|
self.wait(2)
|
|
|
|
self.play(
|
|
equation.next_to, derivative_arrow, UP,
|
|
equation.shift, MED_SMALL_BUFF*RIGHT,
|
|
FadeOut(VGroup(log_words, log_words_arrow)),
|
|
self.teacher.change_mode, "raise_right_hand",
|
|
)
|
|
self.play(
|
|
ShowCreation(derivative_arrow),
|
|
Write(derivative_symbol),
|
|
Write(derivative)
|
|
)
|
|
self.wait(3)
|
|
self.play(self.teacher.change_mode, "happy")
|
|
self.wait(2)
|
|
|
|
student = self.get_students()[1]
|
|
ln = derivative.get_part_by_tex("ln(2)").copy()
|
|
rhs = TexMobject("=%s"%self.get_log_str(2))
|
|
self.play(
|
|
ln.next_to, student, UP+LEFT, MED_LARGE_BUFF,
|
|
student.change_mode, "raise_left_hand",
|
|
)
|
|
rhs.next_to(ln, RIGHT)
|
|
self.play(Write(rhs))
|
|
self.wait(2)
|
|
|
|
|
|
######
|
|
|
|
def get_exp_C(self, C):
|
|
C_str = str(C)
|
|
result = TexMobject(
|
|
"{d(", "e^", "{%s"%C_str, "t}", ")", "\\over", "dt}",
|
|
"=", C_str, "e^", "{%s"%C_str, "t}",
|
|
)
|
|
result.set_color_by_tex(C_str, BLUE)
|
|
result.C_str = C_str
|
|
return result
|
|
|
|
def get_a_to_t(self, a):
|
|
a_str = str(a)
|
|
log_str = self.get_log_str(a)
|
|
result = TexMobject(
|
|
"{d(", a_str, "^t", ")", "\\over", "dt}",
|
|
"=", log_str, a_str, "^t"
|
|
)
|
|
result.set_color_by_tex(log_str, BLUE)
|
|
return result
|
|
|
|
def get_log_str(self, a):
|
|
return "%.4f\\dots"%np.log(float(a))
|
|
|
|
class CompareWaysToWriteExponentials(GraphScene):
|
|
CONFIG = {
|
|
"y_max" : 50,
|
|
"y_tick_frequency" : 5,
|
|
"x_max" : 7,
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
bases = list(range(2, 7))
|
|
graphs = [
|
|
self.get_graph(lambda t : base**t, color = GREEN)
|
|
for base in bases
|
|
]
|
|
graph = graphs[0]
|
|
|
|
a_to_t = TexMobject("a^t")
|
|
a_to_t.move_to(self.coords_to_point(6, 45))
|
|
|
|
cross = TexMobject("\\times")
|
|
cross.set_color(RED)
|
|
cross.replace(a_to_t, stretch = True)
|
|
e_to_ct = TexMobject("e^", "{c", "t}")
|
|
e_to_ct.set_color_by_tex("c", BLUE)
|
|
e_to_ct.scale(1.5)
|
|
e_to_ct.next_to(a_to_t, DOWN)
|
|
|
|
equations = VGroup()
|
|
for base in bases:
|
|
log_str = "%.4f\\dots"%np.log(base)
|
|
equation = TexMobject(
|
|
str(base), "^t", "=",
|
|
"e^", "{(%s)"%log_str, "t}",
|
|
)
|
|
equation.set_color_by_tex(log_str, BLUE)
|
|
equation.scale(1.2)
|
|
equations.add(equation)
|
|
|
|
equation = equations[0]
|
|
equations.next_to(e_to_ct, DOWN, LARGE_BUFF, LEFT)
|
|
|
|
self.play(
|
|
ShowCreation(graph),
|
|
Write(
|
|
a_to_t,
|
|
rate_func = squish_rate_func(smooth, 0.5, 1)
|
|
),
|
|
run_time = 2
|
|
)
|
|
self.play(Write(cross, run_time = 2))
|
|
self.play(Write(e_to_ct, run_time = 2))
|
|
self.wait(2)
|
|
self.play(Write(equation))
|
|
self.wait(2)
|
|
for new_graph, new_equation in zip(graphs, equations)[1:]:
|
|
self.play(
|
|
Transform(graph, new_graph),
|
|
Transform(equation, new_equation)
|
|
)
|
|
self.wait(2)
|
|
self.wait()
|
|
|
|
class ManyExponentialForms(TeacherStudentsScene):
|
|
def construct(self):
|
|
lhs = TexMobject("2", "^t")
|
|
rhs_list = [
|
|
TexMobject("=", "%s^"%tex, "{(%.5f\\dots)"%log, "t}")
|
|
for tex, log in [
|
|
("e", np.log(2)),
|
|
("\\pi", np.log(2)/np.log(np.pi)),
|
|
("42", np.log(2)/np.log(42)),
|
|
]
|
|
]
|
|
group = VGroup(lhs, *rhs_list)
|
|
group.arrange(RIGHT)
|
|
group.set_width(FRAME_WIDTH - LARGE_BUFF)
|
|
group.next_to(self.get_pi_creatures(), UP, 2*LARGE_BUFF)
|
|
for part in group:
|
|
part.set_color_by_tex("t", YELLOW)
|
|
const = part.get_part_by_tex("dots")
|
|
if const:
|
|
const.set_color(BLUE)
|
|
brace = Brace(const, UP)
|
|
log = brace.get_text(
|
|
"$\\log_{%s}(2)$"%part[1].get_tex_string()[:-1]
|
|
)
|
|
log.set_color(BLUE)
|
|
part.add(brace, log)
|
|
exp = VGroup(*rhs_list[0][1:4])
|
|
rect = BackgroundRectangle(group)
|
|
|
|
self.add(lhs, rhs_list[0])
|
|
self.wait()
|
|
for rhs in rhs_list[1:]:
|
|
self.play(FadeIn(
|
|
rhs,
|
|
run_time = 2,
|
|
lag_ratio = 0.5,
|
|
))
|
|
self.wait(2)
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(rect),
|
|
exp.next_to, self.teacher, UP+LEFT,
|
|
self.teacher.change, "raise_right_hand",
|
|
)
|
|
self.play(*[
|
|
ApplyFunction(
|
|
lambda m : m.shift(SMALL_BUFF*UP).set_color(RED),
|
|
part,
|
|
run_time = 2,
|
|
rate_func = squish_rate_func(there_and_back, a, a+0.3)
|
|
)
|
|
for part, a in zip(exp[1], np.linspace(0, 0.7, len(exp[1])))
|
|
])
|
|
self.change_student_modes(
|
|
*["pondering"]*3,
|
|
look_at_arg = exp
|
|
)
|
|
self.wait(3)
|
|
|
|
class TooManySymbols(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.student_says(
|
|
"Too symbol heavy!",
|
|
target_mode = "pleading"
|
|
)
|
|
self.play(self.teacher.change_mode, "guilty")
|
|
self.wait(3)
|
|
|
|
class TemperatureOverTimeOfWarmWater(GraphScene):
|
|
CONFIG = {
|
|
"x_min" : 0,
|
|
"x_axis_label" : "$t$",
|
|
"y_axis_label" : "Temperature",
|
|
"T_room" : 4,
|
|
"include_solution" : False,
|
|
}
|
|
def construct(self):
|
|
self.setup_axes()
|
|
graph = self.get_graph(
|
|
lambda t : 3*np.exp(-0.3*t) + self.T_room,
|
|
color = RED
|
|
)
|
|
h_line = DashedLine(*[
|
|
self.coords_to_point(x, self.T_room)
|
|
for x in (self.x_min, self.x_max)
|
|
])
|
|
T_room_label = TexMobject("T_{\\text{room}}")
|
|
T_room_label.next_to(h_line, LEFT)
|
|
|
|
ode = TexMobject(
|
|
"\\frac{d\\Delta T}{dt} = -k \\Delta T"
|
|
)
|
|
ode.to_corner(UP+RIGHT)
|
|
|
|
solution = TexMobject(
|
|
"\\Delta T(", "t", ") = e", "^{-k", "t}"
|
|
)
|
|
solution.next_to(ode, DOWN, MED_LARGE_BUFF)
|
|
solution.set_color_by_tex("t", YELLOW)
|
|
solution.set_color_by_tex("Delta", WHITE)
|
|
|
|
delta_T_brace = Brace(graph, RIGHT)
|
|
delta_T_label = TexMobject("\\Delta T")
|
|
delta_T_group = VGroup(delta_T_brace, delta_T_label)
|
|
def update_delta_T_group(group):
|
|
brace, label = group
|
|
v_line = Line(
|
|
graph.points[-1],
|
|
graph.points[-1][0]*RIGHT + h_line.get_center()[1]*UP
|
|
)
|
|
brace.set_height(v_line.get_height())
|
|
brace.next_to(v_line, RIGHT, SMALL_BUFF)
|
|
label.set_height(min(
|
|
label.get_height(),
|
|
brace.get_height()
|
|
))
|
|
label.next_to(brace, RIGHT, SMALL_BUFF)
|
|
|
|
self.add(ode)
|
|
self.play(
|
|
Write(T_room_label),
|
|
ShowCreation(h_line, run_time = 2)
|
|
)
|
|
if self.include_solution:
|
|
self.play(Write(solution))
|
|
graph_growth = ShowCreation(graph, rate_func=linear)
|
|
delta_T_group_update = UpdateFromFunc(
|
|
delta_T_group, update_delta_T_group
|
|
)
|
|
self.play(
|
|
GrowFromCenter(delta_T_brace),
|
|
Write(delta_T_label),
|
|
)
|
|
self.play(graph_growth, delta_T_group_update, run_time = 15)
|
|
self.wait(2)
|
|
|
|
class TemperatureOverTimeOfWarmWaterWithSolution(TemperatureOverTimeOfWarmWater):
|
|
CONFIG = {
|
|
"include_solution" : True
|
|
}
|
|
|
|
class InvestedMoney(Scene):
|
|
def construct(self):
|
|
# cash_str = "\\$\\$\\$"
|
|
cash_str = "M"
|
|
equation = TexMobject(
|
|
"{d", cash_str, "\\over", "dt}",
|
|
"=", "(1 + r)", cash_str
|
|
)
|
|
equation.set_color_by_tex(cash_str, GREEN)
|
|
equation.next_to(ORIGIN, LEFT)
|
|
equation.to_edge(UP)
|
|
|
|
arrow = Arrow(LEFT, RIGHT, color = WHITE)
|
|
arrow.next_to(equation)
|
|
|
|
solution = TexMobject(
|
|
cash_str, "(", "t", ")", "=", "e^", "{(1+r)", "t}"
|
|
)
|
|
solution.set_color_by_tex("t", YELLOW)
|
|
solution.set_color_by_tex(cash_str, GREEN)
|
|
solution.next_to(arrow, RIGHT)
|
|
|
|
cash = TexMobject("\\$")
|
|
cash_pile = VGroup(*[
|
|
cash.copy().shift(
|
|
x*(1+MED_SMALL_BUFF)*cash.get_width()*RIGHT +\
|
|
y*(1+MED_SMALL_BUFF)*cash.get_height()*UP
|
|
)
|
|
for x in range(40)
|
|
for y in range(8)
|
|
])
|
|
cash_pile.set_color(GREEN)
|
|
cash_pile.center()
|
|
cash_pile.shift(DOWN)
|
|
|
|
anims = []
|
|
cash_size = len(cash_pile)
|
|
run_time = 10
|
|
const = np.log(cash_size)/run_time
|
|
for i, cash in enumerate(cash_pile):
|
|
start_time = np.log(i+1)/const
|
|
prop = start_time/run_time
|
|
rate_func = squish_rate_func(
|
|
smooth,
|
|
np.clip(prop-0.5/run_time, 0, 1),
|
|
np.clip(prop+0.5/run_time, 0, 1),
|
|
)
|
|
anims.append(GrowFromCenter(
|
|
cash, rate_func = rate_func,
|
|
))
|
|
|
|
self.add(equation)
|
|
self.play(*anims, run_time = run_time)
|
|
self.wait()
|
|
self.play(ShowCreation(arrow))
|
|
self.play(Write(solution, run_time = 2))
|
|
self.wait()
|
|
self.play(FadeOut(cash_pile))
|
|
self.play(*anims, run_time = run_time)
|
|
self.wait()
|
|
|
|
class NaturalLog(Scene):
|
|
def construct(self):
|
|
expressions = VGroup(*list(map(self.get_expression, [2, 3, 7])))
|
|
expressions.arrange(DOWN, buff = MED_SMALL_BUFF)
|
|
expressions.to_edge(LEFT)
|
|
|
|
self.play(FadeIn(
|
|
expressions,
|
|
run_time = 3,
|
|
lag_ratio = 0.5
|
|
))
|
|
self.wait()
|
|
self.play(
|
|
expressions.set_fill, None, 1,
|
|
run_time = 2,
|
|
lag_ratio = 0.5
|
|
)
|
|
self.wait()
|
|
for i in 0, 2, 1:
|
|
self.show_natural_loggedness(expressions[i])
|
|
|
|
def show_natural_loggedness(self, expression):
|
|
base, constant = expression[1], expression[-3]
|
|
|
|
log_constant, exp_constant = constant.copy(), constant.copy()
|
|
log_base, exp_base = base.copy(), base.copy()
|
|
log_equals, exp_equals = list(map(TexMobject, "=="))
|
|
|
|
ln = TexMobject("\\ln(2)")
|
|
log_base.move_to(ln[-2])
|
|
ln.remove(ln[-2])
|
|
log_equals.next_to(ln, LEFT)
|
|
log_constant.next_to(log_equals, LEFT)
|
|
log_expression = VGroup(
|
|
ln, log_constant, log_equals, log_base
|
|
)
|
|
|
|
e = TexMobject("e")
|
|
exp_constant.scale(0.7)
|
|
exp_constant.next_to(e, UP+RIGHT, buff = 0)
|
|
exp_base.next_to(exp_equals, RIGHT)
|
|
VGroup(exp_base, exp_equals).next_to(
|
|
VGroup(e, exp_constant), RIGHT,
|
|
aligned_edge = DOWN
|
|
)
|
|
exp_expression = VGroup(
|
|
e, exp_constant, exp_equals, exp_base
|
|
)
|
|
|
|
for group, vect in (log_expression, UP), (exp_expression, DOWN):
|
|
group.to_edge(RIGHT)
|
|
group.shift(vect)
|
|
|
|
self.play(
|
|
ReplacementTransform(base.copy(), log_base),
|
|
ReplacementTransform(constant.copy(), log_constant),
|
|
run_time = 2
|
|
)
|
|
self.play(Write(ln), Write(log_equals))
|
|
self.wait()
|
|
self.play(
|
|
ReplacementTransform(
|
|
log_expression.copy(),
|
|
exp_expression,
|
|
run_time = 2,
|
|
)
|
|
)
|
|
self.wait(2)
|
|
|
|
ln_a = expression[-1]
|
|
self.play(
|
|
FadeOut(expression[-2]),
|
|
FadeOut(constant),
|
|
ln_a.move_to, constant, LEFT,
|
|
ln_a.set_color, BLUE
|
|
)
|
|
self.wait()
|
|
self.play(*list(map(FadeOut, [log_expression, exp_expression])))
|
|
self.wait()
|
|
|
|
def get_expression(self, base):
|
|
expression = TexMobject(
|
|
"{d(", "%d^"%base, "t", ")", "\\over \\,", "dt}",
|
|
"=", "%d^"%base, "t", "(%.4f\\dots)"%np.log(base),
|
|
)
|
|
expression.set_color_by_tex("t", YELLOW)
|
|
expression.set_color_by_tex("dt", GREEN)
|
|
expression.set_color_by_tex("\\dots", BLUE)
|
|
|
|
brace = Brace(expression.get_part_by_tex("\\dots"), UP)
|
|
brace_text = brace.get_text("$\\ln(%d)$"%base)
|
|
for mob in brace, brace_text:
|
|
mob.set_fill(opacity = 0)
|
|
|
|
expression.add(brace, brace_text)
|
|
return expression
|
|
|
|
class NextVideo(TeacherStudentsScene):
|
|
def construct(self):
|
|
series = VideoSeries()
|
|
series.to_edge(UP)
|
|
this_video = series[3]
|
|
next_video = series[4]
|
|
brace = Brace(this_video, DOWN)
|
|
this_video.save_state()
|
|
this_video.set_color(YELLOW)
|
|
|
|
this_tex = TexMobject(
|
|
"{d(", "a^t", ") \\over dt} = ", "a^t", "\\ln(a)"
|
|
)
|
|
this_tex[1][1].set_color(YELLOW)
|
|
this_tex[3][1].set_color(YELLOW)
|
|
this_tex.next_to(brace, DOWN)
|
|
|
|
next_tex = VGroup(*list(map(TextMobject, [
|
|
"Chain rule", "Product rule", "$\\vdots$"
|
|
])))
|
|
next_tex.arrange(DOWN)
|
|
next_tex.next_to(brace, DOWN)
|
|
next_tex.shift(
|
|
next_video.get_center()[0]*RIGHT\
|
|
-next_tex.get_center()[0]*RIGHT
|
|
)
|
|
|
|
self.add(series, brace, *this_tex[:3])
|
|
self.change_student_modes(
|
|
"confused", "pondering", "erm",
|
|
look_at_arg = this_tex
|
|
)
|
|
self.play(ReplacementTransform(
|
|
this_tex[1].copy(), this_tex[3]
|
|
))
|
|
self.wait()
|
|
self.play(
|
|
Write(this_tex[4]),
|
|
ReplacementTransform(
|
|
this_tex[3][0].copy(),
|
|
this_tex[4][3],
|
|
path_arc = np.pi,
|
|
remover = True
|
|
)
|
|
)
|
|
self.wait(2)
|
|
self.play(this_tex.replace, this_video)
|
|
self.play(
|
|
brace.next_to, next_video, DOWN,
|
|
this_video.restore,
|
|
Animation(this_tex),
|
|
next_video.set_color, YELLOW,
|
|
Write(next_tex),
|
|
self.get_teacher().change_mode, "raise_right_hand"
|
|
)
|
|
self.change_student_modes(
|
|
*["pondering"]*3,
|
|
look_at_arg = next_tex
|
|
)
|
|
self.wait(3)
|
|
|
|
class ExpPatreonThanks(PatreonThanks):
|
|
CONFIG = {
|
|
"specific_patrons" : [
|
|
"Ali Yahya",
|
|
"Meshal Alshammari",
|
|
"CrypticSwarm ",
|
|
"Kathryn Schmiedicke",
|
|
"Nathan Pellegrin",
|
|
"Karan Bhargava",
|
|
"Justin Helps",
|
|
"Ankit Agarwal",
|
|
"Yu Jun",
|
|
"Dave Nicponski",
|
|
"Damion Kistler",
|
|
"Juan Benet",
|
|
"Othman Alikhan",
|
|
"Justin Helps",
|
|
"Markus Persson",
|
|
"Dan Buchoff",
|
|
"Derek Dai",
|
|
"Joseph John Cox",
|
|
"Luc Ritchie",
|
|
"Mustafa Mahdi",
|
|
"Daan Smedinga",
|
|
"Jonathan Eppele",
|
|
"Albert Nguyen",
|
|
"Nils Schneider",
|
|
"Mustafa Mahdi",
|
|
"Mathew Bramson",
|
|
"Guido Gambardella",
|
|
"Jerry Ling",
|
|
"Mark Govea",
|
|
"Vecht",
|
|
"Shimin Kuang",
|
|
"Rish Kundalia",
|
|
"Achille Brighton",
|
|
"Kirk Werklund",
|
|
"Ripta Pasay",
|
|
"Felipe Diniz",
|
|
]
|
|
}
|
|
|
|
class Thumbnail(GraphOfTwoToT):
|
|
CONFIG = {
|
|
"x_axis_label" : "",
|
|
"y_axis_label" : "",
|
|
"x_labeled_nums" : None,
|
|
"y_labeled_nums" : None,
|
|
"y_max" : 32,
|
|
"y_tick_frequency" : 4,
|
|
"graph_origin" : 3*DOWN + 5*LEFT,
|
|
"x_axis_width" : 12,
|
|
}
|
|
def construct(self):
|
|
derivative = TexMobject(
|
|
"\\frac{d(a^t)}{dt} =", "a^t \\ln(a)"
|
|
)
|
|
derivative[0][3].set_color(YELLOW)
|
|
derivative[1][1].set_color(YELLOW)
|
|
derivative[0][2].set_color(BLUE)
|
|
derivative[1][0].set_color(BLUE)
|
|
derivative[1][5].set_color(BLUE)
|
|
derivative.scale(2)
|
|
derivative.add_background_rectangle()
|
|
derivative.to_corner(DOWN+RIGHT, buff = MED_SMALL_BUFF)
|
|
|
|
# brace = Brace(Line(LEFT, RIGHT), UP)
|
|
# brace.set_width(derivative[1].get_width())
|
|
# brace.next_to(derivative[1], UP)
|
|
# question = TextMobject("Why?")
|
|
# question.scale(2.5)
|
|
# question.next_to(brace, UP)
|
|
|
|
# randy = Randolph()
|
|
# randy.scale(1.3)
|
|
# randy.next_to(ORIGIN, LEFT).to_edge(DOWN)
|
|
# randy.change_mode("pondering")
|
|
|
|
question = TextMobject("What is $e\\,$?")
|
|
e = question[-2]
|
|
e.scale(1.2, about_point = e.get_bottom())
|
|
e.set_color(BLUE)
|
|
question.scale(3)
|
|
question.add_background_rectangle()
|
|
question.to_edge(UP)
|
|
# randy.look_at(question)
|
|
|
|
self.setup_axes()
|
|
graph = self.get_graph(np.exp)
|
|
graph.set_stroke(YELLOW, 8)
|
|
|
|
self.add(graph, question, derivative)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|