More ode animations

This commit is contained in:
Grant Sanderson
2019-03-22 11:51:08 -07:00
parent 282dfeedde
commit 217da34de5
3 changed files with 359 additions and 3 deletions

View File

@ -23,4 +23,6 @@ ALL_SCENE_CLASSES = [
BuildUpEquation,
ShowDerivativeVideo,
SubtleAirCurrents,
DefineODE,
ODEvsPDEinFrames,
]

View File

@ -1187,6 +1187,8 @@ class AnalyzePendulumForce(MovingCameraScene):
thought_term.next_to, self.pendulum, DOWN, LARGE_BUFF
)
self.accleration_equation = thought_term
def emphasize_theta(self):
pendulum = self.pendulum
@ -1297,7 +1299,11 @@ class AnalyzePendulumForce(MovingCameraScene):
pass
def circle_g_sin_formula(self):
pass
self.play(
ShowCreationThenFadeAround(
self.accleration_equation
)
)
#
def set_theta(self, value, *added_anims, **kwargs):
@ -1323,7 +1329,7 @@ class BuildUpEquation(Scene):
}
def construct(self):
self.add_center_line()
# self.add_center_line()
self.show_derivatives()
self.show_theta_double_dot_equation()
self.talk_about_sine_component()

View File

@ -1,5 +1,7 @@
from big_ol_pile_of_manim_imports import *
from active_projects.ode.part1.shared_constructs import *
from active_projects.ode.part1.pendulum import Pendulum
from active_projects.ode.part1.pendulum import ThetaVsTAxes
def pendulum_vector_field(point, mu=0.1, g=9.8, L=3):
@ -415,10 +417,356 @@ class ShowGravityAcceleration(Scene):
class ShowDerivativeVideo(Scene):
CONFIG = {
"camera_config": {"background_color": DARKER_GREY}
}
def construct(self):
pass
title = TextMobject("Essence of Calculus")
title.scale(1.25)
title.to_edge(UP)
rect = ScreenRectangle(height=6)
rect = rect.copy()
rect.set_style(
fill_opacity=1,
fill_color=BLACK,
stroke_width=0,
)
rect.next_to(title, DOWN)
animated_rect = AnimatedBoundary(rect)
self.add(title, rect)
self.add(animated_rect)
self.wait(10)
class SubtleAirCurrents(Scene):
def construct(self):
pass
class DefineODE(Scene):
CONFIG = {
"pendulum_config": {
"length": 2,
"top_point": 5 * RIGHT + 2 * UP,
"initial_theta": 150 * DEGREES,
"mu": 0.3,
},
"axes_config": {
"y_axis_config": {"unit_size": 0.75},
"y_max": PI,
"y_min": -PI,
"x_max": 10,
"x_axis_config": {
"numbers_to_show": range(2, 10, 2),
"unit_size": 1,
}
},
}
def construct(self):
self.add_graph()
self.write_differential_equation()
self.dont_know_the_value()
self.show_value_slope_curvature()
self.write_ode()
self.show_second_order()
self.show_changing_curvature_group()
def add_graph(self):
pendulum = Pendulum(**self.pendulum_config)
axes = ThetaVsTAxes(**self.axes_config)
axes.center()
axes.to_corner(DL)
graph = axes.get_live_drawn_graph(pendulum)
pendulum.start_swinging()
self.add(axes, pendulum, graph)
self.pendulum = pendulum
self.axes = axes
self.graph = graph
def write_differential_equation(self):
de_word = TextMobject("Differential", "Equation")
de_word.to_edge(UP)
equation = TexMobject(
"\\ddot \\theta({t}) = "
"-\\mu \\dot \\theta({t})"
"-{g \\over L} \\sin\\big(\\theta({t})\\big)",
tex_to_color_map={
"\\theta": BLUE,
"{t}": WHITE
}
)
equation.next_to(de_word, DOWN)
thetas = equation.get_parts_by_tex("\\theta")
lines = VGroup(*[
Line(v, 1.2 * v)
for v in compass_directions(25)
])
lines.replace(equation, stretch=True)
lines.scale(1.5)
lines.set_stroke(YELLOW)
lines.shuffle()
self.add(equation)
self.wait(5)
self.play(
ShowPassingFlashWithThinningStrokeWidth(
lines,
lag_ratio=0.002,
run_time=1.5,
time_width=0.9,
n_segments=5,
)
)
self.play(FadeInFromDown(de_word))
self.wait(2)
self.play(
LaggedStartMap(
ApplyMethod, thetas,
lambda m: (m.shift, 0.25 * DOWN),
rate_func=there_and_back,
)
)
self.wait()
self.de_word = de_word
self.equation = equation
def dont_know_the_value(self):
graph = self.graph
pendulum = self.pendulum
q_marks = VGroup(*[
TexMobject("?").move_to(graph.point_from_proportion(a))
for a in np.linspace(0, 1, 20)
])
q_marks.set_stroke(width=0, background=True)
self.play(
VFadeOut(graph),
FadeOut(pendulum),
LaggedStart(*[
UpdateFromAlphaFunc(
q_mark,
lambda m, a: m.set_height(0.5 * (1 + a)).set_fill(
opacity=there_and_back(a)
),
)
for q_mark in q_marks
], lag_ratio=0.01, run_time=2)
)
self.remove(q_marks)
def show_value_slope_curvature(self):
axes = self.axes
p = self.pendulum
graph = axes.get_graph(
lambda t: p.initial_theta * np.cos(
np.sqrt(p.gravity / p.length) * t
) * np.exp(-p.mu * t / 2)
)
tex_config = {
"tex_to_color_map": {"\\theta": BLUE},
"height": 0.5,
}
theta, d_theta, dd_theta = [
TexMobject(s + "\\theta(t)", **tex_config)
for s in ("", "\\dot", "\\ddot")
]
t_tracker = ValueTracker(2.5)
get_t = t_tracker.get_value
def get_point(t):
return graph.point_from_proportion(t / axes.x_max)
def get_dot():
return Dot(get_point(get_t())).scale(0.5)
def get_v_line():
point = get_point(get_t())
x_point = axes.x_axis.number_to_point(
axes.x_axis.point_to_number(point)
)
return DashedLine(
x_point, point,
dash_length=0.025,
stroke_color=WHITE,
stroke_width=2,
)
def get_tangent_line(curve, alpha):
line = Line(
ORIGIN, 1.5 * RIGHT,
color=YELLOW,
stroke_width=1.5,
)
da = 0.0001
p0 = curve.point_from_proportion(alpha)
p1 = curve.point_from_proportion(alpha - da)
p2 = curve.point_from_proportion(alpha + da)
angle = angle_of_vector(p2 - p1)
line.rotate(angle)
line.move_to(p0)
return line
def get_slope_line():
return get_tangent_line(
graph, get_t() / axes.x_max
)
def get_curve():
curve = VMobject()
t = get_t()
curve.set_points_smoothly([
get_point(t + a)
for a in np.linspace(-0.5, 0.5, 11)
])
curve.set_stroke(RED, 1)
return curve
v_line = always_redraw(get_v_line)
dot = always_redraw(get_dot)
slope_line = always_redraw(get_slope_line)
curve = always_redraw(get_curve)
theta.next_to(v_line, RIGHT, SMALL_BUFF)
d_theta.next_to(slope_line.get_end(), UP, SMALL_BUFF)
dd_theta.next_to(curve.get_end(), RIGHT, SMALL_BUFF)
thetas = VGroup(theta, d_theta, dd_theta)
words = VGroup(
TextMobject("= Height"),
TextMobject("= Slope").set_color(YELLOW),
TextMobject("= ``Curvature''").set_color(RED),
)
words.scale(0.75)
for word, sym in zip(words, thetas):
word.next_to(sym, RIGHT, buff=2 * SMALL_BUFF)
sym.word = word
self.play(
ShowCreation(v_line),
FadeInFromPoint(dot, v_line.get_start()),
FadeInFrom(theta, DOWN),
FadeInFrom(theta.word, DOWN),
)
self.add(slope_line, dot)
self.play(
ShowCreation(slope_line),
FadeInFrom(d_theta, LEFT),
FadeInFrom(d_theta.word, LEFT),
)
a_tracker = ValueTracker(0)
curve_copy = curve.copy()
changing_slope = always_redraw(
lambda: get_tangent_line(
curve_copy,
a_tracker.get_value(),
).set_stroke(
opacity=there_and_back(a_tracker.get_value())
)
)
self.add(curve, dot)
self.play(
ShowCreation(curve),
FadeInFrom(dd_theta, LEFT),
FadeInFrom(dd_theta.word, LEFT),
)
self.add(changing_slope)
self.play(
a_tracker.set_value, 1,
run_time=3,
)
self.remove(changing_slope, a_tracker)
self.t_tracker = t_tracker
self.curvature_group = VGroup(
v_line, slope_line, curve, dot
)
self.curvature_group_labels = VGroup(thetas, words)
def write_ode(self):
equation = self.equation
axes = self.axes
de_word = self.de_word
ts = equation.get_parts_by_tex("{t}")
t_rects = VGroup(*map(SurroundingRectangle, ts)) # Rawr
x_axis = axes.x_axis
x_axis_line = Line(
x_axis.get_start(), x_axis.get_end(),
stroke_color=YELLOW,
stroke_width=5,
)
ordinary = TextMobject("Ordinary")
de_word.generate_target()
group = VGroup(ordinary, de_word.target)
group.arrange(RIGHT)
group.to_edge(UP)
ordinary_underline = Line(LEFT, RIGHT)
ordinary_underline.replace(ordinary, dim_to_match=0)
ordinary_underline.next_to(ordinary, DOWN, SMALL_BUFF)
ordinary_underline.set_color(YELLOW)
self.play(
ShowCreationThenFadeOut(
t_rects,
lag_ratio=0.8
),
ShowCreationThenFadeOut(x_axis_line)
)
self.play(
MoveToTarget(de_word),
FadeInFrom(ordinary, RIGHT),
GrowFromCenter(ordinary_underline)
)
self.play(FadeOut(ordinary_underline))
self.wait()
self.remove(ordinary, de_word)
ode_word = self.ode_word = VGroup(*ordinary, *de_word)
ode_initials = VGroup(*[word[0] for word in ode_word])
ode_initials.generate_target()
ode_initials.target.scale(1.2)
ode_initials.target.set_color(PINK)
ode_initials.target.arrange(
RIGHT, buff=0.5 * SMALL_BUFF, aligned_edge=DOWN
)
ode_initials.target.to_edge(UP, buff=MED_SMALL_BUFF)
ode_remaining_letters = VGroup(*it.chain(*[
word[1:] for word in ode_word
]))
ode_remaining_letters.generate_target()
for mob in ode_remaining_letters.target:
mob.shift(0.2 * UP)
mob.fade(1)
self.play(
MoveToTarget(ode_initials),
MoveToTarget(ode_remaining_letters, lag_ratio=0.05),
)
self.wait()
self.ode_initials = ode_initials
def show_second_order(self):
pass
def show_changing_curvature_group(self):
pass
class ODEvsPDEinFrames(Scene):
def construct(self):
pass