Rename ode folder to diffyq

This commit is contained in:
Grant Sanderson 2019-06-19 16:11:46 -07:00
parent 96e34b969c
commit 2e0e5cfb5e
26 changed files with 0 additions and 20516 deletions

View file

@ -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,
]

View file

@ -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,
]

View file

@ -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,
]

View file

@ -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,
]

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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",
]
}

View file

@ -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

View file

@ -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)

View file

@ -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),
]
])

View file

@ -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

View file

@ -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",
],
}

View file

@ -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,
}
}

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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