Many more ode1 scenes and fixes as the video gets edited

This commit is contained in:
Grant Sanderson 2019-03-28 16:20:09 -07:00
parent ea4df1f41e
commit 34851761e2
9 changed files with 1267 additions and 135 deletions

View file

@ -6,8 +6,10 @@ from active_projects.ode.part1.wordy_scenes import *
OUTPUT_DIRECTORY = "ode/part1" OUTPUT_DIRECTORY = "ode/part1"
ALL_SCENE_CLASSES = [ ALL_SCENE_CLASSES = [
VectorFieldTest,
IntroducePendulum, IntroducePendulum,
MultiplePendulumsOverlayed, MultiplePendulumsOverlayed,
PeriodFormula,
FormulasAreLies, FormulasAreLies,
MediumAnglePendulum, MediumAnglePendulum,
MediumHighAnglePendulum, MediumHighAnglePendulum,
@ -18,21 +20,31 @@ ALL_SCENE_CLASSES = [
VeryLowAnglePendulum, VeryLowAnglePendulum,
FormulasAreLies, FormulasAreLies,
TourOfDifferentialEquations, TourOfDifferentialEquations,
WherePendulumLeads,
LongDoublePendulum,
# FollowThisThread, # FollowThisThread,
StrogatzQuote, StrogatzQuote,
ShowHorizontalDashedLine,
RabbitFoxPopulations,
RabbitFoxEquation,
# Something... # Something...
ShowGravityAcceleration, ShowGravityAcceleration,
AnalyzePendulumForce, AnalyzePendulumForce,
ShowSineValues,
BuildUpEquation, BuildUpEquation,
ShowDerivativeVideo, ShowDerivativeVideo,
SubtleAirCurrents, SubtleAirCurrents,
SimpleDampenedPendulum,
DefineODE, DefineODE,
SecondOrderEquationExample,
ODEvsPDEinFrames, ODEvsPDEinFrames,
ProveTeacherWrong, ProveTeacherWrong,
SetAsideSeekingSolution, SetAsideSeekingSolution,
ReferencePiCollisionStateSpaces, # VisualizeHeightSlopeCurvature,
VisualizeStates, VisualizeStates,
ReferencePiCollisionStateSpaces,
IntroduceVectorField, IntroduceVectorField,
XComponentArrows,
BreakingSecondOrderIntoTwoFirstOrder, BreakingSecondOrderIntoTwoFirstOrder,
ShowPendulumPhaseFlow, ShowPendulumPhaseFlow,
ShowHighVelocityCase, ShowHighVelocityCase,
@ -42,10 +54,18 @@ ALL_SCENE_CLASSES = [
LorenzVectorField, LorenzVectorField,
ThreeBodiesInSpace, ThreeBodiesInSpace,
AltThreeBodiesInSpace, AltThreeBodiesInSpace,
ThreeBodyTitle,
ThreeBodySymbols, ThreeBodySymbols,
AskAboutActuallySolving, AskAboutActuallySolving,
WriteODESolvingCode, WriteODESolvingCode,
TakeManyTinySteps, TakeManyTinySteps,
InaccurateComputation, InaccurateComputation,
HungerForExactness, HungerForExactness,
ShowRect,
JumpToThisPoint,
ThreeBodyEquation,
ItGetsWorse,
ChaosTitle,
RevisitQuote,
EndScreen,
] ]

View file

@ -287,6 +287,9 @@ class ThetaVsTAxes(Axes):
y_axis.label = theta_label y_axis.label = theta_label
y_axis.add(theta_label) y_axis.add(theta_label)
self.y_axis_label = theta_label
self.x_axis_label = t_label
x_axis.add_numbers() x_axis.add_numbers()
y_axis.add(self.get_y_axis_coordinates(y_axis)) y_axis.add(self.get_y_axis_coordinates(y_axis))
@ -357,6 +360,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
"length": 3, "length": 3,
"top_point": 4 * RIGHT, "top_point": 4 * RIGHT,
"weight_diameter": 0.35, "weight_diameter": 0.35,
"gravity": 20,
}, },
"theta_vs_t_axes_config": { "theta_vs_t_axes_config": {
"y_max": PI / 4, "y_max": PI / 4,
@ -366,6 +370,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
"unit_size": 2, "unit_size": 2,
"tip_length": 0.3, "tip_length": 0.3,
}, },
"x_max": 12,
"number_line_config": { "number_line_config": {
"stroke_width": 2, "stroke_width": 2,
} }
@ -378,12 +383,13 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
def construct(self): def construct(self):
self.add_pendulum() self.add_pendulum()
self.label_pi_creatures() # self.label_pi_creatures()
self.label_pendulum() self.label_pendulum()
self.add_graph() self.add_graph()
self.label_function()
self.show_graph_period() self.show_graph_period()
self.show_length_and_gravity() self.show_length_and_gravity()
self.tweak_length_and_gravity() # self.tweak_length_and_gravity()
def create_pi_creatures(self): def create_pi_creatures(self):
randy = Randolph(color=BLUE_C) randy = Randolph(color=BLUE_C)
@ -437,7 +443,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
GrowArrow(morty_label.arrow), GrowArrow(morty_label.arrow),
morty.change, "raise_right_hand", morty.change, "raise_right_hand",
) )
self.wait() self.wait(2)
def label_pendulum(self): def label_pendulum(self):
pendulum = self.pendulum pendulum = self.pendulum
@ -446,18 +452,18 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
rect = SurroundingRectangle(label, buff=0.5 * SMALL_BUFF) rect = SurroundingRectangle(label, buff=0.5 * SMALL_BUFF)
rect.add_updater(lambda r: r.move_to(label)) 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( self.play(
ShowCreationThenFadeOut(rect), ShowCreationThenFadeOut(rect),
ShowCreationThenDestruction(
label.copy().set_style(
fill_opacity=0,
stroke_color=PINK,
stroke_width=2,
)
),
randy.change, "pondering",
morty.change, "pondering",
) )
self.wait() self.wait()
@ -467,7 +473,10 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
axes.to_corner(UL) axes.to_corner(UL)
self.play( self.play(
Restore(self.camera_frame), Restore(
self.camera_frame,
rate_func=squish_rate_func(smooth, 0, 0.9),
),
DrawBorderThenFill( DrawBorderThenFill(
axes, axes,
rate_func=squish_rate_func(smooth, 0.5, 1), rate_func=squish_rate_func(smooth, 0.5, 1),
@ -481,11 +490,30 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
), ),
run_time=3, 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.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): def show_graph_period(self):
pendulum = self.pendulum pendulum = self.pendulum
@ -503,13 +531,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
line.shift(SMALL_BUFF * RIGHT) line.shift(SMALL_BUFF * RIGHT)
brace = Brace(line, UP, buff=SMALL_BUFF) brace = Brace(line, UP, buff=SMALL_BUFF)
brace.add_to_back(brace.copy().set_style(BLACK, 10)) brace.add_to_back(brace.copy().set_style(BLACK, 10))
formula = TexMobject( formula = get_period_formula()
"\\sqrt{\\,", "2\\pi", "L", "/", "g", "}",
tex_to_color_map={
"L": BLUE,
"g": YELLOW,
}
)
formula.next_to(brace, UP, SMALL_BUFF) formula.next_to(brace, UP, SMALL_BUFF)
self.period_formula = formula self.period_formula = formula
@ -537,29 +559,22 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
self.pendulum, self.pendulum,
length_multiple=0.5 / 9.8, 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( self.play(
ShowCreationThenDestructionAround(L),
ShowCreation(new_rod), ShowCreation(new_rod),
dot.move_to, new_rod,
dot.fade, 1,
) )
self.remove(dot)
self.play(FadeOut(new_rod)) self.play(FadeOut(new_rod))
self.wait()
self.play(ShowCreationThenDestructionAround(g))
dot.move_to(g)
dot.set_fill(opacity=0.5)
self.play( self.play(
ShowCreationThenDestructionAround(g),
GrowArrow(g_vect), GrowArrow(g_vect),
dot.move_to, g_vect,
dot.fade, 1,
) )
self.remove(dot) self.play(self.get_down_vectors_animation(down_vectors))
self.wait(2) self.wait(6)
self.gravity_vector = g_vect self.gravity_vector = g_vect
@ -593,15 +608,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
# new_pendulum_config["initial_theta"] = pendulum.get_theta() # new_pendulum_config["initial_theta"] = pendulum.get_theta()
new_pendulum = Pendulum(**new_pendulum_config) new_pendulum = Pendulum(**new_pendulum_config)
down_vectors = VGroup(*[ down_vectors = self.get_down_vectors()
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)
self.play(randy.change, "happy") self.play(randy.change, "happy")
self.play( self.play(
@ -624,10 +631,7 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
g_vect.scale(2) g_vect.scale(2)
self.play( self.play(
FadeOut(graph2), FadeOut(graph2),
LaggedStart(*[ self.get_down_vectors_animation(down_vectors)
GrowArrow(v, rate_func=there_and_back)
for v in down_vectors
], lag_ratio=0.0005, run_time=2, remover=True)
) )
self.play( self.play(
FadeIn(graph3), FadeIn(graph3),
@ -635,6 +639,30 @@ class IntroducePendulum(PiCreatureScene, MovingCameraScene):
) )
self.wait(6) 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): class MultiplePendulumsOverlayed(Scene):
CONFIG = { 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): class AnalyzePendulumForce(MovingCameraScene):
CONFIG = { CONFIG = {
"pendulum_config": { "pendulum_config": {
@ -1215,13 +1332,22 @@ class AnalyzePendulumForce(MovingCameraScene):
self.play(FocusOn(pendulum.theta_label)) self.play(FocusOn(pendulum.theta_label))
self.play(Indicate(pendulum.theta_label)) self.play(Indicate(pendulum.theta_label))
old_updaters = pendulum.get_updaters()
pendulum.clear_updaters(recursive=False) pendulum_copy = pendulum.deepcopy()
pendulum.start_swinging() 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) self.wait(5)
pendulum.clear_updaters() pendulum_copy.end_swinging()
for updater in old_updaters: self.remove(pendulum_copy)
pendulum.add_updater(updater) pendulum.remove_updater(new_updater)
self.update_mobjects(0)
def show_arc_length(self): def show_arc_length(self):
pendulum = self.pendulum pendulum = self.pendulum
@ -1664,6 +1790,18 @@ class BuildUpEquation(Scene):
self.wait() 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): class NewSceneName(Scene):
def construct(self): def construct(self):
pass pass

View file

@ -951,13 +951,13 @@ class ShowHighVelocityCase(ShowPendulumPhaseFlow, MovingCameraScene):
self.initialize_vector_field() self.initialize_vector_field()
self.add(self.vector_field) self.add(self.vector_field)
self.add_flexible_state() self.add_flexible_state()
self.show_high_vector()
self.show_trajectory() self.show_trajectory()
def show_trajectory(self): def add_flexible_state(self):
super().add_flexible_state()
state = self.state state = self.state
plane = self.plane plane = self.plane
field = self.vector_field
frame = self.camera_frame
state.to_edge(DOWN, buff=SMALL_BUFF), state.to_edge(DOWN, buff=SMALL_BUFF),
start_point = plane.coords_to_point(0, 4) start_point = plane.coords_to_point(0, 4)
@ -965,6 +965,33 @@ class ShowHighVelocityCase(ShowPendulumPhaseFlow, MovingCameraScene):
dot.move_to(start_point) dot.move_to(start_point)
state.update() 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 = VMobject()
traj.start_new_path(start_point) traj.start_new_path(start_point)
dt = 0.01 dt = 0.01
@ -998,6 +1025,10 @@ class ShowHighVelocityCase(ShowPendulumPhaseFlow, MovingCameraScene):
class TweakMuInFormula(Scene): class TweakMuInFormula(Scene):
def construct(self): def construct(self):
self.add(FullScreenFadeRectangle(
opacity=0.75,
))
ode = get_ode() ode = get_ode()
ode.to_edge(DOWN, buff=LARGE_BUFF) ode.to_edge(DOWN, buff=LARGE_BUFF)
mu = ode.get_part_by_tex("\\mu") mu = ode.get_part_by_tex("\\mu")

View file

@ -111,7 +111,11 @@ class FormulasAreLies(PiCreatureScene):
class ProveTeacherWrong(TeacherStudentsScene): class ProveTeacherWrong(TeacherStudentsScene):
def construct(self): def construct(self):
tex_config = { tex_config = {
"tex_to_color_map": {"{\\theta}": BLUE} "tex_to_color_map": {
"{\\theta}": BLUE,
"{\\dot\\theta}": YELLOW,
"{\\ddot\\theta}": RED,
}
} }
func = TexMobject( func = TexMobject(
"{\\theta}(t)", "=", "{\\theta}(t)", "=",
@ -119,23 +123,24 @@ class ProveTeacherWrong(TeacherStudentsScene):
**tex_config, **tex_config,
) )
d_func = TexMobject( d_func = TexMobject(
"\\dot {\\theta}(t)", "=", "{\\dot\\theta}(t)", "=",
"-\\left(\\sqrt{g / L}\\right)", "-\\left(\\sqrt{g / L}\\right)",
"\\theta_0", "\\sin(\\sqrt{g / L} \\cdot t)", "\\theta_0", "\\sin(\\sqrt{g / L} \\cdot t)",
**tex_config, **tex_config,
) )
dd_func = TexMobject( dd_func = TexMobject(
"\\ddot {\\theta}(t)", "=", "{\\ddot\\theta}(t)", "=",
"-\\left(g / L\\right)", "-\\left(g / L\\right)",
"\\theta_0", "\\cos(\\sqrt{g / L} \\cdot t)", "\\theta_0", "\\cos(\\sqrt{g / L} \\cdot t)",
**tex_config, **tex_config,
) )
ode = TexMobject( # ode = TexMobject(
"\\ddot {\\theta}({t})", "=", # "\\ddot {\\theta}({t})", "=",
"-\\mu \\dot {\\theta}({t})", # "-\\mu \\dot {\\theta}({t})",
"-{g \\over L} \\sin\\big({\\theta}({t})\\big)", # "-{g \\over L} \\sin\\big({\\theta}({t})\\big)",
**tex_config, # **tex_config,
) # )
ode = get_ode()
arrows = [TexMobject("\\Downarrow") for x in range(2)] arrows = [TexMobject("\\Downarrow") for x in range(2)]
VGroup(func, d_func, dd_func, ode, *arrows).scale(0.7) VGroup(func, d_func, dd_func, ode, *arrows).scale(0.7)
@ -376,9 +381,44 @@ class HungerForExactness(TeacherStudentsScene):
) )
self.wait() self.wait()
self.wait(3) self.wait(3)
self.change_student_modes("tired", "sad", "concerned_musician")
self.wait(4)
self.look_at(solution)
self.wait(5)
self.play( self.play(
FadeOutAndShift(solution, 2 * LEFT), FadeOutAndShift(solution, 2 * LEFT),
Restore(ode), Restore(ode),
self.get_student_changes(*3 * ["sick"]) self.get_student_changes(
"sick", "angry", "tired",
)
) )
self.wait(3) 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)

View file

@ -35,6 +35,16 @@ def get_ode():
return 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): def pendulum_vector_field_func(point, mu=0.1, g=9.8, L=3):
theta, omega = point[:2] theta, omega = point[:2]
return np.array([ return np.array([

View file

@ -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 Pendulum
from active_projects.ode.part1.pendulum import ThetaVsTAxes from active_projects.ode.part1.pendulum import ThetaVsTAxes
from active_projects.ode.part1.phase_space import IntroduceVectorField from active_projects.ode.part1.phase_space import IntroduceVectorField
from old_projects.div_curl import PhaseSpaceOfPopulationModel
from old_projects.div_curl import ShowTwoPopulations
# Scenes # Scenes
@ -15,16 +17,21 @@ class VectorFieldTest(Scene):
) )
mu_tracker = ValueTracker(1) mu_tracker = ValueTracker(1)
field = VectorField( field = VectorField(
lambda p: pendulum_vector_field( lambda p: pendulum_vector_field_func(
plane.point_to_coords(p), plane.point_to_coords(p),
mu=mu_tracker.get_value() mu=mu_tracker.get_value()
), ),
delta_x=0.5, delta_x=0.5,
delta_y=0.5, delta_y=0.5,
max_magnitude=4, max_magnitude=6,
opacity=0.5, opacity=0.5,
# length_func=lambda norm: norm, # length_func=lambda norm: norm,
) )
field.set_opacity(1)
self.add(plane, field)
return
stream_lines = StreamLines( stream_lines = StreamLines(
field.func, field.func,
delta_x=0.5, delta_x=0.5,
@ -39,6 +46,26 @@ class VectorFieldTest(Scene):
self.wait(10) 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): class TourOfDifferentialEquations(MovingCameraScene):
CONFIG = { CONFIG = {
"screen_rect_style": { "screen_rect_style": {
@ -214,13 +241,32 @@ class HeatEquationPreview(ExternallyAnimatedScene):
pass 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): class ShowGravityAcceleration(Scene):
def construct(self): def construct(self):
self.add_gravity_field() self.add_gravity_field()
self.add_title() self.add_title()
self.pulse_gravity_down() self.pulse_gravity_down()
self.show_g_value()
self.show_trajectory() self.show_trajectory()
self.combine_v_vects() self.combine_v_vects()
self.show_g_symbol()
def add_gravity_field(self): def add_gravity_field(self):
gravity_field = self.gravity_field = VectorField( gravity_field = self.gravity_field = VectorField(
@ -238,17 +284,11 @@ class ShowGravityAcceleration(Scene):
title = self.title = TextMobject("Gravitational acceleration") title = self.title = TextMobject("Gravitational acceleration")
title.scale(1.5) title.scale(1.5)
title.to_edge(UP) title.to_edge(UP)
g_eq = self.g_eq = TexMobject( title.add_background_rectangle(
"{g}", "=", "-9.8", "\\frac{\\text{m/s}}{\\text{s}}",
**Lg_formula_config
)
g_eq.next_to(title, DOWN)
for mob in title, g_eq:
mob.add_background_rectangle_to_submobjects(
buff=0.05, buff=0.05,
opacity=1, opacity=1,
) )
self.add(title, g_eq) self.play(FadeInFromDown(title))
def pulse_gravity_down(self): def pulse_gravity_down(self):
field = self.gravity_field field = self.gravity_field
@ -260,7 +300,36 @@ class ShowGravityAcceleration(Scene):
) )
for vector in field for vector in field
]), run_time=2, lag_ratio=0.001) ]), 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): def show_trajectory(self):
ball = Circle( ball = Circle(
@ -329,6 +398,18 @@ class ShowGravityAcceleration(Scene):
rate_func=squish_rate_func(smooth, 0, 0.1) 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() ball_copies = VGroup()
v_vect_copies = VGroup() v_vect_copies = VGroup()
self.add(dashed_graph, ball) self.add(dashed_graph, ball)
@ -353,11 +434,16 @@ class ShowGravityAcceleration(Scene):
ShowCreation(dashed_graph, **kw), ShowCreation(dashed_graph, **kw),
MoveAlongPath(ball, graph, **kw), MoveAlongPath(ball, graph, **kw),
MoveAlongPath(v_point, velocity_graph, **kw), MoveAlongPath(v_point, velocity_graph, **kw),
ApplyMethod(
time_tracker.increment_value, 1,
rate_func=linear
),
flash, flash,
run_time=1, run_time=1,
) )
dashed_graph.restore() dashed_graph.restore()
randy.clear_updaters() randy.clear_updaters()
self.play(FadeOut(time_group))
self.wait() self.wait()
self.v_vects = v_vect_copies self.v_vects = v_vect_copies
@ -406,16 +492,30 @@ class ShowGravityAcceleration(Scene):
) )
self.wait() 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): class ShowDerivativeVideo(Scene):
CONFIG = {
"camera_config": {"background_color": DARKER_GREY}
}
def construct(self): def construct(self):
title = TextMobject("Essence of Calculus") title = TextMobject("Essence of", "Calculus")
title.scale(1.25) title.scale(1.5)
title.to_edge(UP) title.to_edge(UP)
title2 = TextMobject("Essence of", "Linear Algebra")
title2.scale(1.5)
title2.move_to(title, DOWN)
rect = ScreenRectangle(height=6) rect = ScreenRectangle(height=6)
rect = rect.copy() rect = rect.copy()
rect.set_style( rect.set_style(
@ -428,6 +528,8 @@ class ShowDerivativeVideo(Scene):
self.add(title, rect) self.add(title, rect)
self.add(animated_rect) self.add(animated_rect)
self.wait(5)
self.play(ReplacementTransform(title, title2))
self.wait(10) self.wait(10)
@ -483,7 +585,7 @@ class DefineODE(Scene):
def write_differential_equation(self): def write_differential_equation(self):
de_word = TextMobject("Differential", "Equation") de_word = TextMobject("Differential", "Equation")
de_word.to_edge(UP) de_word.to_edge(UP, buff=MED_SMALL_BUFF)
equation = get_ode() equation = get_ode()
equation.next_to(de_word, DOWN) equation.next_to(de_word, DOWN)
@ -777,11 +879,7 @@ class DefineODE(Scene):
self.second_order_word = so self.second_order_word = so
def show_higher_order_examples(self): def show_higher_order_examples(self):
main_example = VGroup( main_example = self.get_main_example()
self.second_order_word,
self.ode_initials,
self.equation
)
tex_config = {"tex_to_color_map": {"{x}": BLUE}} tex_config = {"tex_to_color_map": {"{x}": BLUE}}
example3 = VGroup( example3 = VGroup(
TextMobject("Third order ODE"), TextMobject("Third order ODE"),
@ -821,6 +919,13 @@ class DefineODE(Scene):
) )
self.wait(2) 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): def show_changing_curvature_group(self):
t_tracker = self.t_tracker t_tracker = self.t_tracker
curvature_group = self.curvature_group curvature_group = self.curvature_group
@ -828,7 +933,8 @@ class DefineODE(Scene):
graph = VMobject() graph = VMobject()
graph.pointwise_become_partial( graph.pointwise_become_partial(
self.fake_graph, self.fake_graph,
0.25, 1, t_tracker.get_value() / self.axes.x_max,
1,
) )
dashed_graph = DashedVMobject(graph, num_dashes=100) dashed_graph = DashedVMobject(graph, num_dashes=100)
dashed_graph.set_stroke(GREEN, 1) dashed_graph.set_stroke(GREEN, 1)
@ -844,14 +950,397 @@ class DefineODE(Scene):
self.wait() 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): 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): class ReferencePiCollisionStateSpaces(Scene):
CONFIG = {
"camera_config": {"background_color": DARKER_GREY}
}
def construct(self): 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): class BreakingSecondOrderIntoTwoFirstOrder(IntroduceVectorField):
@ -879,6 +1368,14 @@ class BreakingSecondOrderIntoTwoFirstOrder(IntroduceVectorField):
system1.next_to(sys_word, DOWN) system1.next_to(sys_word, DOWN)
system2.move_to(system1) 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.add(ode)
self.play(FadeInFrom(so_word, 0.5 * DOWN)) self.play(FadeInFrom(so_word, 0.5 * DOWN))
self.wait() self.wait()
@ -905,6 +1402,13 @@ class BreakingSecondOrderIntoTwoFirstOrder(IntroduceVectorField):
FadeInFromDown(sys_word) FadeInFromDown(sys_word)
) )
self.wait() self.wait()
self.play(LaggedStartMap(
ShowCreationThenFadeAround,
theta_dots,
surrounding_rectangle_config={
"color": PINK,
}
))
self.play(ReplacementTransform(system1, system2)) self.play(ReplacementTransform(system1, system2))
self.wait() self.wait()
@ -993,6 +1497,13 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
axes.set_stroke(width=0.5) axes.set_stroke(width=0.5)
self.add(axes) self.add(axes)
# Orient
self.set_camera_orientation(
phi=70 * DEGREES,
theta=-110 * DEGREES,
)
self.begin_ambient_camera_rotation()
def add_bodies(self): def add_bodies(self):
masses = self.masses masses = self.masses
colors = self.colors colors = self.colors
@ -1071,11 +1582,6 @@ class ThreeBodiesInSpace(SpecialThreeDScene):
self.add(traj, body) self.add(traj, body)
def let_play(self): 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 # Break it up to see partial files as
# it's rendered # it's rendered
for x in range(int(self.play_time)): 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): class DefineODECopy(DefineODE):
pass pass

View file

@ -37,6 +37,40 @@ class SmallAngleApproximationTex(Scene):
class StrogatzQuote(Scene): class StrogatzQuote(Scene):
def construct(self): 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" law_words = "laws of physics"
language_words = "language of differential equations" language_words = "language of differential equations"
author = "-Steven Strogatz" author = "-Steven Strogatz"
@ -51,46 +85,58 @@ class StrogatzQuote(Scene):
arg_separator=" ", arg_separator=" ",
substrings_to_isolate=[law_words, language_words, author] substrings_to_isolate=[law_words, language_words, author]
) )
law_part = quote.get_part_by_tex(law_words) quote.law_part = quote.get_part_by_tex(law_words)
language_part = quote.get_part_by_tex(language_words) quote.language_part = quote.get_part_by_tex(language_words)
author_part = quote.get_part_by_tex(author) quote.author_part = quote.get_part_by_tex(author)
quote.set_width(12) quote.set_width(12)
quote.to_edge(UP) quote.to_edge(UP)
quote[-2].shift(SMALL_BUFF * LEFT) quote[-2].shift(SMALL_BUFF * LEFT)
author_part.shift(RIGHT + 0.5 * DOWN) quote.author_part.shift(RIGHT + 0.5 * DOWN)
author_part.scale(1.2, about_edge=UL) quote.author_part.scale(1.2, about_edge=UL)
movers = VGroup(*quote[:-1].family_members_with_points()) return quote
for mover in movers:
mover.save_state()
disc = Circle(radius=0.05) class ShowSineValues(Scene):
disc.set_stroke(width=0) def construct(self):
disc.set_fill(BLACK, 0) angle_tracker = ValueTracker(60 * DEGREES)
disc.move_to(mover) get_angle = angle_tracker.get_value
mover.become(disc) formula = always_redraw(
self.play( lambda: self.get_sine_formula(get_angle())
FadeInFrom(author_part, LEFT),
LaggedStartMap(
# FadeInFromLarge,
# quote[:-1].family_members_with_points(),
Restore, movers,
lag_ratio=0.005,
run_time=2,
) )
# FadeInFromDown(quote[:-1]), self.add(formula)
# lag_ratio=0.01,
self.play(
angle_tracker.set_value, 0,
run_time=3,
) )
self.wait() self.wait()
self.play( self.play(
Write(law_part.copy().set_color(YELLOW)), angle_tracker.set_value, 90 * DEGREES,
run_time=1, run_time=3,
) )
self.wait() self.wait()
self.play(
Write(language_part.copy().set_color(BLUE)), def get_sine_formula(self, angle):
run_time=1.5, 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): 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): class ThreeBodySymbols(Scene):
def construct(self): def construct(self):
self.init_coord_groups() self.init_coord_groups()
@ -260,3 +314,259 @@ class ThreeBodySymbols(Scene):
rate_func=linear, rate_func=linear,
) )
self.play(FadeOut(coord_copies)) 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",
]
}

View 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

View file

@ -43,7 +43,7 @@ def stage_scenes(module_name):
# } # }
# TODO, fix this # TODO, fix this
animation_dir = os.path.join( animation_dir = os.path.join(
VIDEO_DIR, "clacks_solution2", "1440p60" VIDEO_DIR, "ode", "part1", "1440p60"
) )
# #
files = os.listdir(animation_dir) files = os.listdir(animation_dir)