mirror of
https://github.com/3b1b/manim.git
synced 2025-08-19 13:01:00 +00:00
Many more ode1 scenes and fixes as the video gets edited
This commit is contained in:
parent
ea4df1f41e
commit
34851761e2
9 changed files with 1267 additions and 135 deletions
|
@ -6,8 +6,10 @@ from active_projects.ode.part1.wordy_scenes import *
|
|||
|
||||
OUTPUT_DIRECTORY = "ode/part1"
|
||||
ALL_SCENE_CLASSES = [
|
||||
VectorFieldTest,
|
||||
IntroducePendulum,
|
||||
MultiplePendulumsOverlayed,
|
||||
PeriodFormula,
|
||||
FormulasAreLies,
|
||||
MediumAnglePendulum,
|
||||
MediumHighAnglePendulum,
|
||||
|
@ -18,21 +20,31 @@ ALL_SCENE_CLASSES = [
|
|||
VeryLowAnglePendulum,
|
||||
FormulasAreLies,
|
||||
TourOfDifferentialEquations,
|
||||
WherePendulumLeads,
|
||||
LongDoublePendulum,
|
||||
# FollowThisThread,
|
||||
StrogatzQuote,
|
||||
ShowHorizontalDashedLine,
|
||||
RabbitFoxPopulations,
|
||||
RabbitFoxEquation,
|
||||
# Something...
|
||||
ShowGravityAcceleration,
|
||||
AnalyzePendulumForce,
|
||||
ShowSineValues,
|
||||
BuildUpEquation,
|
||||
ShowDerivativeVideo,
|
||||
SubtleAirCurrents,
|
||||
SimpleDampenedPendulum,
|
||||
DefineODE,
|
||||
SecondOrderEquationExample,
|
||||
ODEvsPDEinFrames,
|
||||
ProveTeacherWrong,
|
||||
SetAsideSeekingSolution,
|
||||
ReferencePiCollisionStateSpaces,
|
||||
# VisualizeHeightSlopeCurvature,
|
||||
VisualizeStates,
|
||||
ReferencePiCollisionStateSpaces,
|
||||
IntroduceVectorField,
|
||||
XComponentArrows,
|
||||
BreakingSecondOrderIntoTwoFirstOrder,
|
||||
ShowPendulumPhaseFlow,
|
||||
ShowHighVelocityCase,
|
||||
|
@ -42,10 +54,18 @@ ALL_SCENE_CLASSES = [
|
|||
LorenzVectorField,
|
||||
ThreeBodiesInSpace,
|
||||
AltThreeBodiesInSpace,
|
||||
ThreeBodyTitle,
|
||||
ThreeBodySymbols,
|
||||
AskAboutActuallySolving,
|
||||
WriteODESolvingCode,
|
||||
TakeManyTinySteps,
|
||||
InaccurateComputation,
|
||||
HungerForExactness,
|
||||
ShowRect,
|
||||
JumpToThisPoint,
|
||||
ThreeBodyEquation,
|
||||
ItGetsWorse,
|
||||
ChaosTitle,
|
||||
RevisitQuote,
|
||||
EndScreen,
|
||||
]
|
||||
|
|
|
@ -287,6 +287,9 @@ class ThetaVsTAxes(Axes):
|
|||
y_axis.label = theta_label
|
||||
y_axis.add(theta_label)
|
||||
|
||||
self.y_axis_label = theta_label
|
||||
self.x_axis_label = t_label
|
||||
|
||||
x_axis.add_numbers()
|
||||
y_axis.add(self.get_y_axis_coordinates(y_axis))
|
||||
|
||||
|
@ -357,6 +360,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
"length": 3,
|
||||
"top_point": 4 * RIGHT,
|
||||
"weight_diameter": 0.35,
|
||||
"gravity": 20,
|
||||
},
|
||||
"theta_vs_t_axes_config": {
|
||||
"y_max": PI / 4,
|
||||
|
@ -366,6 +370,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
"unit_size": 2,
|
||||
"tip_length": 0.3,
|
||||
},
|
||||
"x_max": 12,
|
||||
"number_line_config": {
|
||||
"stroke_width": 2,
|
||||
}
|
||||
|
@ -378,12 +383,13 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
|
||||
def construct(self):
|
||||
self.add_pendulum()
|
||||
self.label_pi_creatures()
|
||||
# self.label_pi_creatures()
|
||||
self.label_pendulum()
|
||||
self.add_graph()
|
||||
self.label_function()
|
||||
self.show_graph_period()
|
||||
self.show_length_and_gravity()
|
||||
self.tweak_length_and_gravity()
|
||||
# self.tweak_length_and_gravity()
|
||||
|
||||
def create_pi_creatures(self):
|
||||
randy = Randolph(color=BLUE_C)
|
||||
|
@ -437,7 +443,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
GrowArrow(morty_label.arrow),
|
||||
morty.change, "raise_right_hand",
|
||||
)
|
||||
self.wait()
|
||||
self.wait(2)
|
||||
|
||||
def label_pendulum(self):
|
||||
pendulum = self.pendulum
|
||||
|
@ -446,18 +452,18 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
rect = SurroundingRectangle(label, buff=0.5 * SMALL_BUFF)
|
||||
rect.add_updater(lambda r: r.move_to(label))
|
||||
|
||||
self.add(rect)
|
||||
for pi in randy, morty:
|
||||
pi.add_updater(
|
||||
lambda m: m.look_at(pendulum.weight)
|
||||
)
|
||||
|
||||
self.play(randy.change, "pondering")
|
||||
self.play(morty.change, "pondering")
|
||||
self.wait(3)
|
||||
randy.clear_updaters()
|
||||
morty.clear_updaters()
|
||||
self.play(
|
||||
ShowCreationThenFadeOut(rect),
|
||||
ShowCreationThenDestruction(
|
||||
label.copy().set_style(
|
||||
fill_opacity=0,
|
||||
stroke_color=PINK,
|
||||
stroke_width=2,
|
||||
)
|
||||
),
|
||||
randy.change, "pondering",
|
||||
morty.change, "pondering",
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
@ -467,7 +473,10 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
axes.to_corner(UL)
|
||||
|
||||
self.play(
|
||||
Restore(self.camera_frame),
|
||||
Restore(
|
||||
self.camera_frame,
|
||||
rate_func=squish_rate_func(smooth, 0, 0.9),
|
||||
),
|
||||
DrawBorderThenFill(
|
||||
axes,
|
||||
rate_func=squish_rate_func(smooth, 0.5, 1),
|
||||
|
@ -481,11 +490,30 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
),
|
||||
run_time=3,
|
||||
)
|
||||
self.wait(2)
|
||||
self.graph = axes.get_live_drawn_graph(self.pendulum)
|
||||
|
||||
self.wait(1.5)
|
||||
self.graph = axes.get_live_drawn_graph(self.pendulum)
|
||||
self.add(self.graph)
|
||||
self.wait(4)
|
||||
|
||||
def label_function(self):
|
||||
hm_word = TextMobject("Simple harmonic motion")
|
||||
hm_word.scale(1.25)
|
||||
hm_word.to_edge(UP)
|
||||
|
||||
formula = TexMobject(
|
||||
"=\\theta_0 \\cos(\\sqrt{g / L} t)"
|
||||
)
|
||||
formula.next_to(
|
||||
self.axes.y_axis_label, RIGHT, SMALL_BUFF
|
||||
)
|
||||
formula.set_stroke(width=0, background=True)
|
||||
|
||||
self.play(FadeInFrom(hm_word, DOWN))
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(formula),
|
||||
hm_word.to_corner, UR
|
||||
)
|
||||
|
||||
def show_graph_period(self):
|
||||
pendulum = self.pendulum
|
||||
|
@ -503,13 +531,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
line.shift(SMALL_BUFF * RIGHT)
|
||||
brace = Brace(line, UP, buff=SMALL_BUFF)
|
||||
brace.add_to_back(brace.copy().set_style(BLACK, 10))
|
||||
formula = TexMobject(
|
||||
"\\sqrt{\\,", "2\\pi", "L", "/", "g", "}",
|
||||
tex_to_color_map={
|
||||
"L": BLUE,
|
||||
"g": YELLOW,
|
||||
}
|
||||
)
|
||||
formula = get_period_formula()
|
||||
formula.next_to(brace, UP, SMALL_BUFF)
|
||||
|
||||
self.period_formula = formula
|
||||
|
@ -537,29 +559,22 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
self.pendulum,
|
||||
length_multiple=0.5 / 9.8,
|
||||
)
|
||||
down_vectors = self.get_down_vectors()
|
||||
down_vectors.set_color(YELLOW)
|
||||
down_vectors.set_opacity(0.5)
|
||||
|
||||
self.play(ShowCreationThenDestructionAround(L))
|
||||
dot = Dot(fill_opacity=0.25)
|
||||
dot.move_to(L)
|
||||
self.play(
|
||||
ShowCreationThenDestructionAround(L),
|
||||
ShowCreation(new_rod),
|
||||
dot.move_to, new_rod,
|
||||
dot.fade, 1,
|
||||
)
|
||||
self.remove(dot)
|
||||
self.play(FadeOut(new_rod))
|
||||
self.wait()
|
||||
|
||||
self.play(ShowCreationThenDestructionAround(g))
|
||||
dot.move_to(g)
|
||||
dot.set_fill(opacity=0.5)
|
||||
self.play(
|
||||
ShowCreationThenDestructionAround(g),
|
||||
GrowArrow(g_vect),
|
||||
dot.move_to, g_vect,
|
||||
dot.fade, 1,
|
||||
)
|
||||
self.remove(dot)
|
||||
self.wait(2)
|
||||
self.play(self.get_down_vectors_animation(down_vectors))
|
||||
self.wait(6)
|
||||
|
||||
self.gravity_vector = g_vect
|
||||
|
||||
|
@ -593,15 +608,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
# new_pendulum_config["initial_theta"] = pendulum.get_theta()
|
||||
new_pendulum = Pendulum(**new_pendulum_config)
|
||||
|
||||
down_vectors = VGroup(*[
|
||||
Vector(0.5 * DOWN)
|
||||
for x in range(10 * 150)
|
||||
])
|
||||
down_vectors.arrange_in_grid(10, 150, buff=MED_SMALL_BUFF)
|
||||
down_vectors.set_color_by_gradient(BLUE, RED)
|
||||
# for vect in down_vectors:
|
||||
# vect.shift(0.1 * np.random.random(3))
|
||||
down_vectors.to_edge(RIGHT)
|
||||
down_vectors = self.get_down_vectors()
|
||||
|
||||
self.play(randy.change, "happy")
|
||||
self.play(
|
||||
|
@ -624,10 +631,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
g_vect.scale(2)
|
||||
self.play(
|
||||
FadeOut(graph2),
|
||||
LaggedStart(*[
|
||||
GrowArrow(v, rate_func=there_and_back)
|
||||
for v in down_vectors
|
||||
], lag_ratio=0.0005, run_time=2, remover=True)
|
||||
self.get_down_vectors_animation(down_vectors)
|
||||
)
|
||||
self.play(
|
||||
FadeIn(graph3),
|
||||
|
@ -635,6 +639,30 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
|
|||
)
|
||||
self.wait(6)
|
||||
|
||||
#
|
||||
def get_down_vectors(self):
|
||||
down_vectors = VGroup(*[
|
||||
Vector(0.5 * DOWN)
|
||||
for x in range(10 * 150)
|
||||
])
|
||||
down_vectors.arrange_in_grid(10, 150, buff=MED_SMALL_BUFF)
|
||||
down_vectors.set_color_by_gradient(BLUE, RED)
|
||||
# for vect in down_vectors:
|
||||
# vect.shift(0.1 * np.random.random(3))
|
||||
down_vectors.to_edge(RIGHT)
|
||||
return down_vectors
|
||||
|
||||
def get_down_vectors_animation(self, down_vectors):
|
||||
return LaggedStart(
|
||||
*[
|
||||
GrowArrow(v, rate_func=there_and_back)
|
||||
for v in down_vectors
|
||||
],
|
||||
lag_ratio=0.0005,
|
||||
run_time=2,
|
||||
remover=True
|
||||
)
|
||||
|
||||
|
||||
class MultiplePendulumsOverlayed(Scene):
|
||||
CONFIG = {
|
||||
|
@ -868,6 +896,95 @@ class VeryLowAnglePendulum(LowAnglePendulum):
|
|||
}
|
||||
|
||||
|
||||
class WherePendulumLeads(PiCreatureScene):
|
||||
def construct(self):
|
||||
pendulum = Pendulum(
|
||||
top_point=UP,
|
||||
length=3,
|
||||
gravity=20,
|
||||
)
|
||||
pendulum.start_swinging()
|
||||
|
||||
l_title = TextMobject("Linearization")
|
||||
l_title.scale(1.5)
|
||||
l_title.to_corner(UL)
|
||||
c_title = TextMobject("Chaos")
|
||||
c_title.scale(1.5)
|
||||
c_title.move_to(l_title)
|
||||
c_title.move_to(
|
||||
c_title.get_center() * np.array([-1, 1, 1])
|
||||
)
|
||||
|
||||
get_theta = pendulum.get_theta
|
||||
spring = always_redraw(
|
||||
lambda: ParametricFunction(
|
||||
lambda t: np.array([
|
||||
np.cos(TAU * t) + (1.4 + get_theta()) * t,
|
||||
np.sin(TAU * t) - 0.5,
|
||||
0,
|
||||
]),
|
||||
t_min=-0.5,
|
||||
t_max=7,
|
||||
color=GREY,
|
||||
sheen_factor=1,
|
||||
sheen_direction=UL,
|
||||
).scale(0.2).to_edge(LEFT, buff=0)
|
||||
)
|
||||
spring_rect = SurroundingRectangle(
|
||||
spring, buff=MED_LARGE_BUFF,
|
||||
stroke_width=0,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=0,
|
||||
)
|
||||
|
||||
weight = Dot(radius=0.25)
|
||||
weight.add_updater(lambda m: m.move_to(
|
||||
spring.points[-1]
|
||||
))
|
||||
weight.set_color(BLUE)
|
||||
weight.set_sheen(1, UL)
|
||||
spring_system = VGroup(spring, weight)
|
||||
|
||||
linear_formula = TexMobject(
|
||||
"\\frac{d \\vec{\\textbf{x}}}{dt}="
|
||||
"A\\vec{\\textbf{x}}"
|
||||
)
|
||||
linear_formula.next_to(spring, UP, LARGE_BUFF)
|
||||
linear_formula.match_x(l_title)
|
||||
|
||||
randy = self.pi_creature
|
||||
randy.set_height(2)
|
||||
randy.center()
|
||||
randy.to_edge(DOWN)
|
||||
randy.shift(3 * LEFT)
|
||||
q_marks = TexMobject("???")
|
||||
q_marks.next_to(randy, UP)
|
||||
|
||||
self.add(pendulum, randy)
|
||||
self.play(
|
||||
randy.change, "pondering", pendulum,
|
||||
FadeInFromDown(q_marks, lag_ratio=0.3)
|
||||
)
|
||||
self.play(randy.look_at, pendulum)
|
||||
self.wait(5)
|
||||
self.play(
|
||||
Animation(VectorizedPoint(pendulum.get_top())),
|
||||
FadeOutAndShift(q_marks, UP, lag_ratio=0.3),
|
||||
)
|
||||
self.add(spring_system)
|
||||
self.play(
|
||||
FadeOut(spring_rect),
|
||||
FadeInFrom(linear_formula, UP),
|
||||
FadeInFromDown(l_title),
|
||||
)
|
||||
self.play(FadeInFromDown(c_title))
|
||||
self.wait(8)
|
||||
|
||||
|
||||
class LongDoublePendulum(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
|
||||
class AnalyzePendulumForce(MovingCameraScene):
|
||||
CONFIG = {
|
||||
"pendulum_config": {
|
||||
|
@ -1215,13 +1332,22 @@ class AnalyzePendulumForce(MovingCameraScene):
|
|||
|
||||
self.play(FocusOn(pendulum.theta_label))
|
||||
self.play(Indicate(pendulum.theta_label))
|
||||
old_updaters = pendulum.get_updaters()
|
||||
pendulum.clear_updaters(recursive=False)
|
||||
pendulum.start_swinging()
|
||||
|
||||
pendulum_copy = pendulum.deepcopy()
|
||||
pendulum_copy.clear_updaters()
|
||||
pendulum_copy.fade(1)
|
||||
pendulum_copy.start_swinging()
|
||||
|
||||
def new_updater(p):
|
||||
p.set_theta(pendulum_copy.get_theta())
|
||||
pendulum.add_updater(new_updater)
|
||||
|
||||
self.add(pendulum_copy)
|
||||
self.wait(5)
|
||||
pendulum.clear_updaters()
|
||||
for updater in old_updaters:
|
||||
pendulum.add_updater(updater)
|
||||
pendulum_copy.end_swinging()
|
||||
self.remove(pendulum_copy)
|
||||
pendulum.remove_updater(new_updater)
|
||||
self.update_mobjects(0)
|
||||
|
||||
def show_arc_length(self):
|
||||
pendulum = self.pendulum
|
||||
|
@ -1664,6 +1790,18 @@ class BuildUpEquation(Scene):
|
|||
self.wait()
|
||||
|
||||
|
||||
class SimpleDampenedPendulum(Scene):
|
||||
def construct(self):
|
||||
pendulum = Pendulum(
|
||||
top_point=ORIGIN,
|
||||
initial_theta=150 * DEGREES,
|
||||
mu=0.5,
|
||||
)
|
||||
self.add(pendulum)
|
||||
pendulum.start_swinging()
|
||||
self.wait(20)
|
||||
|
||||
|
||||
class NewSceneName(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
|
|
@ -951,13 +951,13 @@ class ShowHighVelocityCase(ShowPendulumPhaseFlow, MovingCameraScene):
|
|||
self.initialize_vector_field()
|
||||
self.add(self.vector_field)
|
||||
self.add_flexible_state()
|
||||
self.show_high_vector()
|
||||
self.show_trajectory()
|
||||
|
||||
def show_trajectory(self):
|
||||
def add_flexible_state(self):
|
||||
super().add_flexible_state()
|
||||
state = self.state
|
||||
plane = self.plane
|
||||
field = self.vector_field
|
||||
frame = self.camera_frame
|
||||
|
||||
state.to_edge(DOWN, buff=SMALL_BUFF),
|
||||
start_point = plane.coords_to_point(0, 4)
|
||||
|
@ -965,6 +965,33 @@ class ShowHighVelocityCase(ShowPendulumPhaseFlow, MovingCameraScene):
|
|||
dot.move_to(start_point)
|
||||
state.update()
|
||||
|
||||
self.dot = dot
|
||||
self.start_point = start_point
|
||||
|
||||
def show_high_vector(self):
|
||||
field = self.vector_field
|
||||
top_vectors = VGroup(*filter(
|
||||
lambda a: np.all(a.get_center() > [-10, 1.5, -10]),
|
||||
field
|
||||
)).copy()
|
||||
top_vectors.set_stroke(PINK, 3)
|
||||
top_vectors.sort(lambda p: p[0])
|
||||
|
||||
self.play(
|
||||
ShowCreationThenFadeOut(
|
||||
top_vectors,
|
||||
run_time=2,
|
||||
lag_ratio=0.01,
|
||||
)
|
||||
)
|
||||
|
||||
def show_trajectory(self):
|
||||
state = self.state
|
||||
field = self.vector_field
|
||||
frame = self.camera_frame
|
||||
dot = self.dot
|
||||
start_point = self.start_point
|
||||
|
||||
traj = VMobject()
|
||||
traj.start_new_path(start_point)
|
||||
dt = 0.01
|
||||
|
@ -998,6 +1025,10 @@ class ShowHighVelocityCase(ShowPendulumPhaseFlow, MovingCameraScene):
|
|||
|
||||
class TweakMuInFormula(Scene):
|
||||
def construct(self):
|
||||
self.add(FullScreenFadeRectangle(
|
||||
opacity=0.75,
|
||||
))
|
||||
|
||||
ode = get_ode()
|
||||
ode.to_edge(DOWN, buff=LARGE_BUFF)
|
||||
mu = ode.get_part_by_tex("\\mu")
|
||||
|
|
|
@ -111,7 +111,11 @@ class FormulasAreLies(PiCreatureScene):
|
|||
class ProveTeacherWrong(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
tex_config = {
|
||||
"tex_to_color_map": {"{\\theta}": BLUE}
|
||||
"tex_to_color_map": {
|
||||
"{\\theta}": BLUE,
|
||||
"{\\dot\\theta}": YELLOW,
|
||||
"{\\ddot\\theta}": RED,
|
||||
}
|
||||
}
|
||||
func = TexMobject(
|
||||
"{\\theta}(t)", "=",
|
||||
|
@ -119,23 +123,24 @@ class ProveTeacherWrong(TeacherStudentsScene):
|
|||
**tex_config,
|
||||
)
|
||||
d_func = TexMobject(
|
||||
"\\dot {\\theta}(t)", "=",
|
||||
"{\\dot\\theta}(t)", "=",
|
||||
"-\\left(\\sqrt{g / L}\\right)",
|
||||
"\\theta_0", "\\sin(\\sqrt{g / L} \\cdot t)",
|
||||
**tex_config,
|
||||
)
|
||||
dd_func = TexMobject(
|
||||
"\\ddot {\\theta}(t)", "=",
|
||||
"{\\ddot\\theta}(t)", "=",
|
||||
"-\\left(g / L\\right)",
|
||||
"\\theta_0", "\\cos(\\sqrt{g / L} \\cdot t)",
|
||||
**tex_config,
|
||||
)
|
||||
ode = TexMobject(
|
||||
"\\ddot {\\theta}({t})", "=",
|
||||
"-\\mu \\dot {\\theta}({t})",
|
||||
"-{g \\over L} \\sin\\big({\\theta}({t})\\big)",
|
||||
**tex_config,
|
||||
)
|
||||
# ode = TexMobject(
|
||||
# "\\ddot {\\theta}({t})", "=",
|
||||
# "-\\mu \\dot {\\theta}({t})",
|
||||
# "-{g \\over L} \\sin\\big({\\theta}({t})\\big)",
|
||||
# **tex_config,
|
||||
# )
|
||||
ode = get_ode()
|
||||
arrows = [TexMobject("\\Downarrow") for x in range(2)]
|
||||
|
||||
VGroup(func, d_func, dd_func, ode, *arrows).scale(0.7)
|
||||
|
@ -376,9 +381,44 @@ class HungerForExactness(TeacherStudentsScene):
|
|||
)
|
||||
self.wait()
|
||||
self.wait(3)
|
||||
self.change_student_modes("tired", "sad", "concerned_musician")
|
||||
self.wait(4)
|
||||
self.look_at(solution)
|
||||
self.wait(5)
|
||||
self.play(
|
||||
FadeOutAndShift(solution, 2 * LEFT),
|
||||
Restore(ode),
|
||||
self.get_student_changes(*3 * ["sick"])
|
||||
self.get_student_changes(
|
||||
"sick", "angry", "tired",
|
||||
)
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
mystery = TexMobject(
|
||||
"\\theta(t) = ???",
|
||||
tex_to_color_map={"\\theta": BLUE},
|
||||
)
|
||||
mystery.scale(2)
|
||||
mystery.to_edge(UP)
|
||||
mystery.set_stroke(width=0, background=True)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(mystery),
|
||||
self.teacher.change, "pondering"
|
||||
)
|
||||
self.add(
|
||||
AnimatedBoundary(mystery, stroke_width=1),
|
||||
mystery,
|
||||
)
|
||||
self.change_all_student_modes("sad")
|
||||
self.look_at(mystery)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class ItGetsWorse(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says("It gets\\\\worse")
|
||||
self.change_student_modes(
|
||||
"hesitant", "pleading", "erm"
|
||||
)
|
||||
self.wait(2)
|
||||
|
|
|
@ -35,6 +35,16 @@ def get_ode():
|
|||
return ode
|
||||
|
||||
|
||||
def get_period_formula():
|
||||
return TexMobject(
|
||||
"\\sqrt{\\,", "2\\pi", "L", "/", "g", "}",
|
||||
tex_to_color_map={
|
||||
"L": BLUE,
|
||||
"g": YELLOW,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def pendulum_vector_field_func(point, mu=0.1, g=9.8, L=3):
|
||||
theta, omega = point[:2]
|
||||
return np.array([
|
||||
|
|
|
@ -3,6 +3,8 @@ from active_projects.ode.part1.shared_constructs import *
|
|||
from active_projects.ode.part1.pendulum import Pendulum
|
||||
from active_projects.ode.part1.pendulum import ThetaVsTAxes
|
||||
from active_projects.ode.part1.phase_space import IntroduceVectorField
|
||||
from old_projects.div_curl import PhaseSpaceOfPopulationModel
|
||||
from old_projects.div_curl import ShowTwoPopulations
|
||||
|
||||
|
||||
# Scenes
|
||||
|
@ -15,16 +17,21 @@ class VectorFieldTest(Scene):
|
|||
)
|
||||
mu_tracker = ValueTracker(1)
|
||||
field = VectorField(
|
||||
lambda p: pendulum_vector_field(
|
||||
lambda p: pendulum_vector_field_func(
|
||||
plane.point_to_coords(p),
|
||||
mu=mu_tracker.get_value()
|
||||
),
|
||||
delta_x=0.5,
|
||||
delta_y=0.5,
|
||||
max_magnitude=4,
|
||||
max_magnitude=6,
|
||||
opacity=0.5,
|
||||
# length_func=lambda norm: norm,
|
||||
)
|
||||
field.set_opacity(1)
|
||||
|
||||
self.add(plane, field)
|
||||
return
|
||||
|
||||
stream_lines = StreamLines(
|
||||
field.func,
|
||||
delta_x=0.5,
|
||||
|
@ -39,6 +46,26 @@ class VectorFieldTest(Scene):
|
|||
self.wait(10)
|
||||
|
||||
|
||||
class ShowRect(Scene):
|
||||
def construct(self):
|
||||
rect = Rectangle()
|
||||
rect.set_stroke(YELLOW)
|
||||
rect.set_height(1)
|
||||
rect.set_width(3, stretch=True)
|
||||
self.play(ShowCreation(rect))
|
||||
self.play(FadeOut(rect))
|
||||
|
||||
|
||||
class PeriodFormula(Scene):
|
||||
def construct(self):
|
||||
formula = get_period_formula()
|
||||
formula.scale(2)
|
||||
q_mark = TexMobject("?")
|
||||
q_mark.scale(3)
|
||||
q_mark.next_to(formula, RIGHT)
|
||||
self.add(formula, q_mark)
|
||||
|
||||
|
||||
class TourOfDifferentialEquations(MovingCameraScene):
|
||||
CONFIG = {
|
||||
"screen_rect_style": {
|
||||
|
@ -214,13 +241,32 @@ class HeatEquationPreview(ExternallyAnimatedScene):
|
|||
pass
|
||||
|
||||
|
||||
class ShowHorizontalDashedLine(Scene):
|
||||
def construct(self):
|
||||
line = DashedLine(LEFT_SIDE, RIGHT_SIDE)
|
||||
self.play(ShowCreation(line))
|
||||
self.wait()
|
||||
|
||||
|
||||
class RabbitFoxPopulations(ShowTwoPopulations):
|
||||
pass
|
||||
|
||||
|
||||
class RabbitFoxEquation(PhaseSpaceOfPopulationModel):
|
||||
def construct(self):
|
||||
equations = self.get_equations()
|
||||
self.add(equations)
|
||||
|
||||
|
||||
class ShowGravityAcceleration(Scene):
|
||||
def construct(self):
|
||||
self.add_gravity_field()
|
||||
self.add_title()
|
||||
self.pulse_gravity_down()
|
||||
self.show_g_value()
|
||||
self.show_trajectory()
|
||||
self.combine_v_vects()
|
||||
self.show_g_symbol()
|
||||
|
||||
def add_gravity_field(self):
|
||||
gravity_field = self.gravity_field = VectorField(
|
||||
|
@ -238,17 +284,11 @@ class ShowGravityAcceleration(Scene):
|
|||
title = self.title = TextMobject("Gravitational acceleration")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
g_eq = self.g_eq = TexMobject(
|
||||
"{g}", "=", "-9.8", "\\frac{\\text{m/s}}{\\text{s}}",
|
||||
**Lg_formula_config
|
||||
title.add_background_rectangle(
|
||||
buff=0.05,
|
||||
opacity=1,
|
||||
)
|
||||
g_eq.next_to(title, DOWN)
|
||||
for mob in title, g_eq:
|
||||
mob.add_background_rectangle_to_submobjects(
|
||||
buff=0.05,
|
||||
opacity=1,
|
||||
)
|
||||
self.add(title, g_eq)
|
||||
self.play(FadeInFromDown(title))
|
||||
|
||||
def pulse_gravity_down(self):
|
||||
field = self.gravity_field
|
||||
|
@ -260,7 +300,36 @@ class ShowGravityAcceleration(Scene):
|
|||
)
|
||||
for vector in field
|
||||
]), run_time=2, lag_ratio=0.001)
|
||||
self.add(self.title, self.g_eq)
|
||||
self.add(self.title)
|
||||
|
||||
def show_g_value(self):
|
||||
title = self.title
|
||||
g_eq = self.g_eq = TexMobject(
|
||||
"-9.8", "{\\text{m/s}", "\\over", "\\text{s}}",
|
||||
**Lg_formula_config
|
||||
)
|
||||
g_eq.add_background_rectangle_to_submobjects()
|
||||
g_eq.scale(2)
|
||||
g_eq.center()
|
||||
num, ms, per, s = g_eq
|
||||
|
||||
self.add(num)
|
||||
self.wait(0.75)
|
||||
self.play(
|
||||
FadeInFrom(ms, 0.25 * DOWN, run_time=0.5)
|
||||
)
|
||||
self.wait(0.25)
|
||||
self.play(LaggedStart(
|
||||
GrowFromPoint(per, per.get_left()),
|
||||
FadeInFrom(s, 0.5 * UP),
|
||||
lag_ratio=0.7,
|
||||
run_time=0.75
|
||||
))
|
||||
self.wait()
|
||||
self.play(
|
||||
g_eq.scale, 0.5,
|
||||
g_eq.next_to, title, DOWN,
|
||||
)
|
||||
|
||||
def show_trajectory(self):
|
||||
ball = Circle(
|
||||
|
@ -329,6 +398,18 @@ class ShowGravityAcceleration(Scene):
|
|||
rate_func=squish_rate_func(smooth, 0, 0.1)
|
||||
)
|
||||
|
||||
time_label = TextMobject("Time = ")
|
||||
time_label.shift(MED_SMALL_BUFF * LEFT)
|
||||
time_tracker = ValueTracker(0)
|
||||
time = DecimalNumber(0)
|
||||
time.next_to(time_label, RIGHT)
|
||||
time.add_updater(lambda d, dt: d.set_value(
|
||||
time_tracker.get_value()
|
||||
))
|
||||
time_group = VGroup(time_label, time)
|
||||
time_group.center().to_edge(DOWN)
|
||||
self.add(time_group)
|
||||
|
||||
ball_copies = VGroup()
|
||||
v_vect_copies = VGroup()
|
||||
self.add(dashed_graph, ball)
|
||||
|
@ -353,11 +434,16 @@ class ShowGravityAcceleration(Scene):
|
|||
ShowCreation(dashed_graph, **kw),
|
||||
MoveAlongPath(ball, graph, **kw),
|
||||
MoveAlongPath(v_point, velocity_graph, **kw),
|
||||
ApplyMethod(
|
||||
time_tracker.increment_value, 1,
|
||||
rate_func=linear
|
||||
),
|
||||
flash,
|
||||
run_time=1,
|
||||
)
|
||||
dashed_graph.restore()
|
||||
randy.clear_updaters()
|
||||
self.play(FadeOut(time_group))
|
||||
self.wait()
|
||||
|
||||
self.v_vects = v_vect_copies
|
||||
|
@ -406,16 +492,30 @@ class ShowGravityAcceleration(Scene):
|
|||
)
|
||||
self.wait()
|
||||
|
||||
def show_g_symbol(self):
|
||||
g = TexMobject("g")
|
||||
brace = Brace(self.g_eq[0][2:], UP, buff=SMALL_BUFF)
|
||||
g.scale(1.5)
|
||||
g.next_to(brace, UP)
|
||||
g.set_color(YELLOW)
|
||||
self.play(
|
||||
FadeOut(self.title),
|
||||
GrowFromCenter(brace),
|
||||
FadeInFrom(g, UP),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowDerivativeVideo(Scene):
|
||||
CONFIG = {
|
||||
"camera_config": {"background_color": DARKER_GREY}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
title = TextMobject("Essence of Calculus")
|
||||
title.scale(1.25)
|
||||
title = TextMobject("Essence of", "Calculus")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
|
||||
title2 = TextMobject("Essence of", "Linear Algebra")
|
||||
title2.scale(1.5)
|
||||
title2.move_to(title, DOWN)
|
||||
|
||||
rect = ScreenRectangle(height=6)
|
||||
rect = rect.copy()
|
||||
rect.set_style(
|
||||
|
@ -428,6 +528,8 @@ class ShowDerivativeVideo(Scene):
|
|||
|
||||
self.add(title, rect)
|
||||
self.add(animated_rect)
|
||||
self.wait(5)
|
||||
self.play(ReplacementTransform(title, title2))
|
||||
self.wait(10)
|
||||
|
||||
|
||||
|
@ -483,7 +585,7 @@ class DefineODE(Scene):
|
|||
|
||||
def write_differential_equation(self):
|
||||
de_word = TextMobject("Differential", "Equation")
|
||||
de_word.to_edge(UP)
|
||||
de_word.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
|
||||
equation = get_ode()
|
||||
equation.next_to(de_word, DOWN)
|
||||
|
@ -777,11 +879,7 @@ class DefineODE(Scene):
|
|||
self.second_order_word = so
|
||||
|
||||
def show_higher_order_examples(self):
|
||||
main_example = VGroup(
|
||||
self.second_order_word,
|
||||
self.ode_initials,
|
||||
self.equation
|
||||
)
|
||||
main_example = self.get_main_example()
|
||||
tex_config = {"tex_to_color_map": {"{x}": BLUE}}
|
||||
example3 = VGroup(
|
||||
TextMobject("Third order ODE"),
|
||||
|
@ -821,6 +919,13 @@ class DefineODE(Scene):
|
|||
)
|
||||
self.wait(2)
|
||||
|
||||
def get_main_example(self):
|
||||
return VGroup(
|
||||
self.second_order_word,
|
||||
self.ode_initials,
|
||||
self.equation
|
||||
)
|
||||
|
||||
def show_changing_curvature_group(self):
|
||||
t_tracker = self.t_tracker
|
||||
curvature_group = self.curvature_group
|
||||
|
@ -828,7 +933,8 @@ class DefineODE(Scene):
|
|||
graph = VMobject()
|
||||
graph.pointwise_become_partial(
|
||||
self.fake_graph,
|
||||
0.25, 1,
|
||||
t_tracker.get_value() / self.axes.x_max,
|
||||
1,
|
||||
)
|
||||
dashed_graph = DashedVMobject(graph, num_dashes=100)
|
||||
dashed_graph.set_stroke(GREEN, 1)
|
||||
|
@ -844,14 +950,397 @@ class DefineODE(Scene):
|
|||
self.wait()
|
||||
|
||||
|
||||
class ODEvsPDEinFrames(Scene):
|
||||
# Largely a copy of DefineODE, which is not great.
|
||||
# But what can you do?
|
||||
class SecondOrderEquationExample(DefineODE):
|
||||
def construct(self):
|
||||
pass
|
||||
self.add_graph()
|
||||
self.write_differential_equation()
|
||||
self.show_value_slope_curvature()
|
||||
self.show_higher_order_examples()
|
||||
self.show_changing_curvature_group()
|
||||
|
||||
def add_graph(self):
|
||||
axes = self.axes = Axes(
|
||||
x_min=0,
|
||||
x_max=10.5,
|
||||
y_min=-2.5,
|
||||
y_max=2.5,
|
||||
)
|
||||
axes.center()
|
||||
axes.to_edge(DOWN)
|
||||
x_t = TexMobject("x", "(t)")
|
||||
x_t.set_color_by_tex("x", BLUE)
|
||||
t = TexMobject("t")
|
||||
t.next_to(axes.x_axis.get_right(), UP)
|
||||
x_t.next_to(axes.y_axis.get_top(), UP)
|
||||
|
||||
axes.add(t, x_t)
|
||||
axes.add_coordinates()
|
||||
|
||||
self.add(axes)
|
||||
|
||||
def write_differential_equation(self):
|
||||
de_word = TextMobject("Differential", "Equation")
|
||||
de_word.scale(1.25)
|
||||
de_word.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
so_word = TextMobject("Second Order")
|
||||
so_word.scale(1.25)
|
||||
de_word.generate_target()
|
||||
group = VGroup(so_word, de_word.target)
|
||||
group.arrange(RIGHT)
|
||||
group.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
so_word.align_to(de_word.target[0], DOWN)
|
||||
so_line = Line(LEFT, RIGHT, color=YELLOW)
|
||||
so_line.match_width(so_word)
|
||||
so_line.next_to(so_word, DOWN, buff=SMALL_BUFF)
|
||||
|
||||
equation = TexMobject(
|
||||
"{\\ddot x}(t)", "=",
|
||||
"-\\mu", "{\\dot x}(t)",
|
||||
"-", "\\omega", "{x}(t)",
|
||||
tex_to_color_map={
|
||||
"{x}": BLUE,
|
||||
"{\\dot x}": YELLOW,
|
||||
"{\\ddot x}": RED,
|
||||
}
|
||||
)
|
||||
equation.next_to(de_word, DOWN)
|
||||
|
||||
dd_x_part = equation[:2]
|
||||
dd_x_rect = SurroundingRectangle(dd_x_part)
|
||||
|
||||
self.add(de_word, equation)
|
||||
self.play(
|
||||
MoveToTarget(de_word),
|
||||
FadeInFrom(so_word, RIGHT),
|
||||
GrowFromCenter(so_line),
|
||||
)
|
||||
self.play(ReplacementTransform(so_line, dd_x_rect))
|
||||
self.play(FadeOut(dd_x_rect))
|
||||
|
||||
self.equation = equation
|
||||
self.title = VGroup(*so_word, *de_word)
|
||||
|
||||
def show_value_slope_curvature(self):
|
||||
axes = self.axes
|
||||
graph = axes.get_graph(
|
||||
lambda t: -2.5 * np.cos(2 * t) * np.exp(-0.2 * t)
|
||||
)
|
||||
|
||||
tex_config = {
|
||||
"tex_to_color_map": {
|
||||
"{x}": BLUE,
|
||||
"{\\dot x}": YELLOW,
|
||||
"{\\ddot x}": RED,
|
||||
},
|
||||
"height": 0.5,
|
||||
}
|
||||
x, d_x, dd_x = [
|
||||
TexMobject(
|
||||
"{" + s + "x}(t)",
|
||||
**tex_config
|
||||
)
|
||||
for s in ("", "\\dot ", "\\ddot ")
|
||||
]
|
||||
|
||||
t_tracker = ValueTracker(1.25)
|
||||
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=BLUE,
|
||||
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)
|
||||
|
||||
x.next_to(v_line, RIGHT, SMALL_BUFF)
|
||||
d_x.next_to(slope_line.get_end(), UP, SMALL_BUFF)
|
||||
dd_x.next_to(curve.get_end(), RIGHT, SMALL_BUFF)
|
||||
xs = VGroup(x, d_x, dd_x)
|
||||
|
||||
words = VGroup(
|
||||
TextMobject("= Height").set_color(BLUE),
|
||||
TextMobject("= Slope").set_color(YELLOW),
|
||||
TextMobject("= ``Curvature''").set_color(RED),
|
||||
)
|
||||
words.scale(0.75)
|
||||
for word, sym in zip(words, xs):
|
||||
word.next_to(sym, RIGHT, buff=2 * SMALL_BUFF)
|
||||
sym.word = word
|
||||
|
||||
self.play(
|
||||
ShowCreation(v_line),
|
||||
FadeInFromPoint(dot, v_line.get_start()),
|
||||
FadeInFrom(x, DOWN),
|
||||
FadeInFrom(x.word, DOWN),
|
||||
)
|
||||
self.add(slope_line, dot)
|
||||
self.play(
|
||||
ShowCreation(slope_line),
|
||||
FadeInFrom(d_x, LEFT),
|
||||
FadeInFrom(d_x.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_x, LEFT),
|
||||
FadeInFrom(dd_x.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(xs, words)
|
||||
self.fake_graph = graph
|
||||
|
||||
def get_main_example(self):
|
||||
return VGroup(
|
||||
self.equation,
|
||||
self.title,
|
||||
)
|
||||
|
||||
# class VisualizeHeightSlopeCurvature(DefineODE):
|
||||
# CONFIG = {
|
||||
# "pendulum_config": {
|
||||
# "length": 2,
|
||||
# "top_point": 5 * RIGHT + 2 * UP,
|
||||
# "initial_theta": 175 * DEGREES,
|
||||
# "mu": 0.3,
|
||||
# },
|
||||
# }
|
||||
|
||||
# def construct(self):
|
||||
# self.add_graph()
|
||||
# self.show_value_slope_curvature()
|
||||
# self.show_changing_curvature_group()
|
||||
|
||||
|
||||
class ODEvsPDEinFrames(Scene):
|
||||
CONFIG = {
|
||||
"camera_config": {"background_color": DARKER_GREY}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
frames = VGroup(*[
|
||||
ScreenRectangle(
|
||||
height=3.5,
|
||||
fill_opacity=1,
|
||||
fill_color=BLACK,
|
||||
stroke_width=0,
|
||||
)
|
||||
for x in range(2)
|
||||
])
|
||||
frames.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
frames.shift(0.5 * DOWN)
|
||||
|
||||
animated_frames = VGroup(*[
|
||||
AnimatedBoundary(
|
||||
frame,
|
||||
cycle_rate=0.2,
|
||||
max_stroke_width=1,
|
||||
)
|
||||
for frame in frames
|
||||
])
|
||||
|
||||
titles = VGroup(
|
||||
# TextMobject("ODEs"),
|
||||
# TextMobject("PDEs"),
|
||||
TextMobject("Ordinary", "Differential", "Equations"),
|
||||
TextMobject("Partial", "Differential", "Equations"),
|
||||
)
|
||||
for title, frame in zip(titles, frames):
|
||||
title.arrange(
|
||||
DOWN,
|
||||
buff=MED_SMALL_BUFF,
|
||||
aligned_edge=LEFT
|
||||
)
|
||||
title.next_to(frame, UP, MED_LARGE_BUFF)
|
||||
title.initials = VGroup(*[
|
||||
part[0] for part in title
|
||||
])
|
||||
titles[0][1].shift(0.05 * UP)
|
||||
|
||||
# ODE content
|
||||
ode = get_ode()
|
||||
ode.set_width(frames[0].get_width() - MED_LARGE_BUFF)
|
||||
ode.next_to(frames[0].get_top(), DOWN)
|
||||
ts = ode.get_parts_by_tex("{t}")
|
||||
one_input = TextMobject("One input")
|
||||
one_input.next_to(frames[0].get_bottom(), UP)
|
||||
o_arrows = VGroup(*[
|
||||
Arrow(
|
||||
one_input.get_top(),
|
||||
t.get_bottom(),
|
||||
buff=0.2,
|
||||
color=WHITE,
|
||||
max_tip_length_to_length_ratio=0.075,
|
||||
path_arc=pa
|
||||
)
|
||||
for t, pa in zip(ts, [-0.7, 0, 0.7])
|
||||
])
|
||||
o_arrows.set_stroke(width=3)
|
||||
frames[0].add(ode, one_input, o_arrows)
|
||||
|
||||
# PDE content
|
||||
pde = TexMobject(
|
||||
"""
|
||||
\\frac{\\partial T}{\\partial t}
|
||||
{(x, y, t)} =
|
||||
\\frac{\\partial^2 T}{\\partial x^2}
|
||||
{(x, y, t)} +
|
||||
\\frac{\\partial^2 T}{\\partial y^2}
|
||||
{(x, y, t)}
|
||||
""",
|
||||
tex_to_color_map={"{(x, y, t)}": WHITE}
|
||||
)
|
||||
pde.set_width(frames[1].get_width() - MED_LARGE_BUFF)
|
||||
pde.next_to(frames[1].get_top(), DOWN)
|
||||
inputs = pde.get_parts_by_tex("{(x, y, t)}")
|
||||
multi_input = TextMobject("Multiple inputs")
|
||||
multi_input.next_to(frames[1].get_bottom(), UP)
|
||||
p_arrows = VGroup(*[
|
||||
Arrow(
|
||||
multi_input.get_top(),
|
||||
mob.get_bottom(),
|
||||
buff=0.2,
|
||||
color=WHITE,
|
||||
max_tip_length_to_length_ratio=0.075,
|
||||
path_arc=pa
|
||||
)
|
||||
for mob, pa in zip(inputs, [-0.7, 0, 0.7])
|
||||
])
|
||||
p_arrows.set_stroke(width=3)
|
||||
frames[1].add(pde, multi_input, p_arrows)
|
||||
|
||||
self.add(
|
||||
frames[0],
|
||||
animated_frames[0],
|
||||
titles[0]
|
||||
)
|
||||
self.play(
|
||||
Write(one_input),
|
||||
ShowCreation(o_arrows, lag_ratio=0.5)
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(titles[0].initials.set_color, BLUE)
|
||||
self.wait(7)
|
||||
|
||||
# Transition
|
||||
self.play(
|
||||
TransformFromCopy(*titles),
|
||||
TransformFromCopy(*frames),
|
||||
)
|
||||
self.play(VFadeIn(animated_frames[1]))
|
||||
self.wait()
|
||||
self.play(titles[1].initials.set_color, YELLOW)
|
||||
self.wait(30)
|
||||
|
||||
|
||||
class ReferencePiCollisionStateSpaces(Scene):
|
||||
CONFIG = {
|
||||
"camera_config": {"background_color": DARKER_GREY}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
pass
|
||||
title = TextMobject("The block collision puzzle")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
self.add(title)
|
||||
|
||||
frames = VGroup(*[
|
||||
ScreenRectangle(
|
||||
height=3.5,
|
||||
fill_opacity=1,
|
||||
fill_color=BLACK,
|
||||
stroke_width=0,
|
||||
)
|
||||
for x in range(2)
|
||||
])
|
||||
frames.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
boundary = AnimatedBoundary(frames)
|
||||
self.add(frames, boundary)
|
||||
self.wait(15)
|
||||
|
||||
|
||||
class XComponentArrows(Scene):
|
||||
def construct(self):
|
||||
field = VectorField(
|
||||
lambda p: np.array([p[1], 0, 0])
|
||||
)
|
||||
field.set_opacity(0.75)
|
||||
for u in (1, -1):
|
||||
field.sort(lambda p: u * p[0])
|
||||
self.play(LaggedStartMap(
|
||||
GrowArrow, field,
|
||||
lag_ratio=0.1,
|
||||
run_time=1
|
||||
))
|
||||
self.play(FadeOut(field))
|
||||
|
||||
|
||||
class BreakingSecondOrderIntoTwoFirstOrder(IntroduceVectorField):
|
||||
|
@ -879,6 +1368,14 @@ class BreakingSecondOrderIntoTwoFirstOrder(IntroduceVectorField):
|
|||
system1.next_to(sys_word, DOWN)
|
||||
system2.move_to(system1)
|
||||
|
||||
theta_dots = VGroup(*filter(
|
||||
lambda m: (
|
||||
isinstance(m, SingleStringTexMobject) and
|
||||
"{\\dot\\theta}" == m.get_tex_string()
|
||||
),
|
||||
system1.get_family(),
|
||||
))
|
||||
|
||||
self.add(ode)
|
||||
self.play(FadeInFrom(so_word, 0.5 * DOWN))
|
||||
self.wait()
|
||||
|
@ -905,6 +1402,13 @@ class BreakingSecondOrderIntoTwoFirstOrder(IntroduceVectorField):
|
|||
FadeInFromDown(sys_word)
|
||||
)
|
||||
self.wait()
|
||||
self.play(LaggedStartMap(
|
||||
ShowCreationThenFadeAround,
|
||||
theta_dots,
|
||||
surrounding_rectangle_config={
|
||||
"color": PINK,
|
||||
}
|
||||
))
|
||||
|
||||
self.play(ReplacementTransform(system1, system2))
|
||||
self.wait()
|
||||
|
@ -993,6 +1497,13 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
|
|||
axes.set_stroke(width=0.5)
|
||||
self.add(axes)
|
||||
|
||||
# Orient
|
||||
self.set_camera_orientation(
|
||||
phi=70 * DEGREES,
|
||||
theta=-110 * DEGREES,
|
||||
)
|
||||
self.begin_ambient_camera_rotation()
|
||||
|
||||
def add_bodies(self):
|
||||
masses = self.masses
|
||||
colors = self.colors
|
||||
|
@ -1071,11 +1582,6 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
|
|||
self.add(traj, body)
|
||||
|
||||
def let_play(self):
|
||||
self.set_camera_orientation(
|
||||
phi=70 * DEGREES,
|
||||
theta=-110 * DEGREES,
|
||||
)
|
||||
self.begin_ambient_camera_rotation()
|
||||
# Break it up to see partial files as
|
||||
# it's rendered
|
||||
for x in range(int(self.play_time)):
|
||||
|
@ -1127,6 +1633,20 @@ class AltThreeBodiesInSpace(ThreeBodiesInSpace):
|
|||
}
|
||||
|
||||
|
||||
class TwoBodiesInSpace(ThreeBodiesInSpace):
|
||||
CONFIG = {
|
||||
"colors": [GREY, BLUE],
|
||||
"masses": [1, 6],
|
||||
"play_time": 5,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_axes()
|
||||
self.add_bodies()
|
||||
self.add_trajectories()
|
||||
self.let_play()
|
||||
|
||||
|
||||
class DefineODECopy(DefineODE):
|
||||
pass
|
||||
|
||||
|
|
|
@ -37,6 +37,40 @@ class SmallAngleApproximationTex(Scene):
|
|||
|
||||
class StrogatzQuote(Scene):
|
||||
def construct(self):
|
||||
quote = self.get_quote()
|
||||
movers = VGroup(*quote[:-1].family_members_with_points())
|
||||
for mover in movers:
|
||||
mover.save_state()
|
||||
disc = Circle(radius=0.05)
|
||||
disc.set_stroke(width=0)
|
||||
disc.set_fill(BLACK, 0)
|
||||
disc.move_to(mover)
|
||||
mover.become(disc)
|
||||
self.play(
|
||||
FadeInFrom(quote.author_part, LEFT),
|
||||
LaggedStartMap(
|
||||
# FadeInFromLarge,
|
||||
# quote[:-1].family_members_with_points(),
|
||||
Restore, movers,
|
||||
lag_ratio=0.005,
|
||||
run_time=2,
|
||||
)
|
||||
# FadeInFromDown(quote[:-1]),
|
||||
# lag_ratio=0.01,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(quote.law_part.copy().set_color(YELLOW)),
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(quote.language_part.copy().set_color(BLUE)),
|
||||
run_time=1.5,
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
def get_quote(self):
|
||||
law_words = "laws of physics"
|
||||
language_words = "language of differential equations"
|
||||
author = "-Steven Strogatz"
|
||||
|
@ -51,46 +85,58 @@ class StrogatzQuote(Scene):
|
|||
arg_separator=" ",
|
||||
substrings_to_isolate=[law_words, language_words, author]
|
||||
)
|
||||
law_part = quote.get_part_by_tex(law_words)
|
||||
language_part = quote.get_part_by_tex(language_words)
|
||||
author_part = quote.get_part_by_tex(author)
|
||||
quote.law_part = quote.get_part_by_tex(law_words)
|
||||
quote.language_part = quote.get_part_by_tex(language_words)
|
||||
quote.author_part = quote.get_part_by_tex(author)
|
||||
quote.set_width(12)
|
||||
quote.to_edge(UP)
|
||||
quote[-2].shift(SMALL_BUFF * LEFT)
|
||||
author_part.shift(RIGHT + 0.5 * DOWN)
|
||||
author_part.scale(1.2, about_edge=UL)
|
||||
quote.author_part.shift(RIGHT + 0.5 * DOWN)
|
||||
quote.author_part.scale(1.2, about_edge=UL)
|
||||
|
||||
return quote
|
||||
|
||||
|
||||
class ShowSineValues(Scene):
|
||||
def construct(self):
|
||||
angle_tracker = ValueTracker(60 * DEGREES)
|
||||
get_angle = angle_tracker.get_value
|
||||
formula = always_redraw(
|
||||
lambda: self.get_sine_formula(get_angle())
|
||||
)
|
||||
self.add(formula)
|
||||
|
||||
movers = VGroup(*quote[:-1].family_members_with_points())
|
||||
for mover in movers:
|
||||
mover.save_state()
|
||||
disc = Circle(radius=0.05)
|
||||
disc.set_stroke(width=0)
|
||||
disc.set_fill(BLACK, 0)
|
||||
disc.move_to(mover)
|
||||
mover.become(disc)
|
||||
self.play(
|
||||
FadeInFrom(author_part, LEFT),
|
||||
LaggedStartMap(
|
||||
# FadeInFromLarge,
|
||||
# quote[:-1].family_members_with_points(),
|
||||
Restore, movers,
|
||||
lag_ratio=0.005,
|
||||
run_time=2,
|
||||
)
|
||||
# FadeInFromDown(quote[:-1]),
|
||||
# lag_ratio=0.01,
|
||||
angle_tracker.set_value, 0,
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(law_part.copy().set_color(YELLOW)),
|
||||
run_time=1,
|
||||
angle_tracker.set_value, 90 * DEGREES,
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(language_part.copy().set_color(BLUE)),
|
||||
run_time=1.5,
|
||||
|
||||
def get_sine_formula(self, angle):
|
||||
sin, lp, rp = TexMobject(
|
||||
"\\sin", "(", ") = "
|
||||
)
|
||||
self.wait(2)
|
||||
input_part = Integer(
|
||||
angle / DEGREES,
|
||||
unit="^\\circ",
|
||||
)
|
||||
input_part.set_color(YELLOW)
|
||||
output_part = DecimalNumber(
|
||||
np.sin(input_part.get_value() * DEGREES),
|
||||
num_decimal_places=3,
|
||||
)
|
||||
result = VGroup(
|
||||
sin, lp, input_part, rp, output_part
|
||||
)
|
||||
result.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
sin.scale(1.1, about_edge=DOWN)
|
||||
lp.align_to(rp, UP)
|
||||
return result
|
||||
|
||||
|
||||
class SetAsideSeekingSolution(Scene):
|
||||
|
@ -141,6 +187,14 @@ class SetAsideSeekingSolution(Scene):
|
|||
)
|
||||
|
||||
|
||||
class ThreeBodyTitle(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Three body problem")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
self.add(title)
|
||||
|
||||
|
||||
class ThreeBodySymbols(Scene):
|
||||
def construct(self):
|
||||
self.init_coord_groups()
|
||||
|
@ -260,3 +314,259 @@ class ThreeBodySymbols(Scene):
|
|||
rate_func=linear,
|
||||
)
|
||||
self.play(FadeOut(coord_copies))
|
||||
|
||||
|
||||
class ThreeBodyEquation(Scene):
|
||||
def construct(self):
|
||||
x1 = "\\vec{\\textbf{x}}_1"
|
||||
x2 = "\\vec{\\textbf{x}}_2"
|
||||
x3 = "\\vec{\\textbf{x}}_3"
|
||||
kw = {
|
||||
"tex_to_color_map": {
|
||||
x1: RED,
|
||||
x2: GREEN,
|
||||
x3: BLUE,
|
||||
}
|
||||
}
|
||||
equations = VGroup(*[
|
||||
TexMobject(
|
||||
"{d^2", t1, "\\over dt^2}", "=",
|
||||
"G", "\\left("
|
||||
"{" + m2, "(", t2, "-", t1, ")"
|
||||
"\\over"
|
||||
"||", t2, "-", t1, "||^3}",
|
||||
"+",
|
||||
"{" + m3, "(", t3, "-", t1, ")"
|
||||
"\\over"
|
||||
"||", t3, "-", t1, "||^3}",
|
||||
"\\right)",
|
||||
**kw
|
||||
)
|
||||
for t1, t2, t3, m1, m2, m3 in [
|
||||
(x1, x2, x3, "m_1", "m_2", "m_3"),
|
||||
(x2, x3, x1, "m_2", "m_3", "m_1"),
|
||||
(x3, x1, x2, "m_3", "m_1", "m_2"),
|
||||
]
|
||||
])
|
||||
equations.arrange(DOWN, buff=LARGE_BUFF)
|
||||
|
||||
self.play(LaggedStartMap(
|
||||
FadeInFrom, equations,
|
||||
lambda m: (m, UP),
|
||||
lag_ratio=0.2,
|
||||
))
|
||||
self.wait()
|
||||
|
||||
|
||||
class JumpToThisPoint(Scene):
|
||||
def construct(self):
|
||||
dot = Dot(color=YELLOW)
|
||||
dot.scale(0.5)
|
||||
|
||||
arrow = Vector(DR, color=WHITE)
|
||||
arrow.next_to(dot, UL, SMALL_BUFF)
|
||||
words = TextMobject(
|
||||
"Jump directly to\\\\",
|
||||
"this point?",
|
||||
)
|
||||
words.add_background_rectangle_to_submobjects()
|
||||
words.next_to(arrow.get_start(), UP, SMALL_BUFF)
|
||||
|
||||
self.play(
|
||||
FadeInFromLarge(dot, 20),
|
||||
rate_func=rush_into,
|
||||
)
|
||||
self.play(
|
||||
GrowArrow(arrow),
|
||||
FadeInFromDown(words),
|
||||
)
|
||||
|
||||
|
||||
class ChaosTitle(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Chaos theorey")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
line = Line(LEFT, RIGHT)
|
||||
line.set_width(FRAME_WIDTH - 1)
|
||||
line.next_to(title, DOWN)
|
||||
|
||||
self.play(
|
||||
Write(title),
|
||||
ShowCreation(line),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class RevisitQuote(StrogatzQuote, PiCreatureScene):
|
||||
def construct(self):
|
||||
quote = self.get_quote()
|
||||
quote.law_part.set_color(YELLOW)
|
||||
quote.language_part.set_color(BLUE)
|
||||
quote.set_stroke(BLACK, 6, background=True)
|
||||
quote.scale(0.8, about_edge=UL)
|
||||
|
||||
new_langauge_part = TextMobject(
|
||||
"\\Large Language of differential equations"
|
||||
)
|
||||
new_langauge_part.to_edge(UP)
|
||||
new_langauge_part.match_style(quote.language_part)
|
||||
|
||||
randy = self.pi_creature
|
||||
|
||||
self.play(
|
||||
FadeInFrom(quote[:-1], DOWN),
|
||||
FadeInFrom(quote[-1:], LEFT),
|
||||
randy.change, "raise_right_hand",
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.play(randy.change, "angry")
|
||||
self.play(
|
||||
Blink(randy),
|
||||
VFadeOut(randy, run_time=3)
|
||||
)
|
||||
mover = VGroup(quote.language_part)
|
||||
self.add(quote, mover)
|
||||
self.play(
|
||||
ReplacementTransform(
|
||||
mover, new_langauge_part,
|
||||
),
|
||||
*[
|
||||
FadeOut(part)
|
||||
for part in quote
|
||||
if part is not quote.language_part
|
||||
],
|
||||
run_time=2,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class EndScreen(PatreonEndScreen):
|
||||
CONFIG = {
|
||||
"specific_patrons": [
|
||||
"Juan Benet",
|
||||
"Vassili Philippov",
|
||||
"Burt Humburg",
|
||||
"Carlos Vergara Del Rio",
|
||||
"Matt Russell",
|
||||
"Scott Gray",
|
||||
"soekul",
|
||||
"Tihan Seale",
|
||||
"Ali Yahya",
|
||||
"dave nicponski",
|
||||
"Evan Phillips",
|
||||
"Graham",
|
||||
"Joseph Kelly",
|
||||
"Kaustuv DeBiswas",
|
||||
"LambdaLabs",
|
||||
"Lukas Biewald",
|
||||
"Mike Coleman",
|
||||
"Peter Mcinerney",
|
||||
"Quantopian",
|
||||
"Roy Larson",
|
||||
"Scott Walter, Ph.D.",
|
||||
"Yana Chernobilsky",
|
||||
"Yu Jun",
|
||||
"Jordan Scales",
|
||||
"Lukas -krtek.net- Novy",
|
||||
"John Shaughnessy",
|
||||
"Britt Selvitelle",
|
||||
"David Gow",
|
||||
"J",
|
||||
"Jonathan Wilson",
|
||||
"Joseph John Cox",
|
||||
"Magnus Dahlström",
|
||||
"Randy C. Will",
|
||||
"Ryan Atallah",
|
||||
"Luc Ritchie",
|
||||
"1stViewMaths",
|
||||
"Adrian Robinson",
|
||||
"Alexis Olson",
|
||||
"Andreas Benjamin Brössel",
|
||||
"Andrew Busey",
|
||||
"Ankalagon",
|
||||
"Antonio Juarez",
|
||||
"Arjun Chakroborty",
|
||||
"Art Ianuzzi",
|
||||
"Awoo",
|
||||
"Bernd Sing",
|
||||
"Boris Veselinovich",
|
||||
"Brian Staroselsky",
|
||||
"Chad Hurst",
|
||||
"Charles Southerland",
|
||||
"Chris Connett",
|
||||
"Christian Kaiser",
|
||||
"Clark Gaebel",
|
||||
"Cooper Jones",
|
||||
"Danger Dai",
|
||||
"Dave B",
|
||||
"Dave Kester",
|
||||
"David Clark",
|
||||
"DeathByShrimp",
|
||||
"Delton Ding",
|
||||
"eaglle",
|
||||
"emptymachine",
|
||||
"Eric Younge",
|
||||
"Eryq Ouithaqueue",
|
||||
"Federico Lebron",
|
||||
"Giovanni Filippi",
|
||||
"Hal Hildebrand",
|
||||
"Herman Dieset",
|
||||
"Hitoshi Yamauchi",
|
||||
"Isaac Jeffrey Lee",
|
||||
"j eduardo perez",
|
||||
"Jacob Magnuson",
|
||||
"Jameel Syed",
|
||||
"Jason Hise",
|
||||
"Jeff Linse",
|
||||
"Jeff Straathof",
|
||||
"John Griffith",
|
||||
"John Haley",
|
||||
"John V Wertheim",
|
||||
"Jonathan Eppele",
|
||||
"Kai-Siang Ang",
|
||||
"Kanan Gill",
|
||||
"L0j1k",
|
||||
"Lee Redden",
|
||||
"Linh Tran",
|
||||
"Ludwig Schubert",
|
||||
"Magister Mugit",
|
||||
"Mark B Bahu",
|
||||
"Mark Heising",
|
||||
"Martin Price",
|
||||
"Mathias Jansson",
|
||||
"Matt Langford",
|
||||
"Matt Roveto",
|
||||
"Matthew Cocke",
|
||||
"Michael Faust",
|
||||
"Michael Hardel",
|
||||
"Mirik Gogri",
|
||||
"Mustafa Mahdi",
|
||||
"Márton Vaitkus",
|
||||
"Nero Li",
|
||||
"Nikita Lesnikov",
|
||||
"Omar Zrien",
|
||||
"Owen Campbell-Moore",
|
||||
"Peter Ehrnstrom",
|
||||
"RedAgent14",
|
||||
"rehmi post",
|
||||
"Richard Burgmann",
|
||||
"Richard Comish",
|
||||
"Ripta Pasay",
|
||||
"Rish Kundalia",
|
||||
"Robert Teed",
|
||||
"Roobie",
|
||||
"Ryan Williams",
|
||||
"Samuel D. Judge",
|
||||
"Solara570",
|
||||
"Stevie Metke",
|
||||
"Tal Einav",
|
||||
"Ted Suzman",
|
||||
"Valeriy Skobelev",
|
||||
"Xavier Bernard",
|
||||
"Yavor Ivanov",
|
||||
"Yaw Etse",
|
||||
"YinYangBalance.Asia",
|
||||
"Zach Cardwell",
|
||||
]
|
||||
}
|
||||
|
|
63
active_projects/ode/solve_pendulum_ode_sample_code.py
Normal file
63
active_projects/ode/solve_pendulum_ode_sample_code.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
import numpy as np
|
||||
|
||||
# Physical constants
|
||||
g = 9.8
|
||||
L = 2
|
||||
mu = 0.1
|
||||
|
||||
THETA_0 = np.pi / 3 # 60 degrees
|
||||
THETA_DOT_0 = 0 # No initial angular velocity
|
||||
|
||||
# Definition of ODE
|
||||
def get_theta_double_dot(theta, theta_dot):
|
||||
return -mu * theta_dot - (g / L) * np.sin(theta)
|
||||
|
||||
|
||||
# Solution to the differential equation
|
||||
def theta(t):
|
||||
# Initialize changing values
|
||||
theta = THETA_0
|
||||
theta_dot = THETA_DOT_0
|
||||
delta_t = 0.01 # Some time step
|
||||
for time in np.arange(0, t, delta_t):
|
||||
# Take many little time steps of size delta_t
|
||||
# until the total time is the function's input
|
||||
theta_double_dot = get_theta_double_dot(
|
||||
theta, theta_dot
|
||||
)
|
||||
theta += theta_dot * delta_t
|
||||
theta_dot += theta_double_dot * delta_t
|
||||
return theta
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ def stage_scenes(module_name):
|
|||
# }
|
||||
# TODO, fix this
|
||||
animation_dir = os.path.join(
|
||||
VIDEO_DIR, "clacks_solution2", "1440p60"
|
||||
VIDEO_DIR, "ode", "part1", "1440p60"
|
||||
)
|
||||
#
|
||||
files = os.listdir(animation_dir)
|
||||
|
|
Loading…
Add table
Reference in a new issue