mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 22:47:45 +00:00
Rename ode folder to diffyq
This commit is contained in:
parent
96e34b969c
commit
2e0e5cfb5e
26 changed files with 0 additions and 20516 deletions
|
|
@ -1,107 +0,0 @@
|
|||
from active_projects.ode.part1.pendulum import *
|
||||
from active_projects.ode.part1.staging import *
|
||||
from active_projects.ode.part1.pi_scenes import *
|
||||
from active_projects.ode.part1.phase_space import *
|
||||
from active_projects.ode.part1.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part1"
|
||||
SCENES_IN_ORDER = [
|
||||
WhenChangeIsEasier,
|
||||
VectorFieldTest,
|
||||
IntroducePendulum,
|
||||
MultiplePendulumsOverlayed,
|
||||
PeriodFormula,
|
||||
FormulasAreLies,
|
||||
MediumAnglePendulum,
|
||||
MediumHighAnglePendulum,
|
||||
HighAnglePendulum,
|
||||
LowAnglePendulum,
|
||||
SomeOfYouWatching,
|
||||
SmallAngleApproximationTex,
|
||||
VeryLowAnglePendulum,
|
||||
FormulasAreLies,
|
||||
TourOfDifferentialEquations,
|
||||
WherePendulumLeads,
|
||||
LongDoublePendulum,
|
||||
# FollowThisThread,
|
||||
StrogatzQuote,
|
||||
ShowHorizontalDashedLine,
|
||||
RabbitFoxPopulations,
|
||||
RabbitFoxEquation,
|
||||
# Something...
|
||||
ShowSimpleTrajectory,
|
||||
SimpleProjectileEquation,
|
||||
SimpleProjectileEquationVGraphFreedom,
|
||||
ShowGravityAcceleration,
|
||||
UniversalGravityLawSymbols,
|
||||
ExampleTypicalODE,
|
||||
AnalyzePendulumForce,
|
||||
ShowSineValues,
|
||||
BuildUpEquation,
|
||||
AirResistanceBrace,
|
||||
ShowDerivativeVideo,
|
||||
SubtleAirCurrents,
|
||||
SimpleDampenedPendulum,
|
||||
DefineODE,
|
||||
SecondOrderEquationExample,
|
||||
ODEvsPDEinFrames,
|
||||
ProveTeacherWrong,
|
||||
SetAsideSeekingSolution,
|
||||
#
|
||||
WriteInRadians,
|
||||
XEqLThetaToCorner,
|
||||
ComingUp,
|
||||
InputLabel,
|
||||
SoWhatIsThetaThen,
|
||||
ReallyHardToSolve,
|
||||
ReasonForSolution,
|
||||
PhysicistPhaseSpace,
|
||||
GleickQuote,
|
||||
SpectrumOfStartingStates,
|
||||
WritePhaseFlow,
|
||||
AskAboutStability,
|
||||
LoveExample,
|
||||
PassageOfTime,
|
||||
LovePhaseSpace,
|
||||
ComparePhysicsToLove,
|
||||
FramesComparingPhysicsToLove,
|
||||
SetupToTakingManyTinySteps,
|
||||
ShowClutterPrevention,
|
||||
# VisualizeHeightSlopeCurvature,
|
||||
VisualizeStates,
|
||||
ReferencePiCollisionStateSpaces,
|
||||
IntroduceVectorField,
|
||||
XComponentArrows,
|
||||
BreakingSecondOrderIntoTwoFirstOrder,
|
||||
ShowPendulumPhaseFlow,
|
||||
ShowHighVelocityCase,
|
||||
TweakMuInFormula,
|
||||
TweakMuInVectorField,
|
||||
FromODEToVectorField,
|
||||
LorenzVectorField,
|
||||
ThreeBodiesInSpace,
|
||||
AltThreeBodiesInSpace,
|
||||
TwoBodiesInSpace,
|
||||
TwoBodiesWithZPart,
|
||||
ThreeBodyTitle,
|
||||
ThreeBodySymbols,
|
||||
#
|
||||
HighAmplitudePendulum,
|
||||
WritePhaseSpace,
|
||||
#
|
||||
AskAboutActuallySolving,
|
||||
WriteODESolvingCode,
|
||||
TakeManyTinySteps,
|
||||
ManyStepsFromDifferentStartingPoints,
|
||||
InaccurateComputation,
|
||||
HungerForExactness,
|
||||
ShowRect,
|
||||
ShowSquare,
|
||||
JumpToThisPoint,
|
||||
ThreeBodyEquation,
|
||||
ItGetsWorse,
|
||||
ChaosTitle,
|
||||
RevisitQuote,
|
||||
EndScreen,
|
||||
Thumbnail,
|
||||
]
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
from active_projects.ode.part2.staging import *
|
||||
from active_projects.ode.part2.fourier_series import *
|
||||
from active_projects.ode.part2.heat_equation import *
|
||||
from active_projects.ode.part2.pi_scenes import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part2"
|
||||
SCENES_IN_ORDER = [
|
||||
PartTwoOfTour,
|
||||
HeatEquationIntroTitle,
|
||||
BrownianMotion,
|
||||
BlackScholes,
|
||||
ContrastChapters1And2,
|
||||
FourierSeriesIntro,
|
||||
FourierSeriesIntroBackground20,
|
||||
ExplainCircleAnimations,
|
||||
# FourierSeriesIntroBackground4,
|
||||
# FourierSeriesIntroBackground8,
|
||||
# FourierSeriesIntroBackground12,
|
||||
TwoDBodyWithManyTemperatures,
|
||||
TwoDBodyWithManyTemperaturesGraph,
|
||||
TwoDBodyWithManyTemperaturesContour,
|
||||
BringTwoRodsTogether,
|
||||
ShowEvolvingTempGraphWithArrows,
|
||||
# TodaysTargetWrapper,
|
||||
WriteHeatEquation,
|
||||
ReactionsToInitialHeatEquation,
|
||||
TalkThrough1DHeatGraph,
|
||||
ShowCubeFormation,
|
||||
CompareInputsOfGeneralCaseTo1D,
|
||||
ContrastXChangesToTChanges,
|
||||
ShowPartialDerivativeSymbols,
|
||||
WriteHeatEquation,
|
||||
ShowCurvatureToRateOfChangeIntuition,
|
||||
ContrastPDEToODE,
|
||||
TransitionToTempVsTime,
|
||||
Show1DAnd3DEquations,
|
||||
#
|
||||
AskAboutWhereEquationComesFrom,
|
||||
DiscreteSetup,
|
||||
]
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
from active_projects.ode.part3.staging import *
|
||||
from active_projects.ode.part3.temperature_graphs import *
|
||||
from active_projects.ode.part3.pi_creature_scenes import *
|
||||
from active_projects.ode.part3.wordy_scenes import *
|
||||
from active_projects.ode.part3.discrete_case import *
|
||||
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part3"
|
||||
SCENES_IN_ORDER = [
|
||||
LastChapterWrapper,
|
||||
ThreeConstraints,
|
||||
OceanOfPossibilities,
|
||||
ThreeMainObservations,
|
||||
SimpleCosExpGraph,
|
||||
AddMultipleSolutions,
|
||||
FourierSeriesIllustraiton,
|
||||
BreakDownAFunction,
|
||||
SineCurveIsUnrealistic,
|
||||
AnalyzeSineCurve,
|
||||
EquationAboveSineAnalysis,
|
||||
ExponentialDecay,
|
||||
InvestmentGrowth,
|
||||
GrowingPileOfMoney,
|
||||
CarbonDecayCurve,
|
||||
CarbonDecayingInMammoth,
|
||||
SineWaveScaledByExp,
|
||||
ShowSinExpDerivatives,
|
||||
IfOnly,
|
||||
BoundaryConditionInterlude,
|
||||
BoundaryConditionReference,
|
||||
GiantCross,
|
||||
SimulateRealSineCurve,
|
||||
DerivativesOfLinearFunction,
|
||||
StraightLine3DGraph,
|
||||
SimulateLinearGraph,
|
||||
EmphasizeBoundaryPoints,
|
||||
ShowNewRuleAtDiscreteBoundary,
|
||||
DiscreteEvolutionPoint25,
|
||||
DiscreteEvolutionPoint1,
|
||||
FlatEdgesForDiscreteEvolution,
|
||||
FlatEdgesForDiscreteEvolutionTinySteps,
|
||||
FlatEdgesContinuousEvolution,
|
||||
FlatAtBoundaryWords,
|
||||
SlopeToHeatFlow,
|
||||
CloserLookAtStraightLine,
|
||||
WriteOutBoundaryCondition,
|
||||
SoWeGotNowhere,
|
||||
ManipulateSinExpSurface,
|
||||
HeatEquationFrame,
|
||||
ShowFreq1CosExpDecay,
|
||||
ShowFreq2CosExpDecay,
|
||||
ShowFreq4CosExpDecay,
|
||||
CompareFreqDecays1to2,
|
||||
CompareFreqDecays1to4,
|
||||
CompareFreqDecays2to4,
|
||||
ShowHarmonics,
|
||||
ShowHarmonicSurfaces,
|
||||
|
||||
# SimpleCosExpGraph,
|
||||
# AddMultipleSolutions,
|
||||
# IveHeardOfThis,
|
||||
# FourierSeriesOfLineIllustration,
|
||||
# InFouriersShoes,
|
||||
]
|
||||
|
||||
PART_4_SCENES = [
|
||||
FourierSeriesIllustraiton,
|
||||
FourierNameIntro,
|
||||
CircleAnimationOfF,
|
||||
]
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
from active_projects.ode.part4.staging import *
|
||||
from active_projects.ode.part4.fourier_series_scenes import *
|
||||
from active_projects.ode.part4.pi_creature_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part4"
|
||||
SCENES_IN_ORDER = [
|
||||
ComplexFourierSeriesExample,
|
||||
ComplexFourierSeriesExampleEnd,
|
||||
FourierSeriesExampleWithRectForZoom,
|
||||
ZoomedInFourierSeriesExample,
|
||||
RelationToOtherVideos,
|
||||
WhyWouldYouCare,
|
||||
# Oldies
|
||||
|
||||
# FourierSeriesIllustraiton,
|
||||
# FourierNameIntro,
|
||||
# CircleAnimationOfF,
|
||||
]
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.fourier_series import FourierOfName
|
||||
|
||||
name_color_pairs = [
|
||||
|
||||
]
|
||||
|
||||
circle_counts = [
|
||||
# 10,
|
||||
# 25,
|
||||
100,
|
||||
]
|
||||
|
||||
if __name__ == "__main__":
|
||||
for name, color in name_color_pairs:
|
||||
for n_circles in circle_counts:
|
||||
try:
|
||||
first_name = name.split(" ")[0]
|
||||
scene = FourierOfName(
|
||||
name_text=name,
|
||||
name_color=color,
|
||||
n_circles=n_circles,
|
||||
file_writer_config={
|
||||
"write_to_movie": True,
|
||||
"output_directory": os.path.join(
|
||||
"patron_fourier_names",
|
||||
first_name,
|
||||
),
|
||||
"file_name": "{}_Fouierified_{}_Separate_paths".format(
|
||||
first_name,
|
||||
n_circles
|
||||
),
|
||||
},
|
||||
camera_config={
|
||||
"frame_rate": 24,
|
||||
},
|
||||
)
|
||||
except:
|
||||
pass
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,515 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
|
||||
|
||||
class SomeOfYouWatching(TeacherStudentsScene):
|
||||
CONFIG = {
|
||||
"camera_config": {
|
||||
"background_color": DARKER_GREY,
|
||||
}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
screen = self.screen
|
||||
screen.scale(1.25, about_edge=UL)
|
||||
screen.set_fill(BLACK, 1)
|
||||
self.add(screen)
|
||||
|
||||
self.teacher.change("raise_right_hand")
|
||||
for student in self.students:
|
||||
student.change("pondering", screen)
|
||||
|
||||
self.student_says(
|
||||
"Well...yeah",
|
||||
target_mode="tease"
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class FormulasAreLies(PiCreatureScene):
|
||||
def construct(self):
|
||||
you = self.pi_creature
|
||||
t2c = {
|
||||
"{L}": BLUE,
|
||||
"{g}": YELLOW,
|
||||
"\\theta_0": WHITE,
|
||||
"\\sqrt{\\,": WHITE,
|
||||
}
|
||||
kwargs = {"tex_to_color_map": t2c}
|
||||
period_eq = TexMobject(
|
||||
"\\text{Period} = 2\\pi \\sqrt{\\,{L} / {g}}",
|
||||
**kwargs
|
||||
)
|
||||
theta_eq = TexMobject(
|
||||
"\\theta(t) = \\theta_0 \\cos\\left("
|
||||
"\\sqrt{\\,{L} / {g}} \\cdot t"
|
||||
"\\right)",
|
||||
**kwargs
|
||||
)
|
||||
equations = VGroup(theta_eq, period_eq)
|
||||
equations.arrange(DOWN, buff=LARGE_BUFF)
|
||||
|
||||
for eq in period_eq, theta_eq:
|
||||
i = eq.index_of_part_by_tex("\\sqrt")
|
||||
eq.sqrt_part = eq[i:i + 4]
|
||||
|
||||
theta0 = theta_eq.get_part_by_tex("\\theta_0")
|
||||
theta0_words = TextMobject("Starting angle")
|
||||
theta0_words.next_to(theta0, UL)
|
||||
theta0_words.shift(UP + 0.5 * RIGHT)
|
||||
arrow = Arrow(
|
||||
theta0_words.get_bottom(),
|
||||
theta0,
|
||||
color=WHITE,
|
||||
tip_length=0.25,
|
||||
)
|
||||
|
||||
bubble = SpeechBubble()
|
||||
bubble.pin_to(you)
|
||||
bubble.write("Lies!")
|
||||
bubble.content.scale(2)
|
||||
bubble.resize_to_content()
|
||||
|
||||
self.add(period_eq)
|
||||
you.change("pondering", period_eq)
|
||||
self.wait()
|
||||
theta_eq.remove(*theta_eq.sqrt_part)
|
||||
self.play(
|
||||
TransformFromCopy(
|
||||
period_eq.sqrt_part,
|
||||
theta_eq.sqrt_part,
|
||||
),
|
||||
FadeIn(theta_eq)
|
||||
)
|
||||
theta_eq.add(*theta_eq.sqrt_part)
|
||||
self.play(
|
||||
FadeInFrom(theta0_words, LEFT),
|
||||
GrowArrow(arrow),
|
||||
)
|
||||
self.wait()
|
||||
self.play(you.change, "confused")
|
||||
self.wait()
|
||||
self.play(
|
||||
you.change, "angry",
|
||||
ShowCreation(bubble),
|
||||
FadeInFromPoint(bubble.content, you.mouth),
|
||||
equations.to_edge, LEFT,
|
||||
FadeOut(arrow),
|
||||
FadeOut(theta0_words),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def create_pi_creature(self):
|
||||
return You().flip().to_corner(DR)
|
||||
|
||||
|
||||
# class TourOfDifferentialEquations(Scene):
|
||||
# def construct(self):
|
||||
# pass
|
||||
|
||||
|
||||
class SoWhatIsThetaThen(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
ode = get_ode()
|
||||
ode.to_corner(UL)
|
||||
self.add(ode)
|
||||
|
||||
self.student_says(
|
||||
"Okay, but then\\\\"
|
||||
"what \\emph{is} $\\theta(t)$?"
|
||||
)
|
||||
self.wait()
|
||||
self.play(self.teacher.change, "happy")
|
||||
self.wait(2)
|
||||
self.teacher_says(
|
||||
"First, you must appreciate\\\\"
|
||||
"a deep truth...",
|
||||
added_anims=[self.get_student_changes(
|
||||
*3 * ["confused"]
|
||||
)]
|
||||
)
|
||||
self.wait(4)
|
||||
|
||||
|
||||
class ProveTeacherWrong(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
tex_config = {
|
||||
"tex_to_color_map": {
|
||||
"{\\theta}": BLUE,
|
||||
"{\\dot\\theta}": YELLOW,
|
||||
"{\\ddot\\theta}": RED,
|
||||
}
|
||||
}
|
||||
func = TexMobject(
|
||||
"{\\theta}(t)", "=",
|
||||
"\\theta_0", "\\cos(\\sqrt{g / L} \\cdot t)",
|
||||
**tex_config,
|
||||
)
|
||||
d_func = TexMobject(
|
||||
"{\\dot\\theta}(t)", "=",
|
||||
"-\\left(\\sqrt{g / L}\\right)",
|
||||
"\\theta_0", "\\sin(\\sqrt{g / L} \\cdot t)",
|
||||
**tex_config,
|
||||
)
|
||||
dd_func = TexMobject(
|
||||
"{\\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 = get_ode()
|
||||
arrows = [TexMobject("\\Downarrow") for x in range(2)]
|
||||
|
||||
VGroup(func, d_func, dd_func, ode, *arrows).scale(0.7)
|
||||
|
||||
teacher = self.teacher
|
||||
you = self.students[2]
|
||||
|
||||
self.student_thinks(ode)
|
||||
you.add_updater(lambda m: m.look_at(func))
|
||||
self.teacher_holds_up(func)
|
||||
self.wait()
|
||||
|
||||
group = VGroup(arrows[0], d_func, arrows[1], dd_func)
|
||||
group.arrange(DOWN)
|
||||
group.move_to(func, DOWN)
|
||||
|
||||
arrow = Arrow(
|
||||
group.get_corner(UL),
|
||||
ode.get_top(),
|
||||
path_arc=PI / 2,
|
||||
)
|
||||
q_marks = VGroup(*[
|
||||
TexMobject("?").scale(1.5).next_to(
|
||||
arrow.point_from_proportion(a),
|
||||
UP
|
||||
)
|
||||
for a in np.linspace(0.2, 0.8, 5)
|
||||
])
|
||||
cycle_animation(VFadeInThenOut(
|
||||
q_marks,
|
||||
lag_ratio=0.2,
|
||||
run_time=4,
|
||||
rate_func=squish_rate_func(smooth, 0, 0.5)
|
||||
))
|
||||
|
||||
self.play(
|
||||
func.next_to, group, UP,
|
||||
LaggedStartMap(
|
||||
FadeInFrom, group,
|
||||
lambda m: (m, UP)
|
||||
),
|
||||
teacher.change, "guilty",
|
||||
you.change, "sassy",
|
||||
)
|
||||
|
||||
rect = SurroundingRectangle(
|
||||
VGroup(group, func)
|
||||
)
|
||||
dashed_rect = DashedVMobject(rect, num_dashes=75)
|
||||
animated_rect = AnimatedBoundary(dashed_rect, cycle_rate=1)
|
||||
|
||||
self.wait()
|
||||
self.add(animated_rect, q_marks)
|
||||
self.play(
|
||||
ShowCreation(arrow),
|
||||
# FadeInFromDown(q_mark),
|
||||
self.get_student_changes("confused", "confused")
|
||||
)
|
||||
self.wait(4)
|
||||
self.change_student_modes(
|
||||
*3 * ["pondering"],
|
||||
self.teacher.change, "maybe"
|
||||
)
|
||||
self.wait(8)
|
||||
|
||||
|
||||
class PhysicistPhaseSpace(PiCreatureScene):
|
||||
def construct(self):
|
||||
physy = self.pi_creature
|
||||
name = TextMobject("Physicist")
|
||||
name.scale(1.5)
|
||||
name.to_corner(DL, buff=MED_SMALL_BUFF)
|
||||
physy.next_to(name, UP, SMALL_BUFF)
|
||||
VGroup(name, physy).shift_onto_screen()
|
||||
|
||||
axes = Axes(
|
||||
x_min=-1,
|
||||
x_max=10,
|
||||
y_min=-1,
|
||||
y_max=7,
|
||||
)
|
||||
axes.set_height(6)
|
||||
axes.next_to(physy, RIGHT)
|
||||
axes.to_edge(UP)
|
||||
axes.set_stroke(width=1)
|
||||
x_label = TextMobject("Position")
|
||||
x_label.next_to(axes.x_axis.get_right(), UP)
|
||||
y_label = TextMobject("Momentum")
|
||||
y_label.next_to(axes.y_axis.get_top(), RIGHT)
|
||||
|
||||
title = TextMobject("Phase space")
|
||||
title.scale(1.5)
|
||||
title.set_color(YELLOW)
|
||||
title.move_to(axes)
|
||||
|
||||
self.add(name, physy)
|
||||
|
||||
self.play(
|
||||
physy.change, "angry",
|
||||
Write(axes),
|
||||
FadeInFromDown(title)
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
GrowFromPoint(x_label, physy.get_corner(UR)),
|
||||
physy.change, "raise_right_hand",
|
||||
axes.x_axis.get_right()
|
||||
)
|
||||
self.play(
|
||||
GrowFromPoint(y_label, physy.get_corner(UR)),
|
||||
physy.look_at, axes.y_axis.get_top(),
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
def create_pi_creature(self):
|
||||
return PiCreature(color=GREY).to_corner(DL)
|
||||
|
||||
|
||||
class AskAboutActuallySolving(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
ode = get_ode()
|
||||
ode.to_corner(UL)
|
||||
self.add(ode)
|
||||
morty = self.teacher
|
||||
|
||||
self.student_says(
|
||||
"Yeah yeah, but how do\\\\"
|
||||
"you actually \\emph{solve} it?",
|
||||
student_index=1,
|
||||
target_mode="sassy",
|
||||
added_anims=[morty.change, "thinking"],
|
||||
)
|
||||
self.change_student_modes(
|
||||
"confused", "sassy", "confused",
|
||||
look_at_arg=ode,
|
||||
)
|
||||
self.wait()
|
||||
self.teacher_says(
|
||||
"What do you mean\\\\ by ``solve''?",
|
||||
target_mode="speaking",
|
||||
added_anims=[self.get_student_changes(
|
||||
*3 * ["erm"]
|
||||
)]
|
||||
)
|
||||
self.play(self.students[1].change, "angry")
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class HungerForExactness(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
students = self.students
|
||||
you = students[2]
|
||||
teacher = self.teacher
|
||||
|
||||
ode = get_ode()
|
||||
ode.to_corner(UL)
|
||||
left_part = ode[:5]
|
||||
friction_part = ode[5:11]
|
||||
self.add(ode)
|
||||
|
||||
proposed_solution = TexMobject(
|
||||
"\\theta_0\\cos((\\sqrt{g/L})t)e^{-\\mu t}"
|
||||
)
|
||||
proposed_solution.next_to(
|
||||
you.get_corner(UL), UP, buff=0.7
|
||||
)
|
||||
proposed_solution_rect = SurroundingRectangle(
|
||||
proposed_solution, buff=MED_SMALL_BUFF,
|
||||
)
|
||||
proposed_solution_rect.set_color(BLUE)
|
||||
proposed_solution_rect.round_corners()
|
||||
|
||||
solution_p1 = TexMobject(
|
||||
"""
|
||||
\\theta(t) = 2\\text{am}\\left(
|
||||
\\frac{\\sqrt{2g + Lc_1} (t + c_2)}{2\\sqrt{L}},
|
||||
\\frac{4g}{2g + Lc_1}
|
||||
\\right)
|
||||
""",
|
||||
)
|
||||
solution_p1.to_corner(UL)
|
||||
solution_p2 = TexMobject(
|
||||
"c_1, c_2 = \\text{Constants depending on initial conditions}"
|
||||
)
|
||||
solution_p2.set_color(LIGHT_GREY)
|
||||
solution_p2.scale(0.75)
|
||||
solution_p3 = TexMobject(
|
||||
"""
|
||||
\\text{am}(u, k) =
|
||||
\\int_0^u \\text{dn}(v, k)\\,dv
|
||||
"""
|
||||
)
|
||||
solution_p3.name = TextMobject(
|
||||
"(Jacobi amplitude function)"
|
||||
)
|
||||
solution_p4 = TexMobject(
|
||||
"""
|
||||
\\text{dn}(u, k) =
|
||||
\\sqrt{1 - k^2 \\sin^2(\\phi)}
|
||||
"""
|
||||
)
|
||||
solution_p4.name = TextMobject(
|
||||
"(Jacobi elliptic function)"
|
||||
)
|
||||
solution_p5 = TextMobject("Where $\\phi$ satisfies")
|
||||
solution_p6 = TexMobject(
|
||||
"""
|
||||
u = \\int_0^\\phi \\frac{dt}{\\sqrt{1 - k^2 \\sin^2(t)}}
|
||||
"""
|
||||
)
|
||||
|
||||
solution = VGroup(
|
||||
solution_p1,
|
||||
solution_p2,
|
||||
solution_p3,
|
||||
solution_p4,
|
||||
solution_p5,
|
||||
solution_p6,
|
||||
)
|
||||
solution.arrange(DOWN)
|
||||
solution.scale(0.7)
|
||||
solution.to_corner(UL, buff=MED_SMALL_BUFF)
|
||||
solution.set_stroke(width=0, background=True)
|
||||
|
||||
solution.remove(solution_p2)
|
||||
solution_p1.add(solution_p2)
|
||||
solution.remove(solution_p5)
|
||||
solution_p6.add(solution_p5)
|
||||
|
||||
for part in [solution_p3, solution_p4]:
|
||||
part.name.scale(0.7 * 0.7)
|
||||
part.name.set_color(LIGHT_GREY)
|
||||
part.name.next_to(part, RIGHT)
|
||||
part.add(part.name)
|
||||
|
||||
self.student_says(
|
||||
"Right, but like,\\\\"
|
||||
"what \\emph{is} $\\theta(t)$?",
|
||||
target_mode="sassy",
|
||||
added_anims=[teacher.change, "guilty"],
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFromDown(proposed_solution),
|
||||
RemovePiCreatureBubble(
|
||||
you,
|
||||
target_mode="raise_left_hand",
|
||||
look_at_arg=proposed_solution,
|
||||
),
|
||||
teacher.change, "pondering",
|
||||
students[0].change, "pondering",
|
||||
students[1].change, "hesitant",
|
||||
)
|
||||
self.play(ShowCreation(proposed_solution_rect))
|
||||
self.play(
|
||||
proposed_solution.shift, 3 * RIGHT,
|
||||
proposed_solution_rect.shift, 3 * RIGHT,
|
||||
you.change, "raise_right_hand", teacher.eyes,
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
self.play(
|
||||
FadeOut(proposed_solution),
|
||||
FadeOut(proposed_solution_rect),
|
||||
ode.move_to, self.hold_up_spot, DOWN,
|
||||
ode.shift, LEFT,
|
||||
teacher.change, "raise_right_hand",
|
||||
self.get_student_changes(*3 * ["pondering"])
|
||||
)
|
||||
self.wait()
|
||||
ode.save_state()
|
||||
self.play(
|
||||
left_part.move_to, friction_part, RIGHT,
|
||||
left_part.match_y, left_part,
|
||||
friction_part.to_corner, DR,
|
||||
friction_part.fade, 0.5,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
modes = ["erm", "sad", "sad", "horrified"]
|
||||
for part, mode in zip(solution, modes):
|
||||
self.play(
|
||||
FadeInFrom(part, UP),
|
||||
self.get_student_changes(
|
||||
*3 * [mode],
|
||||
look_at_arg=part,
|
||||
)
|
||||
)
|
||||
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(
|
||||
"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)
|
||||
mystery_boundary = AnimatedBoundary(
|
||||
mystery, stroke_width=1
|
||||
)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(mystery),
|
||||
self.teacher.change, "pondering"
|
||||
)
|
||||
self.add(mystery_boundary, mystery)
|
||||
self.change_all_student_modes("sad")
|
||||
self.look_at(mystery)
|
||||
self.wait(5)
|
||||
|
||||
# Define
|
||||
self.student_says(
|
||||
"Let $\\text{P}(\\mu, g, L; t)$ be a\\\\"
|
||||
"function satisfying this ODE.",
|
||||
student_index=0,
|
||||
target_mode="speaking",
|
||||
added_anims=[
|
||||
FadeOut(mystery),
|
||||
FadeOut(mystery_boundary),
|
||||
ode.to_corner, UR
|
||||
]
|
||||
)
|
||||
self.change_student_modes(
|
||||
"hooray", "sassy", "sassy",
|
||||
look_at_arg=students[0].eyes.get_corner(UR),
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class ItGetsWorse(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says("It gets\\\\worse")
|
||||
self.change_student_modes(
|
||||
"hesitant", "pleading", "erm"
|
||||
)
|
||||
self.wait(5)
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
|
||||
|
||||
Lg_formula_config = {
|
||||
"tex_to_color_map": {
|
||||
"\\theta_0": WHITE,
|
||||
"{L}": BLUE,
|
||||
"{g}": YELLOW,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class You(PiCreature):
|
||||
CONFIG = {
|
||||
"color": BLUE_C,
|
||||
}
|
||||
|
||||
|
||||
def get_ode():
|
||||
tex_config = {
|
||||
"tex_to_color_map": {
|
||||
"{\\theta}": BLUE,
|
||||
"{\\dot\\theta}": RED,
|
||||
"{\\ddot\\theta}": YELLOW,
|
||||
"{t}": WHITE,
|
||||
"{\\mu}": WHITE,
|
||||
}
|
||||
}
|
||||
ode = TexMobject(
|
||||
"{\\ddot\\theta}({t})", "=",
|
||||
"-{\\mu} {\\dot\\theta}({t})",
|
||||
"-{g \\over L} \\sin\\big({\\theta}({t})\\big)",
|
||||
**tex_config,
|
||||
)
|
||||
return ode
|
||||
|
||||
|
||||
def get_period_formula():
|
||||
return TexMobject(
|
||||
"2\\pi", "\\sqrt{\\,", "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([
|
||||
omega,
|
||||
-np.sqrt(g / L) * np.sin(theta) - mu * omega,
|
||||
0,
|
||||
])
|
||||
|
||||
|
||||
def get_vector_symbol(*texs, **kwargs):
|
||||
config = {
|
||||
"include_background_rectangle": True,
|
||||
"bracket_h_buff": SMALL_BUFF,
|
||||
"bracket_v_buff": SMALL_BUFF,
|
||||
"element_alignment_corner": ORIGIN,
|
||||
}
|
||||
config.update(kwargs)
|
||||
array = [[tex] for tex in texs]
|
||||
return Matrix(array, **config)
|
||||
|
||||
|
||||
def get_heart_var(index):
|
||||
heart = SuitSymbol("hearts")
|
||||
if index == 1:
|
||||
heart.set_color(BLUE_C)
|
||||
elif index == 2:
|
||||
heart.set_color(GREEN)
|
||||
heart.set_height(0.7)
|
||||
index = Integer(index)
|
||||
index.move_to(heart.get_corner(DR))
|
||||
heart.add(index)
|
||||
return heart
|
||||
|
||||
|
||||
def get_heart_var_deriv(index):
|
||||
heart = get_heart_var(index)
|
||||
filler_tex = "T"
|
||||
deriv = TexMobject("{d", filler_tex, "\\over", "dt}")
|
||||
deriv.scale(2)
|
||||
filler = deriv.get_part_by_tex(filler_tex)
|
||||
heart.match_height(filler)
|
||||
heart.move_to(filler)
|
||||
heart.scale(1.5, about_edge=UL)
|
||||
deriv.remove(filler)
|
||||
deriv.add(heart)
|
||||
deriv.heart = heart
|
||||
return deriv
|
||||
|
||||
|
||||
def get_love_equation1():
|
||||
equation = VGroup(
|
||||
get_heart_var_deriv(1),
|
||||
TexMobject("=").scale(2),
|
||||
TexMobject("a").scale(2),
|
||||
get_heart_var(2)
|
||||
)
|
||||
equation.arrange(RIGHT)
|
||||
equation[-1].shift(SMALL_BUFF * DL)
|
||||
return equation
|
||||
|
||||
|
||||
def get_love_equation2():
|
||||
equation = VGroup(
|
||||
get_heart_var_deriv(2),
|
||||
TexMobject("=").scale(2),
|
||||
TexMobject("-b").scale(2),
|
||||
get_heart_var(1),
|
||||
)
|
||||
equation.arrange(RIGHT)
|
||||
equation[-1].shift(SMALL_BUFF * DL)
|
||||
return equation
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,855 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
|
||||
|
||||
class SmallAngleApproximationTex(Scene):
|
||||
def construct(self):
|
||||
approx = TexMobject(
|
||||
"\\sin", "(", "\\theta", ") \\approx \\theta",
|
||||
tex_to_color_map={"\\theta": RED},
|
||||
arg_separator="",
|
||||
)
|
||||
|
||||
implies = TexMobject("\\Downarrow")
|
||||
period = TexMobject(
|
||||
"\\text{Period}", "\\approx",
|
||||
"2\\pi \\sqrt{\\,{L} / {g}}",
|
||||
**Lg_formula_config,
|
||||
)
|
||||
group = VGroup(approx, implies, period)
|
||||
group.arrange(DOWN)
|
||||
|
||||
approx_brace = Brace(approx, UP, buff=SMALL_BUFF)
|
||||
approx_words = TextMobject(
|
||||
"For small $\\theta$",
|
||||
tex_to_color_map={"$\\theta$": RED},
|
||||
)
|
||||
approx_words.scale(0.75)
|
||||
approx_words.next_to(approx_brace, UP, SMALL_BUFF)
|
||||
|
||||
self.add(approx, approx_brace, approx_words)
|
||||
self.play(
|
||||
Write(implies),
|
||||
FadeInFrom(period, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
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"
|
||||
quote = TextMobject(
|
||||
"""
|
||||
\\Large
|
||||
``Since Newton, mankind has come to realize
|
||||
that the laws of physics are always expressed
|
||||
in the language of differential equations.''\\\\
|
||||
""" + author,
|
||||
alignment="",
|
||||
arg_separator=" ",
|
||||
substrings_to_isolate=[law_words, language_words, 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)
|
||||
quote.author_part.shift(RIGHT + 0.5 * DOWN)
|
||||
quote.author_part.scale(1.2, about_edge=UL)
|
||||
|
||||
return quote
|
||||
|
||||
|
||||
class WriteInRadians(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("In radians")
|
||||
words.set_color(YELLOW)
|
||||
square = SurroundingRectangle(TexMobject("\\theta"))
|
||||
square.next_to(words, UP)
|
||||
self.play(ShowCreation(square))
|
||||
self.play(Write(words), FadeOut(square))
|
||||
self.wait()
|
||||
|
||||
|
||||
class XEqLThetaToCorner(Scene):
|
||||
def construct(self):
|
||||
equation = TexMobject(
|
||||
"x = L\\theta",
|
||||
tex_to_color_map={
|
||||
"x": GREEN,
|
||||
"\\theta": BLUE,
|
||||
}
|
||||
)
|
||||
equation.move_to(DOWN + 3 * RIGHT)
|
||||
self.add(equation)
|
||||
self.play(equation.to_corner, DL, {"buff": LARGE_BUFF})
|
||||
self.wait()
|
||||
|
||||
|
||||
class ComingUp(Scene):
|
||||
CONFIG = {
|
||||
"camera_config": {"background_color": DARKER_GREY}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
frame = ScreenRectangle(
|
||||
stroke_width=0,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=1,
|
||||
height=6
|
||||
)
|
||||
title = TextMobject("Coming up")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
frame.next_to(title, DOWN)
|
||||
animated_frame = AnimatedBoundary(frame)
|
||||
self.add(frame, title, animated_frame)
|
||||
self.wait(10)
|
||||
|
||||
|
||||
class InputLabel(Scene):
|
||||
def construct(self):
|
||||
label = TextMobject("Input")
|
||||
label.scale(1.25)
|
||||
arrow = Vector(UP)
|
||||
arrow.next_to(label, UP)
|
||||
self.play(
|
||||
FadeInFrom(label, UP),
|
||||
GrowArrow(arrow)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ReallyHardToSolve(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject(
|
||||
"They're", "really\\\\",
|
||||
"freaking", "hard\\\\",
|
||||
"to", "solve\\\\",
|
||||
)
|
||||
words.set_height(6)
|
||||
|
||||
self.wait()
|
||||
for word in words:
|
||||
wait_time = 0.05 * len(word)
|
||||
self.add(word)
|
||||
self.wait(wait_time)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ReasonForSolution(Scene):
|
||||
def construct(self):
|
||||
# Words
|
||||
eq_word = TextMobject("Differential\\\\Equation")
|
||||
s_word = TextMobject("Solution")
|
||||
u_word = TextMobject("Understanding")
|
||||
c_word = TextMobject("Computation")
|
||||
cu_group = VGroup(u_word, c_word)
|
||||
cu_group.arrange(DOWN, buff=2)
|
||||
group = VGroup(eq_word, s_word, cu_group)
|
||||
group.arrange(RIGHT, buff=2)
|
||||
# words = VGroup(eq_word, s_word, u_word, c_word)
|
||||
|
||||
# Arrows
|
||||
arrows = VGroup(
|
||||
Arrow(eq_word.get_right(), s_word.get_left()),
|
||||
Arrow(s_word.get_right(), u_word.get_left()),
|
||||
Arrow(s_word.get_right(), c_word.get_left()),
|
||||
)
|
||||
arrows.set_color(LIGHT_GREY)
|
||||
new_arrows = VGroup(
|
||||
Arrow(
|
||||
eq_word.get_corner(UR),
|
||||
u_word.get_left(),
|
||||
path_arc=-60 * DEGREES,
|
||||
),
|
||||
Arrow(
|
||||
eq_word.get_corner(DR),
|
||||
c_word.get_left(),
|
||||
path_arc=60 * DEGREES,
|
||||
),
|
||||
)
|
||||
new_arrows.set_color(BLUE)
|
||||
|
||||
# Define first examples
|
||||
t2c = {
|
||||
"{x}": BLUE,
|
||||
"{\\dot x}": RED,
|
||||
}
|
||||
equation = TexMobject(
|
||||
"{\\dot x}(t) = k {x}(t)",
|
||||
tex_to_color_map=t2c,
|
||||
)
|
||||
equation.next_to(eq_word, DOWN)
|
||||
solution = TexMobject(
|
||||
"{x}(t) = x_0 e^{kt}",
|
||||
tex_to_color_map=t2c,
|
||||
)
|
||||
solution.next_to(s_word, DOWN, MED_LARGE_BUFF)
|
||||
equation.align_to(solution, DOWN)
|
||||
|
||||
axes = Axes(
|
||||
x_min=-1,
|
||||
x_max=5.5,
|
||||
y_min=-1,
|
||||
y_max=4.5,
|
||||
y_axis_config={"unit_size": 0.5}
|
||||
)
|
||||
axes.set_stroke(width=2)
|
||||
graph_line = axes.get_graph(
|
||||
lambda x: np.exp(0.4 * x)
|
||||
)
|
||||
graph_line.set_stroke(width=2)
|
||||
graph = VGroup(axes, graph_line)
|
||||
graph.scale(0.5)
|
||||
graph.next_to(u_word, UP)
|
||||
|
||||
computation = TexMobject(
|
||||
# "\\displaystyle "
|
||||
"e^x = \\sum_{n=0}^\\infty "
|
||||
"\\frac{x^n}{n!}"
|
||||
)
|
||||
computation.next_to(c_word, DOWN)
|
||||
|
||||
first_examples = VGroup(
|
||||
equation, solution, graph, computation
|
||||
)
|
||||
|
||||
# Second example
|
||||
ode = get_ode()
|
||||
ode.scale(0.75)
|
||||
second_examples = VGroup(
|
||||
ode,
|
||||
TexMobject("???").set_color(LIGHT_GREY),
|
||||
ScreenRectangle(
|
||||
height=2,
|
||||
stroke_width=1,
|
||||
),
|
||||
)
|
||||
for fe, se in zip(first_examples, second_examples):
|
||||
se.move_to(fe, DOWN)
|
||||
|
||||
ode.shift(2 * SMALL_BUFF * DOWN)
|
||||
ode.add_to_back(BackgroundRectangle(ode[-4:]))
|
||||
|
||||
self.add(eq_word)
|
||||
self.add(equation)
|
||||
self.play(
|
||||
FadeInFrom(s_word, LEFT),
|
||||
GrowArrow(arrows[0]),
|
||||
TransformFromCopy(equation, solution)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFrom(c_word, UL),
|
||||
GrowArrow(arrows[2]),
|
||||
FadeInFrom(computation, UP)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFrom(u_word, DL),
|
||||
GrowArrow(arrows[1]),
|
||||
FadeInFromDown(graph)
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
self.play(
|
||||
FadeOut(first_examples),
|
||||
FadeIn(second_examples[:2])
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
arrows.fade, 0.75,
|
||||
s_word.fade, 0.75,
|
||||
second_examples[1].fade, 0.75,
|
||||
ShowCreation(new_arrows[0]),
|
||||
FadeIn(second_examples[2])
|
||||
)
|
||||
self.play(
|
||||
ShowCreation(new_arrows[1]),
|
||||
Animation(second_examples),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class WritePhaseSpace(Scene):
|
||||
def construct(self):
|
||||
word = TextMobject("Phase space")
|
||||
word.scale(2)
|
||||
word.shift(FRAME_WIDTH * LEFT / 4)
|
||||
word.to_edge(UP)
|
||||
word.add_background_rectangle()
|
||||
|
||||
lines = VGroup(*[
|
||||
Line(v, 1.3 * v)
|
||||
for v in compass_directions(50)
|
||||
])
|
||||
lines.replace(word, stretch=True)
|
||||
lines.scale(1.5)
|
||||
lines.set_stroke(YELLOW)
|
||||
lines.shuffle()
|
||||
|
||||
self.add(word)
|
||||
self.play(
|
||||
ShowPassingFlashWithThinningStrokeWidth(
|
||||
lines,
|
||||
lag_ratio=0.002,
|
||||
run_time=1.5,
|
||||
time_width=0.9,
|
||||
n_segments=5,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class GleickQuote(Scene):
|
||||
def construct(self):
|
||||
quote = TextMobject(
|
||||
"``[Phase space is] one of the most\\\\",
|
||||
"powerful inventions", "of modern science.''\\\\",
|
||||
)
|
||||
quote.power_part = quote.get_part_by_tex("power")
|
||||
book = ImageMobject("ChaosBookCover")
|
||||
book.set_height(5)
|
||||
book.next_to(ORIGIN, LEFT)
|
||||
book.to_edge(DOWN)
|
||||
gleick = ImageMobject("JamesGleick")
|
||||
gleick.set_height(5)
|
||||
gleick.next_to(ORIGIN, RIGHT)
|
||||
gleick.to_edge(DOWN)
|
||||
quote.to_edge(UP)
|
||||
|
||||
self.play(
|
||||
FadeInFrom(book, RIGHT),
|
||||
FadeInFrom(gleick, LEFT),
|
||||
)
|
||||
self.wait()
|
||||
self.play(Write(quote))
|
||||
self.play(Write(
|
||||
quote.power_part.copy().set_color(BLUE),
|
||||
run_time=1
|
||||
))
|
||||
self.wait()
|
||||
|
||||
|
||||
class WritePhaseFlow(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject("Phase flow")
|
||||
words.scale(2)
|
||||
words.shift(FRAME_WIDTH * LEFT / 4)
|
||||
words.to_edge(UP)
|
||||
words.add_background_rectangle()
|
||||
self.play(Write(words))
|
||||
self.wait()
|
||||
|
||||
|
||||
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)
|
||||
|
||||
self.play(
|
||||
angle_tracker.set_value, 0,
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
angle_tracker.set_value, 90 * DEGREES,
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def get_sine_formula(self, angle):
|
||||
sin, lp, rp = TexMobject(
|
||||
"\\sin", "(", ") = "
|
||||
)
|
||||
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):
|
||||
def construct(self):
|
||||
ode = get_ode()
|
||||
ode.to_edge(UP)
|
||||
q1 = TextMobject("Find an exact solution")
|
||||
q1.set_color(YELLOW)
|
||||
q2 = TexMobject(
|
||||
"\\text{What is }", "\\theta", "(t)",
|
||||
"\\text{'s personality?}",
|
||||
tex_to_color_map={"\\theta": BLUE},
|
||||
arg_separator="",
|
||||
)
|
||||
theta = q2.get_part_by_tex("\\theta")
|
||||
|
||||
for q in q1, q2:
|
||||
q.scale(1.5)
|
||||
q.next_to(ode, DOWN, MED_LARGE_BUFF)
|
||||
eyes = Eyes(theta, height=0.1)
|
||||
|
||||
self.add(ode)
|
||||
self.add(q1)
|
||||
self.wait()
|
||||
self.play(
|
||||
q1.scale, 0.3,
|
||||
q1.to_corner, UR, MED_SMALL_BUFF,
|
||||
)
|
||||
self.play(FadeInFrom(q2, DOWN))
|
||||
self.play(
|
||||
eyes.blink,
|
||||
rate_func=lambda t: smooth(1 - t),
|
||||
)
|
||||
self.play(eyes.look_at, q2.get_left())
|
||||
self.play(eyes.look_at, q2.get_right())
|
||||
self.play(
|
||||
eyes.blink,
|
||||
rate_func=squish_rate_func(there_and_back)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
eyes.change_mode, "confused",
|
||||
eyes.look_at, ode.get_left(),
|
||||
)
|
||||
self.play(
|
||||
eyes.blink,
|
||||
rate_func=squish_rate_func(there_and_back)
|
||||
)
|
||||
|
||||
|
||||
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()
|
||||
self.introduce_coord_groups()
|
||||
self.count_coords()
|
||||
|
||||
def init_coord_groups(self):
|
||||
kwargs = {
|
||||
"bracket_v_buff": 2 * SMALL_BUFF
|
||||
}
|
||||
positions = VGroup(*[
|
||||
get_vector_symbol(*[
|
||||
"{}_{}".format(s, i)
|
||||
for s in "xyz"
|
||||
], **kwargs)
|
||||
for i in range(1, 4)
|
||||
])
|
||||
velocities = VGroup(*[
|
||||
get_vector_symbol(*[
|
||||
"p^{}_{}".format(s, i)
|
||||
for s in "xyz"
|
||||
], **kwargs)
|
||||
for i in range(1, 4)
|
||||
])
|
||||
groups = VGroup(positions, velocities)
|
||||
colors = [GREEN, RED, BLUE]
|
||||
for group in groups:
|
||||
for matrix in group:
|
||||
matrix.coords = matrix.get_entries()
|
||||
for coord, color in zip(matrix.coords, colors):
|
||||
coord.set_color(color)
|
||||
group.arrange(RIGHT)
|
||||
groups.arrange(DOWN, buff=LARGE_BUFF)
|
||||
groups.to_edge(LEFT)
|
||||
|
||||
self.coord_groups = groups
|
||||
|
||||
def introduce_coord_groups(self):
|
||||
groups = self.coord_groups
|
||||
x_group, p_group = groups
|
||||
x_word = TextMobject("Positions")
|
||||
p_word = TextMobject("Momenta")
|
||||
words = VGroup(x_word, p_word)
|
||||
for word, group in zip(words, groups):
|
||||
word.next_to(group, UP)
|
||||
|
||||
rect_groups = VGroup()
|
||||
for group in groups:
|
||||
rect_group = VGroup(*[
|
||||
SurroundingRectangle(
|
||||
VGroup(*[
|
||||
tm.coords[i]
|
||||
for tm in group
|
||||
]),
|
||||
color=WHITE,
|
||||
stroke_width=2,
|
||||
)
|
||||
for i in range(3)
|
||||
])
|
||||
rect_groups.add(rect_group)
|
||||
|
||||
self.play(
|
||||
*[
|
||||
LaggedStartMap(
|
||||
FadeInFrom, group,
|
||||
lambda m: (m, UP),
|
||||
run_time=1,
|
||||
)
|
||||
for group in groups
|
||||
],
|
||||
*map(FadeInFromDown, words),
|
||||
)
|
||||
for rect_group in rect_groups:
|
||||
self.play(
|
||||
ShowCreationThenFadeOut(
|
||||
rect_group,
|
||||
lag_ratio=0.5,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def count_coords(self):
|
||||
coord_copies = VGroup()
|
||||
for group in self.coord_groups:
|
||||
for tex_mob in group:
|
||||
for coord in tex_mob.coords:
|
||||
coord_copy = coord.copy()
|
||||
coord_copy.set_stroke(
|
||||
WHITE, 2, background=True
|
||||
)
|
||||
coord_copies.add(coord_copy)
|
||||
|
||||
count = Integer()
|
||||
count_word = TextMobject("18", "degrees \\\\ of freedom")[1]
|
||||
count_group = VGroup(count, count_word)
|
||||
count_group.arrange(
|
||||
RIGHT,
|
||||
aligned_edge=DOWN,
|
||||
)
|
||||
count_group.scale(1.5)
|
||||
count_group.next_to(
|
||||
self.coord_groups, RIGHT,
|
||||
aligned_edge=DOWN,
|
||||
)
|
||||
count.add_updater(
|
||||
lambda m: m.set_value(len(coord_copies))
|
||||
)
|
||||
count.add_updater(
|
||||
lambda m: m.next_to(count_word[0][0], LEFT, aligned_edge=DOWN)
|
||||
)
|
||||
|
||||
self.add(count_group)
|
||||
self.play(
|
||||
# ChangeDecimalToValue(count, len(coord_copies)),
|
||||
ShowIncreasingSubsets(coord_copies),
|
||||
run_time=1.5,
|
||||
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 theory")
|
||||
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",
|
||||
]
|
||||
}
|
||||
|
|
@ -1,898 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
# import scipy
|
||||
|
||||
|
||||
class FourierCirclesScene(Scene):
|
||||
CONFIG = {
|
||||
"n_vectors": 10,
|
||||
"big_radius": 2,
|
||||
"colors": [
|
||||
BLUE_D,
|
||||
BLUE_C,
|
||||
BLUE_E,
|
||||
GREY_BROWN,
|
||||
],
|
||||
"circle_style": {
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"vector_config": {
|
||||
"buff": 0,
|
||||
"max_tip_length_to_length_ratio": 0.35,
|
||||
"tip_length": 0.15,
|
||||
"max_stroke_width_to_length_ratio": 10,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"circle_config": {
|
||||
"stroke_width": 1,
|
||||
},
|
||||
"base_frequency": 1,
|
||||
"slow_factor": 0.25,
|
||||
"center_point": ORIGIN,
|
||||
"parametric_function_step_size": 0.001,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
self.slow_factor_tracker = ValueTracker(
|
||||
self.slow_factor
|
||||
)
|
||||
self.vector_clock = ValueTracker(0)
|
||||
self.vector_clock.add_updater(
|
||||
lambda m, dt: m.increment_value(
|
||||
self.get_slow_factor() * dt
|
||||
)
|
||||
)
|
||||
self.add(self.vector_clock)
|
||||
|
||||
def get_slow_factor(self):
|
||||
return self.slow_factor_tracker.get_value()
|
||||
|
||||
def get_vector_time(self):
|
||||
return self.vector_clock.get_value()
|
||||
|
||||
#
|
||||
def get_freqs(self):
|
||||
n = self.n_vectors
|
||||
all_freqs = list(range(n // 2, -n // 2, -1))
|
||||
all_freqs.sort(key=abs)
|
||||
return all_freqs
|
||||
|
||||
def get_coefficients(self):
|
||||
return [complex(0) for x in range(self.n_vectors)]
|
||||
|
||||
def get_color_iterator(self):
|
||||
return it.cycle(self.colors)
|
||||
|
||||
def get_rotating_vectors(self, freqs=None, coefficients=None):
|
||||
vectors = VGroup()
|
||||
self.center_tracker = VectorizedPoint(self.center_point)
|
||||
|
||||
if freqs is None:
|
||||
freqs = self.get_freqs()
|
||||
if coefficients is None:
|
||||
coefficients = self.get_coefficients()
|
||||
|
||||
last_vector = None
|
||||
for freq, coefficient in zip(freqs, coefficients):
|
||||
if last_vector:
|
||||
center_func = last_vector.get_end
|
||||
else:
|
||||
center_func = self.center_tracker.get_location
|
||||
vector = self.get_rotating_vector(
|
||||
coefficient=coefficient,
|
||||
freq=freq,
|
||||
center_func=center_func,
|
||||
)
|
||||
vectors.add(vector)
|
||||
last_vector = vector
|
||||
return vectors
|
||||
|
||||
def get_rotating_vector(self, coefficient, freq, center_func):
|
||||
vector = Vector(RIGHT, **self.vector_config)
|
||||
vector.scale(abs(coefficient))
|
||||
if abs(coefficient) == 0:
|
||||
phase = 0
|
||||
else:
|
||||
phase = np.log(coefficient).imag
|
||||
vector.rotate(phase, about_point=ORIGIN)
|
||||
vector.freq = freq
|
||||
vector.phase = phase
|
||||
vector.coefficient = coefficient
|
||||
vector.center_func = center_func
|
||||
vector.add_updater(self.update_vector)
|
||||
return vector
|
||||
|
||||
def update_vector(self, vector, dt):
|
||||
time = self.get_vector_time()
|
||||
vector.set_angle(
|
||||
vector.phase + time * vector.freq * TAU
|
||||
)
|
||||
vector.shift(
|
||||
vector.center_func() - vector.get_start()
|
||||
)
|
||||
return vector
|
||||
|
||||
def get_circles(self, vectors):
|
||||
return VGroup(*[
|
||||
self.get_circle(
|
||||
vector,
|
||||
color=color
|
||||
)
|
||||
for vector, color in zip(
|
||||
vectors,
|
||||
self.get_color_iterator()
|
||||
)
|
||||
])
|
||||
|
||||
def get_circle(self, vector, color=BLUE):
|
||||
circle = Circle(color=color, **self.circle_config)
|
||||
circle.center_func = vector.get_start
|
||||
circle.radius_func = vector.get_length
|
||||
circle.add_updater(self.update_circle)
|
||||
return circle
|
||||
|
||||
def update_circle(self, circle):
|
||||
circle.set_width(2 * circle.radius_func())
|
||||
circle.move_to(circle.center_func())
|
||||
return circle
|
||||
|
||||
def get_vector_sum_path(self, vectors, color=YELLOW):
|
||||
coefs = [v.coefficient for v in vectors]
|
||||
freqs = [v.freq for v in vectors]
|
||||
center = vectors[0].get_start()
|
||||
|
||||
path = ParametricFunction(
|
||||
lambda t: center + reduce(op.add, [
|
||||
complex_to_R3(
|
||||
coef * np.exp(TAU * 1j * freq * t)
|
||||
)
|
||||
for coef, freq in zip(coefs, freqs)
|
||||
]),
|
||||
t_min=0,
|
||||
t_max=1,
|
||||
color=color,
|
||||
step_size=self.parametric_function_step_size,
|
||||
)
|
||||
return path
|
||||
|
||||
# TODO, this should be a general animated mobect
|
||||
def get_drawn_path(self, vectors, stroke_width=2, **kwargs):
|
||||
path = self.get_vector_sum_path(vectors, **kwargs)
|
||||
broken_path = CurvesAsSubmobjects(path)
|
||||
broken_path.curr_time = 0
|
||||
|
||||
def update_path(path, dt):
|
||||
# alpha = path.curr_time * self.get_slow_factor()
|
||||
alpha = self.get_vector_time()
|
||||
n_curves = len(path)
|
||||
for a, sp in zip(np.linspace(0, 1, n_curves), path):
|
||||
b = alpha - a
|
||||
if b < 0:
|
||||
width = 0
|
||||
else:
|
||||
width = stroke_width * (1 - (b % 1))
|
||||
sp.set_stroke(width=width)
|
||||
path.curr_time += dt
|
||||
return path
|
||||
|
||||
broken_path.set_color(YELLOW)
|
||||
broken_path.add_updater(update_path)
|
||||
return broken_path
|
||||
|
||||
def get_y_component_wave(self,
|
||||
vectors,
|
||||
left_x=1,
|
||||
color=PINK,
|
||||
n_copies=2,
|
||||
right_shift_rate=5):
|
||||
path = self.get_vector_sum_path(vectors)
|
||||
wave = ParametricFunction(
|
||||
lambda t: op.add(
|
||||
right_shift_rate * t * LEFT,
|
||||
path.function(t)[1] * UP
|
||||
),
|
||||
t_min=path.t_min,
|
||||
t_max=path.t_max,
|
||||
color=color,
|
||||
)
|
||||
wave_copies = VGroup(*[
|
||||
wave.copy()
|
||||
for x in range(n_copies)
|
||||
])
|
||||
wave_copies.arrange(RIGHT, buff=0)
|
||||
top_point = wave_copies.get_top()
|
||||
wave.creation = ShowCreation(
|
||||
wave,
|
||||
run_time=(1 / self.get_slow_factor()),
|
||||
rate_func=linear,
|
||||
)
|
||||
cycle_animation(wave.creation)
|
||||
wave.add_updater(lambda m: m.shift(
|
||||
(m.get_left()[0] - left_x) * LEFT
|
||||
))
|
||||
|
||||
def update_wave_copies(wcs):
|
||||
index = int(
|
||||
wave.creation.total_time * self.get_slow_factor()
|
||||
)
|
||||
wcs[:index].match_style(wave)
|
||||
wcs[index:].set_stroke(width=0)
|
||||
wcs.next_to(wave, RIGHT, buff=0)
|
||||
wcs.align_to(top_point, UP)
|
||||
wave_copies.add_updater(update_wave_copies)
|
||||
|
||||
return VGroup(wave, wave_copies)
|
||||
|
||||
def get_wave_y_line(self, vectors, wave):
|
||||
return DashedLine(
|
||||
vectors[-1].get_end(),
|
||||
wave[0].get_end(),
|
||||
stroke_width=1,
|
||||
dash_length=DEFAULT_DASH_LENGTH * 0.5,
|
||||
)
|
||||
|
||||
# Computing Fourier series
|
||||
# i.e. where all the math happens
|
||||
def get_coefficients_of_path(self, path, n_samples=10000, freqs=None):
|
||||
if freqs is None:
|
||||
freqs = self.get_freqs()
|
||||
dt = 1 / n_samples
|
||||
ts = np.arange(0, 1, dt)
|
||||
samples = np.array([
|
||||
path.point_from_proportion(t)
|
||||
for t in ts
|
||||
])
|
||||
samples -= self.center_point
|
||||
complex_samples = samples[:, 0] + 1j * samples[:, 1]
|
||||
|
||||
result = []
|
||||
for freq in freqs:
|
||||
riemann_sum = np.array([
|
||||
np.exp(-TAU * 1j * freq * t) * cs
|
||||
for t, cs in zip(ts, complex_samples)
|
||||
]).sum() * dt
|
||||
result.append(riemann_sum)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class FourierSeriesIntroBackground4(FourierCirclesScene):
|
||||
CONFIG = {
|
||||
"n_vectors": 4,
|
||||
"center_point": 4 * LEFT,
|
||||
"run_time": 30,
|
||||
"big_radius": 1.5,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
circles = self.get_circles()
|
||||
path = self.get_drawn_path(circles)
|
||||
wave = self.get_y_component_wave(circles)
|
||||
h_line = always_redraw(
|
||||
lambda: self.get_wave_y_line(circles, wave)
|
||||
)
|
||||
|
||||
# Why?
|
||||
circles.update(-1 / self.camera.frame_rate)
|
||||
#
|
||||
self.add(circles, path, wave, h_line)
|
||||
self.wait(self.run_time)
|
||||
|
||||
def get_ks(self):
|
||||
return np.arange(1, 2 * self.n_vectors + 1, 2)
|
||||
|
||||
def get_freqs(self):
|
||||
return self.base_frequency * self.get_ks()
|
||||
|
||||
def get_coefficients(self):
|
||||
return self.big_radius / self.get_ks()
|
||||
|
||||
|
||||
class FourierSeriesIntroBackground8(FourierSeriesIntroBackground4):
|
||||
CONFIG = {
|
||||
"n_vectors": 8,
|
||||
}
|
||||
|
||||
|
||||
class FourierSeriesIntroBackground12(FourierSeriesIntroBackground4):
|
||||
CONFIG = {
|
||||
"n_vectors": 12,
|
||||
}
|
||||
|
||||
|
||||
class FourierSeriesIntroBackground20(FourierSeriesIntroBackground4):
|
||||
CONFIG = {
|
||||
"n_vectors": 20,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfPiSymbol(FourierCirclesScene):
|
||||
CONFIG = {
|
||||
"n_vectors": 51,
|
||||
"center_point": ORIGIN,
|
||||
"slow_factor": 0.1,
|
||||
"n_cycles": 1,
|
||||
"tex": "\\pi",
|
||||
"start_drawn": False,
|
||||
"max_circle_stroke_width": 1,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_vectors_circles_path()
|
||||
for n in range(self.n_cycles):
|
||||
self.run_one_cycle()
|
||||
|
||||
def add_vectors_circles_path(self):
|
||||
path = self.get_path()
|
||||
coefs = self.get_coefficients_of_path(path)
|
||||
vectors = self.get_rotating_vectors(coefficients=coefs)
|
||||
circles = self.get_circles(vectors)
|
||||
self.set_decreasing_stroke_widths(circles)
|
||||
# approx_path = self.get_vector_sum_path(circles)
|
||||
drawn_path = self.get_drawn_path(vectors)
|
||||
if self.start_drawn:
|
||||
self.vector_clock.increment_value(1)
|
||||
|
||||
self.add(path)
|
||||
self.add(vectors)
|
||||
self.add(circles)
|
||||
self.add(drawn_path)
|
||||
|
||||
self.vectors = vectors
|
||||
self.circles = circles
|
||||
self.path = path
|
||||
self.drawn_path = drawn_path
|
||||
|
||||
def run_one_cycle(self):
|
||||
time = 1 / self.slow_factor
|
||||
self.wait(time)
|
||||
|
||||
def set_decreasing_stroke_widths(self, circles):
|
||||
mcsw = self.max_circle_stroke_width
|
||||
for k, circle in zip(it.count(1), circles):
|
||||
circle.set_stroke(width=max(
|
||||
# mcsw / np.sqrt(k),
|
||||
mcsw / k,
|
||||
mcsw,
|
||||
))
|
||||
return circles
|
||||
|
||||
def get_path(self):
|
||||
tex_mob = TexMobject(self.tex)
|
||||
tex_mob.set_height(6)
|
||||
path = tex_mob.family_members_with_points()[0]
|
||||
path.set_fill(opacity=0)
|
||||
path.set_stroke(WHITE, 1)
|
||||
return path
|
||||
|
||||
|
||||
class FourierOfName(FourierOfPiSymbol):
|
||||
CONFIG = {
|
||||
"n_vectors": 100,
|
||||
"name_color": WHITE,
|
||||
"name_text": "Abc",
|
||||
"time_per_symbol": 5,
|
||||
"slow_factor": 1 / 5,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
name = TextMobject(self.name_text)
|
||||
max_width = FRAME_WIDTH - 2
|
||||
max_height = FRAME_HEIGHT - 2
|
||||
name.set_width(max_width)
|
||||
if name.get_height() > max_height:
|
||||
name.set_height(max_height)
|
||||
|
||||
circles = VGroup(VectorizedPoint())
|
||||
for path in name.family_members_with_points():
|
||||
for subpath in path.get_subpaths():
|
||||
sp_mob = VMobject()
|
||||
sp_mob.set_points(subpath)
|
||||
coefs = self.get_coefficients_of_path(sp_mob)
|
||||
new_circles = self.get_circles(
|
||||
coefficients=coefs
|
||||
)
|
||||
self.set_decreasing_stroke_widths(new_circles)
|
||||
drawn_path = self.get_drawn_path(new_circles)
|
||||
drawn_path.clear_updaters()
|
||||
drawn_path.set_stroke(self.name_color, 3)
|
||||
|
||||
new_circles.suspend_updating()
|
||||
self.play(ReplacementTransform(circles, new_circles))
|
||||
new_circles.resume_updating()
|
||||
circles = new_circles
|
||||
self.play(
|
||||
ShowCreation(drawn_path),
|
||||
rate_func=linear,
|
||||
run_time=self.time_per_symbol
|
||||
)
|
||||
circles.suspend_updating()
|
||||
self.play(FadeOut(circles))
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class FourierOfPiSymbol5(FourierOfPiSymbol):
|
||||
CONFIG = {
|
||||
"n_vectors": 5,
|
||||
"run_time": 10,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfTrebleClef(FourierOfPiSymbol):
|
||||
CONFIG = {
|
||||
"n_vectors": 101,
|
||||
"run_time": 10,
|
||||
"start_drawn": True,
|
||||
"file_name": "TrebleClef",
|
||||
"height": 7.5,
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
shape = SVGMobject(self.file_name)
|
||||
return shape
|
||||
|
||||
def get_path(self):
|
||||
shape = self.get_shape()
|
||||
path = shape.family_members_with_points()[0]
|
||||
path.set_height(self.height)
|
||||
path.set_fill(opacity=0)
|
||||
path.set_stroke(WHITE, 0)
|
||||
return path
|
||||
|
||||
|
||||
class FourierOfIP(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"file_name": "IP_logo2",
|
||||
"height": 6,
|
||||
"n_vectors": 100,
|
||||
}
|
||||
|
||||
# def construct(self):
|
||||
# path = self.get_path()
|
||||
# self.add(path)
|
||||
|
||||
def get_shape(self):
|
||||
shape = SVGMobject(self.file_name)
|
||||
return shape
|
||||
|
||||
def get_path(self):
|
||||
shape = self.get_shape()
|
||||
path = shape.family_members_with_points()[0]
|
||||
path.add_line_to(path.get_start())
|
||||
# path.make_smooth()
|
||||
|
||||
path.set_height(self.height)
|
||||
path.set_fill(opacity=0)
|
||||
path.set_stroke(WHITE, 0)
|
||||
return path
|
||||
|
||||
|
||||
class FourierOfEighthNote(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"file_name": "EighthNote"
|
||||
}
|
||||
|
||||
|
||||
class FourierOfN(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 6,
|
||||
"n_vectors": 1000,
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
return TexMobject("N")
|
||||
|
||||
|
||||
class FourierNailAndGear(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 6,
|
||||
"n_vectors": 200,
|
||||
"run_time": 100,
|
||||
"slow_factor": 0.01,
|
||||
"parametric_function_step_size": 0.0001,
|
||||
"arrow_config": {
|
||||
"tip_length": 0.1,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
shape = SVGMobject("Nail_And_Gear")[1]
|
||||
return shape
|
||||
|
||||
|
||||
class FourierBatman(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 4,
|
||||
"n_vectors": 100,
|
||||
"run_time": 10,
|
||||
"arrow_config": {
|
||||
"tip_length": 0.1,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
shape = SVGMobject("BatmanLogo")[1]
|
||||
return shape
|
||||
|
||||
|
||||
class FourierHeart(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 4,
|
||||
"n_vectors": 100,
|
||||
"run_time": 10,
|
||||
"arrow_config": {
|
||||
"tip_length": 0.1,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
shape = SuitSymbol("hearts")
|
||||
return shape
|
||||
|
||||
def get_drawn_path(self, *args, **kwargs):
|
||||
kwargs["stroke_width"] = 5
|
||||
path = super().get_drawn_path(*args, **kwargs)
|
||||
path.set_color(PINK)
|
||||
return path
|
||||
|
||||
|
||||
class FourierNDQ(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"height": 4,
|
||||
"n_vectors": 1000,
|
||||
"run_time": 10,
|
||||
"arrow_config": {
|
||||
"tip_length": 0.1,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
path = VMobject()
|
||||
shape = TexMobject("NDQ")
|
||||
for sp in shape.family_members_with_points():
|
||||
path.append_points(sp.points)
|
||||
return path
|
||||
|
||||
|
||||
class FourierGoogleG(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"n_vectors": 10,
|
||||
"height": 5,
|
||||
"g_colors": [
|
||||
"#4285F4",
|
||||
"#DB4437",
|
||||
"#F4B400",
|
||||
"#0F9D58",
|
||||
]
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
g = SVGMobject("google_logo")[5]
|
||||
g.center()
|
||||
self.add(g)
|
||||
return g
|
||||
|
||||
def get_drawn_path(self, *args, **kwargs):
|
||||
kwargs["stroke_width"] = 7
|
||||
path = super().get_drawn_path(*args, **kwargs)
|
||||
|
||||
blue, red, yellow, green = self.g_colors
|
||||
|
||||
path[:250].set_color(blue)
|
||||
path[250:333].set_color(green)
|
||||
path[333:370].set_color(yellow)
|
||||
path[370:755].set_color(red)
|
||||
path[755:780].set_color(yellow)
|
||||
path[780:860].set_color(green)
|
||||
path[860:].set_color(blue)
|
||||
|
||||
return path
|
||||
|
||||
|
||||
class ExplainCircleAnimations(FourierCirclesScene):
|
||||
CONFIG = {
|
||||
"n_vectors": 100,
|
||||
"center_point": 2 * DOWN,
|
||||
"n_top_circles": 9,
|
||||
"path_height": 3,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_path()
|
||||
self.add_circles()
|
||||
self.wait(8)
|
||||
self.organize_circles_in_a_row()
|
||||
self.show_frequencies()
|
||||
self.show_examples_for_frequencies()
|
||||
self.show_as_vectors()
|
||||
self.show_vector_sum()
|
||||
self.tweak_starting_vectors()
|
||||
|
||||
def add_path(self):
|
||||
self.path = self.get_path()
|
||||
self.add(self.path)
|
||||
|
||||
def add_circles(self):
|
||||
coefs = self.get_coefficients_of_path(self.path)
|
||||
self.circles = self.get_circles(coefficients=coefs)
|
||||
|
||||
self.add(self.circles)
|
||||
self.drawn_path = self.get_drawn_path(self.circles)
|
||||
self.add(self.drawn_path)
|
||||
|
||||
def organize_circles_in_a_row(self):
|
||||
circles = self.circles
|
||||
top_circles = circles[:self.n_top_circles].copy()
|
||||
|
||||
center_trackers = VGroup()
|
||||
for circle in top_circles:
|
||||
tracker = VectorizedPoint(circle.center_func())
|
||||
circle.center_func = tracker.get_location
|
||||
center_trackers.add(tracker)
|
||||
tracker.freq = circle.freq
|
||||
tracker.circle = circle
|
||||
|
||||
center_trackers.submobjects.sort(
|
||||
key=lambda m: m.freq
|
||||
)
|
||||
center_trackers.generate_target()
|
||||
right_buff = 1.45
|
||||
center_trackers.target.arrange(RIGHT, buff=right_buff)
|
||||
center_trackers.target.to_edge(UP, buff=1.25)
|
||||
|
||||
self.add(top_circles)
|
||||
self.play(
|
||||
MoveToTarget(center_trackers),
|
||||
run_time=2
|
||||
)
|
||||
self.wait(4)
|
||||
|
||||
self.top_circles = top_circles
|
||||
self.center_trackers = center_trackers
|
||||
|
||||
def show_frequencies(self):
|
||||
center_trackers = self.center_trackers
|
||||
|
||||
freq_numbers = VGroup()
|
||||
for ct in center_trackers:
|
||||
number = Integer(ct.freq)
|
||||
number.next_to(ct, DOWN, buff=1)
|
||||
freq_numbers.add(number)
|
||||
ct.circle.number = number
|
||||
|
||||
ld, rd = [
|
||||
TexMobject("\\dots")
|
||||
for x in range(2)
|
||||
]
|
||||
ld.next_to(freq_numbers, LEFT, MED_LARGE_BUFF)
|
||||
rd.next_to(freq_numbers, RIGHT, MED_LARGE_BUFF)
|
||||
freq_numbers.add_to_back(ld)
|
||||
freq_numbers.add(rd)
|
||||
|
||||
freq_word = TextMobject("Frequencies")
|
||||
freq_word.scale(1.5)
|
||||
freq_word.set_color(YELLOW)
|
||||
freq_word.next_to(freq_numbers, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
FadeInFromDown, freq_numbers
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
Write(freq_word),
|
||||
LaggedStartMap(
|
||||
ShowCreationThenFadeAround, freq_numbers,
|
||||
)
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
self.freq_numbers = freq_numbers
|
||||
self.freq_word = freq_word
|
||||
|
||||
def show_examples_for_frequencies(self):
|
||||
top_circles = self.top_circles
|
||||
c1, c2, c3 = [
|
||||
list(filter(
|
||||
lambda c: c.freq == k,
|
||||
top_circles
|
||||
))[0]
|
||||
for k in (1, 2, 3)
|
||||
]
|
||||
|
||||
neg_circles = VGroup(*filter(
|
||||
lambda c: c.freq < 0,
|
||||
top_circles
|
||||
))
|
||||
|
||||
for c in [c1, c2, c3, *neg_circles]:
|
||||
c.rect = SurroundingRectangle(c)
|
||||
|
||||
self.play(
|
||||
ShowCreation(c2.rect),
|
||||
WiggleOutThenIn(c2.number),
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
ReplacementTransform(c2.rect, c1.rect),
|
||||
)
|
||||
self.play(FadeOut(c1.rect))
|
||||
self.wait()
|
||||
self.play(
|
||||
ShowCreation(c3.rect),
|
||||
WiggleOutThenIn(c3.number),
|
||||
)
|
||||
self.play(
|
||||
FadeOut(c3.rect),
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
LaggedStart(*[
|
||||
ShowCreationThenFadeOut(c.rect)
|
||||
for c in neg_circles
|
||||
])
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(FadeOut(self.freq_word))
|
||||
|
||||
def show_as_vectors(self):
|
||||
top_circles = self.top_circles
|
||||
top_vectors = self.get_rotating_vectors(top_circles)
|
||||
top_vectors.set_color(WHITE)
|
||||
|
||||
original_circles = top_circles.copy()
|
||||
self.play(
|
||||
FadeIn(top_vectors),
|
||||
top_circles.set_opacity, 0,
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(
|
||||
top_circles.match_style, original_circles
|
||||
)
|
||||
self.remove(top_vectors)
|
||||
|
||||
self.top_vectors = top_vectors
|
||||
|
||||
def show_vector_sum(self):
|
||||
trackers = self.center_trackers.copy()
|
||||
trackers.sort(
|
||||
submob_func=lambda t: abs(t.circle.freq - 0.1)
|
||||
)
|
||||
plane = self.plane = NumberPlane(
|
||||
x_min=-3,
|
||||
x_max=3,
|
||||
y_min=-2,
|
||||
y_max=2,
|
||||
axis_config={
|
||||
"stroke_color": LIGHT_GREY,
|
||||
}
|
||||
)
|
||||
plane.set_stroke(width=1)
|
||||
plane.fade(0.5)
|
||||
plane.move_to(self.center_point)
|
||||
|
||||
self.play(
|
||||
FadeOut(self.drawn_path),
|
||||
FadeOut(self.circles),
|
||||
self.slow_factor_tracker.set_value, 0.05,
|
||||
)
|
||||
self.add(plane, self.path)
|
||||
self.play(FadeIn(plane))
|
||||
|
||||
new_circles = VGroup()
|
||||
last_tracker = None
|
||||
for tracker in trackers:
|
||||
if last_tracker:
|
||||
tracker.new_location_func = last_tracker.circle.get_start
|
||||
else:
|
||||
tracker.new_location_func = lambda: self.center_point
|
||||
|
||||
original_circle = tracker.circle
|
||||
tracker.circle = original_circle.copy()
|
||||
tracker.circle.center_func = tracker.get_location
|
||||
new_circles.add(tracker.circle)
|
||||
|
||||
self.add(tracker, tracker.circle)
|
||||
start_point = tracker.get_location()
|
||||
self.play(
|
||||
UpdateFromAlphaFunc(
|
||||
tracker, lambda t, a: t.move_to(
|
||||
interpolate(
|
||||
start_point,
|
||||
tracker.new_location_func(),
|
||||
a,
|
||||
)
|
||||
),
|
||||
run_time=2
|
||||
)
|
||||
)
|
||||
tracker.add_updater(lambda t: t.move_to(
|
||||
t.new_location_func()
|
||||
))
|
||||
self.wait(2)
|
||||
last_tracker = tracker
|
||||
|
||||
self.wait(3)
|
||||
|
||||
self.clear()
|
||||
self.slow_factor_tracker.set_value(0.1)
|
||||
self.add(
|
||||
self.top_circles,
|
||||
self.freq_numbers,
|
||||
self.path,
|
||||
)
|
||||
self.add_circles()
|
||||
for tc in self.top_circles:
|
||||
for c in self.circles:
|
||||
if c.freq == tc.freq:
|
||||
tc.rotate(
|
||||
angle_of_vector(c.get_start() - c.get_center()) -
|
||||
angle_of_vector(tc.get_start() - tc.get_center())
|
||||
)
|
||||
self.wait(10)
|
||||
|
||||
def tweak_starting_vectors(self):
|
||||
top_circles = self.top_circles
|
||||
circles = self.circles
|
||||
path = self.path
|
||||
drawn_path = self.drawn_path
|
||||
|
||||
new_path = self.get_new_path()
|
||||
new_coefs = self.get_coefficients_of_path(new_path)
|
||||
new_circles = self.get_circles(coefficients=new_coefs)
|
||||
|
||||
new_top_circles = VGroup()
|
||||
new_top_vectors = VGroup()
|
||||
for top_circle in top_circles:
|
||||
for circle in new_circles:
|
||||
if circle.freq == top_circle.freq:
|
||||
new_top_circle = circle.copy()
|
||||
new_top_circle.center_func = top_circle.get_center
|
||||
new_top_vector = self.get_rotating_vector(
|
||||
new_top_circle
|
||||
)
|
||||
new_top_circles.add(new_top_circle)
|
||||
new_top_vectors.add(new_top_vector)
|
||||
|
||||
self.play(
|
||||
self.slow_factor_tracker.set_value, 0,
|
||||
FadeOut(drawn_path)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ReplacementTransform(top_circles, new_top_circles),
|
||||
ReplacementTransform(circles, new_circles),
|
||||
FadeOut(path),
|
||||
run_time=3,
|
||||
)
|
||||
new_drawn_path = self.get_drawn_path(
|
||||
new_circles, stroke_width=4,
|
||||
)
|
||||
self.add(new_drawn_path)
|
||||
self.slow_factor_tracker.set_value(0.1)
|
||||
self.wait(20)
|
||||
|
||||
#
|
||||
def configure_path(self, path):
|
||||
path.set_stroke(WHITE, 1)
|
||||
path.set_fill(BLACK, opacity=1)
|
||||
path.set_height(self.path_height)
|
||||
path.move_to(self.center_point)
|
||||
return path
|
||||
|
||||
def get_path(self):
|
||||
tex = TexMobject("f")
|
||||
path = tex.family_members_with_points()[0]
|
||||
self.configure_path(path)
|
||||
return path
|
||||
# return Square().set_height(3)
|
||||
|
||||
def get_new_path(self):
|
||||
shape = SVGMobject("TrebleClef")
|
||||
path = shape.family_members_with_points()[0]
|
||||
self.configure_path(path)
|
||||
path.scale(1.5, about_edge=DOWN)
|
||||
return path
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,142 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
|
||||
|
||||
class ReactionsToInitialHeatEquation(PiCreatureScene):
|
||||
def construct(self):
|
||||
randy = self.pi_creature
|
||||
randy.set_color(BLUE_C)
|
||||
randy.center()
|
||||
|
||||
point = VectorizedPoint().next_to(randy, UL, LARGE_BUFF)
|
||||
randy.add_updater(lambda r: r.look_at(point))
|
||||
|
||||
self.play(randy.change, "horrified")
|
||||
self.wait()
|
||||
self.play(randy.change, "pondering")
|
||||
self.wait()
|
||||
self.play(
|
||||
randy.change, "confused",
|
||||
point.next_to, randy, UR, LARGE_BUFF,
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
point.shift, 2 * DOWN,
|
||||
randy.change, "horrified"
|
||||
)
|
||||
self.wait(4)
|
||||
|
||||
|
||||
class ContrastPDEToODE(TeacherStudentsScene):
|
||||
CONFIG = {
|
||||
"random_seed": 2,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
student = self.students[2]
|
||||
pde, ode = words = VGroup(*[
|
||||
TextMobject(
|
||||
text + "\\\\",
|
||||
"Differential\\\\",
|
||||
"Equation"
|
||||
)
|
||||
for text in ("Partial", "Ordinary")
|
||||
])
|
||||
pde[0].set_color(YELLOW)
|
||||
ode[0].set_color(BLUE)
|
||||
for word in words:
|
||||
word.arrange(DOWN, aligned_edge=LEFT)
|
||||
|
||||
words.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
words.next_to(student.get_corner(UR), UP, MED_LARGE_BUFF)
|
||||
words.shift(UR)
|
||||
lt = TexMobject("<")
|
||||
lt.scale(1.5)
|
||||
lt.move_to(Line(pde.get_right(), ode.get_left()))
|
||||
|
||||
for pi in self.pi_creatures:
|
||||
pi.add_updater(lambda p: p.look_at(pde))
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(VGroup(words, lt)),
|
||||
student.change, "raise_right_hand",
|
||||
)
|
||||
self.play(
|
||||
self.get_student_changes("pondering", "pondering", "hooray"),
|
||||
self.teacher.change, "happy"
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(
|
||||
Swap(ode, pde),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
self.get_student_changes(
|
||||
"erm", "sassy", "confused"
|
||||
)
|
||||
)
|
||||
self.look_at(words)
|
||||
self.change_student_modes(
|
||||
"thinking", "thinking", "tease",
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class AskAboutWhereEquationComesFrom(TeacherStudentsScene, WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation()
|
||||
equation.move_to(self.hold_up_spot, DOWN)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(equation),
|
||||
self.teacher.change, "raise_right_hand"
|
||||
)
|
||||
self.student_says(
|
||||
"Um...why?",
|
||||
target_mode="sassy",
|
||||
student_index=2,
|
||||
bubble_kwargs={"direction": RIGHT},
|
||||
)
|
||||
self.change_student_modes(
|
||||
"confused", "confused", "sassy",
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
self.teacher.change, "pondering",
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class AskWhyRewriteIt(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"Why?", student_index=1,
|
||||
bubble_kwargs={"height": 2, "width": 2},
|
||||
)
|
||||
self.students[1].bubble = None
|
||||
self.teacher_says(
|
||||
"One step closer\\\\to derivatives"
|
||||
)
|
||||
self.change_student_modes(
|
||||
"thinking", "thinking", "thinking",
|
||||
look_at_arg=4 * LEFT + 2 * UP
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class ReferenceKhanVideo(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
khan_logo = ImageMobject("KhanLogo")
|
||||
khan_logo.set_height(1)
|
||||
khan_logo.next_to(self.teacher, UP, buff=2)
|
||||
khan_logo.shift(2 * LEFT)
|
||||
|
||||
self.play(
|
||||
self.teacher.change, "raise_right_hand",
|
||||
)
|
||||
self.change_student_modes(
|
||||
"thinking", "pondering", "thinking",
|
||||
look_at_arg=self.screen
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFromDown(khan_logo))
|
||||
self.look_at(self.screen)
|
||||
self.wait(15)
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
|
||||
TIME_COLOR = YELLOW
|
||||
X_COLOR = GREEN
|
||||
|
||||
|
||||
def get_heat_equation():
|
||||
pass
|
||||
|
||||
|
||||
def temperature_to_color(temp, min_temp=-1, max_temp=1):
|
||||
colors = [BLUE, TEAL, GREEN, YELLOW, "#ff0000"]
|
||||
|
||||
alpha = inverse_interpolate(min_temp, max_temp, temp)
|
||||
index, sub_alpha = integer_interpolate(
|
||||
0, len(colors) - 1, alpha
|
||||
)
|
||||
return interpolate_color(
|
||||
colors[index], colors[index + 1], sub_alpha
|
||||
)
|
||||
|
||||
|
||||
def two_d_temp_func(x, y, t):
|
||||
return np.sum([
|
||||
c * np.sin(f * var) * np.exp(-(f**2) * t)
|
||||
for c, f, var in [
|
||||
(0.2, 1, x),
|
||||
(0.3, 3, x),
|
||||
(0.02, 5, x),
|
||||
(0.01, 7, x),
|
||||
(0.5, 2, y),
|
||||
(0.1, 10, y),
|
||||
(0.01, 20, y),
|
||||
]
|
||||
])
|
||||
|
|
@ -1,794 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.staging import TourOfDifferentialEquations
|
||||
|
||||
|
||||
class PartTwoOfTour(TourOfDifferentialEquations):
|
||||
CONFIG = {
|
||||
"zoomed_thumbnail_index": 1,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.show_thumbnails()
|
||||
self.zoom_in_to_one_thumbnail()
|
||||
|
||||
def zoom_in_to_one_thumbnail(self):
|
||||
frame = self.camera_frame
|
||||
thumbnails = self.thumbnails
|
||||
|
||||
ode = TextMobject("Ordinary\\\\", "Differential Equation")
|
||||
pde = TextMobject("Partial\\\\", "Differential Equation")
|
||||
for word, thumbnail, vect in zip([ode, pde], thumbnails, [DOWN, UP]):
|
||||
word.match_width(thumbnail)
|
||||
word.next_to(thumbnail, vect)
|
||||
ode[0].set_color(BLUE)
|
||||
pde[0].set_color(YELLOW)
|
||||
|
||||
self.add(ode)
|
||||
|
||||
frame.save_state()
|
||||
self.play(
|
||||
frame.replace,
|
||||
thumbnails[0],
|
||||
run_time=1,
|
||||
)
|
||||
self.play(
|
||||
Restore(frame, run_time=3),
|
||||
)
|
||||
self.play(
|
||||
TransformFromCopy(ode, pde),
|
||||
)
|
||||
self.play(
|
||||
ApplyMethod(
|
||||
frame.replace, thumbnails[1],
|
||||
path_arc=(-30 * DEGREES),
|
||||
run_time=3
|
||||
),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class BrownianMotion(Scene):
|
||||
CONFIG = {
|
||||
"wait_time": 60,
|
||||
"L": 3, # Box in [-L, L] x [-L, L]
|
||||
"n_particles": 100,
|
||||
"m1": 1,
|
||||
"m2": 100,
|
||||
"r1": 0.05,
|
||||
"r2": 0.5,
|
||||
"max_v": 5,
|
||||
"random_seed": 2,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.add_particles()
|
||||
self.wait(self.wait_time)
|
||||
|
||||
def add_title(self):
|
||||
square = Square(side_length=2 * self.L)
|
||||
title = TextMobject("Brownian motion")
|
||||
title.scale(1.5)
|
||||
title.next_to(square, UP)
|
||||
|
||||
self.add(square)
|
||||
self.add(title)
|
||||
|
||||
def add_particles(self):
|
||||
m1 = self.m1
|
||||
m2 = self.m2
|
||||
r1 = self.r1
|
||||
r2 = self.r2
|
||||
L = self.L
|
||||
max_v = self.max_v
|
||||
n_particles = self.n_particles
|
||||
|
||||
lil_particles = VGroup(*[
|
||||
self.get_particle(m1, r1, L, max_v)
|
||||
for k in range(n_particles)
|
||||
])
|
||||
big_particle = self.get_particle(m2, r2, L=r2, max_v=0)
|
||||
big_particle.set_fill(YELLOW, 1)
|
||||
|
||||
for p in lil_particles:
|
||||
if self.are_colliding(p, big_particle):
|
||||
lil_particles.remove(p)
|
||||
all_particles = VGroup(big_particle, *lil_particles)
|
||||
all_particles.add_updater(self.update_particles)
|
||||
|
||||
path = self.get_traced_path(big_particle)
|
||||
|
||||
self.add(all_particles)
|
||||
self.add(path)
|
||||
|
||||
self.particles = all_particles
|
||||
self.big_particle = big_particle
|
||||
self.path = path
|
||||
|
||||
def get_particle(self, m, r, L, max_v):
|
||||
dot = Dot(radius=r)
|
||||
dot.set_fill(WHITE, 0.7)
|
||||
dot.mass = m
|
||||
dot.radius = r
|
||||
dot.center = op.add(
|
||||
np.random.uniform(-L + r, L - r) * RIGHT,
|
||||
np.random.uniform(-L + r, L - r) * UP
|
||||
)
|
||||
dot.move_to(dot.center)
|
||||
dot.velocity = rotate_vector(
|
||||
np.random.uniform(0, max_v) * RIGHT,
|
||||
np.random.uniform(0, TAU),
|
||||
)
|
||||
return dot
|
||||
|
||||
def are_colliding(self, p1, p2):
|
||||
d = get_norm(p1.get_center() - p2.get_center())
|
||||
return (d < p1.radius + p2.radius)
|
||||
|
||||
def get_traced_path(self, particle):
|
||||
path = VMobject()
|
||||
path.set_stroke(BLUE, 3)
|
||||
path.start_new_path(particle.get_center())
|
||||
|
||||
buff = 0.02
|
||||
|
||||
def update_path(path):
|
||||
new_point = particle.get_center()
|
||||
if get_norm(new_point - path.get_last_point()) > buff:
|
||||
path.add_line_to(new_point)
|
||||
|
||||
path.add_updater(update_path)
|
||||
return path
|
||||
|
||||
def update_particles(self, particles, dt):
|
||||
for p1 in particles:
|
||||
p1.center += p1.velocity * dt
|
||||
|
||||
# Check particle collisions
|
||||
buff = 0.01
|
||||
for p2 in particles:
|
||||
if p1 is p2:
|
||||
continue
|
||||
v = p2.center - p1.center
|
||||
dist = get_norm(v)
|
||||
r_sum = p1.radius + p2.radius
|
||||
diff = dist - r_sum
|
||||
if diff < 0:
|
||||
unit_v = v / dist
|
||||
p1.center += (diff - buff) * unit_v / 2
|
||||
p2.center += -(diff - buff) * unit_v / 2
|
||||
u1 = p1.velocity
|
||||
u2 = p2.velocity
|
||||
m1 = p1.mass
|
||||
m2 = p2.mass
|
||||
v1 = (
|
||||
(m2 * (u2 - u1) + m1 * u1 + m2 * u2) /
|
||||
(m1 + m2)
|
||||
)
|
||||
v2 = (
|
||||
(m1 * (u1 - u2) + m1 * u1 + m2 * u2) /
|
||||
(m1 + m2)
|
||||
)
|
||||
p1.velocity = v1
|
||||
p2.velocity = v2
|
||||
|
||||
# Check edge collisions
|
||||
r1 = p1.radius
|
||||
c1 = p1.center
|
||||
for i in [0, 1]:
|
||||
if abs(c1[i]) + r1 > self.L:
|
||||
c1[i] = np.sign(c1[i]) * (self.L - r1)
|
||||
p1.velocity[i] *= -1 * op.mul(
|
||||
np.sign(p1.velocity[i]),
|
||||
np.sign(c1[i])
|
||||
)
|
||||
|
||||
for p in particles:
|
||||
p.move_to(p.center)
|
||||
return particles
|
||||
|
||||
|
||||
class AltBrownianMotion(BrownianMotion):
|
||||
CONFIG = {
|
||||
"wait_time": 20,
|
||||
"n_particles": 100,
|
||||
"m2": 10,
|
||||
}
|
||||
|
||||
|
||||
class BlackScholes(AltBrownianMotion):
|
||||
def construct(self):
|
||||
# For some reason I'm amused by the thought
|
||||
# Of this graph perfectly matching the Brownian
|
||||
# Motion y-coordiante
|
||||
self.add_title()
|
||||
self.add_particles()
|
||||
self.particles.set_opacity(0)
|
||||
self.remove(self.path)
|
||||
self.add_graph()
|
||||
self.wait(self.wait_time)
|
||||
|
||||
def add_title(self):
|
||||
title = TextMobject("Black-Sholes equations")
|
||||
title.scale(1.5)
|
||||
title.next_to(2 * UP, UP)
|
||||
|
||||
equation = TexMobject(
|
||||
"{\\partial V \\over \\partial t}", "+",
|
||||
"\\frac{1}{2} \\sigma^2 S^2",
|
||||
"{\\partial^2 V \\over \\partial S^2}", "+",
|
||||
"rS", "{\\partial V \\over \\partial S}",
|
||||
"-rV", "=", "0",
|
||||
)
|
||||
equation.scale(0.8)
|
||||
equation.next_to(title, DOWN)
|
||||
|
||||
self.add(title)
|
||||
self.add(equation)
|
||||
self.title = title
|
||||
self.equation = equation
|
||||
|
||||
def add_graph(self):
|
||||
axes = Axes(
|
||||
x_min=-1,
|
||||
x_max=20,
|
||||
y_min=0,
|
||||
y_max=10,
|
||||
number_line_config={
|
||||
"unit_size": 0.5,
|
||||
},
|
||||
)
|
||||
axes.set_height(4)
|
||||
axes.move_to(DOWN)
|
||||
|
||||
def get_graph_point():
|
||||
return axes.c2p(
|
||||
self.get_time(),
|
||||
5 + 2 * self.big_particle.get_center()[1]
|
||||
)
|
||||
|
||||
graph = VMobject()
|
||||
graph.match_style(self.path)
|
||||
graph.start_new_path(get_graph_point())
|
||||
graph.add_updater(
|
||||
lambda g: g.add_line_to(get_graph_point())
|
||||
)
|
||||
|
||||
self.add(axes)
|
||||
self.add(graph)
|
||||
|
||||
|
||||
class ContrastChapters1And2(Scene):
|
||||
def construct(self):
|
||||
c1_frame, c2_frame = frames = VGroup(*[
|
||||
ScreenRectangle(height=3.5)
|
||||
for x in range(2)
|
||||
])
|
||||
frames.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
|
||||
c1_title, c2_title = titles = VGroup(
|
||||
TextMobject("Chapter 1"),
|
||||
TextMobject("Chapter 2"),
|
||||
)
|
||||
titles.scale(1.5)
|
||||
|
||||
ode, pde = des = VGroup(
|
||||
TextMobject(
|
||||
"Ordinary",
|
||||
"Differential Equations\\\\",
|
||||
"ODEs",
|
||||
),
|
||||
TextMobject(
|
||||
"Partial",
|
||||
"Differential Equations\\\\",
|
||||
"PDEs",
|
||||
),
|
||||
)
|
||||
ode[0].set_color(BLUE)
|
||||
pde[0].set_color(YELLOW)
|
||||
for de in des:
|
||||
de[-1][0].match_color(de[0])
|
||||
de[-1].scale(1.5, about_point=de.get_top())
|
||||
|
||||
for title, frame, de in zip(titles, frames, des):
|
||||
title.next_to(frame, UP)
|
||||
de.match_width(frame)
|
||||
de.next_to(frame, DOWN)
|
||||
|
||||
lt = TexMobject("<")
|
||||
lt.move_to(Line(ode.get_right(), pde.get_left()))
|
||||
lt.scale(2, about_edge=UP)
|
||||
|
||||
c1_words = TextMobject(
|
||||
"They're", "really\\\\", "{}",
|
||||
"freaking", "hard\\\\",
|
||||
"to", "solve\\\\",
|
||||
)
|
||||
c1_words.set_height(0.5 * c1_frame.get_height())
|
||||
c1_words.move_to(c1_frame)
|
||||
|
||||
c2_words = TextMobject(
|
||||
"They're", "really", "\\emph{really}\\\\",
|
||||
"freaking", "hard\\\\",
|
||||
"to", "solve\\\\",
|
||||
)
|
||||
c2_words.set_color_by_tex("\\emph", YELLOW)
|
||||
c2_words.move_to(c2_frame)
|
||||
edit_shift = MED_LARGE_BUFF * RIGHT
|
||||
c2_edits = VGroup(
|
||||
TextMobject("sometimes").next_to(
|
||||
c2_words[1:3], UP,
|
||||
aligned_edge=LEFT,
|
||||
),
|
||||
Line(
|
||||
c2_words[1].get_left(),
|
||||
c2_words[2].get_right(),
|
||||
stroke_width=8,
|
||||
),
|
||||
TextMobject("not too").next_to(
|
||||
c2_words[3], LEFT,
|
||||
),
|
||||
Line(
|
||||
c2_words[3].get_left(),
|
||||
c2_words[3].get_right(),
|
||||
stroke_width=8,
|
||||
),
|
||||
)
|
||||
c2_edits.set_color(RED)
|
||||
c2_edits[2:].shift(edit_shift)
|
||||
|
||||
self.add(titles)
|
||||
self.add(frames)
|
||||
self.add(des)
|
||||
|
||||
self.wait()
|
||||
self.play(LaggedStartMap(
|
||||
FadeInFromDown, c1_words,
|
||||
lag_ratio=0.1,
|
||||
))
|
||||
self.wait()
|
||||
# self.play(FadeIn(ode))
|
||||
self.play(
|
||||
# TransformFromCopy(ode, pde),
|
||||
TransformFromCopy(c1_words, c2_words),
|
||||
Write(lt)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
Write(c2_edits[:2], run_time=1),
|
||||
)
|
||||
self.play(
|
||||
c2_words[3:5].shift, edit_shift,
|
||||
Write(c2_edits[2:]),
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowCubeFormation(ThreeDScene):
|
||||
CONFIG = {
|
||||
"camera_config": {
|
||||
"shading_factor": 1.0,
|
||||
},
|
||||
"color": False,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
light_source = self.camera.light_source
|
||||
light_source.move_to(np.array([-6, -3, 6]))
|
||||
|
||||
cube = Cube(
|
||||
side_length=4,
|
||||
fill_color=GREY,
|
||||
stroke_color=WHITE,
|
||||
stroke_width=0.5,
|
||||
)
|
||||
cube.set_fill(opacity=1)
|
||||
if self.color:
|
||||
# cube[0].set_color(BLUE)
|
||||
# cube[1].set_color(RED)
|
||||
# for face in cube[2:]:
|
||||
# face.set_color([BLUE, RED])
|
||||
cube.color_using_background_image("VerticalTempGradient")
|
||||
|
||||
# light_source.next_to(cube, np.array([1, -1, 1]), buff=2)
|
||||
|
||||
cube_3d = cube.copy()
|
||||
cube_2d = cube_3d.copy().stretch(0, 2)
|
||||
cube_1d = cube_2d.copy().stretch(0, 1)
|
||||
cube_0d = cube_1d.copy().stretch(0, 0)
|
||||
|
||||
cube.become(cube_0d)
|
||||
|
||||
self.set_camera_orientation(
|
||||
phi=70 * DEGREES,
|
||||
theta=-145 * DEGREES,
|
||||
)
|
||||
self.begin_ambient_camera_rotation(rate=0.05)
|
||||
|
||||
for target in [cube_1d, cube_2d, cube_3d]:
|
||||
self.play(
|
||||
Transform(cube, target, run_time=1.5)
|
||||
)
|
||||
self.wait(8)
|
||||
|
||||
|
||||
class ShowCubeFormationWithColor(ShowCubeFormation):
|
||||
CONFIG = {
|
||||
"color": True,
|
||||
}
|
||||
|
||||
|
||||
class ShowRect(Scene):
|
||||
CONFIG = {
|
||||
"height": 1,
|
||||
"width": 3,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
rect = Rectangle(
|
||||
height=self.height,
|
||||
width=self.width,
|
||||
)
|
||||
rect.set_color(YELLOW)
|
||||
self.play(ShowCreationThenFadeOut(rect))
|
||||
|
||||
|
||||
class ShowSquare(ShowRect):
|
||||
CONFIG = {
|
||||
"height": 1,
|
||||
"width": 1,
|
||||
}
|
||||
|
||||
|
||||
class ShowHLine(Scene):
|
||||
def construct(self):
|
||||
line = Line(LEFT, RIGHT)
|
||||
line.set_color(BLUE)
|
||||
self.play(ShowCreationThenFadeOut(line))
|
||||
|
||||
|
||||
class ShowCross(Scene):
|
||||
def construct(self):
|
||||
cross = Cross(Square())
|
||||
cross.set_width(3)
|
||||
cross.set_height(1, stretch=True)
|
||||
self.play(ShowCreation(cross))
|
||||
|
||||
|
||||
class TwoBodyEquations(Scene):
|
||||
def construct(self):
|
||||
kw = {
|
||||
"tex_to_color_map": {
|
||||
"x_1": LIGHT_GREY,
|
||||
"y_1": LIGHT_GREY,
|
||||
"x_2": BLUE,
|
||||
"y_2": BLUE,
|
||||
"=": WHITE,
|
||||
}
|
||||
}
|
||||
equations = VGroup(
|
||||
TexMobject(
|
||||
"{d^2 x_1 \\over dt^2}",
|
||||
"=",
|
||||
"{x_2 - x_1 \\over m_1 \\left(",
|
||||
"(x_2 - x_1)^2 + (y_2 - y_1)^2",
|
||||
"\\right)^{3/2}",
|
||||
**kw
|
||||
),
|
||||
TexMobject(
|
||||
"{d^2 y_1 \\over dt^2}",
|
||||
"=",
|
||||
"{y_2 - y_1 \\over m_1 \\left(",
|
||||
"(x_2 - x_1)^2 + (y_2 - y_1)^2",
|
||||
"\\right)^{3/2}",
|
||||
**kw
|
||||
),
|
||||
TexMobject(
|
||||
"{d^2 x_2 \\over dt^2}",
|
||||
"=",
|
||||
"{x_1 - x_2 \\over m_2 \\left(",
|
||||
"(x_2 - x_1)^2 + (y_2 - y_1)^2",
|
||||
"\\right)^{3/2}",
|
||||
**kw
|
||||
),
|
||||
TexMobject(
|
||||
"{d^2 y_2 \\over dt^2}",
|
||||
"=",
|
||||
"{y_1 - y_2 \\over m_2 \\left(",
|
||||
"(x_2 - x_1)^2 + (y_2 - y_1)^2",
|
||||
"\\right)^{3/2}",
|
||||
**kw
|
||||
),
|
||||
)
|
||||
|
||||
equations.arrange(DOWN, buff=LARGE_BUFF)
|
||||
equations.set_height(6)
|
||||
equations.to_edge(LEFT)
|
||||
|
||||
variables = VGroup()
|
||||
lhss = VGroup()
|
||||
rhss = VGroup()
|
||||
for equation in equations:
|
||||
variable = equation[1]
|
||||
lhs = equation[:4]
|
||||
rhs = equation[4:]
|
||||
variables.add(variable)
|
||||
lhss.add(lhs)
|
||||
rhss.add(rhs)
|
||||
lhss_copy = lhss.copy()
|
||||
|
||||
for variable, lhs in zip(variables, lhss):
|
||||
variable.save_state()
|
||||
variable.match_height(lhs)
|
||||
variable.scale(0.7)
|
||||
variable.move_to(lhs, LEFT)
|
||||
|
||||
self.play(LaggedStart(*[
|
||||
FadeInFrom(v, RIGHT)
|
||||
for v in variables
|
||||
]))
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStartMap(Restore, variables),
|
||||
FadeIn(
|
||||
lhss_copy,
|
||||
remover=True,
|
||||
lag_ratio=0.1,
|
||||
run_time=2,
|
||||
)
|
||||
)
|
||||
self.add(lhss)
|
||||
self.wait()
|
||||
self.play(LaggedStartMap(
|
||||
FadeIn, rhss
|
||||
))
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStart(*[
|
||||
ShowCreationThenFadeAround(lhs[:3])
|
||||
for lhs in lhss
|
||||
])
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
ShowCreationThenFadeAround,
|
||||
rhss,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class LaplacianIntuition(SpecialThreeDScene):
|
||||
CONFIG = {
|
||||
"three_d_axes_config": {
|
||||
"x_min": -5,
|
||||
"x_max": 5,
|
||||
"y_min": -5,
|
||||
"y_max": 5,
|
||||
},
|
||||
"surface_resolution": 32,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
axes = self.get_axes()
|
||||
axes.scale(0.5, about_point=ORIGIN)
|
||||
self.set_camera_to_default_position()
|
||||
self.begin_ambient_camera_rotation()
|
||||
|
||||
def func(x, y):
|
||||
return np.array([
|
||||
x, y,
|
||||
2.7 + 0.5 * (np.sin(x) + np.cos(y)) -
|
||||
0.025 * (x**2 + y**2)
|
||||
])
|
||||
|
||||
surface_config = {
|
||||
"u_min": -5,
|
||||
"u_max": 5,
|
||||
"v_min": -5,
|
||||
"v_max": 5,
|
||||
"resolution": self.surface_resolution,
|
||||
}
|
||||
# plane = ParametricSurface(
|
||||
# lambda u, v: np.array([u, v, 0]),
|
||||
# **surface_config
|
||||
# )
|
||||
# plane.set_stroke(WHITE, width=0.1)
|
||||
# plane.set_fill(WHITE, opacity=0.1)
|
||||
plane = Square(
|
||||
side_length=10,
|
||||
stroke_width=0,
|
||||
fill_color=WHITE,
|
||||
fill_opacity=0.1,
|
||||
)
|
||||
plane.center()
|
||||
plane.set_shade_in_3d(True)
|
||||
|
||||
surface = ParametricSurface(
|
||||
func, **surface_config
|
||||
)
|
||||
surface.set_stroke(BLUE, width=0.1)
|
||||
surface.set_fill(BLUE, opacity=0.25)
|
||||
|
||||
self.add(axes, plane, surface)
|
||||
|
||||
point = VectorizedPoint(np.array([2, -2, 0]))
|
||||
dot = Dot()
|
||||
dot.set_color(GREEN)
|
||||
dot.add_updater(lambda d: d.move_to(point))
|
||||
line = always_redraw(lambda: DashedLine(
|
||||
point.get_location(),
|
||||
func(*point.get_location()[:2]),
|
||||
background_image_file="VerticalTempGradient",
|
||||
))
|
||||
|
||||
circle = Circle(radius=0.25)
|
||||
circle.set_color(YELLOW)
|
||||
circle.insert_n_curves(20)
|
||||
circle.add_updater(lambda m: m.move_to(point))
|
||||
circle.set_shade_in_3d(True)
|
||||
surface_circle = always_redraw(
|
||||
lambda: circle.copy().apply_function(
|
||||
lambda p: func(*p[:2])
|
||||
).shift(
|
||||
0.02 * IN
|
||||
).color_using_background_image("VerticalTempGradient")
|
||||
)
|
||||
|
||||
self.play(FadeInFromLarge(dot))
|
||||
self.play(ShowCreation(line))
|
||||
self.play(TransformFromCopy(dot, circle))
|
||||
self.play(
|
||||
Transform(
|
||||
circle.copy(),
|
||||
surface_circle.copy().clear_updaters(),
|
||||
remover=True,
|
||||
)
|
||||
)
|
||||
self.add(surface_circle)
|
||||
|
||||
self.wait()
|
||||
for vect in [4 * LEFT, DOWN, 4 * RIGHT, UP]:
|
||||
self.play(
|
||||
point.shift, vect,
|
||||
run_time=3,
|
||||
)
|
||||
|
||||
|
||||
class StrogatzMention(PiCreatureScene):
|
||||
def construct(self):
|
||||
self.show_book()
|
||||
self.show_motives()
|
||||
self.show_pages()
|
||||
|
||||
def show_book(self):
|
||||
morty = self.pi_creature
|
||||
book = ImageMobject("InfinitePowers")
|
||||
book.set_height(5)
|
||||
book.to_edge(LEFT)
|
||||
|
||||
steve = ImageMobject("Strogatz_by_bricks")
|
||||
steve.set_height(5)
|
||||
steve.to_edge(LEFT)
|
||||
|
||||
name = TextMobject("Steven Strogatz")
|
||||
name.match_width(steve)
|
||||
name.next_to(steve, DOWN)
|
||||
|
||||
self.think(
|
||||
"Hmm...many good\\\\lessons here...",
|
||||
run_time=1
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFromDown(steve))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFrom(book, DOWN),
|
||||
steve.shift, 4 * RIGHT,
|
||||
RemovePiCreatureBubble(
|
||||
morty, target_mode="thinking"
|
||||
)
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(
|
||||
FadeOut(steve),
|
||||
FadeOut(morty),
|
||||
)
|
||||
|
||||
self.book = book
|
||||
|
||||
def show_motives(self):
|
||||
motives = VGroup(
|
||||
TextMobject("1) Scratch and itch"),
|
||||
TextMobject("2) Make people love math"),
|
||||
)
|
||||
motives.scale(1.5)
|
||||
motives.arrange(
|
||||
DOWN, LARGE_BUFF,
|
||||
aligned_edge=LEFT,
|
||||
)
|
||||
motives.move_to(
|
||||
Line(
|
||||
self.book.get_right(),
|
||||
FRAME_WIDTH * RIGHT / 2
|
||||
)
|
||||
)
|
||||
motives.to_edge(UP)
|
||||
|
||||
for motive in motives:
|
||||
self.play(FadeInFromDown(motive))
|
||||
self.wait(2)
|
||||
self.play(FadeOut(motives))
|
||||
|
||||
def show_pages(self):
|
||||
book = self.book
|
||||
pages = Group(*[
|
||||
ImageMobject("IP_Sample_Page{}".format(i))
|
||||
for i in range(1, 4)
|
||||
])
|
||||
for page in pages:
|
||||
page.match_height(book)
|
||||
page.next_to(book, RIGHT)
|
||||
|
||||
last_page = VectorizedPoint()
|
||||
for page in pages:
|
||||
self.play(
|
||||
FadeOut(last_page),
|
||||
FadeIn(page)
|
||||
)
|
||||
self.wait()
|
||||
last_page = page
|
||||
|
||||
self.play(FadeOut(last_page))
|
||||
|
||||
def create_pi_creature(self):
|
||||
return Mortimer().to_corner(DR)
|
||||
|
||||
|
||||
class Thumbnail(Scene):
|
||||
def construct(self):
|
||||
image = ImageMobject("HeatSurfaceExampleFlipped")
|
||||
image.set_height(6.5)
|
||||
image.to_edge(DOWN, buff=-SMALL_BUFF)
|
||||
self.add(image)
|
||||
|
||||
equation = TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}", "=",
|
||||
"\\alpha", "\\nabla^2 {T}",
|
||||
tex_to_color_map={
|
||||
"{t}": YELLOW,
|
||||
"{T}": RED,
|
||||
}
|
||||
)
|
||||
equation.scale(2)
|
||||
equation.to_edge(UP)
|
||||
|
||||
self.add(equation)
|
||||
|
||||
Group(equation, image).shift(1.5 * RIGHT)
|
||||
|
||||
question = TextMobject("What is\\\\this?")
|
||||
question.scale(2.5)
|
||||
question.to_edge(LEFT)
|
||||
arrow = Arrow(
|
||||
question.get_top(),
|
||||
equation.get_left(),
|
||||
buff=0.5,
|
||||
path_arc=-90 * DEGREES,
|
||||
)
|
||||
arrow.set_stroke(width=5)
|
||||
|
||||
self.add(question, arrow)
|
||||
|
||||
|
||||
class ShowNewton(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
|
||||
class ShowCupOfWater(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
|
@ -1,785 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
|
||||
|
||||
class WriteHeatEquationTemplate(Scene):
|
||||
CONFIG = {
|
||||
"tex_mobject_config": {
|
||||
"tex_to_color_map": {
|
||||
"{T}": WHITE,
|
||||
"{t}": YELLOW,
|
||||
"{x}": GREEN,
|
||||
"{y}": RED,
|
||||
"{z}": BLUE,
|
||||
"\\partial": WHITE,
|
||||
"2": WHITE,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def get_d1_equation(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}({x}, {t})", "=",
|
||||
"\\alpha \\cdot",
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2} ({x}, {t})",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
|
||||
def get_d1_equation_without_inputs(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}", "=",
|
||||
"\\alpha \\cdot",
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
|
||||
def get_d3_equation(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}", "=",
|
||||
"\\alpha \\left(",
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2} + ",
|
||||
"{\\partial^2 {T} \\over \\partial {y}^2} + ",
|
||||
"{\\partial^2 {T} \\over \\partial {z}^2}",
|
||||
"\\right)",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
|
||||
def get_general_equation(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}", "=",
|
||||
"\\alpha", "\\nabla^2 {T}",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
|
||||
def get_d3_equation_with_inputs(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}",
|
||||
"({x}, {y}, {z}, {t})", "=",
|
||||
"\\alpha \\left(",
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2}",
|
||||
"({x}, {y}, {z}, {t}) + ",
|
||||
"{\\partial^2 {T} \\over \\partial {y}^2}",
|
||||
"({x}, {y}, {z}, {t}) + ",
|
||||
"{\\partial^2 {T} \\over \\partial {z}^2}",
|
||||
"({x}, {y}, {z}, {t})",
|
||||
"\\right)",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
|
||||
def get_d1_words(self):
|
||||
return TextMobject("Heat equation\\\\", "(1 dimension)")
|
||||
|
||||
def get_d3_words(self):
|
||||
return TextMobject("Heat equation\\\\", "(3 dimensions)")
|
||||
|
||||
def get_d1_group(self):
|
||||
group = VGroup(
|
||||
self.get_d1_words(),
|
||||
self.get_d1_equation(),
|
||||
)
|
||||
group.arrange(DOWN, buff=MED_LARGE_BUFF)
|
||||
return group
|
||||
|
||||
def get_d3_group(self):
|
||||
group = VGroup(
|
||||
self.get_d3_words(),
|
||||
self.get_d3_equation(),
|
||||
)
|
||||
group.arrange(DOWN, buff=MED_LARGE_BUFF)
|
||||
return group
|
||||
|
||||
|
||||
class HeatEquationIntroTitle(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
scale_factor = 1.25
|
||||
title = TextMobject("The Heat Equation")
|
||||
title.scale(scale_factor)
|
||||
title.to_edge(UP)
|
||||
|
||||
equation = self.get_general_equation()
|
||||
equation.scale(scale_factor)
|
||||
equation.next_to(title, DOWN, MED_LARGE_BUFF)
|
||||
equation.set_color_by_tex("{T}", RED)
|
||||
|
||||
self.play(
|
||||
FadeInFrom(title, DOWN),
|
||||
FadeInFrom(equation, UP),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class BringTogether(Scene):
|
||||
def construct(self):
|
||||
arrows = VGroup(Vector(2 * RIGHT), Vector(2 * LEFT))
|
||||
arrows.arrange(RIGHT, buff=2)
|
||||
words = TextMobject("Bring together")[0]
|
||||
words.next_to(arrows, DOWN)
|
||||
words.save_state()
|
||||
words.space_out_submobjects(1.2)
|
||||
|
||||
self.play(
|
||||
VFadeIn(words),
|
||||
Restore(words),
|
||||
arrows.arrange, RIGHT, {"buff": SMALL_BUFF},
|
||||
VFadeIn(arrows),
|
||||
)
|
||||
self.play(FadeOut(words), FadeOut(arrows))
|
||||
|
||||
|
||||
class FourierSeriesIntro(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
title_scale_value = 1.5
|
||||
|
||||
title = TextMobject(
|
||||
"Fourier ", "Series",
|
||||
)
|
||||
title.scale(title_scale_value)
|
||||
title.to_edge(UP)
|
||||
title.generate_target()
|
||||
|
||||
details_coming = TextMobject("Details coming...")
|
||||
details_coming.next_to(title.get_corner(DR), DOWN)
|
||||
details_coming.set_color(LIGHT_GREY)
|
||||
|
||||
# physics = TextMobject("Physics")
|
||||
heat = TextMobject("Heat")
|
||||
heat.scale(title_scale_value)
|
||||
physics = self.get_general_equation()
|
||||
physics.set_color_by_tex("{T}", RED)
|
||||
arrow1 = Arrow(LEFT, RIGHT)
|
||||
arrow2 = Arrow(LEFT, RIGHT)
|
||||
group = VGroup(
|
||||
heat, arrow1, physics, arrow2, title.target
|
||||
)
|
||||
group.arrange(RIGHT)
|
||||
# physics.align_to(title.target, UP)
|
||||
group.to_edge(UP)
|
||||
|
||||
rot_square = Square()
|
||||
rot_square.fade(1)
|
||||
rot_square.add_updater(lambda m, dt: m.rotate(dt))
|
||||
|
||||
def update_heat_colors(heat):
|
||||
colors = [YELLOW, RED]
|
||||
vertices = rot_square.get_vertices()
|
||||
letters = heat.family_members_with_points()
|
||||
for letter, vertex in zip(letters, vertices):
|
||||
alpha = (normalize(vertex)[0] + 1) / 2
|
||||
i, sa = integer_interpolate(0, len(colors) - 1, alpha)
|
||||
letter.set_color(interpolate_color(
|
||||
colors[i], colors[i + 1], alpha,
|
||||
))
|
||||
heat.add_updater(update_heat_colors)
|
||||
|
||||
image = ImageMobject("Joseph Fourier")
|
||||
image.set_height(5)
|
||||
image.next_to(title, DOWN, LARGE_BUFF)
|
||||
image.to_edge(LEFT)
|
||||
name = TextMobject("Joseph", "Fourier")
|
||||
name.next_to(image, DOWN)
|
||||
|
||||
bubble = ThoughtBubble(
|
||||
height=2,
|
||||
width=2.5,
|
||||
direction=RIGHT,
|
||||
)
|
||||
bubble.set_fill(opacity=0)
|
||||
bubble.set_stroke(WHITE)
|
||||
bubble.set_stroke(BLACK, 5, background=True)
|
||||
bubble.shift(heat.get_center() - bubble.get_bubble_center())
|
||||
bubble[:-1].shift(LEFT + 0.2 * DOWN)
|
||||
bubble[:-1].rotate(-20 * DEGREES)
|
||||
for mob in bubble[:-1]:
|
||||
mob.rotate(20 * DEGREES)
|
||||
|
||||
# self.play(FadeInFromDown(title))
|
||||
self.add(title)
|
||||
self.play(
|
||||
FadeInFromDown(image),
|
||||
TransformFromCopy(
|
||||
title.get_part_by_tex("Fourier"),
|
||||
name.get_part_by_tex("Fourier"),
|
||||
path_arc=90 * DEGREES,
|
||||
),
|
||||
FadeIn(name.get_part_by_tex("Joseph")),
|
||||
)
|
||||
self.play(Write(details_coming, run_time=1))
|
||||
self.play(LaggedStartMap(FadeOut, details_coming[0], run_time=1))
|
||||
self.wait()
|
||||
self.add(rot_square)
|
||||
self.play(
|
||||
FadeInFrom(physics, RIGHT),
|
||||
GrowArrow(arrow2),
|
||||
FadeInFrom(heat, RIGHT),
|
||||
GrowArrow(arrow1),
|
||||
MoveToTarget(title),
|
||||
)
|
||||
self.play(ShowCreation(bubble))
|
||||
self.wait(10)
|
||||
|
||||
|
||||
class CompareODEToPDE(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
|
||||
class TodaysTargetWrapper(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
|
||||
class TwoGraphTypeTitles(Scene):
|
||||
def construct(self):
|
||||
left_title = TextMobject(
|
||||
"Represent time\\\\with actual time"
|
||||
)
|
||||
left_title.shift(FRAME_WIDTH * LEFT / 4)
|
||||
right_title = TextMobject(
|
||||
"Represent time\\\\with an axis"
|
||||
)
|
||||
right_title.shift(FRAME_WIDTH * RIGHT / 4)
|
||||
|
||||
titles = VGroup(left_title, right_title)
|
||||
for title in titles:
|
||||
title.scale(1.25)
|
||||
title.to_edge(UP)
|
||||
|
||||
self.play(FadeInFromDown(right_title))
|
||||
self.wait()
|
||||
self.play(FadeInFromDown(left_title))
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowPartialDerivativeSymbols(Scene):
|
||||
def construct(self):
|
||||
t2c = {
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
d_derivs, del_derivs = VGroup(*[
|
||||
VGroup(*[
|
||||
TexMobject(
|
||||
"{" + sym, "T", "\\over", sym, var + "}",
|
||||
"(", "{x}", ",", "{t}", ")",
|
||||
).set_color_by_tex_to_color_map(t2c)
|
||||
for var in ("{x}", "{t}")
|
||||
])
|
||||
for sym in ("d", "\\partial")
|
||||
])
|
||||
dTdx, dTdt = d_derivs
|
||||
delTdelx, delTdelx = del_derivs
|
||||
dels = VGroup(*it.chain(*[
|
||||
del_deriv.get_parts_by_tex("\\partial")
|
||||
for del_deriv in del_derivs
|
||||
]))
|
||||
|
||||
dTdx.to_edge(UP)
|
||||
self.play(FadeInFrom(dTdx, DOWN))
|
||||
self.wait()
|
||||
self.play(ShowCreationThenFadeAround(dTdx[3:5]))
|
||||
self.play(ShowCreationThenFadeAround(dTdx[:2]))
|
||||
self.wait()
|
||||
|
||||
dTdt.move_to(dTdx)
|
||||
self.play(
|
||||
dTdx.next_to, dTdt, RIGHT, {"buff": 1.5},
|
||||
dTdx.set_opacity, 0.5,
|
||||
FadeInFromDown(dTdt)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
for m1, m2 in zip(d_derivs, del_derivs):
|
||||
m2.move_to(m1)
|
||||
|
||||
pd_words = TextMobject("Partial derivatives")
|
||||
pd_words.next_to(del_derivs, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
Write(pd_words),
|
||||
dTdx.set_opacity, 1,
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ReplacementTransform(d_derivs, del_derivs)
|
||||
)
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
ShowCreationThenFadeAround,
|
||||
dels,
|
||||
surrounding_rectangle_config={
|
||||
"color": BLUE,
|
||||
"buff": 0.5 * SMALL_BUFF,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
num_words = VGroup(*[
|
||||
TextMobject(
|
||||
"Change in $T$\\\\caused by {}",
|
||||
"$\\partial$", "${}$".format(var),
|
||||
arg_separator="",
|
||||
).set_color_by_tex_to_color_map(t2c)
|
||||
for var in ("{x}", "{t}")
|
||||
])
|
||||
num_words.scale(0.8)
|
||||
for word, deriv in zip(num_words, del_derivs):
|
||||
num = deriv[:2]
|
||||
word.move_to(num, UP)
|
||||
word.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
deriv.rect = SurroundingRectangle(
|
||||
num,
|
||||
buff=SMALL_BUFF,
|
||||
stroke_width=2,
|
||||
color=word[-1].get_color(),
|
||||
)
|
||||
deriv.rect.mob = num
|
||||
deriv.rect.add_updater(lambda r: r.move_to(r.mob))
|
||||
|
||||
self.play(
|
||||
Write(num_words[1]),
|
||||
VGroup(del_derivs, pd_words).shift, DOWN,
|
||||
ShowCreation(del_derivs[1].rect),
|
||||
)
|
||||
self.play(
|
||||
Write(num_words[0]),
|
||||
ShowCreation(del_derivs[0].rect),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class WriteHeatEquation(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
title = TextMobject("The Heat Equation")
|
||||
title.to_edge(UP)
|
||||
|
||||
equation = self.get_d1_equation()
|
||||
equation.next_to(title, DOWN)
|
||||
|
||||
eq_i = equation.index_of_part_by_tex("=")
|
||||
dt_part = equation[:eq_i]
|
||||
dx_part = equation[eq_i + 3:]
|
||||
dt_rect = SurroundingRectangle(dt_part)
|
||||
dt_rect.set_stroke(YELLOW, 2)
|
||||
dx_rect = SurroundingRectangle(dx_part)
|
||||
dx_rect.set_stroke(GREEN, 2)
|
||||
|
||||
two_outlines = equation.get_parts_by_tex("2").copy()
|
||||
two_outlines.set_stroke(YELLOW, 2)
|
||||
two_outlines.set_fill(opacity=0)
|
||||
|
||||
to_be_explained = TextMobject(
|
||||
"To be explained shortly..."
|
||||
)
|
||||
to_be_explained.scale(0.7)
|
||||
to_be_explained.next_to(equation, RIGHT, MED_LARGE_BUFF)
|
||||
to_be_explained.fade(1)
|
||||
|
||||
pde = TextMobject("Partial Differential Equation")
|
||||
pde.move_to(title)
|
||||
|
||||
del_outlines = equation.get_parts_by_tex("\\partial").copy()
|
||||
del_outlines.set_stroke(YELLOW, 2)
|
||||
del_outlines.set_fill(opacity=0)
|
||||
|
||||
self.play(
|
||||
FadeInFrom(title, 0.5 * DOWN),
|
||||
FadeInFrom(equation, 0.5 * UP),
|
||||
)
|
||||
self.wait()
|
||||
self.play(ShowCreation(dt_rect))
|
||||
self.wait()
|
||||
self.play(TransformFromCopy(dt_rect, dx_rect))
|
||||
self.play(ShowCreationThenDestruction(two_outlines))
|
||||
self.wait()
|
||||
self.play(Write(to_be_explained, run_time=1))
|
||||
self.wait(2)
|
||||
self.play(
|
||||
ShowCreationThenDestruction(
|
||||
del_outlines,
|
||||
lag_ratio=0.1,
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
FadeOutAndShift(title, UP),
|
||||
FadeInFrom(pde, DOWN),
|
||||
FadeOut(dt_rect),
|
||||
FadeOut(dx_rect),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class Show3DEquation(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d3_equation_with_inputs()
|
||||
equation.set_width(FRAME_WIDTH - 1)
|
||||
inputs = VGroup(*it.chain(*[
|
||||
equation.get_parts_by_tex(s)
|
||||
for s in ["{x}", "{y}", "{z}", "{t}"]
|
||||
]))
|
||||
inputs.sort()
|
||||
equation.to_edge(UP)
|
||||
|
||||
self.add(equation)
|
||||
self.play(LaggedStartMap(
|
||||
ShowCreationThenFadeAround, inputs,
|
||||
surrounding_rectangle_config={
|
||||
"buff": 0.05,
|
||||
"stroke_width": 2,
|
||||
}
|
||||
))
|
||||
self.wait()
|
||||
|
||||
|
||||
class Show1DAnd3DEquations(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
d1_group = self.get_d1_group()
|
||||
d3_group = self.get_d3_group()
|
||||
d1_words, d1_equation = d1_group
|
||||
d3_words, d3_equation = d3_group
|
||||
|
||||
groups = VGroup(d1_group, d3_group)
|
||||
for group in groups:
|
||||
group.arrange(DOWN, buff=MED_LARGE_BUFF)
|
||||
groups.arrange(RIGHT, buff=1.5)
|
||||
groups.to_edge(UP)
|
||||
|
||||
d3_rhs = d3_equation[9:-2]
|
||||
d3_brace = Brace(d3_rhs, DOWN)
|
||||
nabla_words = TextMobject("Sometimes written as")
|
||||
nabla_words.match_width(d3_brace)
|
||||
nabla_words.next_to(d3_brace, DOWN)
|
||||
nabla_exp = TexMobject(
|
||||
"\\nabla^2 {T}",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
nabla_exp.next_to(nabla_words, DOWN)
|
||||
# nabla_group = VGroup(nabla_words, nabla_exp)
|
||||
|
||||
d1_group.save_state()
|
||||
d1_group.center().to_edge(UP)
|
||||
|
||||
self.play(
|
||||
Write(d1_words),
|
||||
FadeInFrom(d1_equation, UP),
|
||||
run_time=1,
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
Restore(d1_group),
|
||||
FadeInFrom(d3_group, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
GrowFromCenter(d3_brace),
|
||||
Write(nabla_words),
|
||||
TransformFromCopy(d3_rhs, nabla_exp),
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class D1EquationNoInputs(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation_without_inputs()
|
||||
equation.to_edge(UP)
|
||||
# i1 = equation.index_of_part_by_tex("\\partial")
|
||||
# i2 = equation.index_of_part_by_tex("\\cdot")
|
||||
# equation[i1:i1 + 2].set_color(RED)
|
||||
# equation[i2 + 1:i2 + 6].set_color(RED)
|
||||
equation.set_color_by_tex("{T}", RED)
|
||||
self.add(equation)
|
||||
|
||||
|
||||
class AltHeatRHS(Scene):
|
||||
def construct(self):
|
||||
formula = TexMobject(
|
||||
"{\\alpha \\over 2}", "\\Big(",
|
||||
"T({x} - 1, {t}) + T({x} + 1, {t})"
|
||||
"\\Big)",
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
)
|
||||
self.add(formula)
|
||||
|
||||
|
||||
class CompareInputsOfGeneralCaseTo1D(WriteHeatEquation):
|
||||
def construct(self):
|
||||
three_d_expr, one_d_expr = [
|
||||
TexMobject(
|
||||
"{T}(" + inputs + ", {t})",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
for inputs in ["{x}, {y}, {z}", "{x}"]
|
||||
]
|
||||
for expr in three_d_expr, one_d_expr:
|
||||
expr.scale(2)
|
||||
expr.to_edge(UP)
|
||||
|
||||
x, y, z = [
|
||||
three_d_expr.get_part_by_tex(letter)
|
||||
for letter in ["x", "y", "z"]
|
||||
]
|
||||
|
||||
self.play(FadeInFromDown(three_d_expr))
|
||||
self.play(LaggedStartMap(
|
||||
ShowCreationThenFadeAround,
|
||||
VGroup(x, y, z)
|
||||
))
|
||||
self.wait()
|
||||
low = 3
|
||||
high = -3
|
||||
self.play(
|
||||
ReplacementTransform(three_d_expr[:low], one_d_expr[:low]),
|
||||
ReplacementTransform(three_d_expr[high:], one_d_expr[high:]),
|
||||
three_d_expr[low:high].scale, 0,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowLaplacian(WriteHeatEquation):
|
||||
def construct(self):
|
||||
equation = self.get_d3_equation()
|
||||
equation.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
|
||||
parts = VGroup()
|
||||
plusses = VGroup()
|
||||
for char in "xyz":
|
||||
index = equation.index_of_part_by_tex(
|
||||
"{" + char + "}"
|
||||
)
|
||||
part = equation[index - 6:index + 3]
|
||||
rect = SurroundingRectangle(part)
|
||||
rect.match_color(equation[index])
|
||||
parts.add(part)
|
||||
part.rect = rect
|
||||
if char in "yz":
|
||||
plus = equation[index - 8]
|
||||
part.plus = plus
|
||||
plusses.add(plus)
|
||||
|
||||
lp = equation.get_part_by_tex("(")
|
||||
rp = equation.get_part_by_tex(")")
|
||||
|
||||
for part in parts:
|
||||
part.rp = rp.copy()
|
||||
part.rp.next_to(part, RIGHT, SMALL_BUFF)
|
||||
part.rp.align_to(lp, UP)
|
||||
rp.become(parts[0].rp)
|
||||
|
||||
# Show new second derivatives
|
||||
self.add(*equation)
|
||||
self.remove(*plusses, *parts[1], *parts[2])
|
||||
for part in parts[1:]:
|
||||
self.play(
|
||||
rp.become, part.rp,
|
||||
FadeInFrom(part, LEFT),
|
||||
Write(part.plus),
|
||||
ShowCreation(part.rect),
|
||||
)
|
||||
self.play(
|
||||
FadeOut(part.rect),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# Show laplacian
|
||||
brace = Brace(parts, DOWN)
|
||||
laplacian = TexMobject("\\nabla^2", "T")
|
||||
laplacian.next_to(brace, DOWN)
|
||||
laplacian_name = TextMobject(
|
||||
"``Laplacian''"
|
||||
)
|
||||
laplacian_name.next_to(laplacian, DOWN)
|
||||
|
||||
T_parts = VGroup(*[part[3] for part in parts])
|
||||
non_T_parts = VGroup(*[
|
||||
VGroup(*part[:3], *part[4:])
|
||||
for part in parts
|
||||
])
|
||||
|
||||
self.play(GrowFromCenter(brace))
|
||||
self.play(Write(laplacian_name))
|
||||
self.play(
|
||||
TransformFromCopy(non_T_parts, laplacian[0])
|
||||
)
|
||||
self.play(
|
||||
TransformFromCopy(T_parts, laplacian[1])
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class AskAboutActuallySolving(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation()
|
||||
equation.center()
|
||||
|
||||
q1 = TextMobject("Solve for T?")
|
||||
q1.next_to(equation, UP, LARGE_BUFF)
|
||||
q2 = TextMobject("What does it \\emph{mean} to solve this?")
|
||||
q2.next_to(equation, UP, LARGE_BUFF)
|
||||
formula = TexMobject(
|
||||
"T({x}, {t}) = \\sin\\big(a{x}\\big) e^{-\\alpha \\cdot a^2 {t}}",
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
)
|
||||
formula.next_to(equation, DOWN, LARGE_BUFF)
|
||||
q3 = TextMobject("Is this it?")
|
||||
arrow = Vector(LEFT, color=WHITE)
|
||||
arrow.next_to(formula, RIGHT)
|
||||
q3.next_to(arrow, RIGHT)
|
||||
|
||||
self.add(equation)
|
||||
self.play(FadeInFromDown(q1))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeInFromDown(q2),
|
||||
q1.shift, 1.5 * UP,
|
||||
)
|
||||
self.play(FadeInFrom(formula, UP))
|
||||
self.play(
|
||||
GrowArrow(arrow),
|
||||
FadeInFrom(q3, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class PDEPatreonEndscreen(PatreonEndScreen):
|
||||
CONFIG = {
|
||||
"specific_patrons": [
|
||||
"Juan Benet",
|
||||
"Vassili Philippov",
|
||||
"Burt Humburg",
|
||||
"Matt Russell",
|
||||
"Scott Gray",
|
||||
"soekul",
|
||||
"Tihan Seale",
|
||||
"Richard Barthel",
|
||||
"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",
|
||||
"D. Sivakumar",
|
||||
"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",
|
||||
"Antoine Bruguier",
|
||||
"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 B. Hill",
|
||||
"David Clark",
|
||||
"DeathByShrimp",
|
||||
"Delton Ding",
|
||||
"eaglle",
|
||||
"emptymachine",
|
||||
"Eric Younge",
|
||||
"Eryq Ouithaqueue",
|
||||
"Federico Lebron",
|
||||
"Giovanni Filippi",
|
||||
"Hal Hildebrand",
|
||||
"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 Beck",
|
||||
"Lee Redden",
|
||||
"Linh Tran",
|
||||
"Ludwig Schubert",
|
||||
"Magister Mugit",
|
||||
"Mark B Bahu",
|
||||
"Mark Heising",
|
||||
"Martin Price",
|
||||
"Mathias Jansson",
|
||||
"Matt Langford",
|
||||
"Matt Roveto",
|
||||
"Matthew Bouchard",
|
||||
"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",
|
||||
"Sachit Nagpal",
|
||||
"Solara570",
|
||||
"Stevie Metke",
|
||||
"Tal Einav",
|
||||
"Ted Suzman",
|
||||
"Thomas Tarler",
|
||||
"Tom Fleming",
|
||||
"Valeriy Skobelev",
|
||||
"Xavier Bernard",
|
||||
"Yavor Ivanov",
|
||||
"Yaw Etse",
|
||||
"YinYangBalance.Asia",
|
||||
"Zach Cardwell",
|
||||
],
|
||||
}
|
||||
|
|
@ -1,303 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.heat_equation import *
|
||||
|
||||
|
||||
class ShowNewRuleAtDiscreteBoundary(DiscreteSetup):
|
||||
CONFIG = {
|
||||
"axes_config": {
|
||||
"x_min": 0,
|
||||
"stroke_width": 1,
|
||||
"x_axis_config": {
|
||||
"include_tip": False,
|
||||
},
|
||||
},
|
||||
"freq_amplitude_pairs": [
|
||||
(1, 0.5),
|
||||
(2, 1),
|
||||
(3, 0.5),
|
||||
(4, 0.3),
|
||||
],
|
||||
"v_line_class": DashedLine,
|
||||
"v_line_config": {
|
||||
|
||||
},
|
||||
"step_size": 1,
|
||||
"wait_time": 15,
|
||||
"alpha": 0.25,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_axes()
|
||||
self.set_points()
|
||||
self.show_boundary_point_influenced_by_neighbor()
|
||||
self.add_clock()
|
||||
self.let_evolve()
|
||||
|
||||
def set_points(self):
|
||||
axes = self.axes
|
||||
for mob in axes.family_members_with_points():
|
||||
if isinstance(mob, Line):
|
||||
mob.set_stroke(width=1)
|
||||
|
||||
step_size = self.step_size
|
||||
xs = np.arange(
|
||||
axes.x_min,
|
||||
axes.x_max + step_size,
|
||||
step_size
|
||||
)
|
||||
|
||||
dots = self.dots = self.get_dots(axes, xs)
|
||||
self.v_lines = self.get_v_lines(dots)
|
||||
self.rod_pieces = self.get_rod_pieces(dots)
|
||||
|
||||
# rod_pieces
|
||||
|
||||
self.add(self.dots)
|
||||
self.add(self.v_lines)
|
||||
self.add(self.rod_pieces)
|
||||
|
||||
def show_boundary_point_influenced_by_neighbor(self):
|
||||
dots = self.dots
|
||||
ld = dots[0]
|
||||
ld_in = dots[1]
|
||||
rd = dots[-1]
|
||||
rd_in = dots[-2]
|
||||
v_len = 0.75
|
||||
l_arrow = Vector(v_len * LEFT)
|
||||
l_arrow.move_to(ld.get_left(), RIGHT)
|
||||
r_arrow = Vector(v_len * RIGHT)
|
||||
r_arrow.move_to(rd.get_right(), LEFT)
|
||||
arrows = VGroup(l_arrow, r_arrow)
|
||||
q_marks = VGroup(*[
|
||||
TexMobject("?").scale(1.5).next_to(
|
||||
arrow, arrow.get_vector()
|
||||
)
|
||||
for arrow in arrows
|
||||
])
|
||||
|
||||
arrows.set_color(YELLOW)
|
||||
q_marks.set_color(YELLOW)
|
||||
|
||||
blocking_rects = VGroup(*[
|
||||
BackgroundRectangle(VGroup(
|
||||
*dots[i:-i],
|
||||
*self.rod_pieces[i:-i]
|
||||
))
|
||||
for i in [1, 2]
|
||||
])
|
||||
for rect in blocking_rects:
|
||||
rect.stretch(1.1, dim=1, about_edge=UP)
|
||||
|
||||
self.play(FadeIn(blocking_rects[0]))
|
||||
self.play(
|
||||
LaggedStartMap(ShowCreation, arrows),
|
||||
LaggedStart(*[
|
||||
FadeInFrom(q_mark, -arrow.get_vector())
|
||||
for q_mark, arrow in zip(q_marks, arrows)
|
||||
]),
|
||||
run_time=1.5
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# Point to inward neighbor
|
||||
new_arrows = VGroup(*[
|
||||
Arrow(
|
||||
d1.get_center(),
|
||||
VGroup(d1, d2).get_center(),
|
||||
buff=0,
|
||||
).match_style(l_arrow)
|
||||
for d1, d2 in [(ld, ld_in), (rd, rd_in)]
|
||||
])
|
||||
new_arrows.match_style(arrows)
|
||||
|
||||
l_brace = Brace(VGroup(ld, ld_in), DOWN)
|
||||
r_brace = Brace(VGroup(rd, rd_in), DOWN)
|
||||
braces = VGroup(l_brace, r_brace)
|
||||
for brace in braces:
|
||||
brace.align_to(
|
||||
self.axes.x_axis.get_center(), UP
|
||||
)
|
||||
brace.shift(SMALL_BUFF * DOWN)
|
||||
brace.add(brace.get_tex("\\Delta x"))
|
||||
|
||||
self.play(
|
||||
ReplacementTransform(arrows, new_arrows),
|
||||
FadeOut(q_marks),
|
||||
ReplacementTransform(*blocking_rects)
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFrom(braces, UP))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOut(new_arrows),
|
||||
FadeOut(blocking_rects[1]),
|
||||
FadeOut(braces),
|
||||
)
|
||||
|
||||
def add_clock(self):
|
||||
super().add_clock()
|
||||
self.time_label.add_updater(
|
||||
lambda d, dt: d.increment_value(dt)
|
||||
)
|
||||
VGroup(
|
||||
self.clock,
|
||||
self.time_label
|
||||
).shift(2 * LEFT)
|
||||
|
||||
def let_evolve(self):
|
||||
dots = self.dots
|
||||
dots.add_updater(self.update_dots)
|
||||
|
||||
wait_time = self.wait_time
|
||||
self.play(
|
||||
ClockPassesTime(
|
||||
self.clock,
|
||||
run_time=wait_time,
|
||||
hours_passed=wait_time,
|
||||
),
|
||||
)
|
||||
|
||||
#
|
||||
|
||||
def get_dots(self, axes, xs):
|
||||
dots = VGroup(*[
|
||||
Dot(axes.c2p(x, self.temp_func(x, 0)))
|
||||
for x in xs
|
||||
])
|
||||
|
||||
max_width = 0.8 * self.step_size
|
||||
for dot in dots:
|
||||
dot.add_updater(self.update_dot_color)
|
||||
if dot.get_width() > max_width:
|
||||
dot.set_width(max_width)
|
||||
|
||||
return dots
|
||||
|
||||
def get_v_lines(self, dots):
|
||||
return always_redraw(lambda: VGroup(*[
|
||||
self.get_v_line(dot)
|
||||
for dot in dots
|
||||
]))
|
||||
|
||||
def get_v_line(self, dot):
|
||||
x_axis = self.axes.x_axis
|
||||
bottom = dot.get_bottom()
|
||||
x = x_axis.p2n(bottom)
|
||||
proj_point = x_axis.n2p(x)
|
||||
return self.v_line_class(
|
||||
proj_point, bottom,
|
||||
**self.v_line_config,
|
||||
)
|
||||
|
||||
def get_rod_pieces(self, dots):
|
||||
axis = self.axes.x_axis
|
||||
factor = 1 - np.exp(-(0.8 / self.step_size)**2)
|
||||
width = factor * self.step_size
|
||||
|
||||
pieces = VGroup()
|
||||
for dot in dots:
|
||||
piece = Line(ORIGIN, width * RIGHT)
|
||||
piece.set_stroke(width=5)
|
||||
piece.move_to(dot)
|
||||
piece.set_y(axis.get_center()[1])
|
||||
piece.dot = dot
|
||||
piece.add_updater(
|
||||
lambda p: p.match_color(p.dot)
|
||||
)
|
||||
pieces.add(piece)
|
||||
return pieces
|
||||
|
||||
def update_dot_color(self, dot):
|
||||
y = self.axes.y_axis.p2n(dot.get_center())
|
||||
dot.set_color(self.y_to_color(y))
|
||||
|
||||
def update_dots(self, dots, dt):
|
||||
for ds in zip(dots, dots[1:], dots[2:]):
|
||||
points = [d.get_center() for d in ds]
|
||||
x0, x1, x2 = [p[0] for p in points]
|
||||
dx = x1 - x0
|
||||
y0, y1, y2 = [p[1] for p in points]
|
||||
|
||||
self.update_dot(
|
||||
dot=ds[1],
|
||||
dt=dt,
|
||||
mean_diff=0.5 * (y2 - 2 * y1 + y0) / dx
|
||||
)
|
||||
if ds[0] is dots[0]:
|
||||
self.update_dot(
|
||||
dot=ds[0],
|
||||
dt=dt,
|
||||
mean_diff=(y1 - y0) / dx
|
||||
)
|
||||
elif ds[-1] is dots[-1]:
|
||||
self.update_dot(
|
||||
dot=ds[-1],
|
||||
dt=dt,
|
||||
mean_diff=(y1 - y2) / dx
|
||||
)
|
||||
|
||||
def update_dot(self, dot, dt, mean_diff):
|
||||
dot.shift(mean_diff * self.alpha * dt * UP)
|
||||
|
||||
|
||||
class DiscreteEvolutionPoint25(ShowNewRuleAtDiscreteBoundary):
|
||||
CONFIG = {
|
||||
"step_size": 0.25,
|
||||
"alpha": 0.5,
|
||||
"wait_time": 30,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_axes()
|
||||
self.set_points()
|
||||
self.add_clock()
|
||||
self.let_evolve()
|
||||
|
||||
|
||||
class DiscreteEvolutionPoint1(DiscreteEvolutionPoint25):
|
||||
CONFIG = {
|
||||
"step_size": 0.1,
|
||||
"v_line_config": {
|
||||
"stroke_width": 1,
|
||||
},
|
||||
"wait_time": 30,
|
||||
}
|
||||
|
||||
|
||||
class FlatEdgesForDiscreteEvolution(DiscreteEvolutionPoint1):
|
||||
CONFIG = {
|
||||
"wait_time": 20,
|
||||
"step_size": 0.1,
|
||||
}
|
||||
|
||||
def let_evolve(self):
|
||||
lines = VGroup(*[
|
||||
Line(LEFT, RIGHT)
|
||||
for x in range(2)
|
||||
])
|
||||
lines.set_width(1.5)
|
||||
lines.set_stroke(WHITE, 5, opacity=0.5)
|
||||
lines.add_updater(self.update_lines)
|
||||
|
||||
turn_animation_into_updater(
|
||||
ShowCreation(lines, run_time=2)
|
||||
)
|
||||
self.add(lines)
|
||||
|
||||
super().let_evolve()
|
||||
|
||||
def update_lines(self, lines):
|
||||
dots = self.dots
|
||||
for line, dot in zip(lines, [dots[0], dots[-1]]):
|
||||
line.move_to(dot)
|
||||
|
||||
|
||||
class FlatEdgesForDiscreteEvolutionTinySteps(FlatEdgesForDiscreteEvolution):
|
||||
CONFIG = {
|
||||
"step_size": 0.025,
|
||||
"wait_time": 10,
|
||||
"v_line_class": Line,
|
||||
"v_line_config": {
|
||||
"stroke_opacity": 0.5,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
|
||||
|
||||
class IveHeardOfThis(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
point = VectorizedPoint()
|
||||
point.move_to(3 * RIGHT + 2 * UP)
|
||||
self.student_says(
|
||||
"I've heard\\\\", "of this!",
|
||||
student_index=1,
|
||||
target_mode="hooray",
|
||||
bubble_kwargs={
|
||||
"height": 3,
|
||||
"width": 3,
|
||||
"direction": RIGHT,
|
||||
},
|
||||
run_time=1,
|
||||
)
|
||||
self.change_student_modes(
|
||||
"thinking", "hooray", "thinking",
|
||||
look_at_arg=point,
|
||||
added_anims=[self.teacher.change, "happy"]
|
||||
)
|
||||
self.wait(3)
|
||||
self.student_says(
|
||||
"But who\\\\", "cares?",
|
||||
student_index=1,
|
||||
target_mode="maybe",
|
||||
bubble_kwargs={
|
||||
"direction": RIGHT,
|
||||
"width": 3,
|
||||
"height": 3,
|
||||
},
|
||||
run_time=1,
|
||||
)
|
||||
self.change_student_modes(
|
||||
"pondering", "maybe", "pondering",
|
||||
look_at_arg=point,
|
||||
added_anims=[self.teacher.change, "guilty"]
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class InFouriersShoes(PiCreatureScene, WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
randy = self.pi_creature
|
||||
fourier = ImageMobject("Joseph Fourier")
|
||||
fourier.set_height(4)
|
||||
fourier.next_to(randy, RIGHT, LARGE_BUFF)
|
||||
fourier.align_to(randy, DOWN)
|
||||
|
||||
equation = self.get_d1_equation()
|
||||
equation.next_to(fourier, UP, MED_LARGE_BUFF)
|
||||
|
||||
decades = list(range(1740, 2040, 20))
|
||||
time_line = NumberLine(
|
||||
x_min=decades[0],
|
||||
x_max=decades[-1],
|
||||
tick_frequency=1,
|
||||
tick_size=0.05,
|
||||
longer_tick_multiple=4,
|
||||
unit_size=0.2,
|
||||
numbers_with_elongated_ticks=decades,
|
||||
numbers_to_show=decades,
|
||||
decimal_number_config={
|
||||
"group_with_commas": False,
|
||||
},
|
||||
stroke_width=2,
|
||||
)
|
||||
time_line.add_numbers()
|
||||
time_line.move_to(ORIGIN, RIGHT)
|
||||
time_line.to_edge(UP)
|
||||
triangle = ArrowTip(start_angle=-90 * DEGREES)
|
||||
triangle.set_height(0.25)
|
||||
triangle.move_to(time_line.n2p(2019), DOWN)
|
||||
triangle.set_color(WHITE)
|
||||
|
||||
self.play(FadeInFrom(fourier, 2 * LEFT))
|
||||
self.play(randy.change, "pondering")
|
||||
self.wait()
|
||||
self.play(
|
||||
DrawBorderThenFill(triangle, run_time=1),
|
||||
FadeInFromDown(equation),
|
||||
FadeIn(time_line),
|
||||
)
|
||||
self.play(
|
||||
Animation(triangle),
|
||||
ApplyMethod(
|
||||
time_line.shift,
|
||||
time_line.n2p(2019) - time_line.n2p(1822),
|
||||
run_time=5
|
||||
),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class SineCurveIsUnrealistic(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"But that would\\\\never happen!",
|
||||
student_index=1,
|
||||
bubble_kwargs={
|
||||
"direction": RIGHT,
|
||||
"height": 3,
|
||||
"width": 4,
|
||||
},
|
||||
target_mode="angry"
|
||||
)
|
||||
self.change_student_modes(
|
||||
"guilty", "angry", "hesitant",
|
||||
added_anims=[
|
||||
self.teacher.change, "tease"
|
||||
]
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(
|
||||
RemovePiCreatureBubble(self.students[1]),
|
||||
self.teacher.change, "raise_right_hand"
|
||||
)
|
||||
self.change_all_student_modes(
|
||||
"pondering",
|
||||
look_at_arg=3 * UP,
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class IfOnly(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says(
|
||||
"If only!",
|
||||
target_mode="angry"
|
||||
)
|
||||
self.change_all_student_modes(
|
||||
"confused",
|
||||
look_at_arg=self.screen
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class SoWeGotNowhere(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"So we've gotten\\\\nowhere!",
|
||||
target_mode="angry",
|
||||
added_anims=[
|
||||
self.teacher.change, "guilty"
|
||||
]
|
||||
)
|
||||
self.change_all_student_modes("angry")
|
||||
self.wait()
|
||||
text = TexMobject(
|
||||
"&\\text{Actually,}\\\\",
|
||||
"&\\sin\\left({x}\\right)"
|
||||
"e^{-\\alpha {t}}\\\\",
|
||||
"&\\text{isn't far off.}",
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
)
|
||||
text.scale(0.8)
|
||||
self.teacher_says(
|
||||
text,
|
||||
content_introduction_class=FadeIn,
|
||||
bubble_kwargs={
|
||||
"width": 4,
|
||||
"height": 3.5,
|
||||
}
|
||||
)
|
||||
self.change_all_student_modes(
|
||||
"pondering",
|
||||
look_at_arg=self.screen
|
||||
)
|
||||
self.wait(3)
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,919 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
|
||||
|
||||
class ThreeMainObservations(Scene):
|
||||
def construct(self):
|
||||
fourier = ImageMobject("Joseph Fourier")
|
||||
name = TextMobject("Joseph Fourier")
|
||||
name.match_width(fourier)
|
||||
name.next_to(fourier, DOWN, SMALL_BUFF)
|
||||
fourier.add(name)
|
||||
fourier.set_height(5)
|
||||
fourier.to_corner(DR)
|
||||
fourier.shift(LEFT)
|
||||
bubble = ThoughtBubble(
|
||||
direction=RIGHT,
|
||||
height=3,
|
||||
width=4,
|
||||
)
|
||||
bubble.move_tip_to(fourier.get_corner(UL) + 0.5 * DR)
|
||||
|
||||
observations = VGroup(
|
||||
TextMobject(
|
||||
"1)",
|
||||
"Sine = Nice",
|
||||
),
|
||||
TextMobject(
|
||||
"2)",
|
||||
"Linearity"
|
||||
),
|
||||
TextMobject(
|
||||
"3)",
|
||||
"Fourier series"
|
||||
),
|
||||
)
|
||||
# heart = SuitSymbol("hearts")
|
||||
# heart.replace(observations[0][2])
|
||||
# observations[0][2].become(heart)
|
||||
# observations[0][1].add(happiness)
|
||||
# observations[2][2].align_to(
|
||||
# observations[2][1], LEFT,
|
||||
# )
|
||||
|
||||
observations.arrange(
|
||||
DOWN,
|
||||
aligned_edge=LEFT,
|
||||
buff=2 * LARGE_BUFF,
|
||||
)
|
||||
observations.set_height(FRAME_HEIGHT - 2)
|
||||
observations.to_corner(UL, buff=LARGE_BUFF)
|
||||
|
||||
self.add(fourier)
|
||||
self.play(ShowCreation(bubble))
|
||||
self.wait()
|
||||
self.play(LaggedStart(*[
|
||||
TransformFromCopy(bubble, observation[0])
|
||||
for observation in observations
|
||||
], lag_ratio=0.2))
|
||||
self.play(
|
||||
FadeOut(fourier),
|
||||
FadeOut(bubble),
|
||||
)
|
||||
self.wait()
|
||||
for obs in observations:
|
||||
self.play(FadeInFrom(obs[1], LEFT))
|
||||
self.wait()
|
||||
|
||||
|
||||
class LastChapterWrapper(Scene):
|
||||
def construct(self):
|
||||
full_rect = FullScreenFadeRectangle(
|
||||
fill_color=DARK_GREY,
|
||||
fill_opacity=1,
|
||||
)
|
||||
rect = ScreenRectangle(height=6)
|
||||
rect.set_stroke(WHITE, 2)
|
||||
rect.set_fill(BLACK, 1)
|
||||
title = TextMobject("Last chapter")
|
||||
title.scale(2)
|
||||
title.to_edge(UP)
|
||||
rect.next_to(title, DOWN)
|
||||
|
||||
self.add(full_rect)
|
||||
self.play(
|
||||
FadeIn(rect),
|
||||
Write(title, run_time=2),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ThreeConstraints(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
self.cross_out_solving()
|
||||
self.show_three_conditions()
|
||||
|
||||
def cross_out_solving(self):
|
||||
equation = self.get_d1_equation()
|
||||
words = TextMobject("Solve this equation")
|
||||
words.to_edge(UP)
|
||||
equation.next_to(words, DOWN)
|
||||
cross = Cross(words)
|
||||
|
||||
self.add(words, equation)
|
||||
self.wait()
|
||||
self.play(ShowCreation(cross))
|
||||
self.wait()
|
||||
|
||||
self.equation = equation
|
||||
self.to_remove = VGroup(words, cross)
|
||||
|
||||
def show_three_conditions(self):
|
||||
equation = self.equation
|
||||
to_remove = self.to_remove
|
||||
|
||||
title = TexMobject(
|
||||
"\\text{Constraints }"
|
||||
"T({x}, {t})"
|
||||
"\\text{ must satisfy:}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
title.to_edge(UP)
|
||||
|
||||
items = VGroup(
|
||||
TextMobject("1)", "The PDE"),
|
||||
TextMobject("2)", "Boundary condition"),
|
||||
TextMobject("3)", "Initial condition"),
|
||||
)
|
||||
items.scale(0.7)
|
||||
items.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
items.set_width(FRAME_WIDTH - 2)
|
||||
items.next_to(title, DOWN, LARGE_BUFF)
|
||||
items[1].set_color(MAROON_B)
|
||||
items[2].set_color(RED)
|
||||
|
||||
bc_paren = TextMobject("(Explained soon)")
|
||||
bc_paren.scale(0.7)
|
||||
bc_paren.next_to(items[1], DOWN)
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(title),
|
||||
FadeOutAndShift(to_remove, UP),
|
||||
equation.scale, 0.6,
|
||||
equation.next_to, items[0], DOWN,
|
||||
equation.shift_onto_screen,
|
||||
LaggedStartMap(FadeIn, [
|
||||
items[0],
|
||||
items[1][0],
|
||||
items[2][0],
|
||||
])
|
||||
)
|
||||
self.wait()
|
||||
self.play(Write(items[1][1]))
|
||||
bc_paren.match_y(equation)
|
||||
self.play(FadeInFrom(bc_paren, UP))
|
||||
self.wait(2)
|
||||
self.play(Write(items[2][1]))
|
||||
self.wait(2)
|
||||
|
||||
self.title = title
|
||||
self.items = items
|
||||
self.pde = equation
|
||||
self.bc_paren = bc_paren
|
||||
|
||||
|
||||
class RectAroundEquation(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
eq = self.get_d1_equation()
|
||||
self.play(ShowCreationThenFadeAround(eq))
|
||||
|
||||
|
||||
class BorderRect(Scene):
|
||||
def construct(self):
|
||||
rect = FullScreenFadeRectangle()
|
||||
rect.set_stroke(WHITE, 3)
|
||||
rect.set_fill(opacity=0)
|
||||
self.add(rect)
|
||||
|
||||
|
||||
class SeekIdealized(Scene):
|
||||
def construct(self):
|
||||
phrases = VGroup(*[
|
||||
TextMobject(
|
||||
"Seek", text, "problems",
|
||||
tex_to_color_map={
|
||||
"realistic": GREEN,
|
||||
"{idealized}": YELLOW,
|
||||
"over-idealized": YELLOW,
|
||||
"general": BLUE,
|
||||
}
|
||||
)
|
||||
for text in [
|
||||
"realistic",
|
||||
"{idealized}",
|
||||
"over-idealized",
|
||||
"general",
|
||||
]
|
||||
])
|
||||
phrases.scale(2)
|
||||
words = VGroup()
|
||||
for phrase in phrases:
|
||||
phrase.center()
|
||||
word = phrase[1]
|
||||
words.add(word)
|
||||
phrase.remove(word)
|
||||
arrow = Vector(DOWN)
|
||||
arrow.set_stroke(WHITE, 6)
|
||||
arrow.next_to(words[3], UP)
|
||||
low_arrow = arrow.copy()
|
||||
low_arrow.next_to(words[3], DOWN)
|
||||
|
||||
solutions = TextMobject("solutions")
|
||||
solutions.scale(2)
|
||||
solutions.move_to(phrases[3][1], UL)
|
||||
models = TextMobject("models")
|
||||
models.scale(2)
|
||||
models.next_to(
|
||||
words[0], RIGHT, buff=0.35,
|
||||
aligned_edge=DOWN
|
||||
)
|
||||
|
||||
phrases.center()
|
||||
phrase = phrases[0]
|
||||
|
||||
self.add(phrase)
|
||||
self.add(words[0])
|
||||
self.wait()
|
||||
words[0].save_state()
|
||||
self.play(
|
||||
words[0].to_edge, DOWN,
|
||||
words[0].set_opacity, 0.5,
|
||||
Transform(phrase, phrases[1]),
|
||||
FadeInFrom(words[1], UP)
|
||||
)
|
||||
self.wait()
|
||||
# self.play(
|
||||
# words[1].move_to, words[2], RIGHT,
|
||||
# FadeIn(words[2]),
|
||||
# Transform(phrase, phrases[2])
|
||||
# )
|
||||
# self.wait()
|
||||
self.play(
|
||||
words[1].next_to, arrow, UP,
|
||||
ShowCreation(arrow),
|
||||
MaintainPositionRelativeTo(
|
||||
phrase, words[1]
|
||||
),
|
||||
FadeInFrom(solutions, LEFT),
|
||||
FadeIn(words[3]),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
words[0].generate_target()
|
||||
words[0].target.next_to(low_arrow, DOWN)
|
||||
words[0].target.set_opacity(1)
|
||||
models.shift(
|
||||
words[0].target.get_center() -
|
||||
words[0].saved_state.get_center()
|
||||
)
|
||||
self.play(
|
||||
MoveToTarget(words[0]),
|
||||
ShowCreation(low_arrow),
|
||||
FadeInFrom(models, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class SecondDerivativeOfSine(Scene):
|
||||
def construct(self):
|
||||
equation = TexMobject(
|
||||
"{d^2 \\over d{x}^2}",
|
||||
"\\cos\\left({x}\\right) =",
|
||||
"-\\cos\\left({x}\\right)",
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
}
|
||||
)
|
||||
|
||||
self.add(equation)
|
||||
|
||||
|
||||
class EquationAboveSineAnalysis(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation()
|
||||
equation.to_edge(UP)
|
||||
equation.shift(2 * LEFT)
|
||||
eq_index = equation.index_of_part_by_tex("=")
|
||||
lhs = equation[:eq_index]
|
||||
eq = equation[eq_index]
|
||||
rhs = equation[eq_index + 1:]
|
||||
t_terms = equation.get_parts_by_tex("{t}")[1:]
|
||||
t_terms.save_state()
|
||||
zeros = VGroup(*[
|
||||
TexMobject("0").replace(t, dim_to_match=1)
|
||||
for t in t_terms
|
||||
])
|
||||
zeros.align_to(t_terms, DOWN)
|
||||
new_rhs = TexMobject(
|
||||
"=", "-\\alpha \\cdot {T}", "({x}, 0)",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
# new_rhs.move_to(equation.get_right())
|
||||
# new_rhs.next_to(equation, DOWN, MED_LARGE_BUFF)
|
||||
# new_rhs.align_to(eq, LEFT)
|
||||
new_rhs.next_to(equation, RIGHT)
|
||||
new_rhs.shift(SMALL_BUFF * DOWN)
|
||||
|
||||
self.add(equation)
|
||||
self.play(ShowCreationThenFadeAround(rhs))
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeOutAndShift(t_terms, UP),
|
||||
FadeInFrom(zeros, DOWN),
|
||||
)
|
||||
t_terms.fade(1)
|
||||
self.wait()
|
||||
self.play(
|
||||
# VGroup(equation, zeros).next_to,
|
||||
# new_rhs, LEFT,
|
||||
FadeIn(new_rhs),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
VGroup(
|
||||
lhs[6:],
|
||||
eq,
|
||||
rhs,
|
||||
new_rhs[0],
|
||||
new_rhs[-3:],
|
||||
zeros,
|
||||
).fade, 0.5,
|
||||
)
|
||||
self.play(ShowCreationThenFadeAround(lhs[:6]))
|
||||
self.play(ShowCreationThenFadeAround(new_rhs[1:-3]))
|
||||
self.wait()
|
||||
|
||||
|
||||
class ExpVideoWrapper(Scene):
|
||||
def construct(self):
|
||||
self.add(FullScreenFadeRectangle(
|
||||
fill_color=DARKER_GREY,
|
||||
fill_opacity=1,
|
||||
))
|
||||
|
||||
screen = ImageMobject("eoc_chapter5_thumbnail")
|
||||
screen.set_height(6)
|
||||
rect = SurroundingRectangle(screen, buff=0)
|
||||
rect.set_stroke(WHITE, 2)
|
||||
screen.add(rect)
|
||||
title = TextMobject("Need a refresher?")
|
||||
title.scale(1.5)
|
||||
title.to_edge(UP)
|
||||
screen.next_to(title, DOWN)
|
||||
|
||||
screen.center()
|
||||
self.play(
|
||||
# FadeInFrom(title, LEFT),
|
||||
FadeInFrom(screen, DOWN),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowSinExpDerivatives(WriteHeatEquationTemplate):
|
||||
CONFIG = {
|
||||
"tex_mobject_config": {
|
||||
"tex_to_color_map": {
|
||||
"{0}": WHITE,
|
||||
"\\partial": WHITE,
|
||||
"=": WHITE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
pde = self.get_d1_equation_without_inputs()
|
||||
pde.to_edge(UP)
|
||||
pde.generate_target()
|
||||
|
||||
new_rhs = TexMobject(
|
||||
"=- \\alpha \\cdot T",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
new_rhs.next_to(pde, RIGHT)
|
||||
new_rhs.align_to(pde.get_part_by_tex("alpha"), DOWN)
|
||||
|
||||
equation1 = TexMobject(
|
||||
"T({x}, {0}) = \\sin\\left({x}\\right)",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
equation2 = TexMobject(
|
||||
"T({x}, {t}) = \\sin\\left({x}\\right)",
|
||||
"e^{-\\alpha{t}}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
for eq in equation1, equation2:
|
||||
eq.next_to(pde, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
eq2_part1 = equation2[:len(equation1)]
|
||||
eq2_part2 = equation2[len(equation1):]
|
||||
|
||||
# Rectangles
|
||||
exp_rect = SurroundingRectangle(eq2_part2)
|
||||
exp_rect.set_stroke(RED, 3)
|
||||
sin_rect = SurroundingRectangle(
|
||||
eq2_part1[-3:]
|
||||
)
|
||||
sin_rect.set_color(BLUE)
|
||||
|
||||
VGroup(pde.target, new_rhs).center().to_edge(UP)
|
||||
|
||||
# Show proposed solution
|
||||
self.add(pde)
|
||||
self.add(equation1)
|
||||
self.wait()
|
||||
self.play(
|
||||
MoveToTarget(pde),
|
||||
FadeInFrom(new_rhs, LEFT)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
ReplacementTransform(equation1, eq2_part1),
|
||||
FadeIn(eq2_part2),
|
||||
)
|
||||
self.play(ShowCreation(exp_rect))
|
||||
self.wait()
|
||||
self.play(FadeOut(exp_rect))
|
||||
|
||||
# Take partial derivatives wrt x
|
||||
q_mark = TexMobject("?")
|
||||
q_mark.next_to(pde.get_part_by_tex("="), UP)
|
||||
q_mark.set_color(RED)
|
||||
|
||||
arrow1 = Vector(3 * DOWN + 1 * RIGHT, color=WHITE)
|
||||
arrow1.scale(1.2 / arrow1.get_length())
|
||||
arrow1.next_to(
|
||||
eq2_part2.get_corner(DL),
|
||||
DOWN, MED_LARGE_BUFF
|
||||
)
|
||||
ddx_label1 = TexMobject(
|
||||
"\\partial \\over \\partial {x}",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
ddx_label1.scale(0.7)
|
||||
ddx_label1.next_to(
|
||||
arrow1.point_from_proportion(0.8),
|
||||
UR, SMALL_BUFF
|
||||
)
|
||||
|
||||
pde_ddx = VGroup(
|
||||
*pde.get_parts_by_tex("\\partial")[2:],
|
||||
pde.get_parts_by_tex("\\over")[1],
|
||||
pde.get_part_by_tex("{x}"),
|
||||
)
|
||||
pde_ddx_rect = SurroundingRectangle(pde_ddx)
|
||||
pde_ddx_rect.set_color(GREEN)
|
||||
|
||||
eq2_part2_rect = SurroundingRectangle(eq2_part2)
|
||||
|
||||
dx = TexMobject(
|
||||
"\\cos\\left({x}\\right)", "e^{-\\alpha {t}}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
ddx = TexMobject(
|
||||
"-\\sin\\left({x}\\right)", "e^{-\\alpha {t}}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
dx.next_to(arrow1, DOWN)
|
||||
dx.align_to(eq2_part2, RIGHT)
|
||||
x_shift = arrow1.get_end()[0] - arrow1.get_start()[0]
|
||||
x_shift *= 2
|
||||
dx.shift(x_shift * RIGHT)
|
||||
arrow2 = arrow1.copy()
|
||||
arrow2.next_to(dx, DOWN)
|
||||
arrow2.shift(MED_SMALL_BUFF * RIGHT)
|
||||
dx_arrows = VGroup(arrow1, arrow2)
|
||||
|
||||
ddx_label2 = ddx_label1.copy()
|
||||
ddx_label2.shift(
|
||||
arrow2.get_center() - arrow1.get_center()
|
||||
)
|
||||
ddx.next_to(arrow2, DOWN)
|
||||
ddx.align_to(eq2_part2, RIGHT)
|
||||
ddx.shift(2 * x_shift * RIGHT)
|
||||
|
||||
rhs = equation2[-6:]
|
||||
|
||||
self.play(
|
||||
FadeInFromDown(q_mark)
|
||||
)
|
||||
self.play(
|
||||
ShowCreation(pde_ddx_rect)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStart(
|
||||
GrowArrow(arrow1),
|
||||
GrowArrow(arrow2),
|
||||
),
|
||||
TransformFromCopy(
|
||||
pde_ddx[0], ddx_label1
|
||||
),
|
||||
TransformFromCopy(
|
||||
pde_ddx[0], ddx_label2
|
||||
),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
TransformFromCopy(rhs, dx)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
FadeIn(eq2_part2_rect)
|
||||
)
|
||||
self.play(
|
||||
Transform(
|
||||
eq2_part2_rect,
|
||||
SurroundingRectangle(dx[-3:])
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
FadeOut(eq2_part2_rect)
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
TransformFromCopy(dx, ddx)
|
||||
)
|
||||
self.play(
|
||||
FadeIn(
|
||||
SurroundingRectangle(ddx).match_style(
|
||||
pde_ddx_rect
|
||||
)
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# Take partial derivative wrt t
|
||||
pde_ddt = pde[:pde.index_of_part_by_tex("=") - 1]
|
||||
pde_ddt_rect = SurroundingRectangle(pde_ddt)
|
||||
|
||||
dt_arrow = Arrow(
|
||||
arrow1.get_start(),
|
||||
arrow2.get_end() + RIGHT,
|
||||
buff=0
|
||||
)
|
||||
dt_arrow.flip(UP)
|
||||
dt_arrow.next_to(dx_arrows, LEFT, MED_LARGE_BUFF)
|
||||
|
||||
dt_label = TexMobject(
|
||||
"\\partial \\over \\partial {t}",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
dt_label.scale(1)
|
||||
dt_label.next_to(
|
||||
dt_arrow.get_center(), UL,
|
||||
SMALL_BUFF,
|
||||
)
|
||||
|
||||
rhs_copy = rhs.copy()
|
||||
rhs_copy.next_to(dt_arrow.get_end(), DOWN)
|
||||
rhs_copy.shift(MED_LARGE_BUFF * LEFT)
|
||||
rhs_copy.match_y(ddx)
|
||||
|
||||
minus_alpha_in_exp = rhs_copy[-3][1:].copy()
|
||||
minus_alpha_in_exp.set_color(RED)
|
||||
minus_alpha = TexMobject("-\\alpha")
|
||||
minus_alpha.next_to(rhs_copy, LEFT)
|
||||
minus_alpha.align_to(rhs_copy[0][0], DOWN)
|
||||
dot = TexMobject("\\cdot")
|
||||
dot.move_to(midpoint(
|
||||
minus_alpha.get_right(),
|
||||
rhs_copy.get_left(),
|
||||
))
|
||||
|
||||
self.play(
|
||||
TransformFromCopy(
|
||||
pde_ddx_rect,
|
||||
pde_ddt_rect,
|
||||
)
|
||||
)
|
||||
self.play(
|
||||
GrowArrow(dt_arrow),
|
||||
TransformFromCopy(
|
||||
pde_ddt,
|
||||
dt_label,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
self.play(TransformFromCopy(rhs, rhs_copy))
|
||||
self.play(FadeIn(minus_alpha_in_exp))
|
||||
self.play(
|
||||
ApplyMethod(
|
||||
minus_alpha_in_exp.replace, minus_alpha,
|
||||
path_arc=TAU / 4
|
||||
),
|
||||
FadeIn(dot),
|
||||
)
|
||||
self.play(
|
||||
FadeIn(minus_alpha),
|
||||
FadeOut(minus_alpha_in_exp),
|
||||
)
|
||||
self.wait()
|
||||
rhs_copy.add(minus_alpha, dot)
|
||||
self.play(
|
||||
FadeIn(SurroundingRectangle(rhs_copy))
|
||||
)
|
||||
self.wait()
|
||||
|
||||
#
|
||||
checkmark = TexMobject("\\checkmark")
|
||||
checkmark.set_color(GREEN)
|
||||
checkmark.move_to(q_mark, DOWN)
|
||||
self.play(
|
||||
FadeInFromDown(checkmark),
|
||||
FadeOutAndShift(q_mark, UP)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class DerivativesOfLinearFunction(WriteHeatEquationTemplate):
|
||||
CONFIG = {
|
||||
"tex_mobject_config": {
|
||||
"tex_to_color_map": {
|
||||
"{c}": WHITE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
func = TexMobject(
|
||||
"T({x}, {t}) = {c} \\cdot {x}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
dx_T = TexMobject("{c}", **self.tex_mobject_config)
|
||||
ddx_T = TexMobject("0")
|
||||
dt_T = TexMobject("0")
|
||||
|
||||
for mob in func, dx_T, ddx_T, dt_T:
|
||||
mob.scale(1.5)
|
||||
|
||||
func.generate_target()
|
||||
|
||||
arrows = VGroup(*[
|
||||
Vector(1.5 * RIGHT, color=WHITE)
|
||||
for x in range(3)
|
||||
])
|
||||
dx_arrows = arrows[:2]
|
||||
dt_arrow = arrows[2]
|
||||
dt_arrow.rotate(-TAU / 4)
|
||||
dx_group = VGroup(
|
||||
func.target,
|
||||
dx_arrows[0],
|
||||
dx_T,
|
||||
dx_arrows[1],
|
||||
ddx_T,
|
||||
)
|
||||
dx_group.arrange(RIGHT)
|
||||
for arrow, char, vect in zip(arrows, "xxt", [UP, UP, RIGHT]):
|
||||
label = TexMobject(
|
||||
"\\partial \\over \\partial {%s}" % char,
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
label.scale(0.7)
|
||||
label.next_to(arrow.get_center(), vect)
|
||||
arrow.add(label)
|
||||
|
||||
dt_arrow.shift(
|
||||
func.target[-3:].get_bottom() + MED_SMALL_BUFF * DOWN -
|
||||
dt_arrow.get_start(),
|
||||
)
|
||||
dt_T.next_to(dt_arrow.get_end(), DOWN)
|
||||
|
||||
self.play(FadeInFromDown(func))
|
||||
self.wait()
|
||||
self.play(
|
||||
MoveToTarget(func),
|
||||
LaggedStartMap(Write, dx_arrows),
|
||||
run_time=1,
|
||||
)
|
||||
self.play(
|
||||
TransformFromCopy(func[-3:], dx_T),
|
||||
path_arc=-TAU / 4,
|
||||
)
|
||||
self.play(
|
||||
TransformFromCopy(dx_T, ddx_T),
|
||||
path_arc=-TAU / 4,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
# dt
|
||||
self.play(Write(dt_arrow))
|
||||
self.play(
|
||||
TransformFromCopy(func[-3:], dt_T)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class FlatAtBoundaryWords(Scene):
|
||||
def construct(self):
|
||||
words = self.get_bc_words()
|
||||
self.play(Write(words))
|
||||
self.wait()
|
||||
|
||||
def get_bc_words(self):
|
||||
return TextMobject(
|
||||
"Flat at boundary\\\\"
|
||||
"for all", "${t}$", "$> 0$",
|
||||
)
|
||||
|
||||
|
||||
class WriteOutBoundaryCondition(FlatAtBoundaryWords, ThreeConstraints, MovingCameraScene):
|
||||
def construct(self):
|
||||
self.force_skipping()
|
||||
ThreeConstraints.construct(self)
|
||||
self.revert_to_original_skipping_status()
|
||||
|
||||
self.add_ic()
|
||||
self.write_bc_words()
|
||||
self.write_bc_equation()
|
||||
|
||||
def add_ic(self):
|
||||
image = ImageMobject("temp_initial_condition_example")
|
||||
image.set_width(3)
|
||||
border = SurroundingRectangle(image, buff=SMALL_BUFF)
|
||||
border.shift(SMALL_BUFF * UP)
|
||||
border.set_stroke(WHITE, 2)
|
||||
group = Group(image, border)
|
||||
group.next_to(self.items[2], DOWN)
|
||||
self.add(group)
|
||||
|
||||
def write_bc_words(self):
|
||||
bc_paren = self.bc_paren
|
||||
bc_words = self.get_bc_words()
|
||||
bc_words.match_width(self.items[1][1])
|
||||
bc_words.move_to(bc_paren, UP)
|
||||
bc_words.set_color_by_tex("{t}", YELLOW)
|
||||
|
||||
self.play(ShowCreationThenFadeAround(
|
||||
VGroup(self.items[0], self.pde)
|
||||
))
|
||||
self.play(
|
||||
FadeOutAndShift(bc_paren, UP),
|
||||
FadeInFrom(bc_words, DOWN),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.bc_words = bc_words
|
||||
|
||||
def write_bc_equation(self):
|
||||
bc_words = self.bc_words
|
||||
|
||||
equation = TexMobject(
|
||||
"{\\partial {T} \\over \\partial {x}}(0, {t}) = ",
|
||||
"{\\partial {T} \\over \\partial {x}}(L, {t}) = ",
|
||||
"0",
|
||||
**self.tex_mobject_config,
|
||||
)
|
||||
equation.next_to(bc_words, DOWN, MED_LARGE_BUFF)
|
||||
|
||||
self.play(
|
||||
self.camera_frame.shift, 0.8 * DOWN,
|
||||
)
|
||||
self.play(FadeInFrom(equation, UP))
|
||||
self.wait()
|
||||
|
||||
|
||||
class HeatEquationFrame(WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
equation = self.get_d1_equation()
|
||||
equation.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
|
||||
ddx = equation[-11:]
|
||||
dt = equation[:11]
|
||||
|
||||
full_rect = FullScreenFadeRectangle(
|
||||
fill_color=DARK_GREY,
|
||||
fill_opacity=1,
|
||||
)
|
||||
smaller_rect = ScreenRectangle(
|
||||
height=6,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=1,
|
||||
stroke_color=WHITE,
|
||||
stroke_width=2,
|
||||
)
|
||||
smaller_rect.next_to(equation, DOWN)
|
||||
|
||||
self.add(full_rect)
|
||||
self.add(smaller_rect)
|
||||
self.add(equation)
|
||||
self.wait()
|
||||
self.play(ShowCreationThenFadeAround(
|
||||
ddx,
|
||||
surrounding_rectangle_config={
|
||||
"stroke_color": GREEN,
|
||||
}
|
||||
))
|
||||
self.wait()
|
||||
self.play(ShowCreationThenFadeAround(dt))
|
||||
self.wait()
|
||||
|
||||
|
||||
class CompareFreqDecays1to2(Scene):
|
||||
CONFIG = {
|
||||
"freqs": [1, 2]
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
background = FullScreenFadeRectangle(
|
||||
fill_color=DARKER_GREY,
|
||||
fill_opacity=1,
|
||||
)
|
||||
|
||||
screens = VGroup(*[
|
||||
ScreenRectangle(
|
||||
height=4,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=1,
|
||||
stroke_width=1,
|
||||
stroke_color=WHITE,
|
||||
)
|
||||
for x in range(2)
|
||||
])
|
||||
screens.arrange(RIGHT)
|
||||
screens.set_width(FRAME_WIDTH - 1)
|
||||
|
||||
formulas = VGroup(*[
|
||||
self.get_formula(freq)
|
||||
for freq in self.freqs
|
||||
])
|
||||
for formula, screen in zip(formulas, screens):
|
||||
formula.next_to(screen, UP)
|
||||
|
||||
self.add(background)
|
||||
self.add(screens)
|
||||
self.add(formulas)
|
||||
self.wait()
|
||||
|
||||
def get_formula(self, freq):
|
||||
f_str = str(freq)
|
||||
return TexMobject(
|
||||
"\\cos\\left(%s \\cdot {x}\\right)" % f_str,
|
||||
"e^{-\\alpha \\cdot %s^2 \\cdot {t}}" % f_str,
|
||||
tex_to_color_map={
|
||||
"{x}": GREEN,
|
||||
"{t}": YELLOW,
|
||||
f_str: MAROON_B,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class CompareFreqDecays1to4(CompareFreqDecays1to2):
|
||||
CONFIG = {
|
||||
"freqs": [1, 4],
|
||||
}
|
||||
|
||||
|
||||
class CompareFreqDecays2to4(CompareFreqDecays1to2):
|
||||
CONFIG = {
|
||||
"freqs": [2, 4],
|
||||
}
|
||||
|
||||
|
||||
class WorryAboutGenerality(TeacherStudentsScene, WriteHeatEquationTemplate):
|
||||
def construct(self):
|
||||
eq = self.get_d1_equation()
|
||||
diffyq = self.get_diffyq_set()
|
||||
is_in = TexMobject("\\in")
|
||||
is_in.scale(2)
|
||||
|
||||
group = VGroup(eq, is_in, diffyq)
|
||||
group.arrange(RIGHT, buff=MED_LARGE_BUFF)
|
||||
group.to_edge(UP)
|
||||
|
||||
arrow = Vector(DOWN)
|
||||
arrow.set_stroke(WHITE, 5)
|
||||
arrow.next_to(eq, DOWN)
|
||||
themes = TextMobject("Frequent themes")
|
||||
themes.scale(1.5)
|
||||
themes.next_to(arrow, DOWN)
|
||||
|
||||
self.play(
|
||||
self.get_student_changes(
|
||||
"sad", "tired", "pleading"
|
||||
),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
FadeInFromDown(eq)
|
||||
)
|
||||
self.play(Write(group[1:]))
|
||||
self.wait(2)
|
||||
self.play(
|
||||
ShowCreation(arrow),
|
||||
self.get_student_changes(*3 * ["pondering"]),
|
||||
)
|
||||
self.play(
|
||||
FadeInFrom(themes, UP),
|
||||
self.get_student_changes(*3 * ["thinking"]),
|
||||
self.teacher.change, "happy"
|
||||
)
|
||||
self.wait(4)
|
||||
|
||||
|
||||
# def get_d1_equation(self):
|
||||
# result = super().get_d1_equation()
|
||||
# lp, rp = parens = TexMobject("(", ")")
|
||||
# parens.match_height(result)
|
||||
# lp.next_to(result, LEFT, SMALL_BUFF)
|
||||
# rp.next_to(result, RIGHT, SMALL_BUFF)
|
||||
# result.add_to_back(lp)
|
||||
# result.add(rp)
|
||||
# return result
|
||||
|
||||
def get_diffyq_set(self):
|
||||
words = TextMobject(
|
||||
"Differential\\\\equations"
|
||||
)
|
||||
words.scale(1.5)
|
||||
words.set_color(BLUE)
|
||||
lb = Brace(words, LEFT)
|
||||
rb = Brace(words, RIGHT)
|
||||
return VGroup(lb, words, rb)
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
|
||||
from active_projects.ode.part2.fourier_series import FourierOfTrebleClef
|
||||
|
||||
|
||||
class ComplexFourierSeriesExample(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"file_name": "EighthNote",
|
||||
"run_time": 10,
|
||||
"n_vectors": 200,
|
||||
"n_cycles": 2,
|
||||
"max_circle_stroke_width": 0.75,
|
||||
"drawing_height": 5,
|
||||
"center_point": DOWN,
|
||||
"top_row_y": 3,
|
||||
"top_row_label_y": 2,
|
||||
"top_row_x_spacing": 1.75,
|
||||
"top_row_copy_scale_factor": 0.9,
|
||||
"start_drawn": False,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_vectors_circles_path()
|
||||
self.add_top_row(self.vectors, self.circles)
|
||||
self.write_title()
|
||||
self.highlight_vectors_one_by_one()
|
||||
self.change_shape()
|
||||
|
||||
def write_title(self):
|
||||
title = TextMobject("Complex\\\\Fourier series")
|
||||
title.scale(1.5)
|
||||
title.to_edge(LEFT)
|
||||
title.match_y(self.path)
|
||||
|
||||
self.wait(5)
|
||||
self.play(FadeInFromDown(title))
|
||||
self.wait(2)
|
||||
self.title = title
|
||||
|
||||
def highlight_vectors_one_by_one(self):
|
||||
# Don't know why these vectors can't get copied.
|
||||
# That seems like a problem that will come up again.
|
||||
labels = self.top_row[-1]
|
||||
next_anims = []
|
||||
for vector, circle, label in zip(self.vectors, self.circles, labels):
|
||||
# v_color = vector.get_color()
|
||||
c_color = circle.get_color()
|
||||
c_stroke_width = circle.get_stroke_width()
|
||||
|
||||
rect = SurroundingRectangle(label, color=PINK)
|
||||
self.play(
|
||||
# vector.set_color, PINK,
|
||||
circle.set_stroke, RED, 3,
|
||||
FadeIn(rect),
|
||||
*next_anims
|
||||
)
|
||||
self.wait()
|
||||
next_anims = [
|
||||
# vector.set_color, v_color,
|
||||
circle.set_stroke, c_color, c_stroke_width,
|
||||
FadeOut(rect),
|
||||
]
|
||||
self.play(*next_anims)
|
||||
|
||||
def change_shape(self):
|
||||
# path_mob = TexMobject("\\pi")
|
||||
path_mob = SVGMobject("Nail_And_Gear")
|
||||
new_path = path_mob.family_members_with_points()[0]
|
||||
new_path.set_height(4)
|
||||
new_path.move_to(self.path, DOWN)
|
||||
new_path.shift(0.5 * UP)
|
||||
new_coefs = self.get_coefficients_of_path(new_path)
|
||||
new_vectors = self.get_rotating_vectors(
|
||||
coefficients=new_coefs
|
||||
)
|
||||
new_drawn_path = self.get_drawn_path(new_vectors)
|
||||
|
||||
self.vector_clock.set_value(0)
|
||||
self.vector_clock.suspend_updating(0)
|
||||
|
||||
vectors = self.vectors
|
||||
anims = []
|
||||
|
||||
for vect, new_vect in zip(vectors, new_vectors):
|
||||
new_vect.update()
|
||||
new_vect.clear_updaters()
|
||||
|
||||
line = Line(stroke_width=0)
|
||||
line.put_start_and_end_on(*vect.get_start_and_end())
|
||||
anims.append(ApplyMethod(
|
||||
line.put_start_and_end_on,
|
||||
*new_vect.get_start_and_end()
|
||||
))
|
||||
vect.freq = new_vect.freq
|
||||
vect.phase = new_vect.phase
|
||||
vect.coefficient = new_vect.coefficient
|
||||
|
||||
vect.line = line
|
||||
vect.add_updater(
|
||||
lambda v: v.put_start_and_end_on(
|
||||
*v.line.get_start_and_end()
|
||||
)
|
||||
)
|
||||
anims += [
|
||||
FadeOut(self.drawn_path)
|
||||
]
|
||||
|
||||
self.play(*anims, run_time=3)
|
||||
self.vector_clock.resume_updating()
|
||||
for vect in self.vectors:
|
||||
vect.remove_updater(vect.updaters[-1])
|
||||
|
||||
self.add(new_drawn_path)
|
||||
for n in range(self.n_cycles):
|
||||
self.run_one_cycle()
|
||||
|
||||
#
|
||||
def get_path(self):
|
||||
path = super().get_path()
|
||||
path.set_height(self.drawing_height)
|
||||
path.to_edge(DOWN)
|
||||
return path
|
||||
|
||||
def add_top_row(self, vectors, circles, max_freq=3):
|
||||
self.top_row = self.get_top_row(
|
||||
vectors, circles, max_freq
|
||||
)
|
||||
self.add(self.top_row)
|
||||
|
||||
def get_top_row(self, vectors, circles, max_freq=3):
|
||||
vector_copies = VGroup()
|
||||
circle_copies = VGroup()
|
||||
for vector, circle in zip(vectors, circles):
|
||||
if vector.freq > max_freq:
|
||||
break
|
||||
vcopy = vector.copy()
|
||||
vcopy.clear_updaters()
|
||||
ccopy = circle.copy()
|
||||
ccopy.clear_updaters()
|
||||
ccopy.original = circle
|
||||
vcopy.original = vector
|
||||
|
||||
vcopy.center_point = np.array([
|
||||
vector.freq * self.top_row_x_spacing,
|
||||
self.top_row_y,
|
||||
0
|
||||
])
|
||||
ccopy.center_point = vcopy.center_point
|
||||
vcopy.add_updater(self.update_top_row_vector_copy)
|
||||
ccopy.add_updater(self.update_top_row_circle_copy)
|
||||
vector_copies.add(vcopy)
|
||||
circle_copies.add(ccopy)
|
||||
|
||||
dots = VGroup(*[
|
||||
TexMobject("\\dots").next_to(
|
||||
circle_copies, direction,
|
||||
MED_LARGE_BUFF,
|
||||
)
|
||||
for direction in [LEFT, RIGHT]
|
||||
])
|
||||
labels = self.get_top_row_labels(vector_copies)
|
||||
return VGroup(
|
||||
vector_copies,
|
||||
circle_copies,
|
||||
dots,
|
||||
labels,
|
||||
)
|
||||
|
||||
def update_top_row_vector_copy(self, vcopy):
|
||||
vcopy.become(vcopy.original)
|
||||
vcopy.scale(self.top_row_copy_scale_factor)
|
||||
vcopy.shift(vcopy.center_point - vcopy.get_start())
|
||||
return vcopy
|
||||
|
||||
def update_top_row_circle_copy(self, ccopy):
|
||||
ccopy.become(ccopy.original)
|
||||
ccopy.scale(self.top_row_copy_scale_factor)
|
||||
ccopy.move_to(ccopy.center_point)
|
||||
return ccopy
|
||||
|
||||
def get_top_row_labels(self, vector_copies):
|
||||
labels = VGroup()
|
||||
for vector_copy in vector_copies:
|
||||
freq = vector_copy.freq
|
||||
label = Integer(freq)
|
||||
label.move_to(np.array([
|
||||
freq * self.top_row_x_spacing,
|
||||
self.top_row_label_y,
|
||||
0
|
||||
]))
|
||||
labels.add(label)
|
||||
return labels
|
||||
|
||||
|
||||
class ComplexFourierSeriesExampleEnd(ExternallyAnimatedScene):
|
||||
pass
|
||||
|
||||
|
||||
class FourierSeriesExampleWithRectForZoom(ComplexFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"n_vectors": 100,
|
||||
"slow_factor": 0.01,
|
||||
"rect_scale_factor": 0.15,
|
||||
"parametric_function_step_size": 0.0001,
|
||||
"start_drawn": True,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_vectors_circles_path()
|
||||
self.circles.set_stroke(opacity=0.5)
|
||||
rect = self.get_rect()
|
||||
rect.set_height(self.rect_scale_factor * FRAME_HEIGHT)
|
||||
rect.add_updater(lambda m: m.move_to(
|
||||
center_of_mass([
|
||||
v.get_end()
|
||||
for v in self.vectors
|
||||
])
|
||||
))
|
||||
self.add(rect)
|
||||
self.run_one_cycle()
|
||||
|
||||
def get_rect(self):
|
||||
return ScreenRectangle(
|
||||
color=WHITE,
|
||||
stroke_width=2,
|
||||
)
|
||||
|
||||
|
||||
class ZoomedInFourierSeriesExample(FourierSeriesExampleWithRectForZoom, MovingCameraScene):
|
||||
CONFIG = {
|
||||
"vector_config": {
|
||||
"max_tip_length_to_length_ratio": 0.15,
|
||||
"tip_length": 0.05,
|
||||
}
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
ComplexFourierSeriesExample.setup(self)
|
||||
MovingCameraScene.setup(self)
|
||||
|
||||
def get_rect(self):
|
||||
return self.camera_frame
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
|
||||
|
||||
class WhyWouldYouCare(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"Who cares!",
|
||||
target_mode="sassy",
|
||||
student_index=2,
|
||||
added_anims=[self.teacher.change, "guilty"],
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
RemovePiCreatureBubble(self.students[2]),
|
||||
self.teacher.change, "raise_right_hand",
|
||||
self.get_student_changes(
|
||||
"pondering", "erm", "thinking",
|
||||
look_at_arg=self.screen,
|
||||
)
|
||||
)
|
||||
self.look_at(self.screen)
|
||||
self.wait(5)
|
||||
|
|
@ -1,345 +0,0 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part3.temperature_graphs import TemperatureGraphScene
|
||||
from active_projects.ode.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
|
||||
|
||||
class RelationToOtherVideos(Scene):
|
||||
CONFIG = {
|
||||
"camera_config": {
|
||||
"background_color": DARK_GREY,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
# Show three videos
|
||||
videos = self.get_video_thumbnails()
|
||||
brace = Brace(videos, UP)
|
||||
text = TextMobject("Heat equation")
|
||||
text.scale(2)
|
||||
text.next_to(brace, UP)
|
||||
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
FadeInFrom, videos,
|
||||
lambda m: (m, LEFT),
|
||||
lag_ratio=0.4,
|
||||
run_time=2,
|
||||
),
|
||||
GrowFromCenter(brace),
|
||||
FadeInFromDown(text),
|
||||
)
|
||||
self.wait()
|
||||
group = Group(text, brace, videos)
|
||||
|
||||
# Show Fourier thinking
|
||||
fourier = ImageMobject("Joseph Fourier")
|
||||
fourier.set_height(4)
|
||||
fourier.to_edge(RIGHT)
|
||||
group.generate_target()
|
||||
group.target.to_edge(DOWN)
|
||||
fourier.align_to(group.target[0], DOWN)
|
||||
bubble = ThoughtBubble(
|
||||
direction=RIGHT,
|
||||
width=3,
|
||||
height=2,
|
||||
fill_opacity=0.5,
|
||||
stroke_color=WHITE,
|
||||
)
|
||||
bubble[-1].shift(0.25 * DOWN + 0.5 * LEFT)
|
||||
bubble[:-1].rotate(20 * DEGREES)
|
||||
for mob in bubble[:-1]:
|
||||
mob.rotate(-20 * DEGREES)
|
||||
bubble.move_tip_to(
|
||||
fourier.get_corner(UL) + DOWN
|
||||
)
|
||||
bubble.to_edge(UP, buff=SMALL_BUFF)
|
||||
|
||||
self.play(
|
||||
MoveToTarget(group),
|
||||
FadeInFrom(fourier, LEFT)
|
||||
)
|
||||
self.play(Write(bubble, run_time=1))
|
||||
self.wait()
|
||||
|
||||
# Discount first two
|
||||
first_two = videos[:2]
|
||||
first_two.generate_target()
|
||||
first_two.target.scale(0.5)
|
||||
first_two.target.to_corner(DL)
|
||||
new_brace = Brace(first_two.target, UP)
|
||||
|
||||
self.play(
|
||||
# fourier.scale, 0.8,
|
||||
fourier.match_x, new_brace,
|
||||
fourier.to_edge, UP,
|
||||
MoveToTarget(first_two),
|
||||
Transform(brace, new_brace),
|
||||
text.scale, 0.7,
|
||||
text.next_to, new_brace, UP,
|
||||
FadeOutAndShift(bubble, LEFT),
|
||||
)
|
||||
self.play(
|
||||
videos[2].scale, 1.7,
|
||||
videos[2].to_corner, UR,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
#
|
||||
def get_video_thumbnails(self):
|
||||
thumbnails = Group(
|
||||
ImageMobject("diffyq_part2_thumbnail"),
|
||||
ImageMobject("diffyq_part3_thumbnail"),
|
||||
ImageMobject("diffyq_part4_thumbnail"),
|
||||
)
|
||||
for thumbnail in thumbnails:
|
||||
thumbnail.set_height(4)
|
||||
thumbnail.add(SurroundingRectangle(
|
||||
thumbnail,
|
||||
color=WHITE,
|
||||
stroke_width=2,
|
||||
buff=0
|
||||
))
|
||||
thumbnails.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
thumbnails.set_width(FRAME_WIDTH - 1)
|
||||
return thumbnails
|
||||
|
||||
|
||||
class ShowLinearity(WriteHeatEquationTemplate, TemperatureGraphScene):
|
||||
CONFIG = {
|
||||
"temp_text": "Temp",
|
||||
"alpha": 0.1,
|
||||
"axes_config": {
|
||||
"z_max": 2,
|
||||
"z_min": -2,
|
||||
"z_axis_config": {
|
||||
"tick_frequency": 0.5,
|
||||
"unit_size": 1.5,
|
||||
},
|
||||
},
|
||||
"default_surface_config": {
|
||||
"resolution": (16, 16)
|
||||
# "resolution": (4, 4)
|
||||
},
|
||||
"freqs": [2, 5],
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
TemperatureGraphScene.setup(self)
|
||||
WriteHeatEquationTemplate.setup(self)
|
||||
|
||||
def construct(self):
|
||||
self.init_camera()
|
||||
self.add_three_graphs()
|
||||
self.show_words()
|
||||
self.add_function_labels()
|
||||
self.change_scalars()
|
||||
|
||||
def init_camera(self):
|
||||
self.camera.set_distance(1000)
|
||||
|
||||
def add_three_graphs(self):
|
||||
axes_group = self.get_axes_group()
|
||||
axes0, axes1, axes2 = axes_group
|
||||
freqs = self.freqs
|
||||
scalar_trackers = Group(
|
||||
ValueTracker(1),
|
||||
ValueTracker(1),
|
||||
)
|
||||
graphs = VGroup(
|
||||
self.get_graph(axes0, [freqs[0]], [scalar_trackers[0]]),
|
||||
self.get_graph(axes1, [freqs[1]], [scalar_trackers[1]]),
|
||||
self.get_graph(axes2, freqs, scalar_trackers),
|
||||
)
|
||||
|
||||
plus = TexMobject("+").scale(2)
|
||||
equals = TexMobject("=").scale(2)
|
||||
plus.move_to(midpoint(
|
||||
axes0.get_right(),
|
||||
axes1.get_left(),
|
||||
))
|
||||
equals.move_to(midpoint(
|
||||
axes1.get_right(),
|
||||
axes2.get_left(),
|
||||
))
|
||||
|
||||
self.add(axes_group)
|
||||
self.add(graphs)
|
||||
self.add(plus)
|
||||
self.add(equals)
|
||||
|
||||
self.axes_group = axes_group
|
||||
self.graphs = graphs
|
||||
self.scalar_trackers = scalar_trackers
|
||||
self.plus = plus
|
||||
self.equals = equals
|
||||
|
||||
def show_words(self):
|
||||
equation = self.get_d1_equation()
|
||||
name = TextMobject("Heat equation")
|
||||
name.next_to(equation, DOWN)
|
||||
name.set_color_by_gradient(RED, YELLOW)
|
||||
group = VGroup(equation, name)
|
||||
group.to_edge(UP)
|
||||
|
||||
shift_val = 0.5 * RIGHT
|
||||
|
||||
arrow = Vector(1.5 * RIGHT)
|
||||
arrow.move_to(group)
|
||||
arrow.shift(shift_val)
|
||||
linear_word = TextMobject("``Linear''")
|
||||
linear_word.scale(2)
|
||||
linear_word.next_to(arrow, RIGHT)
|
||||
|
||||
self.add(group)
|
||||
self.wait()
|
||||
self.play(
|
||||
ShowCreation(arrow),
|
||||
group.next_to, arrow, LEFT
|
||||
)
|
||||
self.play(FadeInFrom(linear_word, LEFT))
|
||||
self.wait()
|
||||
|
||||
def add_function_labels(self):
|
||||
axes_group = self.axes_group
|
||||
graphs = self.graphs
|
||||
|
||||
solution_labels = VGroup()
|
||||
for axes in axes_group:
|
||||
label = TextMobject("Solution", "$\\checkmark$")
|
||||
label.set_color_by_tex("checkmark", GREEN)
|
||||
label.next_to(axes, DOWN)
|
||||
solution_labels.add(label)
|
||||
|
||||
kw = {
|
||||
"tex_to_color_map": {
|
||||
"T_1": BLUE,
|
||||
"T_2": GREEN,
|
||||
}
|
||||
}
|
||||
T1 = TexMobject("a", "T_1", **kw)
|
||||
T2 = TexMobject("b", "T_2", **kw)
|
||||
T_sum = TexMobject("T_1", "+", "T_2", **kw)
|
||||
T_sum_with_scalars = TexMobject(
|
||||
"a", "T_1", "+", "b", "T_2", **kw
|
||||
)
|
||||
|
||||
T1.next_to(graphs[0], UP)
|
||||
T2.next_to(graphs[1], UP)
|
||||
T_sum.next_to(graphs[2], UP)
|
||||
T_sum.shift(SMALL_BUFF * DOWN)
|
||||
T_sum_with_scalars.move_to(T_sum)
|
||||
|
||||
a_brace = Brace(T1[0], UP, buff=SMALL_BUFF)
|
||||
b_brace = Brace(T2[0], UP, buff=SMALL_BUFF)
|
||||
s1_decimal = DecimalNumber()
|
||||
s1_decimal.match_color(T1[1])
|
||||
s1_decimal.next_to(a_brace, UP, SMALL_BUFF)
|
||||
s1_decimal.add_updater(lambda m: m.set_value(
|
||||
self.scalar_trackers[0].get_value()
|
||||
))
|
||||
s2_decimal = DecimalNumber()
|
||||
s2_decimal.match_color(T2[1])
|
||||
s2_decimal.next_to(b_brace, UP, SMALL_BUFF)
|
||||
s2_decimal.add_updater(lambda m: m.set_value(
|
||||
self.scalar_trackers[1].get_value()
|
||||
))
|
||||
|
||||
self.play(
|
||||
FadeInFrom(T1[1], DOWN),
|
||||
FadeInFrom(solution_labels[0], UP),
|
||||
)
|
||||
self.play(
|
||||
FadeInFrom(T2[1], DOWN),
|
||||
FadeInFrom(solution_labels[1], UP),
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
TransformFromCopy(T1[1], T_sum[0]),
|
||||
TransformFromCopy(T2[1], T_sum[2]),
|
||||
TransformFromCopy(self.plus, T_sum[1]),
|
||||
*[
|
||||
Transform(
|
||||
graph.copy().set_fill(opacity=0),
|
||||
graphs[2].copy().set_fill(opacity=0),
|
||||
remover=True
|
||||
)
|
||||
for graph in graphs[:2]
|
||||
]
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeInFrom(solution_labels[2], UP))
|
||||
self.wait()
|
||||
|
||||
# Show constants
|
||||
self.play(
|
||||
FadeIn(T1[0]),
|
||||
FadeIn(T2[0]),
|
||||
FadeIn(a_brace),
|
||||
FadeIn(b_brace),
|
||||
FadeIn(s1_decimal),
|
||||
FadeIn(s2_decimal),
|
||||
FadeOut(T_sum),
|
||||
FadeIn(T_sum_with_scalars),
|
||||
)
|
||||
|
||||
def change_scalars(self):
|
||||
s1, s2 = self.scalar_trackers
|
||||
|
||||
kw = {
|
||||
"run_time": 2,
|
||||
}
|
||||
for graph in self.graphs:
|
||||
graph.resume_updating()
|
||||
self.play(s2.set_value, -0.5, **kw)
|
||||
self.play(s1.set_value, -0.2, **kw)
|
||||
self.play(s2.set_value, 1.5, **kw)
|
||||
self.play(s1.set_value, 1.2)
|
||||
self.play(s2.set_value, 0.3)
|
||||
self.wait()
|
||||
|
||||
#
|
||||
def get_axes_group(self):
|
||||
axes_group = VGroup(*[
|
||||
self.get_axes()
|
||||
for x in range(3)
|
||||
])
|
||||
axes_group.arrange(RIGHT, buff=2)
|
||||
axes_group.set_width(FRAME_WIDTH - 1)
|
||||
axes_group.to_edge(DOWN, buff=1)
|
||||
return axes_group
|
||||
|
||||
def get_axes(self):
|
||||
axes = self.get_three_d_axes()
|
||||
# axes.input_plane.set_fill(opacity=0)
|
||||
# axes.input_plane.set_stroke(width=0.5)
|
||||
# axes.add(axes.input_plane)
|
||||
self.orient_three_d_mobject(axes)
|
||||
axes.rotate(-5 * DEGREES, UP)
|
||||
axes.set_width(4)
|
||||
axes.x_axis.label.next_to(
|
||||
axes.x_axis.get_end(), DOWN,
|
||||
buff=2 * SMALL_BUFF
|
||||
)
|
||||
return axes
|
||||
|
||||
def get_graph(self, axes, freqs, scalar_trackers):
|
||||
L = axes.x_max
|
||||
a = self.alpha
|
||||
|
||||
def func(x, t):
|
||||
scalars = [st.get_value() for st in scalar_trackers]
|
||||
return np.sum([
|
||||
s * np.cos(k * x) * np.exp(-a * (k**2) * t)
|
||||
for freq, s in zip(freqs, scalars)
|
||||
for k in [freq * PI / L]
|
||||
])
|
||||
|
||||
def get_surface_graph_group():
|
||||
return VGroup(
|
||||
self.get_surface(axes, func),
|
||||
self.get_time_slice_graph(axes, func, t=0),
|
||||
)
|
||||
|
||||
result = always_redraw(get_surface_graph_group)
|
||||
result.suspend_updating()
|
||||
return result
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Add table
Reference in a new issue