mirror of
https://github.com/3b1b/manim.git
synced 2025-08-02 11:03:03 +08:00
Final animations for de chapter2
This commit is contained in:
@ -5,7 +5,7 @@ from active_projects.ode.part1.phase_space import *
|
||||
from active_projects.ode.part1.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part1"
|
||||
ALL_SCENE_CLASSES = [
|
||||
SCENES_IN_ORDER = [
|
||||
WhenChangeIsEasier,
|
||||
VectorFieldTest,
|
||||
IntroducePendulum,
|
||||
|
@ -5,33 +5,24 @@ from active_projects.ode.part2.pi_scenes import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part2"
|
||||
ALL_SCENE_CLASSES = [
|
||||
# Tests
|
||||
FourierOfPiSymbol,
|
||||
FourierOfPiSymbol5,
|
||||
FourierOfTrebleClef,
|
||||
FourierOfEighthNote,
|
||||
FourierOfN,
|
||||
FourierNailAndGear,
|
||||
FourierNDQ,
|
||||
FourierBatman,
|
||||
FourierGoogleG,
|
||||
FourierHeart,
|
||||
# CirclesDrawingWave,
|
||||
# Scenes for video
|
||||
ExplainCircleAnimations,
|
||||
FourierSeriesIntroBackground4,
|
||||
FourierSeriesIntroBackground8,
|
||||
FourierSeriesIntroBackground12,
|
||||
FourierSeriesIntroBackground20,
|
||||
FourierSeriesIntro,
|
||||
SCENES_IN_ORDER = [
|
||||
PartTwoOfTour,
|
||||
HeatEquationIntroTitle,
|
||||
BrownianMotion,
|
||||
BlackScholes,
|
||||
ContrastChapters1And2,
|
||||
FourierSeriesIntro,
|
||||
FourierSeriesIntroBackground20,
|
||||
ExplainCircleAnimations,
|
||||
# FourierSeriesIntroBackground4,
|
||||
# FourierSeriesIntroBackground8,
|
||||
# FourierSeriesIntroBackground12,
|
||||
TwoDBodyWithManyTemperatures,
|
||||
TwoDBodyWithManyTemperaturesGraph,
|
||||
TwoDBodyWithManyTemperaturesContour,
|
||||
BringTwoRodsTogether,
|
||||
ShowEvolvingTempGraphWithArrows,
|
||||
TodaysTargetWrapper,
|
||||
# TodaysTargetWrapper,
|
||||
WriteHeatEquation,
|
||||
ReactionsToInitialHeatEquation,
|
||||
TalkThrough1DHeatGraph,
|
||||
@ -39,8 +30,12 @@ ALL_SCENE_CLASSES = [
|
||||
CompareInputsOfGeneralCaseTo1D,
|
||||
ContrastXChangesToTChanges,
|
||||
ShowPartialDerivativeSymbols,
|
||||
WriteHeatEquation,
|
||||
ShowCurvatureToRateOfChangeIntuition,
|
||||
ContrastPDEToODE,
|
||||
TransitionToTempVsTime,
|
||||
ShowNewton,
|
||||
ShowCupOfWater,
|
||||
ShowNewtonsLawGraph,
|
||||
Show1DAnd3DEquations,
|
||||
#
|
||||
AskAboutWhereEquationComesFrom,
|
||||
DiscreteSetup,
|
||||
]
|
||||
|
@ -108,6 +108,7 @@ class TourOfDifferentialEquations(MovingCameraScene):
|
||||
def construct(self):
|
||||
self.add_title()
|
||||
self.show_thumbnails()
|
||||
self.zoom_in_to_one_thumbnail()
|
||||
# self.show_words()
|
||||
|
||||
def add_title(self):
|
||||
@ -166,9 +167,13 @@ class TourOfDifferentialEquations(MovingCameraScene):
|
||||
)
|
||||
self.play(Write(dots))
|
||||
self.wait()
|
||||
|
||||
self.thumbnails = thumbnails
|
||||
|
||||
def zoom_in_to_one_thumbnail(self):
|
||||
self.play(
|
||||
self.camera_frame.replace,
|
||||
thumbnails[self.zoomed_thumbnail_index],
|
||||
self.thumbnails[self.zoomed_thumbnail_index],
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
|
@ -185,7 +185,7 @@ class ReasonForSolution(Scene):
|
||||
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)
|
||||
# words = VGroup(eq_word, s_word, u_word, c_word)
|
||||
|
||||
# Arrows
|
||||
arrows = VGroup(
|
||||
|
@ -367,6 +367,33 @@ class FourierOfTrebleClef(FourierOfPiSymbol):
|
||||
return path
|
||||
|
||||
|
||||
class FourierOfIP(FourierOfTrebleClef):
|
||||
CONFIG = {
|
||||
"file_name": "IP_logo2",
|
||||
"height": 6,
|
||||
"n_circles": 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"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
||||
from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
|
||||
|
||||
class ReactionsToInitialHeatEquation(PiCreatureScene):
|
||||
@ -19,5 +20,123 @@ class ReactionsToInitialHeatEquation(PiCreatureScene):
|
||||
point.next_to, randy, UR, LARGE_BUFF,
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(point.shift, 2 * DOWN)
|
||||
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)
|
||||
|
@ -2,92 +2,376 @@ from big_ol_pile_of_manim_imports import *
|
||||
from active_projects.ode.part1.staging import TourOfDifferentialEquations
|
||||
|
||||
|
||||
class FourierSeriesIntro(Scene):
|
||||
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")
|
||||
physics.scale(title_scale_value)
|
||||
arrow = Arrow(LEFT, RIGHT)
|
||||
group = VGroup(physics, arrow, 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))
|
||||
heat = TextMobject("Heat")
|
||||
heat.scale(title_scale_value)
|
||||
heat.move_to(physics[0][-1], DR)
|
||||
|
||||
def update_heat_colors(heat):
|
||||
vertices = rot_square.get_vertices()
|
||||
letters = heat.family_members_with_points()
|
||||
for letter, vertex in zip(letters, vertices):
|
||||
alpha = (normalize(vertex)[0] + 1) / 2
|
||||
letter.set_color(interpolate_color(
|
||||
YELLOW, RED, alpha,
|
||||
))
|
||||
heat.add_updater(update_heat_colors)
|
||||
|
||||
image = ImageMobject("Joseph Fourier")
|
||||
image.set_height(5)
|
||||
image.next_to(title, DOWN, MED_LARGE_BUFF)
|
||||
image.to_edge(LEFT)
|
||||
name = TextMobject("Joseph", "Fourier")
|
||||
name.next_to(image, DOWN)
|
||||
|
||||
# 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.play(
|
||||
FadeInFrom(physics, RIGHT),
|
||||
GrowArrow(arrow),
|
||||
MoveToTarget(title)
|
||||
)
|
||||
self.wait()
|
||||
self.add(rot_square)
|
||||
self.play(
|
||||
FadeOutAndShift(physics, UP),
|
||||
FadeInFromDown(heat, DOWN),
|
||||
)
|
||||
self.wait(10)
|
||||
|
||||
|
||||
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):
|
||||
@ -101,6 +385,12 @@ class ShowCubeFormation(ThreeDScene):
|
||||
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)
|
||||
|
||||
@ -121,7 +411,341 @@ class ShowCubeFormation(ThreeDScene):
|
||||
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 ShowNewton(Scene):
|
||||
|
@ -1,6 +1,222 @@
|
||||
from big_ol_pile_of_manim_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
|
||||
@ -11,11 +227,33 @@ class TodaysTargetWrapper(Scene):
|
||||
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}": PINK,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
d_derivs, del_derivs = VGroup(*[
|
||||
VGroup(*[
|
||||
@ -94,6 +332,7 @@ class ShowPartialDerivativeSymbols(Scene):
|
||||
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))
|
||||
@ -110,19 +349,90 @@ class ShowPartialDerivativeSymbols(Scene):
|
||||
self.wait()
|
||||
|
||||
|
||||
class WriteHeatEquation(Scene):
|
||||
CONFIG = {
|
||||
"tex_mobject_config": {
|
||||
"tex_to_color_map": {
|
||||
"{T}": YELLOW,
|
||||
"{t}": WHITE,
|
||||
"{x}": GREEN,
|
||||
"{y}": RED,
|
||||
"{z}": BLUE,
|
||||
},
|
||||
},
|
||||
}
|
||||
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()
|
||||
@ -132,10 +442,10 @@ class WriteHeatEquation(Scene):
|
||||
groups = VGroup(d1_group, d3_group)
|
||||
for group in groups:
|
||||
group.arrange(DOWN, buff=MED_LARGE_BUFF)
|
||||
groups.arrange(RIGHT, buff=2)
|
||||
groups.arrange(RIGHT, buff=1.5)
|
||||
groups.to_edge(UP)
|
||||
|
||||
d3_rhs = d3_equation[6:]
|
||||
d3_rhs = d3_equation[9:-2]
|
||||
d3_brace = Brace(d3_rhs, DOWN)
|
||||
nabla_words = TextMobject("Sometimes written as")
|
||||
nabla_words.match_width(d3_brace)
|
||||
@ -169,55 +479,31 @@ class WriteHeatEquation(Scene):
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def get_d1_equation(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}}({x}, {t})="
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2} ({x}, {t})",
|
||||
**self.tex_mobject_config
|
||||
|
||||
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,
|
||||
}
|
||||
)
|
||||
|
||||
def get_d3_equation(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}} = ",
|
||||
"{\\partial^2 {T} \\over \\partial {x}^2} + ",
|
||||
"{\\partial^2 {T} \\over \\partial {y}^2} + ",
|
||||
"{\\partial^2 {T} \\over \\partial {z}^2}",
|
||||
**self.tex_mobject_config
|
||||
)
|
||||
|
||||
def get_d3_equation_with_inputs(self):
|
||||
return TexMobject(
|
||||
"{\\partial {T} \\over \\partial {t}} = ",
|
||||
"{\\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)",
|
||||
**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
|
||||
self.add(formula)
|
||||
|
||||
|
||||
class CompareInputsOfGeneralCaseTo1D(WriteHeatEquation):
|
||||
@ -252,3 +538,248 @@ class CompareInputsOfGeneralCaseTo1D(WriteHeatEquation):
|
||||
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",
|
||||
],
|
||||
}
|
||||
|
Reference in New Issue
Block a user