mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 22:57:44 +00:00
commit
c7e6d9d474
41 changed files with 7970 additions and 470 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,6 +7,7 @@ cairo_test.py
|
|||
mayavi_test.py
|
||||
random_scenes/
|
||||
files/
|
||||
assets/
|
||||
ben_playground.py
|
||||
ben_cairo_test.py
|
||||
.floo
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
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 *
|
||||
from active_projects.diffyq.part1.pendulum import *
|
||||
from active_projects.diffyq.part1.staging import *
|
||||
from active_projects.diffyq.part1.pi_scenes import *
|
||||
from active_projects.diffyq.part1.phase_space import *
|
||||
from active_projects.diffyq.part1.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part1"
|
||||
OUTPUT_DIRECTORY = "diffyq/part1"
|
||||
SCENES_IN_ORDER = [
|
||||
WhenChangeIsEasier,
|
||||
VectorFieldTest,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
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 *
|
||||
from active_projects.diffyq.part2.staging import *
|
||||
from active_projects.diffyq.part2.fourier_series import *
|
||||
from active_projects.diffyq.part2.heat_equation import *
|
||||
from active_projects.diffyq.part2.pi_scenes import *
|
||||
from active_projects.diffyq.part2.wordy_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part2"
|
||||
OUTPUT_DIRECTORY = "diffyq/part2"
|
||||
SCENES_IN_ORDER = [
|
||||
PartTwoOfTour,
|
||||
HeatEquationIntroTitle,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
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 *
|
||||
from active_projects.diffyq.part3.staging import *
|
||||
from active_projects.diffyq.part3.temperature_graphs import *
|
||||
from active_projects.diffyq.part3.pi_creature_scenes import *
|
||||
from active_projects.diffyq.part3.wordy_scenes import *
|
||||
from active_projects.diffyq.part3.discrete_case import *
|
||||
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part3"
|
||||
OUTPUT_DIRECTORY = "diffyq/part3"
|
||||
SCENES_IN_ORDER = [
|
||||
LastChapterWrapper,
|
||||
ThreeConstraints,
|
||||
|
|
|
|||
|
|
@ -1,17 +1,64 @@
|
|||
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 *
|
||||
from active_projects.diffyq.part4.staging import *
|
||||
from active_projects.diffyq.part4.fourier_series_scenes import *
|
||||
from active_projects.diffyq.part4.pi_creature_scenes import *
|
||||
from active_projects.diffyq.part4.three_d_graphs import *
|
||||
from active_projects.diffyq.part4.temperature_scenes import *
|
||||
from active_projects.diffyq.part4.complex_functions import *
|
||||
from active_projects.diffyq.part4.long_fourier_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "ode/part4"
|
||||
from active_projects.diffyq.part3.staging import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part4"
|
||||
SCENES_IN_ORDER = [
|
||||
ComplexFourierSeriesExample,
|
||||
ComplexFourierSeriesExampleEnd,
|
||||
FourierSeriesExampleWithRectForZoom,
|
||||
ZoomedInFourierSeriesExample,
|
||||
FourierOfFourier,
|
||||
FourierOfFourierZoomedIn,
|
||||
FourierOfFourier100xZoom,
|
||||
FourierSeriesFormula,
|
||||
RelationToOtherVideos,
|
||||
WhyWouldYouCare,
|
||||
# Oldies
|
||||
ShowLinearity,
|
||||
CombineSeveralSolutions,
|
||||
FourierGainsImmortality,
|
||||
SolveForWavesNothingElse,
|
||||
CycleThroughManyLinearCombinations,
|
||||
StepFunctionExample,
|
||||
WhichWavesAreAvailable,
|
||||
AlternateBoundaryConditions,
|
||||
AskQuestionOfGraph,
|
||||
CommentOnFouriersImmortality,
|
||||
HangOnThere,
|
||||
ShowInfiniteSum,
|
||||
TechnicalNuances,
|
||||
BreakDownStepFunction,
|
||||
StepFunctionSolutionFormla,
|
||||
# How to compute
|
||||
FourierSeriesOfLineIllustration,
|
||||
GeneralizeToComplexFunctions,
|
||||
ClarifyInputAndOutput,
|
||||
GraphForFlattenedPi,
|
||||
PiFourierSeries,
|
||||
RealValuedFunctionFourierSeries,
|
||||
YouSaidThisWasEasier,
|
||||
AskAboutComplexNotVector,
|
||||
SimpleComplexExponentExample,
|
||||
LooseWithLanguage,
|
||||
DemonstrateAddingArrows,
|
||||
TRangingFrom0To1,
|
||||
LabelRotatingVectors,
|
||||
IntegralTrick,
|
||||
SwapIntegralAndSum,
|
||||
FootnoteOnSwappingIntegralAndSum,
|
||||
FormulaOutOfContext,
|
||||
ShowRangeOfCnFormulas,
|
||||
DescribeSVG,
|
||||
# TODO
|
||||
IncreaseOrderOfApproximation,
|
||||
ShowStepFunctionIn2dView,
|
||||
StepFunctionIntegral,
|
||||
GeneralChallenge,
|
||||
|
||||
# Oldies
|
||||
# FourierSeriesIllustraiton,
|
||||
# FourierNameIntro,
|
||||
# CircleAnimationOfF,
|
||||
|
|
|
|||
5
active_projects/diffyq/all_part5_scenes.py
Normal file
5
active_projects/diffyq/all_part5_scenes.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from active_projects.diffyq.part5.staging import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part5"
|
||||
SCENES_IN_ORDER = [
|
||||
]
|
||||
23
active_projects/diffyq/fourier_montage_scenes.py
Normal file
23
active_projects/diffyq/fourier_montage_scenes.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from active_projects.diffyq.part4.long_fourier_scenes import *
|
||||
|
||||
OUTPUT_DIRECTORY = "diffyq/part4"
|
||||
SCENES_IN_ORDER = [
|
||||
ZoomedInFourierSeriesExample,
|
||||
FourierSeriesExampleWithRectForZoom,
|
||||
ZoomedInFourierSeriesExample100x,
|
||||
FourierOfFourier100xZoom,
|
||||
FourierOfFourierZoomedIn,
|
||||
FourierOfFourier,
|
||||
SigmaZoomedInFourierSeriesExample,
|
||||
SigmaFourierSeriesExampleWithRectForZoom,
|
||||
NailAndGearZoomedInFourierSeriesExample,
|
||||
NailAndGearFourierSeriesExampleWithRectForZoom,
|
||||
TrebleClefZoomedInFourierSeriesExample,
|
||||
TrebleClefFourierSeriesExampleWithRectForZoom,
|
||||
FourierOfSeattle,
|
||||
FourierOfSeattleZoomedIn,
|
||||
FourierOfBritain,
|
||||
FourierOfBritainZoomedIn,
|
||||
FourierOfHilbert,
|
||||
FourierOfHilbertZoomedIn,
|
||||
]
|
||||
|
|
@ -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
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
|
||||
|
||||
class Pendulum(VGroup):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.ode.part1.pendulum import Pendulum
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.pendulum import Pendulum
|
||||
|
||||
|
||||
# TODO: Arguably separate the part showing many
|
||||
|
|
@ -2012,11 +2012,18 @@ class ManyStepsFromDifferentStartingPoints(TakeManyTinySteps):
|
|||
class Thumbnail(IntroduceVectorField):
|
||||
CONFIG = {
|
||||
"vector_field_config": {
|
||||
"delta_x": 0.5,
|
||||
"delta_y": 0.5,
|
||||
# "delta_x": 0.5,
|
||||
# "delta_y": 0.5,
|
||||
# "max_magnitude": 5,
|
||||
# "length_func": lambda norm: 0.5 * sigmoid(norm),
|
||||
"delta_x": 1,
|
||||
"delta_y": 1,
|
||||
"max_magnitude": 5,
|
||||
"length_func": lambda norm: 0.5 * sigmoid(norm),
|
||||
}
|
||||
"length_func": lambda norm: 0.9 * sigmoid(norm),
|
||||
},
|
||||
"big_pendulum_config": {
|
||||
"damping": 0.4,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
|
@ -2027,7 +2034,7 @@ class Thumbnail(IntroduceVectorField):
|
|||
field = self.vector_field
|
||||
field.set_stroke(width=5)
|
||||
for vector in field:
|
||||
vector.set_stroke(width=3)
|
||||
vector.set_stroke(width=8)
|
||||
vector.tip.set_stroke(width=0)
|
||||
vector.tip.scale(1.5, about_point=vector.get_last_point())
|
||||
vector.set_opacity(1)
|
||||
|
|
@ -2063,17 +2070,43 @@ class Thumbnail(IntroduceVectorField):
|
|||
new_mob.set_stroke(width=0)
|
||||
black_parts.add(new_mob)
|
||||
|
||||
for vect in field:
|
||||
for mob in title.family_members_with_points():
|
||||
for p in [vect.get_start(), vect.get_end()]:
|
||||
x, y = p[:2]
|
||||
x0, y0 = mob.get_corner(DL)[:2]
|
||||
x1, y1 = mob.get_corner(UR)[:2]
|
||||
if x0 < x < x1 and y0 < y < y1:
|
||||
vect.set_opacity(0.25)
|
||||
vect.tip.set_stroke(width=0)
|
||||
# for vect in field:
|
||||
# for mob in title.family_members_with_points():
|
||||
# for p in [vect.get_start(), vect.get_end()]:
|
||||
# x, y = p[:2]
|
||||
# x0, y0 = mob.get_corner(DL)[:2]
|
||||
# x1, y1 = mob.get_corner(UR)[:2]
|
||||
# if x0 < x < x1 and y0 < y < y1:
|
||||
# vect.set_opacity(0.25)
|
||||
# vect.tip.set_stroke(width=0)
|
||||
|
||||
self.add(self.plane)
|
||||
self.add(field)
|
||||
self.add(black_parts)
|
||||
self.add(title)
|
||||
# self.add(black_parts)
|
||||
# self.add(title)
|
||||
|
||||
self.add_line(self.plane)
|
||||
|
||||
def add_line(self, axes):
|
||||
func = self.vector_field_func
|
||||
|
||||
line = VMobject()
|
||||
line.start_new_path(axes.c2p(-TAU, 3.5))
|
||||
|
||||
dt = 0.1
|
||||
t = 0
|
||||
total_time = 40
|
||||
|
||||
while t < total_time:
|
||||
t += dt
|
||||
last_point = line.get_last_point()
|
||||
new_point = last_point + dt * func(last_point)
|
||||
if new_point[0] > FRAME_WIDTH / 2:
|
||||
new_point = last_point + FRAME_WIDTH * LEFT
|
||||
line.start_new_path(new_point)
|
||||
else:
|
||||
line.add_smooth_curve_to(new_point)
|
||||
|
||||
line.set_stroke(WHITE, 6)
|
||||
line.make_smooth()
|
||||
self.add(line)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
|
||||
|
||||
class SomeOfYouWatching(TeacherStudentsScene):
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.ode.part1.pendulum import Pendulum
|
||||
from active_projects.ode.part1.pendulum import ThetaVsTAxes
|
||||
from active_projects.ode.part1.phase_space import IntroduceVectorField
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.pendulum import Pendulum
|
||||
from active_projects.diffyq.part1.pendulum import ThetaVsTAxes
|
||||
from active_projects.diffyq.part1.phase_space import IntroduceVectorField
|
||||
from old_projects.div_curl import PhaseSpaceOfPopulationModel
|
||||
from old_projects.div_curl import ShowTwoPopulations
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.shared_constructs import *
|
||||
from active_projects.diffyq.part1.shared_constructs import *
|
||||
|
||||
|
||||
class SmallAngleApproximationTex(Scene):
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ class FourierCirclesScene(Scene):
|
|||
"slow_factor": 0.25,
|
||||
"center_point": ORIGIN,
|
||||
"parametric_function_step_size": 0.001,
|
||||
"drawn_path_color": YELLOW,
|
||||
"drawn_path_stroke_width": 2,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
|
|
@ -95,7 +97,6 @@ class FourierCirclesScene(Scene):
|
|||
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)
|
||||
|
|
@ -103,12 +104,13 @@ class FourierCirclesScene(Scene):
|
|||
|
||||
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()
|
||||
)
|
||||
coef = vector.coefficient
|
||||
freq = vector.freq
|
||||
phase = np.log(coef).imag
|
||||
|
||||
vector.set_length(abs(coef))
|
||||
vector.set_angle(phase + time * freq * TAU)
|
||||
vector.shift(vector.center_func() - vector.get_start())
|
||||
return vector
|
||||
|
||||
def get_circles(self, vectors):
|
||||
|
|
@ -155,14 +157,19 @@ class FourierCirclesScene(Scene):
|
|||
return path
|
||||
|
||||
# TODO, this should be a general animated mobect
|
||||
def get_drawn_path(self, vectors, stroke_width=2, **kwargs):
|
||||
def get_drawn_path_alpha(self):
|
||||
return self.get_vector_time()
|
||||
|
||||
def get_drawn_path(self, vectors, stroke_width=None, **kwargs):
|
||||
if stroke_width is None:
|
||||
stroke_width = self.drawn_path_stroke_width
|
||||
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()
|
||||
alpha = self.get_drawn_path_alpha()
|
||||
n_curves = len(path)
|
||||
for a, sp in zip(np.linspace(0, 1, n_curves), path):
|
||||
b = alpha - a
|
||||
|
|
@ -174,7 +181,7 @@ class FourierCirclesScene(Scene):
|
|||
path.curr_time += dt
|
||||
return path
|
||||
|
||||
broken_path.set_color(YELLOW)
|
||||
broken_path.set_color(self.drawn_path_color)
|
||||
broken_path.add_updater(update_path)
|
||||
return broken_path
|
||||
|
||||
|
|
@ -372,6 +379,7 @@ class FourierOfName(FourierOfPiSymbol):
|
|||
"name_text": "Abc",
|
||||
"time_per_symbol": 5,
|
||||
"slow_factor": 1 / 5,
|
||||
"parametric_function_step_size": 0.01,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
|
|
@ -382,31 +390,49 @@ class FourierOfName(FourierOfPiSymbol):
|
|||
if name.get_height() > max_height:
|
||||
name.set_height(max_height)
|
||||
|
||||
vectors = VGroup(VectorizedPoint())
|
||||
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(
|
||||
new_vectors = self.get_rotating_vectors(
|
||||
coefficients=coefs
|
||||
)
|
||||
new_circles = self.get_circles(new_vectors)
|
||||
self.set_decreasing_stroke_widths(new_circles)
|
||||
drawn_path = self.get_drawn_path(new_circles)
|
||||
|
||||
drawn_path = self.get_drawn_path(new_vectors)
|
||||
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
|
||||
static_vectors = VMobject().become(new_vectors)
|
||||
static_circles = VMobject().become(new_circles)
|
||||
# static_circles = new_circles.deepcopy()
|
||||
# static_vectors.clear_updaters()
|
||||
# static_circles.clear_updaters()
|
||||
|
||||
self.play(
|
||||
Transform(vectors, static_vectors, remover=True),
|
||||
Transform(circles, static_circles, remover=True),
|
||||
)
|
||||
|
||||
self.add(new_vectors, new_circles)
|
||||
self.vector_clock.set_value(0)
|
||||
self.play(
|
||||
ShowCreation(drawn_path),
|
||||
rate_func=linear,
|
||||
run_time=self.time_per_symbol
|
||||
)
|
||||
circles.suspend_updating()
|
||||
self.play(FadeOut(circles))
|
||||
self.remove(new_vectors, new_circles)
|
||||
self.add(static_vectors, static_circles)
|
||||
|
||||
vectors = static_vectors
|
||||
circles = static_circles
|
||||
self.play(
|
||||
FadeOut(vectors)
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.shared_constructs import *
|
||||
from active_projects.diffyq.part2.shared_constructs import *
|
||||
|
||||
|
||||
class TwoDBodyWithManyTemperatures(ThreeDScene):
|
||||
|
|
@ -164,8 +164,12 @@ class BringTwoRodsTogether(Scene):
|
|||
"tick_frequency": 10,
|
||||
},
|
||||
},
|
||||
"y_labels": range(20, 100, 20),
|
||||
"graph_x_min": 0,
|
||||
"graph_x_max": 10,
|
||||
"midpoint": 5,
|
||||
"max_temp": 90,
|
||||
"min_temp": 10,
|
||||
"wait_time": 30,
|
||||
"default_n_rod_pieces": 20,
|
||||
"alpha": 1.0,
|
||||
|
|
@ -187,9 +191,7 @@ class BringTwoRodsTogether(Scene):
|
|||
y_label.to_edge(UP)
|
||||
axes.y_axis.label = y_label
|
||||
axes.y_axis.add(y_label)
|
||||
axes.y_axis.add_numbers(
|
||||
*range(20, 100, 20)
|
||||
)
|
||||
axes.y_axis.add_numbers(*self.y_labels)
|
||||
|
||||
self.axes = axes
|
||||
self.y_label = y_label
|
||||
|
|
@ -200,7 +202,7 @@ class BringTwoRodsTogether(Scene):
|
|||
x_min=self.graph_x_min,
|
||||
x_max=self.graph_x_max,
|
||||
step_size=self.step_size,
|
||||
discontinuities=[5],
|
||||
discontinuities=[self.midpoint],
|
||||
)
|
||||
graph.color_using_background_image("VerticalTempGradient")
|
||||
|
||||
|
|
@ -315,20 +317,27 @@ class BringTwoRodsTogether(Scene):
|
|||
rods.add_updater(self.update_rods)
|
||||
|
||||
self.play(
|
||||
ClockPassesTime(
|
||||
self.clock,
|
||||
run_time=self.wait_time,
|
||||
hours_passed=self.wait_time,
|
||||
),
|
||||
self.get_clock_anim(self.wait_time),
|
||||
FadeOut(labels)
|
||||
)
|
||||
|
||||
#
|
||||
def get_clock_anim(self, time, **kwargs):
|
||||
config = {
|
||||
"run_time": time,
|
||||
"hours_passed": time,
|
||||
}
|
||||
config.update(kwargs)
|
||||
return ClockPassesTime(self.clock, **config)
|
||||
|
||||
def initial_function(self, x):
|
||||
if x <= 5:
|
||||
return 90
|
||||
epsilon = 1e-10
|
||||
if x < self.midpoint - epsilon:
|
||||
return self.max_temp
|
||||
elif x > self.midpoint + epsilon:
|
||||
return self.min_temp
|
||||
else:
|
||||
return 10
|
||||
return (self.min_temp + self.max_temp) / 2
|
||||
|
||||
def update_graph(self, graph, dt, alpha=None, n_mini_steps=500):
|
||||
if alpha is None:
|
||||
|
|
@ -432,7 +441,10 @@ class BringTwoRodsTogether(Scene):
|
|||
)
|
||||
|
||||
def y_to_color(self, y):
|
||||
return temperature_to_color((y - 45) / 45)
|
||||
y_max = self.max_temp
|
||||
y_min = self.min_temp
|
||||
alpha = inverse_interpolate(y_min, y_max, y)
|
||||
return temperature_to_color(interpolate(-0.8, 0.8, alpha))
|
||||
|
||||
def rod_point_to_color(self, point):
|
||||
return self.y_to_color(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
from active_projects.diffyq.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
|
||||
|
||||
class ReactionsToInitialHeatEquation(PiCreatureScene):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part1.staging import TourOfDifferentialEquations
|
||||
from active_projects.diffyq.part1.staging import TourOfDifferentialEquations
|
||||
|
||||
|
||||
class PartTwoOfTour(TourOfDifferentialEquations):
|
||||
|
|
@ -210,7 +210,7 @@ class BlackScholes(AltBrownianMotion):
|
|||
self.wait(self.wait_time)
|
||||
|
||||
def add_title(self):
|
||||
title = TextMobject("Black-Sholes equations")
|
||||
title = TextMobject("Black-Scholes equations")
|
||||
title.scale(1.5)
|
||||
title.next_to(2 * UP, UP)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.heat_equation import *
|
||||
from active_projects.diffyq.part2.heat_equation import *
|
||||
|
||||
|
||||
class ShowNewRuleAtDiscreteBoundary(DiscreteSetup):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
from active_projects.diffyq.part2.wordy_scenes import *
|
||||
|
||||
|
||||
class IveHeardOfThis(TeacherStudentsScene):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from manimlib.imports import *
|
||||
|
||||
from active_projects.ode.part2.fourier_series import FourierOfTrebleClef
|
||||
from active_projects.diffyq.part2.fourier_series import FourierOfTrebleClef
|
||||
|
||||
|
||||
class FourierNameIntro(Scene):
|
||||
|
|
@ -245,42 +245,20 @@ class FourierSeriesIllustraiton(Scene):
|
|||
"x_max": 1,
|
||||
"y_min": -1,
|
||||
"y_max": 1,
|
||||
}
|
||||
},
|
||||
"colors": [BLUE, GREEN, RED, YELLOW, PINK],
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
n_range = self.n_range
|
||||
aaa_group = self.get_axes_arrow_axes()
|
||||
aaa_group.shift(2 * UP)
|
||||
aaa_group.shift_onto_screen()
|
||||
axes1, arrow, axes2 = aaa_group
|
||||
|
||||
axes1 = Axes(**self.axes_config)
|
||||
axes1.x_axis.add_numbers(
|
||||
0.5, 1,
|
||||
number_config={"num_decimal_places": 1}
|
||||
)
|
||||
axes2 = axes1.copy()
|
||||
target_func_graph = self.get_target_func_graph(axes2)
|
||||
axes2.add(target_func_graph)
|
||||
axes2.add(self.get_target_func_graph(axes2))
|
||||
|
||||
arrow = Arrow(LEFT, RIGHT, color=WHITE)
|
||||
group = VGroup(axes1, arrow, axes2)
|
||||
group.arrange(RIGHT, buff=LARGE_BUFF)
|
||||
group.shift(2 * UP)
|
||||
group.shift_onto_screen()
|
||||
|
||||
sine_graphs = VGroup(*[
|
||||
axes1.get_graph(self.generate_nth_func(n))
|
||||
for n in n_range
|
||||
])
|
||||
sine_graphs.set_stroke(width=3)
|
||||
sine_graphs.set_color_by_gradient(
|
||||
BLUE, GREEN, RED, YELLOW, PINK,
|
||||
BLUE, GREEN, RED, YELLOW, PINK,
|
||||
)
|
||||
|
||||
partial_sums = VGroup(*[
|
||||
axes1.get_graph(self.generate_kth_partial_sum_func(k + 1))
|
||||
for k in range(len(n_range))
|
||||
])
|
||||
partial_sums.match_style(sine_graphs)
|
||||
sine_graphs = self.get_sine_graphs(axes1)
|
||||
partial_sums = self.get_partial_sums(axes1, sine_graphs)
|
||||
|
||||
sum_tex = self.get_sum_tex()
|
||||
sum_tex.next_to(axes1, DOWN, LARGE_BUFF)
|
||||
|
|
@ -311,7 +289,6 @@ class FourierSeriesIllustraiton(Scene):
|
|||
)
|
||||
|
||||
self.add(axes1, arrow, axes2)
|
||||
self.add(target_func_graph)
|
||||
self.add(sum_tex, eq, target_func_tex)
|
||||
self.add(range_words)
|
||||
|
||||
|
|
@ -340,6 +317,42 @@ class FourierSeriesIllustraiton(Scene):
|
|||
self.play(*anims2)
|
||||
curr_partial_sum = partial_sum
|
||||
|
||||
def get_axes_arrow_axes(self):
|
||||
axes1 = Axes(**self.axes_config)
|
||||
axes1.x_axis.add_numbers(
|
||||
0.5, 1,
|
||||
number_config={"num_decimal_places": 1}
|
||||
)
|
||||
axes1.y_axis.add_numbers(
|
||||
-1, 1,
|
||||
number_config={"num_decimal_places": 1},
|
||||
direction=LEFT,
|
||||
)
|
||||
axes2 = axes1.deepcopy()
|
||||
|
||||
arrow = Arrow(LEFT, RIGHT, color=WHITE)
|
||||
group = VGroup(axes1, arrow, axes2)
|
||||
group.arrange(RIGHT, buff=MED_LARGE_BUFF)
|
||||
return group
|
||||
|
||||
def get_sine_graphs(self, axes):
|
||||
sine_graphs = VGroup(*[
|
||||
axes.get_graph(self.generate_nth_func(n))
|
||||
for n in self.n_range
|
||||
])
|
||||
sine_graphs.set_stroke(width=3)
|
||||
for graph, color in zip(sine_graphs, it.cycle(self.colors)):
|
||||
graph.set_color(color)
|
||||
return sine_graphs
|
||||
|
||||
def get_partial_sums(self, axes, sine_graphs):
|
||||
partial_sums = VGroup(*[
|
||||
axes.get_graph(self.generate_kth_partial_sum_func(k + 1))
|
||||
for k in range(len(self.n_range))
|
||||
])
|
||||
partial_sums.match_style(sine_graphs)
|
||||
return partial_sums
|
||||
|
||||
def get_sum_tex(self):
|
||||
return TexMobject(
|
||||
"\\frac{4}{\\pi} \\left(",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from scipy import integrate
|
||||
|
||||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.heat_equation import *
|
||||
from active_projects.diffyq.part2.heat_equation import *
|
||||
|
||||
|
||||
class TemperatureGraphScene(SpecialThreeDScene):
|
||||
|
|
@ -137,19 +137,19 @@ class TemperatureGraphScene(SpecialThreeDScene):
|
|||
|
||||
def get_surface(self, axes, func, **kwargs):
|
||||
config = {
|
||||
"u_min": axes.x_min,
|
||||
"u_max": axes.x_max,
|
||||
"v_min": axes.y_min,
|
||||
"v_max": axes.y_max,
|
||||
"u_min": axes.y_min,
|
||||
"u_max": axes.y_max,
|
||||
"v_min": axes.x_min,
|
||||
"v_max": axes.x_max,
|
||||
"resolution": (
|
||||
(axes.x_max - axes.x_min) // axes.x_axis.tick_frequency,
|
||||
(axes.y_max - axes.y_min) // axes.y_axis.tick_frequency,
|
||||
(axes.x_max - axes.x_min) // axes.x_axis.tick_frequency,
|
||||
),
|
||||
}
|
||||
config.update(self.default_surface_config)
|
||||
config.update(kwargs)
|
||||
return ParametricSurface(
|
||||
lambda x, t: axes.c2p(
|
||||
lambda t, x: axes.c2p(
|
||||
x, t, func(x, t)
|
||||
),
|
||||
**config
|
||||
|
|
@ -181,13 +181,12 @@ class TemperatureGraphScene(SpecialThreeDScene):
|
|||
fill_color=WHITE,
|
||||
fill_opacity=0.2
|
||||
)
|
||||
plane.add_updater(lambda m: m.move_to(
|
||||
plane.add_updater(lambda m: m.shift(
|
||||
axes.c2p(
|
||||
axes.x_min,
|
||||
t_tracker.get_value(),
|
||||
axes.z_min,
|
||||
),
|
||||
IN + LEFT,
|
||||
) - plane.points[0]
|
||||
))
|
||||
plane.t_tracker = t_tracker
|
||||
return plane
|
||||
|
|
@ -380,6 +379,10 @@ class BreakDownAFunction(SimpleCosExpGraph):
|
|||
"z_min": -2,
|
||||
"y_max": 20,
|
||||
},
|
||||
"low_axes_config": {
|
||||
"z_min": -3,
|
||||
"z_axis_config": {"unit_size": 1}
|
||||
},
|
||||
"n_low_axes": 4,
|
||||
"k": 0.2,
|
||||
}
|
||||
|
|
@ -403,10 +406,7 @@ class BreakDownAFunction(SimpleCosExpGraph):
|
|||
top_axes.center()
|
||||
top_axes.to_edge(UP)
|
||||
|
||||
low_axes = self.get_three_d_axes(
|
||||
z_min=-3,
|
||||
z_axis_config={"unit_size": 1}
|
||||
)
|
||||
low_axes = self.get_three_d_axes(**self.low_axes_config)
|
||||
low_axes.y_axis.set_opacity(0)
|
||||
for axis in low_axes:
|
||||
axis.label.fade(1)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.ode.part2.wordy_scenes import *
|
||||
from active_projects.diffyq.part2.wordy_scenes import *
|
||||
|
||||
|
||||
class ThreeMainObservations(Scene):
|
||||
|
|
|
|||
712
active_projects/diffyq/part4/complex_functions.py
Normal file
712
active_projects/diffyq/part4/complex_functions.py
Normal file
|
|
@ -0,0 +1,712 @@
|
|||
from manimlib.imports import *
|
||||
|
||||
|
||||
class GeneralizeToComplexFunctions(Scene):
|
||||
CONFIG = {
|
||||
"axes_config": {
|
||||
"x_min": 0,
|
||||
"x_max": 10,
|
||||
"x_axis_config": {
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"y_min": -2.5,
|
||||
"y_max": 2.5,
|
||||
"y_axis_config": {
|
||||
"tick_frequency": 0.25,
|
||||
"unit_size": 1.5,
|
||||
"include_tip": False,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
},
|
||||
"complex_plane_config": {
|
||||
"axis_config": {
|
||||
"unit_size": 2
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.show_cosine_wave()
|
||||
self.transition_to_complex_plane()
|
||||
self.add_rotating_vectors_making_cos()
|
||||
|
||||
def show_cosine_wave(self):
|
||||
axes = Axes(**self.axes_config)
|
||||
axes.shift(2 * LEFT - axes.c2p(0, 0))
|
||||
y_axis = axes.y_axis
|
||||
y_labels = y_axis.get_number_mobjects(
|
||||
*range(-2, 3),
|
||||
number_config={"num_decimal_places": 1},
|
||||
)
|
||||
|
||||
t_tracker = ValueTracker(0)
|
||||
t_tracker.add_updater(lambda t, dt: t.increment_value(dt))
|
||||
get_t = t_tracker.get_value
|
||||
|
||||
def func(x):
|
||||
return 2 * np.cos(x)
|
||||
|
||||
cos_x_max = 20
|
||||
cos_wave = axes.get_graph(func, x_max=cos_x_max)
|
||||
cos_wave.set_color(YELLOW)
|
||||
shown_cos_wave = cos_wave.copy()
|
||||
shown_cos_wave.add_updater(
|
||||
lambda m: m.pointwise_become_partial(
|
||||
cos_wave, 0,
|
||||
np.clip(get_t() / cos_x_max, 0, 1),
|
||||
),
|
||||
)
|
||||
|
||||
dot = Dot()
|
||||
dot.set_color(PINK)
|
||||
dot.add_updater(lambda d: d.move_to(
|
||||
y_axis.n2p(func(get_t())),
|
||||
))
|
||||
|
||||
h_line = always_redraw(lambda: Line(
|
||||
dot.get_right(),
|
||||
shown_cos_wave.get_end(),
|
||||
stroke_width=1,
|
||||
))
|
||||
|
||||
real_words = TextMobject(
|
||||
"Real number\\\\output"
|
||||
)
|
||||
real_words.to_edge(LEFT)
|
||||
real_words.shift(2 * UP)
|
||||
real_arrow = Arrow()
|
||||
real_arrow.add_updater(
|
||||
lambda m: m.put_start_and_end_on(
|
||||
real_words.get_corner(DR),
|
||||
dot.get_center(),
|
||||
).scale(0.9),
|
||||
)
|
||||
|
||||
self.add(t_tracker)
|
||||
self.add(axes)
|
||||
self.add(y_labels)
|
||||
self.add(shown_cos_wave)
|
||||
self.add(dot)
|
||||
self.add(h_line)
|
||||
|
||||
self.wait(2)
|
||||
self.play(
|
||||
FadeInFrom(real_words, RIGHT),
|
||||
FadeIn(real_arrow),
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
y_axis.generate_target()
|
||||
y_axis.target.rotate(-90 * DEGREES)
|
||||
y_axis.target.center()
|
||||
y_axis.target.scale(2 / 1.5)
|
||||
y_labels.generate_target()
|
||||
for label in y_labels.target:
|
||||
label.next_to(
|
||||
y_axis.target.n2p(label.get_value()),
|
||||
DOWN, MED_SMALL_BUFF,
|
||||
)
|
||||
self.play(
|
||||
FadeOut(shown_cos_wave),
|
||||
FadeOut(axes.x_axis),
|
||||
FadeOut(h_line),
|
||||
)
|
||||
self.play(
|
||||
MoveToTarget(y_axis),
|
||||
MoveToTarget(y_labels),
|
||||
real_words.shift, 2 * RIGHT + UP,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.y_axis = y_axis
|
||||
self.y_labels = y_labels
|
||||
self.real_words = real_words
|
||||
self.real_arrow = real_arrow
|
||||
self.dot = dot
|
||||
self.t_tracker = t_tracker
|
||||
|
||||
def transition_to_complex_plane(self):
|
||||
y_axis = self.y_axis
|
||||
y_labels = self.y_labels
|
||||
|
||||
plane = self.get_complex_plane()
|
||||
plane_words = plane.label
|
||||
|
||||
self.add(plane, *self.get_mobjects())
|
||||
self.play(
|
||||
FadeOut(y_labels),
|
||||
FadeOut(y_axis),
|
||||
ShowCreation(plane),
|
||||
)
|
||||
self.play(Write(plane_words))
|
||||
self.wait()
|
||||
|
||||
self.plane = plane
|
||||
self.plane_words = plane_words
|
||||
|
||||
def add_rotating_vectors_making_cos(self):
|
||||
plane = self.plane
|
||||
real_words = self.real_words
|
||||
real_arrow = self.real_arrow
|
||||
t_tracker = self.t_tracker
|
||||
get_t = t_tracker.get_value
|
||||
|
||||
v1 = Vector(2 * RIGHT)
|
||||
v2 = Vector(2 * RIGHT)
|
||||
v1.set_color(BLUE)
|
||||
v2.set_color(interpolate_color(GREY_BROWN, WHITE, 0.5))
|
||||
v1.add_updater(
|
||||
lambda v: v.set_angle(get_t())
|
||||
)
|
||||
v2.add_updater(
|
||||
lambda v: v.set_angle(-get_t())
|
||||
)
|
||||
v1.add_updater(
|
||||
lambda v: v.shift(plane.n2p(0) - v.get_start())
|
||||
)
|
||||
# Change?
|
||||
v2.add_updater(
|
||||
lambda v: v.shift(plane.n2p(0) - v.get_start())
|
||||
)
|
||||
|
||||
ghost_v1 = v1.copy()
|
||||
ghost_v1.set_opacity(0.5)
|
||||
ghost_v1.add_updater(
|
||||
lambda v: v.shift(
|
||||
v2.get_end() - v.get_start()
|
||||
)
|
||||
)
|
||||
|
||||
ghost_v2 = v2.copy()
|
||||
ghost_v2.set_opacity(0.5)
|
||||
ghost_v2.add_updater(
|
||||
lambda v: v.shift(
|
||||
v1.get_end() - v.get_start()
|
||||
)
|
||||
)
|
||||
|
||||
circle = Circle(color=GREY_BROWN)
|
||||
circle.set_stroke(width=1)
|
||||
circle.set_width(2 * v1.get_length())
|
||||
circle.move_to(plane.n2p(0))
|
||||
|
||||
formula = TexMobject(
|
||||
# "\\cos(x) ="
|
||||
# "{1 \\over 2}e^{ix} +"
|
||||
# "{1 \\over 2}e^{-ix}",
|
||||
"2\\cos(x) =",
|
||||
"e^{ix}", "+", "e^{-ix}",
|
||||
tex_to_color_map={
|
||||
"e^{ix}": v1.get_color(),
|
||||
"e^{-ix}": v2.get_color(),
|
||||
}
|
||||
)
|
||||
formula.next_to(ORIGIN, UP, buff=0.75)
|
||||
# formula.add_background_rectangle()
|
||||
formula.set_stroke(BLACK, 3, background=True)
|
||||
formula.to_edge(LEFT, buff=MED_SMALL_BUFF)
|
||||
formula_brace = Brace(formula[1:], UP)
|
||||
formula_words = formula_brace.get_text(
|
||||
"Sum of\\\\rotations"
|
||||
)
|
||||
formula_words.set_stroke(BLACK, 3, background=True)
|
||||
|
||||
randy = Randolph()
|
||||
randy.to_corner(DL)
|
||||
randy.look_at(formula)
|
||||
|
||||
self.play(
|
||||
FadeOut(real_words),
|
||||
FadeOut(real_arrow),
|
||||
)
|
||||
self.play(
|
||||
FadeIn(v1),
|
||||
FadeIn(v2),
|
||||
FadeIn(circle),
|
||||
FadeIn(ghost_v1),
|
||||
FadeIn(ghost_v2),
|
||||
)
|
||||
self.wait(3)
|
||||
self.play(FadeInFromDown(formula))
|
||||
self.play(
|
||||
GrowFromCenter(formula_brace),
|
||||
FadeIn(formula_words),
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(FadeIn(randy))
|
||||
self.play(randy.change, "pleading")
|
||||
self.play(Blink(randy))
|
||||
self.wait()
|
||||
self.play(randy.change, "confused")
|
||||
self.play(Blink(randy))
|
||||
self.wait()
|
||||
self.play(FadeOut(randy))
|
||||
self.wait(20)
|
||||
|
||||
#
|
||||
def get_complex_plane(self):
|
||||
plane = ComplexPlane(**self.complex_plane_config)
|
||||
plane.add_coordinates()
|
||||
|
||||
plane.label = TextMobject("Complex plane")
|
||||
plane.label.scale(1.5)
|
||||
plane.label.to_corner(UR, buff=MED_SMALL_BUFF)
|
||||
return plane
|
||||
|
||||
|
||||
class ClarifyInputAndOutput(GeneralizeToComplexFunctions):
|
||||
CONFIG = {
|
||||
"input_space_rect_config": {
|
||||
"stroke_color": WHITE,
|
||||
"stroke_width": 1,
|
||||
"fill_color": DARKER_GREY,
|
||||
"fill_opacity": 1,
|
||||
"width": 6,
|
||||
"height": 2,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_plane()
|
||||
self.setup_input_space()
|
||||
self.setup_input_trackers()
|
||||
|
||||
self.describe_input()
|
||||
self.describe_output()
|
||||
|
||||
def setup_plane(self):
|
||||
plane = self.get_complex_plane()
|
||||
plane.sublabel = TextMobject("(Output space)")
|
||||
plane.sublabel.add_background_rectangle()
|
||||
plane.sublabel.next_to(plane.label, DOWN)
|
||||
self.add(plane, plane.label)
|
||||
self.plane = plane
|
||||
|
||||
def setup_input_space(self):
|
||||
rect = Rectangle(**self.input_space_rect_config)
|
||||
rect.to_corner(UL, buff=SMALL_BUFF)
|
||||
|
||||
input_line = self.get_input_line(rect)
|
||||
input_words = TextMobject("Input space")
|
||||
input_words.next_to(
|
||||
rect.get_bottom(), UP,
|
||||
SMALL_BUFF,
|
||||
)
|
||||
|
||||
self.add(rect)
|
||||
self.add(input_line)
|
||||
|
||||
self.input_rect = rect
|
||||
self.input_line = input_line
|
||||
self.input_words = input_words
|
||||
|
||||
def setup_input_trackers(self):
|
||||
plane = self.plane
|
||||
input_line = self.input_line
|
||||
input_tracker = ValueTracker(0)
|
||||
get_input = input_tracker.get_value
|
||||
|
||||
input_dot = Dot()
|
||||
input_dot.set_color(PINK)
|
||||
f_always(
|
||||
input_dot.move_to,
|
||||
lambda: input_line.n2p(get_input())
|
||||
)
|
||||
|
||||
input_decimal = DecimalNumber()
|
||||
input_decimal.scale(0.7)
|
||||
always(input_decimal.next_to, input_dot, UP)
|
||||
f_always(input_decimal.set_value, get_input)
|
||||
|
||||
path = self.get_path()
|
||||
|
||||
def get_output_point():
|
||||
return path.point_from_proportion(
|
||||
get_input()
|
||||
)
|
||||
|
||||
output_dot = Dot()
|
||||
output_dot.match_style(input_dot)
|
||||
f_always(output_dot.move_to, get_output_point)
|
||||
|
||||
output_vector = Vector()
|
||||
output_vector.set_color(WHITE)
|
||||
output_vector.add_updater(
|
||||
lambda v: v.put_start_and_end_on(
|
||||
plane.n2p(0),
|
||||
get_output_point()
|
||||
)
|
||||
)
|
||||
|
||||
output_decimal = DecimalNumber()
|
||||
output_decimal.scale(0.7)
|
||||
always(output_decimal.next_to, output_dot, UR, SMALL_BUFF)
|
||||
f_always(
|
||||
output_decimal.set_value,
|
||||
lambda: plane.p2n(get_output_point()),
|
||||
)
|
||||
|
||||
self.input_tracker = input_tracker
|
||||
self.input_dot = input_dot
|
||||
self.input_decimal = input_decimal
|
||||
self.path = path
|
||||
self.output_dot = output_dot
|
||||
self.output_vector = output_vector
|
||||
self.output_decimal = output_decimal
|
||||
|
||||
def describe_input(self):
|
||||
input_tracker = self.input_tracker
|
||||
|
||||
self.play(FadeInFrom(self.input_words, UP))
|
||||
self.play(
|
||||
FadeInFromLarge(self.input_dot),
|
||||
FadeIn(self.input_decimal),
|
||||
)
|
||||
for value in 1, 0:
|
||||
self.play(
|
||||
input_tracker.set_value, value,
|
||||
run_time=2
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def describe_output(self):
|
||||
path = self.path
|
||||
output_dot = self.output_dot
|
||||
output_decimal = self.output_decimal
|
||||
input_dot = self.input_dot
|
||||
input_tracker = self.input_tracker
|
||||
plane = self.plane
|
||||
real_line = plane.x_axis.copy()
|
||||
real_line.set_stroke(RED, 4)
|
||||
real_words = TextMobject("Real number line")
|
||||
real_words.next_to(ORIGIN, UP)
|
||||
real_words.to_edge(RIGHT)
|
||||
|
||||
traced_path = TracedPath(output_dot.get_center)
|
||||
traced_path.match_style(path)
|
||||
|
||||
self.play(
|
||||
ShowCreation(real_line),
|
||||
FadeInFrom(real_words, DOWN)
|
||||
)
|
||||
self.play(
|
||||
FadeOut(real_line),
|
||||
FadeOut(real_words),
|
||||
)
|
||||
self.play(
|
||||
FadeInFrom(plane.sublabel, UP)
|
||||
)
|
||||
self.play(
|
||||
FadeIn(output_decimal),
|
||||
TransformFromCopy(input_dot, output_dot),
|
||||
)
|
||||
|
||||
kw = {
|
||||
"run_time": 10,
|
||||
"rate_func": lambda t: smooth(t, 1),
|
||||
}
|
||||
self.play(
|
||||
ApplyMethod(input_tracker.set_value, 1, **kw),
|
||||
ShowCreation(path.copy(), remover=True, **kw),
|
||||
)
|
||||
self.add(path)
|
||||
self.add(output_dot)
|
||||
self.wait()
|
||||
|
||||
# Flatten to 1d
|
||||
real_function_word = TextMobject(
|
||||
"Real-valued function"
|
||||
)
|
||||
real_function_word.next_to(ORIGIN, DOWN, MED_LARGE_BUFF)
|
||||
path.generate_target()
|
||||
path.target.stretch(0, 1)
|
||||
path.target.move_to(plane.n2p(0))
|
||||
|
||||
self.play(
|
||||
FadeIn(real_function_word),
|
||||
MoveToTarget(path),
|
||||
)
|
||||
input_tracker.set_value(0)
|
||||
self.play(
|
||||
input_tracker.set_value, 1,
|
||||
**kw
|
||||
)
|
||||
|
||||
#
|
||||
def get_input_line(self, input_rect):
|
||||
input_line = UnitInterval()
|
||||
input_line.move_to(input_rect)
|
||||
input_line.shift(0.25 * UP)
|
||||
input_line.set_width(
|
||||
input_rect.get_width() - 1
|
||||
)
|
||||
input_line.add_numbers(0, 0.5, 1)
|
||||
return input_line
|
||||
|
||||
def get_path(self):
|
||||
# mob = SVGMobject("BatmanLogo")
|
||||
mob = TexMobject("\\pi")
|
||||
path = mob.family_members_with_points()[0]
|
||||
path.set_height(3.5)
|
||||
path.move_to(2 * DOWN, DOWN)
|
||||
path.set_stroke(YELLOW, 2)
|
||||
path.set_fill(opacity=0)
|
||||
return path
|
||||
|
||||
|
||||
class GraphForFlattenedPi(ClarifyInputAndOutput):
|
||||
CONFIG = {
|
||||
"camera_config": {"background_color": DARKER_GREY},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_plane()
|
||||
plane = self.plane
|
||||
self.remove(plane, plane.label)
|
||||
|
||||
path = self.get_path()
|
||||
|
||||
axes = Axes(
|
||||
x_min=0,
|
||||
x_max=1,
|
||||
x_axis_config={
|
||||
"unit_size": 7,
|
||||
"include_tip": False,
|
||||
"tick_frequency": 0.1,
|
||||
},
|
||||
y_min=-1.5,
|
||||
y_max=1.5,
|
||||
y_axis_config={
|
||||
"include_tip": False,
|
||||
"unit_size": 2.5,
|
||||
"tick_frequency": 0.5,
|
||||
},
|
||||
)
|
||||
axes.set_width(FRAME_WIDTH - 1)
|
||||
axes.set_height(FRAME_HEIGHT - 1, stretch=True)
|
||||
axes.center()
|
||||
|
||||
axes.x_axis.add_numbers(
|
||||
0.5, 1.0,
|
||||
number_config={"num_decimal_places": 1},
|
||||
)
|
||||
axes.y_axis.add_numbers(
|
||||
-1.0, 1.0,
|
||||
number_config={"num_decimal_places": 1},
|
||||
)
|
||||
|
||||
def func(t):
|
||||
return plane.x_axis.p2n(
|
||||
path.point_from_proportion(t)
|
||||
)
|
||||
|
||||
graph = axes.get_graph(func)
|
||||
graph.set_color(PINK)
|
||||
|
||||
v_line = always_redraw(lambda: Line(
|
||||
axes.x_axis.n2p(axes.x_axis.p2n(graph.get_end())),
|
||||
graph.get_end(),
|
||||
stroke_width=1,
|
||||
))
|
||||
|
||||
self.add(axes)
|
||||
self.add(v_line)
|
||||
|
||||
kw = {
|
||||
"run_time": 10,
|
||||
"rate_func": lambda t: smooth(t, 1),
|
||||
}
|
||||
self.play(ShowCreation(graph, **kw))
|
||||
self.wait()
|
||||
|
||||
|
||||
class SimpleComplexExponentExample(ClarifyInputAndOutput):
|
||||
CONFIG = {
|
||||
"input_space_rect_config": {
|
||||
"width": 14,
|
||||
"height": 1.5,
|
||||
},
|
||||
"input_line_config": {
|
||||
"unit_size": 0.5,
|
||||
"x_min": 0,
|
||||
"x_max": 25,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"input_numbers": range(0, 30, 5),
|
||||
"input_tex_args": ["t", "="],
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_plane()
|
||||
self.setup_input_space()
|
||||
self.setup_input_trackers()
|
||||
self.setup_output_trackers()
|
||||
|
||||
# Testing
|
||||
time = self.input_line.x_max
|
||||
self.play(
|
||||
self.input_tracker.set_value, time,
|
||||
run_time=time,
|
||||
rate_func=linear,
|
||||
)
|
||||
|
||||
def setup_plane(self):
|
||||
plane = ComplexPlane()
|
||||
plane.scale(2)
|
||||
plane.add_coordinates()
|
||||
plane.shift(DOWN)
|
||||
self.plane = plane
|
||||
self.add(plane)
|
||||
|
||||
def setup_input_trackers(self):
|
||||
input_line = self.input_line
|
||||
input_tracker = ValueTracker(0)
|
||||
get_input = input_tracker.get_value
|
||||
|
||||
input_tip = ArrowTip(start_angle=-TAU / 4)
|
||||
input_tip.scale(0.5)
|
||||
input_tip.set_color(PINK)
|
||||
f_always(
|
||||
input_tip.move_to,
|
||||
lambda: input_line.n2p(get_input()),
|
||||
lambda: DOWN,
|
||||
)
|
||||
|
||||
input_label = VGroup(
|
||||
TexMobject(*self.input_tex_args),
|
||||
DecimalNumber(),
|
||||
)
|
||||
input_label[0].set_color_by_tex("t", PINK)
|
||||
input_label.scale(0.7)
|
||||
input_label.add_updater(
|
||||
lambda m: m.arrange(RIGHT, buff=SMALL_BUFF)
|
||||
)
|
||||
input_label.add_updater(
|
||||
lambda m: m[1].set_value(get_input())
|
||||
)
|
||||
input_label.add_updater(
|
||||
lambda m: m.next_to(input_tip, UP, SMALL_BUFF)
|
||||
)
|
||||
|
||||
self.input_tracker = input_tracker
|
||||
self.input_tip = input_tip
|
||||
self.input_label = input_label
|
||||
|
||||
self.add(input_tip, input_label)
|
||||
|
||||
def setup_output_trackers(self):
|
||||
plane = self.plane
|
||||
get_input = self.input_tracker.get_value
|
||||
|
||||
def get_output():
|
||||
return np.exp(complex(0, get_input()))
|
||||
|
||||
def get_output_point():
|
||||
return plane.n2p(get_output())
|
||||
|
||||
output_label, static_output_label = [
|
||||
TexMobject(
|
||||
"e^{i t}" + s,
|
||||
tex_to_color_map={"t": PINK},
|
||||
background_stroke_width=3,
|
||||
)
|
||||
for s in ["", "\\approx"]
|
||||
]
|
||||
output_label.scale(1.2)
|
||||
output_label.add_updater(
|
||||
lambda m: m.shift(
|
||||
-m.get_bottom() +
|
||||
get_output_point() +
|
||||
rotate_vector(
|
||||
0.35 * RIGHT,
|
||||
get_input(),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
output_vector = Vector()
|
||||
output_vector.set_opacity(0.75)
|
||||
output_vector.add_updater(
|
||||
lambda m: m.put_start_and_end_on(
|
||||
plane.n2p(0), get_output_point(),
|
||||
)
|
||||
)
|
||||
|
||||
t_max = 40
|
||||
full_output_path = ParametricFunction(
|
||||
lambda t: plane.n2p(np.exp(complex(0, t))),
|
||||
t_min=0,
|
||||
t_max=t_max
|
||||
)
|
||||
output_path = VMobject()
|
||||
output_path.set_stroke(YELLOW, 2)
|
||||
output_path.add_updater(
|
||||
lambda m: m.pointwise_become_partial(
|
||||
full_output_path,
|
||||
0, get_input() / t_max,
|
||||
)
|
||||
)
|
||||
|
||||
static_output_label.next_to(plane.c2p(1, 1), UR)
|
||||
output_decimal = DecimalNumber(
|
||||
include_sign=True,
|
||||
)
|
||||
output_decimal.scale(0.8)
|
||||
output_decimal.set_stroke(BLACK, 3, background=True)
|
||||
output_decimal.add_updater(
|
||||
lambda m: m.set_value(get_output())
|
||||
)
|
||||
output_decimal.add_updater(
|
||||
lambda m: m.next_to(
|
||||
static_output_label,
|
||||
RIGHT, 2 * SMALL_BUFF,
|
||||
aligned_edge=DOWN,
|
||||
)
|
||||
)
|
||||
|
||||
self.add(output_path)
|
||||
self.add(output_vector)
|
||||
self.add(output_label)
|
||||
self.add(static_output_label)
|
||||
self.add(BackgroundRectangle(output_decimal))
|
||||
self.add(output_decimal)
|
||||
|
||||
#
|
||||
def get_input_line(self, input_rect):
|
||||
input_line = NumberLine(**self.input_line_config)
|
||||
input_line.move_to(input_rect)
|
||||
input_line.set_width(
|
||||
input_rect.get_width() - 1.5,
|
||||
stretch=True,
|
||||
)
|
||||
input_line.add_numbers(*self.input_numbers)
|
||||
return input_line
|
||||
|
||||
|
||||
class TRangingFrom0To1(SimpleComplexExponentExample):
|
||||
CONFIG = {
|
||||
"input_space_rect_config": {
|
||||
"width": 6,
|
||||
"height": 2,
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_input_space()
|
||||
self.setup_input_trackers()
|
||||
|
||||
self.play(
|
||||
self.input_tracker.set_value, 1,
|
||||
run_time=10,
|
||||
rate_func=linear
|
||||
)
|
||||
|
||||
def get_input_line(self, rect):
|
||||
result = ClarifyInputAndOutput.get_input_line(self, rect)
|
||||
result.stretch(0.9, 0)
|
||||
result.set_stroke(width=2)
|
||||
for sm in result.get_family():
|
||||
if isinstance(sm, DecimalNumber):
|
||||
sm.stretch(1 / 0.9, 0)
|
||||
sm.set_stroke(width=0)
|
||||
return result
|
||||
File diff suppressed because it is too large
Load diff
242
active_projects/diffyq/part4/long_fourier_scenes.py
Normal file
242
active_projects/diffyq/part4/long_fourier_scenes.py
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
from manimlib.imports import *
|
||||
|
||||
from active_projects.diffyq.part4.fourier_series_scenes import ComplexFourierSeriesExample
|
||||
from manimlib.once_useful_constructs.fractals import HilbertCurve
|
||||
|
||||
|
||||
class FourierSeriesExampleWithRectForZoom(ComplexFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"n_vectors": 100,
|
||||
"slow_factor": 0.01,
|
||||
"rect_scale_factor": 0.1,
|
||||
"start_drawn": True,
|
||||
"drawing_height": 7,
|
||||
"rect_stroke_width": 1,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_vectors_circles_path()
|
||||
self.circles.set_stroke(opacity=0.5)
|
||||
rect = self.rect = self.get_rect()
|
||||
rect.set_height(self.rect_scale_factor * FRAME_HEIGHT)
|
||||
rect.add_updater(lambda m: m.move_to(
|
||||
self.get_rect_center()
|
||||
))
|
||||
self.add(rect)
|
||||
self.run_one_cycle()
|
||||
|
||||
def get_rect_center(self):
|
||||
return center_of_mass([
|
||||
v.get_end()
|
||||
for v in self.vectors
|
||||
])
|
||||
|
||||
def get_rect(self):
|
||||
return ScreenRectangle(
|
||||
color=BLUE,
|
||||
stroke_width=self.rect_stroke_width,
|
||||
)
|
||||
|
||||
|
||||
class ZoomedInFourierSeriesExample(FourierSeriesExampleWithRectForZoom, MovingCameraScene):
|
||||
CONFIG = {
|
||||
"vector_config": {
|
||||
"max_tip_length_to_length_ratio": 0.15,
|
||||
"tip_length": 0.05,
|
||||
},
|
||||
"parametric_function_step_size": 0.001,
|
||||
}
|
||||
|
||||
def setup(self):
|
||||
ComplexFourierSeriesExample.setup(self)
|
||||
MovingCameraScene.setup(self)
|
||||
|
||||
def get_rect(self):
|
||||
return self.camera_frame
|
||||
|
||||
def add_vectors_circles_path(self):
|
||||
super().add_vectors_circles_path()
|
||||
for v in self.vectors:
|
||||
if v.get_stroke_width() < 1:
|
||||
v.set_stroke(width=1)
|
||||
|
||||
|
||||
class ZoomedInFourierSeriesExample100x(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"vector_config": {
|
||||
"max_tip_length_to_length_ratio": 0.15 * 0.4,
|
||||
"tip_length": 0.05 * 0.2,
|
||||
"max_stroke_width_to_length_ratio": 80,
|
||||
"stroke_width": 3,
|
||||
},
|
||||
"max_circle_stroke_width": 0.5,
|
||||
"rect_scale_factor": 0.01,
|
||||
# "parametric_function_step_size": 0.01,
|
||||
}
|
||||
|
||||
def get_rect_center(self):
|
||||
return self.vectors[-1].get_end()
|
||||
|
||||
# def get_drawn_path(self, vectors, stroke_width=2, **kwargs):
|
||||
# return self.get_path_end(vectors, stroke_width, **kwargs)
|
||||
|
||||
|
||||
class TrebleClefFourierSeriesExampleWithRectForZoom(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "TrebleClef",
|
||||
"drawn_path_stroke_width": 10,
|
||||
}
|
||||
|
||||
|
||||
class TrebleClefZoomedInFourierSeriesExample(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"file_name": "TrebleClef",
|
||||
}
|
||||
|
||||
|
||||
class NailAndGearFourierSeriesExampleWithRectForZoom(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "Nail_And_Gear",
|
||||
"n_vectors": 200,
|
||||
"drawn_path_color": "#39FF14",
|
||||
}
|
||||
|
||||
|
||||
class NailAndGearZoomedInFourierSeriesExample(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"file_name": "Nail_And_Gear",
|
||||
"n_vectors": 200,
|
||||
"drawn_path_color": "#39FF14",
|
||||
}
|
||||
|
||||
|
||||
class SigmaFourierSeriesExampleWithRectForZoom(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"n_vectors": 200,
|
||||
"drawn_path_color": PINK,
|
||||
"rect_stroke_width": 0,
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
return TexMobject("\\Sigma")
|
||||
|
||||
|
||||
class SigmaZoomedInFourierSeriesExample(SigmaFourierSeriesExampleWithRectForZoom, ZoomedInFourierSeriesExample):
|
||||
pass
|
||||
|
||||
|
||||
class FourierOfFourier(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "FourierOneLine",
|
||||
"n_vectors": 300,
|
||||
"rect_stroke_width": 1,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfFourierZoomedIn(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"file_name": "FourierOneLine",
|
||||
"max_circle_stroke_width": 0.3,
|
||||
"n_vectors": 300,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfFourier100xZoom(ZoomedInFourierSeriesExample100x):
|
||||
CONFIG = {
|
||||
"file_name": "FourierOneLine",
|
||||
"max_circle_stroke_width": 0.3,
|
||||
"n_vectors": 300,
|
||||
"slow_factor": 0.001,
|
||||
}
|
||||
|
||||
def run_one_cycle(self):
|
||||
self.vector_clock.set_value(0.3)
|
||||
self.wait(40)
|
||||
|
||||
|
||||
class FourierOfHilbert(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"n_vectors": 300,
|
||||
"rect_stroke_width": 1,
|
||||
"drawn_path_stroke_width": 4,
|
||||
"drawn_path_color": BLUE,
|
||||
}
|
||||
|
||||
def get_path(self):
|
||||
path = HilbertCurve(order=5)
|
||||
path.set_height(self.drawing_height)
|
||||
path.to_edge(DOWN)
|
||||
combined_path = VMobject()
|
||||
for sm in path.family_members_with_points():
|
||||
combined_path.append_vectorized_mobject(sm)
|
||||
start = combined_path.get_start()
|
||||
end = combined_path.get_end()
|
||||
points = [
|
||||
interpolate(end, start, alpha)
|
||||
for alpha in np.linspace(0, 1, 10)
|
||||
]
|
||||
for point in points:
|
||||
combined_path.add_line_to(point)
|
||||
|
||||
combined_path.set_stroke(width=0)
|
||||
return combined_path
|
||||
|
||||
|
||||
class FourierOfHilbertZoomedIn(FourierOfHilbert, ZoomedInFourierSeriesExample):
|
||||
pass
|
||||
|
||||
|
||||
class FourierOfBritain(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "Britain",
|
||||
"n_vectors": 500,
|
||||
"drawn_path_color": RED,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfBritainZoomedIn(FourierOfBritain, ZoomedInFourierSeriesExample):
|
||||
pass
|
||||
|
||||
|
||||
class FourierOfSeattle(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "SeattleSkyline",
|
||||
"drawing_height": 7,
|
||||
"n_vectors": 400,
|
||||
"drawn_path_color": TEAL,
|
||||
"drawn_path_stroke_width": 5,
|
||||
}
|
||||
|
||||
|
||||
class FourierOfSeattleZoomedIn(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
"file_name": "SeattleSkyline",
|
||||
"drawing_height": 7,
|
||||
"n_vectors": 400,
|
||||
"drawn_path_color": TEAL,
|
||||
"drawn_path_stroke_width": 5,
|
||||
"max_circle_stroke_width": 0.3,
|
||||
}
|
||||
|
||||
|
||||
class VideoWrapper(Scene):
|
||||
def construct(self):
|
||||
fade_rect = FullScreenFadeRectangle()
|
||||
fade_rect.set_fill(DARK_GREY, 1)
|
||||
screen_rect = ScreenRectangle()
|
||||
screen_rect.set_height(4)
|
||||
screen_rect.set_fill(BLACK, 1)
|
||||
screen_rect.set_stroke(width=0)
|
||||
|
||||
boundary = AnimatedBoundary(screen_rect)
|
||||
|
||||
title = TextMobject("Learn the math")
|
||||
title.scale(1.5)
|
||||
title.next_to(screen_rect, UP)
|
||||
|
||||
self.add(fade_rect)
|
||||
self.add(screen_rect)
|
||||
self.add(boundary)
|
||||
|
||||
self.play(FadeInFromDown(title))
|
||||
self.wait(19)
|
||||
|
|
@ -20,3 +20,216 @@ class WhyWouldYouCare(TeacherStudentsScene):
|
|||
)
|
||||
self.look_at(self.screen)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class SolveForWavesNothingElse(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.student_says(
|
||||
"Sure, we can\\\\solve it for\\\\sums of waves...",
|
||||
target_mode="sassy",
|
||||
student_index=2,
|
||||
added_anims=[self.teacher.change, "guilty"]
|
||||
)
|
||||
self.change_student_modes("pondering", "pondering", "sassy")
|
||||
self.look_at(self.screen)
|
||||
self.wait(4)
|
||||
self.student_says(
|
||||
"But nothing else!",
|
||||
target_mode="angry",
|
||||
)
|
||||
self.change_student_modes(
|
||||
"concerned_musician",
|
||||
"concerned_musician",
|
||||
"angry",
|
||||
)
|
||||
self.wait(5)
|
||||
|
||||
|
||||
class HangOnThere(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
student = self.students[2]
|
||||
|
||||
axes1 = Axes(
|
||||
x_min=0,
|
||||
x_max=1,
|
||||
y_min=-1.5,
|
||||
y_max=1.5,
|
||||
x_axis_config={
|
||||
"tick_frequency": 0.25,
|
||||
"include_tip": False,
|
||||
"unit_size": 3,
|
||||
},
|
||||
y_axis_config={
|
||||
"tick_frequency": 0.5,
|
||||
"include_tip": False,
|
||||
},
|
||||
)
|
||||
axes1.set_stroke(width=2)
|
||||
axes2 = axes1.deepcopy()
|
||||
neq = TexMobject("\\neq")
|
||||
neq.scale(2)
|
||||
|
||||
group = VGroup(axes1, neq, axes2)
|
||||
group.arrange(RIGHT)
|
||||
group.set_height(4)
|
||||
group.next_to(
|
||||
student.get_corner(UL), UP,
|
||||
buff=LARGE_BUFF,
|
||||
)
|
||||
|
||||
step_graph = axes1.get_graph(
|
||||
lambda x: (1 if x < 0.5 else -1),
|
||||
discontinuities=[0.5],
|
||||
)
|
||||
step_graph.set_color(YELLOW)
|
||||
wave_graphs = VGroup(*[
|
||||
axes2.get_graph(
|
||||
lambda x: (4 / PI) * np.sum([
|
||||
(u / n) * np.cos(n * PI * x)
|
||||
for u, n in zip(
|
||||
it.cycle([1, -1]),
|
||||
range(1, max_n, 2),
|
||||
)
|
||||
]),
|
||||
)
|
||||
for max_n in range(3, 103, 2)
|
||||
])
|
||||
wave_graphs.set_stroke(width=3)
|
||||
wave_graphs.set_color_by_gradient(WHITE, PINK)
|
||||
last_wave_graph = wave_graphs[-1]
|
||||
last_wave_graph.set_stroke(PINK, 2)
|
||||
wave_graphs.remove(last_wave_graph)
|
||||
# wave_graphs[-1].set_stroke(width=3)
|
||||
# wave_graphs[-1].set_stroke(BLACK, 5, background=True)
|
||||
group.add(step_graph)
|
||||
|
||||
self.student_says(
|
||||
"Hang on\\\\hang on\\\\hang on...",
|
||||
target_mode="surprised",
|
||||
content_introduction_class=FadeIn,
|
||||
student_index=2,
|
||||
added_anims=[
|
||||
self.teacher.change, "guilty"
|
||||
],
|
||||
run_time=1,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
RemovePiCreatureBubble(
|
||||
student,
|
||||
target_mode="raise_left_hand",
|
||||
look_at_arg=group,
|
||||
),
|
||||
FadeInFromDown(group),
|
||||
)
|
||||
|
||||
last_wg = VectorizedPoint()
|
||||
n_first_fades = 4
|
||||
for wg in wave_graphs[:n_first_fades]:
|
||||
self.play(
|
||||
last_wg.set_stroke, {"width": 0.1},
|
||||
FadeIn(wg),
|
||||
)
|
||||
last_wg = wg
|
||||
self.play(
|
||||
LaggedStart(
|
||||
*[
|
||||
UpdateFromAlphaFunc(
|
||||
wg,
|
||||
lambda m, a: m.set_stroke(
|
||||
width=(3 * there_and_back(a) + 0.1 * a)
|
||||
),
|
||||
)
|
||||
for wg in wave_graphs[n_first_fades:]
|
||||
],
|
||||
run_time=5,
|
||||
lag_ratio=0.2,
|
||||
),
|
||||
ApplyMethod(
|
||||
last_wg.set_stroke, {"width": 0.1},
|
||||
run_time=0.25,
|
||||
),
|
||||
FadeIn(
|
||||
last_wave_graph,
|
||||
rate_func=squish_rate_func(smooth, 0.9, 1),
|
||||
run_time=5,
|
||||
),
|
||||
self.teacher.change, "thinking",
|
||||
)
|
||||
self.change_student_modes(
|
||||
"confused", "confused", "angry"
|
||||
)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class YouSaidThisWasEasier(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.change_all_student_modes(
|
||||
"confused", look_at_arg=self.screen,
|
||||
)
|
||||
self.student_says(
|
||||
"I'm sorry, you said\\\\this was easier?",
|
||||
target_mode="sassy"
|
||||
)
|
||||
self.play(self.teacher.change, "guilty")
|
||||
self.wait(3)
|
||||
self.teacher_says(
|
||||
"Bear with\\\\me",
|
||||
bubble_kwargs={"height": 3, "width": 3},
|
||||
)
|
||||
self.look_at(self.screen)
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class LooseWithLanguage(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
terms = VGroup(
|
||||
TextMobject("``Complex number''"),
|
||||
TextMobject("``Vector''"),
|
||||
)
|
||||
colors = [YELLOW, BLUE]
|
||||
for term, color in zip(terms, colors):
|
||||
term.set_color(color)
|
||||
|
||||
terms.scale(1.5)
|
||||
terms.arrange(DOWN, buff=LARGE_BUFF)
|
||||
terms.to_edge(UP)
|
||||
terms.match_x(self.students)
|
||||
|
||||
self.teacher_says(
|
||||
"Loose with\\\\language",
|
||||
bubble_kwargs={"width": 3, "height": 3},
|
||||
run_time=2,
|
||||
)
|
||||
self.play(
|
||||
FadeInFrom(terms[1], DOWN),
|
||||
self.get_student_changes(
|
||||
"thinking", "pondering", "erm",
|
||||
look_at_arg=terms,
|
||||
)
|
||||
)
|
||||
self.play(FadeInFromDown(terms[0]))
|
||||
self.wait()
|
||||
self.play(Swap(*terms))
|
||||
self.wait(3)
|
||||
|
||||
|
||||
class FormulaOutOfContext(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
formula = TexMobject(
|
||||
"c_{n} = \\int_0^1 e^{-2\\pi i {n} {t}}f({t}){dt}",
|
||||
tex_to_color_map={
|
||||
"{n}": YELLOW,
|
||||
"{t}": PINK,
|
||||
}
|
||||
)
|
||||
formula.scale(1.5)
|
||||
formula.next_to(self.students, UP, LARGE_BUFF)
|
||||
|
||||
self.add(formula)
|
||||
self.change_all_student_modes(
|
||||
"horrified",
|
||||
look_at_arg=formula,
|
||||
)
|
||||
self.play(self.teacher.change, "tease")
|
||||
self.wait(3)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
371
active_projects/diffyq/part4/temperature_scenes.py
Normal file
371
active_projects/diffyq/part4/temperature_scenes.py
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.diffyq.part2.heat_equation import BringTwoRodsTogether
|
||||
from active_projects.diffyq.part3.staging import FourierSeriesIllustraiton
|
||||
|
||||
|
||||
class StepFunctionExample(BringTwoRodsTogether, FourierSeriesIllustraiton):
|
||||
CONFIG = {
|
||||
"axes_config": {
|
||||
"y_min": -1.5,
|
||||
"y_max": 1.5,
|
||||
"y_axis_config": {
|
||||
"unit_size": 2.5,
|
||||
"tick_frequency": 0.5,
|
||||
},
|
||||
"x_min": 0,
|
||||
"x_max": 1,
|
||||
"x_axis_config": {
|
||||
"unit_size": 8,
|
||||
"tick_frequency": 0.1,
|
||||
"include_tip": False,
|
||||
},
|
||||
},
|
||||
"y_labels": [-1, 1],
|
||||
"graph_x_min": 0,
|
||||
"graph_x_max": 1,
|
||||
"midpoint": 0.5,
|
||||
"min_temp": -1,
|
||||
"max_temp": 1,
|
||||
"alpha": 0.25,
|
||||
"step_size": 0.01,
|
||||
"n_range": range(1, 41, 2),
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.setup_graph()
|
||||
self.setup_clock()
|
||||
|
||||
self.bring_rods_together()
|
||||
self.let_evolve_for_a_bit()
|
||||
self.add_labels()
|
||||
self.compare_to_sine_wave()
|
||||
self.sum_of_sine_waves()
|
||||
|
||||
def bring_rods_together(self):
|
||||
rods = VGroup(
|
||||
self.get_rod(0, 0.5),
|
||||
self.get_rod(0.5, 1),
|
||||
)
|
||||
rods.add_updater(self.update_rods)
|
||||
|
||||
arrows = VGroup(
|
||||
Vector(RIGHT).next_to(rods[0], UP),
|
||||
Vector(LEFT).next_to(rods[1], UP),
|
||||
)
|
||||
|
||||
words = VGroup(
|
||||
TextMobject("Hot").next_to(rods[0], DOWN),
|
||||
TextMobject("Cold").next_to(rods[1], DOWN),
|
||||
)
|
||||
|
||||
for pair in rods, words:
|
||||
pair.save_state()
|
||||
pair.space_out_submobjects(1.2)
|
||||
|
||||
black_rects = VGroup(*[
|
||||
Square(
|
||||
side_length=1,
|
||||
fill_color=BLACK,
|
||||
fill_opacity=1,
|
||||
stroke_width=0,
|
||||
).move_to(self.axes.c2p(0, u))
|
||||
for u in [1, -1]
|
||||
])
|
||||
black_rects[0].add_updater(
|
||||
lambda m: m.align_to(rods[0].get_right(), LEFT)
|
||||
)
|
||||
black_rects[1].add_updater(
|
||||
lambda m: m.align_to(rods[1].get_left(), RIGHT)
|
||||
)
|
||||
|
||||
self.add(
|
||||
self.axes,
|
||||
self.graph,
|
||||
self.clock,
|
||||
)
|
||||
self.add(rods, words)
|
||||
self.add(black_rects)
|
||||
|
||||
kw = {
|
||||
"run_time": 2,
|
||||
"rate_func": rush_into,
|
||||
}
|
||||
self.play(
|
||||
Restore(rods, **kw),
|
||||
Restore(words, **kw),
|
||||
*map(ShowCreation, arrows)
|
||||
)
|
||||
self.remove(black_rects)
|
||||
|
||||
self.to_fade = VGroup(words, arrows)
|
||||
self.rods = rods
|
||||
|
||||
def let_evolve_for_a_bit(self):
|
||||
rods = self.rods
|
||||
# axes = self.axes
|
||||
time_label = self.time_label
|
||||
graph = self.graph
|
||||
graph.save_state()
|
||||
|
||||
graph.add_updater(self.update_graph)
|
||||
time_label.next_to(self.clock, DOWN)
|
||||
time_label.add_updater(
|
||||
lambda d, dt: d.increment_value(dt)
|
||||
)
|
||||
rods.add_updater(self.update_rods)
|
||||
|
||||
self.add(time_label)
|
||||
self.play(
|
||||
FadeOut(self.to_fade),
|
||||
self.get_clock_anim(1)
|
||||
)
|
||||
self.play(self.get_clock_anim(3))
|
||||
|
||||
time_label.clear_updaters()
|
||||
graph.clear_updaters()
|
||||
self.play(
|
||||
self.get_clock_anim(
|
||||
-4,
|
||||
run_time=1,
|
||||
rate_func=smooth,
|
||||
),
|
||||
graph.restore,
|
||||
time_label.set_value, 0,
|
||||
)
|
||||
rods.clear_updaters()
|
||||
self.wait()
|
||||
|
||||
def add_labels(self):
|
||||
axes = self.axes
|
||||
y_axis = axes.y_axis
|
||||
x_axis = axes.x_axis
|
||||
y_numbers = y_axis.get_number_mobjects(
|
||||
*np.arange(-1, 1.5, 0.5),
|
||||
number_config={
|
||||
"unit": "^\\circ",
|
||||
"num_decimal_places": 1,
|
||||
}
|
||||
)
|
||||
x_numbers = x_axis.get_number_mobjects(
|
||||
*np.arange(0.2, 1.2, 0.2),
|
||||
number_config={
|
||||
"num_decimal_places": 1,
|
||||
},
|
||||
)
|
||||
|
||||
self.play(FadeIn(y_numbers))
|
||||
self.play(ShowCreationThenFadeAround(y_numbers[-1]))
|
||||
self.play(ShowCreationThenFadeAround(y_numbers[0]))
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
FadeInFrom, x_numbers,
|
||||
lambda m: (m, UP)
|
||||
),
|
||||
self.rods.set_opacity, 0.8,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def compare_to_sine_wave(self):
|
||||
phi_tracker = ValueTracker(0)
|
||||
get_phi = phi_tracker.get_value
|
||||
k_tracker = ValueTracker(TAU)
|
||||
get_k = k_tracker.get_value
|
||||
A_tracker = ValueTracker(1)
|
||||
get_A = A_tracker.get_value
|
||||
|
||||
sine_wave = always_redraw(lambda: self.axes.get_graph(
|
||||
lambda x: get_A() * np.sin(
|
||||
get_k() * x - get_phi()
|
||||
),
|
||||
x_min=self.graph_x_min,
|
||||
x_max=self.graph_x_max,
|
||||
).color_using_background_image("VerticalTempGradient"))
|
||||
|
||||
self.play(ShowCreation(sine_wave, run_time=3))
|
||||
self.wait()
|
||||
self.play(A_tracker.set_value, 1.25)
|
||||
self.play(A_tracker.set_value, 0.75)
|
||||
self.play(phi_tracker.set_value, -PI / 2)
|
||||
self.play(k_tracker.set_value, 3 * TAU)
|
||||
self.play(k_tracker.set_value, 2 * TAU)
|
||||
self.play(
|
||||
k_tracker.set_value, PI,
|
||||
A_tracker.set_value, 4 / PI,
|
||||
run_time=3
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.sine_wave = sine_wave
|
||||
|
||||
def sum_of_sine_waves(self):
|
||||
curr_sine_wave = self.sine_wave
|
||||
axes = self.axes
|
||||
|
||||
sine_graphs = self.get_sine_graphs(axes)
|
||||
partial_sums = self.get_partial_sums(axes, sine_graphs)
|
||||
|
||||
curr_partial_sum = partial_sums[0]
|
||||
curr_partial_sum.set_color(WHITE)
|
||||
self.play(
|
||||
FadeOut(curr_sine_wave),
|
||||
FadeIn(curr_partial_sum),
|
||||
FadeOut(self.rods),
|
||||
)
|
||||
# Copy-pasting from superclass...in theory,
|
||||
# this should be better abstracted, but eh.
|
||||
pairs = list(zip(sine_graphs, partial_sums))[1:]
|
||||
for sine_graph, partial_sum in pairs:
|
||||
anims1 = [
|
||||
ShowCreation(sine_graph)
|
||||
]
|
||||
partial_sum.set_stroke(BLACK, 4, background=True)
|
||||
anims2 = [
|
||||
curr_partial_sum.set_stroke,
|
||||
{"width": 1, "opacity": 0.25},
|
||||
curr_partial_sum.set_stroke,
|
||||
{"width": 0, "background": True},
|
||||
ReplacementTransform(
|
||||
sine_graph, partial_sum,
|
||||
remover=True
|
||||
),
|
||||
]
|
||||
self.play(*anims1)
|
||||
self.play(*anims2)
|
||||
curr_partial_sum = partial_sum
|
||||
|
||||
#
|
||||
def setup_axes(self):
|
||||
super().setup_axes()
|
||||
self.axes.shift(
|
||||
self.axes.c2p(0, 0)[1] * DOWN
|
||||
)
|
||||
|
||||
|
||||
class BreakDownStepFunction(StepFunctionExample):
|
||||
CONFIG = {
|
||||
"axes_config": {
|
||||
"x_axis_config": {
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"y_axis_config": {
|
||||
"tick_frequency": 0.25,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"y_min": -1.25,
|
||||
"y_max": 1.25,
|
||||
},
|
||||
"alpha": 0.1,
|
||||
"wait_time": 30,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.setup_graph()
|
||||
self.setup_clock()
|
||||
self.add_rod()
|
||||
|
||||
self.wait()
|
||||
self.init_updaters()
|
||||
self.play(
|
||||
self.get_clock_anim(self.wait_time)
|
||||
)
|
||||
|
||||
def setup_axes(self):
|
||||
super().setup_axes()
|
||||
axes = self.axes
|
||||
axes.to_edge(LEFT)
|
||||
|
||||
mini_axes = VGroup(*[
|
||||
axes.deepcopy()
|
||||
for x in range(4)
|
||||
])
|
||||
for n, ma in zip(it.count(1, 2), mini_axes):
|
||||
if n == 1:
|
||||
t1 = TexMobject("1")
|
||||
t2 = TexMobject("-1")
|
||||
else:
|
||||
t1 = TexMobject("1 / " + str(n))
|
||||
t2 = TexMobject("-1 / " + str(n))
|
||||
VGroup(t1, t2).scale(1.5)
|
||||
t1.next_to(ma.y_axis.n2p(1), LEFT, MED_SMALL_BUFF)
|
||||
t2.next_to(ma.y_axis.n2p(-1), LEFT, MED_SMALL_BUFF)
|
||||
ma.y_axis.numbers.set_opacity(0)
|
||||
ma.y_axis.add(t1, t2)
|
||||
|
||||
for mob in mini_axes.get_family():
|
||||
if isinstance(mob, Line):
|
||||
mob.set_stroke(width=1, family=False)
|
||||
mini_axes.arrange(DOWN, buff=2)
|
||||
mini_axes.set_height(FRAME_HEIGHT - 1.5)
|
||||
mini_axes.to_corner(UR)
|
||||
self.scale_factor = fdiv(
|
||||
mini_axes[0].get_width(),
|
||||
axes.get_width(),
|
||||
)
|
||||
|
||||
# mini_axes.arrange(RIGHT, buff=2)
|
||||
# mini_axes.set_width(FRAME_WIDTH - 1.5)
|
||||
# mini_axes.to_edge(LEFT)
|
||||
|
||||
dots = TexMobject("\\vdots")
|
||||
dots.next_to(mini_axes, DOWN)
|
||||
dots.shift_onto_screen()
|
||||
|
||||
self.add(axes)
|
||||
self.add(mini_axes)
|
||||
self.add(dots)
|
||||
|
||||
self.mini_axes = mini_axes
|
||||
|
||||
def setup_graph(self):
|
||||
super().setup_graph()
|
||||
graph = self.graph
|
||||
self.add(graph)
|
||||
|
||||
mini_axes = self.mini_axes
|
||||
mini_graphs = VGroup()
|
||||
for axes, u, n in zip(mini_axes, it.cycle([1, -1]), it.count(1, 2)):
|
||||
mini_graph = axes.get_graph(
|
||||
lambda x: (4 / PI) * (u / 1) * np.cos(PI * n * x),
|
||||
)
|
||||
mini_graph.set_stroke(WHITE, width=2)
|
||||
mini_graphs.add(mini_graph)
|
||||
# mini_graphs.set_color_by_gradient(
|
||||
# BLUE, GREEN, RED, YELLOW,
|
||||
# )
|
||||
|
||||
self.mini_graphs = mini_graphs
|
||||
self.add(mini_graphs)
|
||||
|
||||
def setup_clock(self):
|
||||
super().setup_clock()
|
||||
clock = self.clock
|
||||
time_label = self.time_label
|
||||
|
||||
clock.move_to(3 * RIGHT)
|
||||
clock.to_corner(UP)
|
||||
time_label.next_to(clock, DOWN)
|
||||
|
||||
self.add(clock)
|
||||
self.add(time_label)
|
||||
|
||||
def add_rod(self):
|
||||
self.rod = self.get_rod(0, 1)
|
||||
self.add(self.rod)
|
||||
|
||||
def init_updaters(self):
|
||||
self.graph.add_updater(self.update_graph)
|
||||
for mg in self.mini_graphs:
|
||||
mg.add_updater(
|
||||
lambda m, dt: self.update_graph(
|
||||
m, dt,
|
||||
alpha=self.scale_factor * self.alpha
|
||||
)
|
||||
)
|
||||
self.time_label.add_updater(
|
||||
lambda d, dt: d.increment_value(dt)
|
||||
)
|
||||
self.rod.add_updater(
|
||||
lambda r: self.update_rods([r])
|
||||
)
|
||||
474
active_projects/diffyq/part4/three_d_graphs.py
Normal file
474
active_projects/diffyq/part4/three_d_graphs.py
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
from manimlib.imports import *
|
||||
from active_projects.diffyq.part3.temperature_graphs import TemperatureGraphScene
|
||||
from active_projects.diffyq.part2.wordy_scenes import WriteHeatEquationTemplate
|
||||
|
||||
|
||||
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, **kw)
|
||||
self.play(s2.set_value, 0.3, **kw)
|
||||
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, **kwargs):
|
||||
axes = self.get_three_d_axes(**kwargs)
|
||||
# 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.func = func
|
||||
result.suspend_updating()
|
||||
return result
|
||||
|
||||
|
||||
class CombineSeveralSolutions(ShowLinearity):
|
||||
CONFIG = {
|
||||
"default_surface_config": {
|
||||
"resolution": (16, 16),
|
||||
# "resolution": (4, 4),
|
||||
},
|
||||
"n_top_graphs": 5,
|
||||
"axes_config": {
|
||||
"y_max": 15,
|
||||
},
|
||||
"target_scalars": [
|
||||
0.81, -0.53, 0.41, 0.62, -0.95
|
||||
],
|
||||
"final_run_time": 14,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.init_camera()
|
||||
self.add_all_axes()
|
||||
self.setup_all_graphs()
|
||||
self.show_infinite_family()
|
||||
self.show_sum()
|
||||
self.show_time_passing()
|
||||
|
||||
def add_all_axes(self):
|
||||
top_axes_group = VGroup(*[
|
||||
self.get_axes(
|
||||
z_min=-1.25,
|
||||
z_max=1.25,
|
||||
z_axis_config={
|
||||
"unit_size": 2,
|
||||
"tick_frequency": 0.5,
|
||||
},
|
||||
)
|
||||
for x in range(self.n_top_graphs)
|
||||
])
|
||||
top_axes_group.arrange(RIGHT, buff=2)
|
||||
top_axes_group.set_width(FRAME_WIDTH - 1.5)
|
||||
top_axes_group.to_corner(UL)
|
||||
dots = TexMobject("\\dots")
|
||||
dots.next_to(top_axes_group, RIGHT)
|
||||
|
||||
low_axes = self.get_axes()
|
||||
low_axes.center()
|
||||
low_axes.scale(1.2)
|
||||
low_axes.to_edge(DOWN, buff=SMALL_BUFF)
|
||||
|
||||
self.add(top_axes_group)
|
||||
self.add(dots)
|
||||
self.add(low_axes)
|
||||
|
||||
self.top_axes_group = top_axes_group
|
||||
self.low_axes = low_axes
|
||||
|
||||
def setup_all_graphs(self):
|
||||
scalar_trackers = Group(*[
|
||||
ValueTracker(1)
|
||||
for x in range(self.n_top_graphs)
|
||||
])
|
||||
freqs = np.arange(self.n_top_graphs)
|
||||
freqs += 1
|
||||
self.top_graphs = VGroup(*[
|
||||
self.get_graph(axes, [n], [st])
|
||||
for axes, n, st in zip(
|
||||
self.top_axes_group,
|
||||
freqs,
|
||||
scalar_trackers,
|
||||
)
|
||||
])
|
||||
self.low_graph = self.get_graph(
|
||||
self.low_axes, freqs, scalar_trackers
|
||||
)
|
||||
|
||||
self.scalar_trackers = scalar_trackers
|
||||
|
||||
def show_infinite_family(self):
|
||||
top_axes_group = self.top_axes_group
|
||||
top_graphs = self.top_graphs
|
||||
scalar_trackers = self.scalar_trackers
|
||||
|
||||
decimals = self.get_decimals(
|
||||
top_axes_group, scalar_trackers
|
||||
)
|
||||
|
||||
self.play(LaggedStart(*[
|
||||
AnimationGroup(
|
||||
Write(graph[0]),
|
||||
FadeIn(graph[1]),
|
||||
)
|
||||
for graph in top_graphs
|
||||
]))
|
||||
self.wait()
|
||||
self.play(FadeIn(decimals))
|
||||
for graph in top_graphs:
|
||||
graph.resume_updating()
|
||||
|
||||
self.play(LaggedStart(*[
|
||||
ApplyMethod(st.set_value, value)
|
||||
for st, value in zip(
|
||||
scalar_trackers,
|
||||
self.target_scalars,
|
||||
)
|
||||
]), run_time=3)
|
||||
self.wait()
|
||||
|
||||
def show_sum(self):
|
||||
top_graphs = self.top_graphs
|
||||
low_graph = self.low_graph
|
||||
low_graph.resume_updating()
|
||||
low_graph.update()
|
||||
|
||||
self.play(
|
||||
LaggedStart(*[
|
||||
Transform(
|
||||
top_graph.copy().set_fill(opacity=0),
|
||||
low_graph.copy().set_fill(opacity=0),
|
||||
remover=True,
|
||||
)
|
||||
for top_graph in top_graphs
|
||||
]),
|
||||
FadeIn(
|
||||
low_graph,
|
||||
rate_func=squish_rate_func(smooth, 0.7, 1)
|
||||
),
|
||||
run_time=3,
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def show_time_passing(self):
|
||||
all_graphs = [*self.top_graphs, self.low_graph]
|
||||
all_axes = [*self.top_axes_group, self.low_axes]
|
||||
|
||||
time_tracker = ValueTracker(0)
|
||||
get_t = time_tracker.get_value
|
||||
|
||||
anims = [
|
||||
ApplyMethod(
|
||||
time_tracker.set_value, 1,
|
||||
run_time=1,
|
||||
rate_func=linear
|
||||
)
|
||||
]
|
||||
|
||||
for axes, graph_group in zip(all_axes, all_graphs):
|
||||
graph_group.clear_updaters()
|
||||
surface, gslice = graph_group
|
||||
plane = self.get_const_time_plane(axes)
|
||||
plane.t_tracker.add_updater(
|
||||
lambda m: m.set_value(get_t())
|
||||
)
|
||||
gslice.axes = axes
|
||||
gslice.func = graph_group.func
|
||||
gslice.add_updater(lambda m: m.become(
|
||||
self.get_time_slice_graph(
|
||||
m.axes, m.func, t=get_t()
|
||||
)
|
||||
))
|
||||
self.add(gslice)
|
||||
self.add(plane.t_tracker)
|
||||
anims.append(FadeIn(plane))
|
||||
|
||||
self.play(*anims)
|
||||
run_time = self.final_run_time
|
||||
self.play(
|
||||
time_tracker.increment_value, run_time,
|
||||
run_time=run_time,
|
||||
rate_func=linear,
|
||||
)
|
||||
|
||||
#
|
||||
def get_decimals(self, axes_group, scalar_trackers):
|
||||
result = VGroup()
|
||||
for axes, st in zip(axes_group, scalar_trackers):
|
||||
decimal = DecimalNumber()
|
||||
decimal.move_to(axes.get_bottom(), UP)
|
||||
decimal.shift(SMALL_BUFF * RIGHT)
|
||||
decimal.set_color(YELLOW)
|
||||
decimal.scalar_tracker = st
|
||||
times = TexMobject("\\times")
|
||||
times.next_to(decimal, LEFT, SMALL_BUFF)
|
||||
decimal.add_updater(lambda d: d.set_value(
|
||||
d.scalar_tracker.get_value()
|
||||
))
|
||||
group = VGroup(times, decimal)
|
||||
group.scale(0.7)
|
||||
result.add(group)
|
||||
return result
|
||||
|
||||
|
||||
class CycleThroughManyLinearCombinations(CombineSeveralSolutions):
|
||||
CONFIG = {
|
||||
"default_surface_config": {
|
||||
"resolution": (16, 16),
|
||||
# "resolution": (4, 4),
|
||||
},
|
||||
"n_cycles": 10,
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.init_camera()
|
||||
self.add_all_axes()
|
||||
self.setup_all_graphs()
|
||||
#
|
||||
self.cycle_through_superpositions()
|
||||
|
||||
def cycle_through_superpositions(self):
|
||||
top_graphs = self.top_graphs
|
||||
low_graph = self.low_graph
|
||||
scalar_trackers = self.scalar_trackers
|
||||
self.add(self.get_decimals(
|
||||
self.top_axes_group, scalar_trackers
|
||||
))
|
||||
|
||||
for graph in [low_graph, *top_graphs]:
|
||||
graph.resume_updating()
|
||||
self.add(graph)
|
||||
|
||||
nst = len(scalar_trackers)
|
||||
for x in range(self.n_cycles):
|
||||
self.play(LaggedStart(*[
|
||||
ApplyMethod(st.set_value, value)
|
||||
for st, value in zip(
|
||||
scalar_trackers,
|
||||
3 * np.random.random(nst) - 1.5
|
||||
)
|
||||
]), run_time=3)
|
||||
self.wait()
|
||||
1586
active_projects/diffyq/part5/staging.py
Normal file
1586
active_projects/diffyq/part5/staging.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -6,6 +6,7 @@ VIDEO_DIR = ""
|
|||
VIDEO_OUTPUT_DIR = ""
|
||||
TEX_DIR = ""
|
||||
|
||||
|
||||
def initialize_directories(config):
|
||||
global MEDIA_DIR
|
||||
global VIDEO_DIR
|
||||
|
|
@ -13,14 +14,6 @@ def initialize_directories(config):
|
|||
global TEX_DIR
|
||||
|
||||
video_path_specified = config["video_dir"] or config["video_output_dir"]
|
||||
if not video_path_specified:
|
||||
VIDEO_DIR = os.path.join(MEDIA_DIR, "videos")
|
||||
elif config["video_output_dir"]:
|
||||
VIDEO_OUTPUT_DIR = config["video_output_dir"]
|
||||
else:
|
||||
VIDEO_DIR = config["video_dir"]
|
||||
|
||||
TEX_DIR = config["tex_dir"] or os.path.join(MEDIA_DIR, "Tex")
|
||||
|
||||
if not (video_path_specified and config["tex_dir"]):
|
||||
if config["media_dir"]:
|
||||
|
|
@ -43,10 +36,20 @@ def initialize_directories(config):
|
|||
"directory were both passed"
|
||||
)
|
||||
|
||||
TEX_DIR = config["tex_dir"] or os.path.join(MEDIA_DIR, "Tex")
|
||||
if not video_path_specified:
|
||||
VIDEO_DIR = os.path.join(MEDIA_DIR, "videos")
|
||||
VIDEO_OUTPUT_DIR = os.path.join(MEDIA_DIR, "videos")
|
||||
elif config["video_output_dir"]:
|
||||
VIDEO_OUTPUT_DIR = config["video_output_dir"]
|
||||
else:
|
||||
VIDEO_DIR = config["video_dir"]
|
||||
|
||||
for folder in [VIDEO_DIR, VIDEO_OUTPUT_DIR, TEX_DIR]:
|
||||
if folder != "" and not os.path.exists(folder):
|
||||
os.makedirs(folder)
|
||||
|
||||
|
||||
TEX_USE_CTEX = False
|
||||
TEX_TEXT_TO_REPLACE = "YourTextHere"
|
||||
TEMPLATE_TEX_FILE = os.path.join(
|
||||
|
|
@ -228,6 +231,7 @@ COLOR_MAP = {
|
|||
"DARKER_GRAY": "#222222",
|
||||
"GREY_BROWN": "#736357",
|
||||
"PINK": "#D147BD",
|
||||
"LIGHT_PINK": "#DC75CD",
|
||||
"GREEN_SCREEN": "#00FF00",
|
||||
"ORANGE": "#FF862F",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,8 +148,8 @@ class PatreonThanks(Scene):
|
|||
|
||||
class PatreonEndScreen(PatreonThanks, PiCreatureScene):
|
||||
CONFIG = {
|
||||
"n_patron_columns": 3,
|
||||
"max_patron_width": 3.5,
|
||||
"n_patron_columns": 4,
|
||||
"max_patron_width": 5,
|
||||
"run_time": 20,
|
||||
"randomize_order": True,
|
||||
"capitalize": True,
|
||||
|
|
@ -236,10 +236,11 @@ class PatreonEndScreen(PatreonThanks, PiCreatureScene):
|
|||
RIGHT, buff=LARGE_BUFF,
|
||||
aligned_edge=UP,
|
||||
)
|
||||
if columns.get_width() > self.max_patron_width:
|
||||
columns.set_width(total_width - 1)
|
||||
|
||||
thanks.to_edge(RIGHT, buff=MED_SMALL_BUFF)
|
||||
max_width = FRAME_WIDTH - 1
|
||||
if columns.get_width() > max_width:
|
||||
columns.set_width(max_width)
|
||||
underline.match_width(columns)
|
||||
# thanks.to_edge(RIGHT, buff=MED_SMALL_BUFF)
|
||||
columns.next_to(underline, DOWN, buff=2)
|
||||
|
||||
columns.generate_target()
|
||||
|
|
@ -257,8 +258,11 @@ class PatreonEndScreen(PatreonThanks, PiCreatureScene):
|
|||
self.wait(wait_time)
|
||||
|
||||
def modify_patron_name(self, name):
|
||||
if name == "RedAgent14":
|
||||
if name.lower() == "RedAgent14".lower():
|
||||
return "Brian Shepetofsky"
|
||||
elif name.lower() == "DeathByShrimp".lower():
|
||||
return "Henry Bresnahan"
|
||||
|
||||
return name
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import random
|
|||
|
||||
from manimlib.animation.transform import ReplacementTransform
|
||||
from manimlib.animation.transform import Transform
|
||||
from manimlib.animation.transform import ApplyMethod
|
||||
from manimlib.animation.composition import LaggedStart
|
||||
from manimlib.animation.update import UpdateFromAlphaFunc
|
||||
from manimlib.constants import *
|
||||
from manimlib.for_3b1b_videos.pi_creature import Mortimer
|
||||
from manimlib.for_3b1b_videos.pi_creature import PiCreature
|
||||
|
|
@ -12,12 +12,12 @@ from manimlib.for_3b1b_videos.pi_creature import Randolph
|
|||
from manimlib.for_3b1b_videos.pi_creature_animations import Blink
|
||||
from manimlib.for_3b1b_videos.pi_creature_animations import PiCreatureBubbleIntroduction
|
||||
from manimlib.for_3b1b_videos.pi_creature_animations import RemovePiCreatureBubble
|
||||
from manimlib.mobject.mobject import Group
|
||||
from manimlib.mobject.frame import ScreenRectangle
|
||||
from manimlib.mobject.svg.drawings import SpeechBubble
|
||||
from manimlib.mobject.svg.drawings import ThoughtBubble
|
||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
||||
from manimlib.scene.scene import Scene
|
||||
from manimlib.utils.bezier import interpolate
|
||||
from manimlib.utils.rate_functions import squish_rate_func
|
||||
from manimlib.utils.rate_functions import there_and_back
|
||||
from manimlib.utils.space_ops import get_norm
|
||||
|
|
@ -154,6 +154,8 @@ class PiCreatureScene(Scene):
|
|||
first mobject being animated with each .play call
|
||||
"""
|
||||
animations = Scene.compile_play_args_to_animation_list(self, *args, **kwargs)
|
||||
anim_mobjects = Group(*[a.mobject for a in animations])
|
||||
all_movers = anim_mobjects.get_family()
|
||||
if not self.any_pi_creatures_on_screen():
|
||||
return animations
|
||||
|
||||
|
|
@ -169,19 +171,12 @@ class PiCreatureScene(Scene):
|
|||
# is being animated
|
||||
first_anim = non_pi_creature_anims[0]
|
||||
main_mobject = first_anim.mobject
|
||||
animations += [
|
||||
UpdateFromAlphaFunc(
|
||||
pi_creature,
|
||||
lambda p, a: p.look_at(
|
||||
interpolate(
|
||||
p.get_look_at_spot(),
|
||||
main_mobject.get_center(),
|
||||
a,
|
||||
)
|
||||
),
|
||||
)
|
||||
for pi_creature in pi_creatures
|
||||
]
|
||||
for pi_creature in pi_creatures:
|
||||
if pi_creature not in all_movers:
|
||||
animations.append(ApplyMethod(
|
||||
pi_creature.look_at,
|
||||
main_mobject,
|
||||
))
|
||||
return animations
|
||||
|
||||
def blink(self):
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class AnimatedBoundary(VGroup):
|
|||
draw_alpha = self.draw_rate_func(alpha)
|
||||
fade_alpha = self.fade_rate_func(alpha)
|
||||
|
||||
if self.back_and_forth and int(time) % 1 == 0:
|
||||
if self.back_and_forth and int(time) % 2 == 1:
|
||||
bounds = (1 - draw_alpha, 1)
|
||||
else:
|
||||
bounds = (0, draw_alpha)
|
||||
|
|
|
|||
|
|
@ -388,10 +388,16 @@ class ComplexPlane(NumberPlane):
|
|||
number = complex(number)
|
||||
return self.coords_to_point(number.real, number.imag)
|
||||
|
||||
def n2p(self, number):
|
||||
return self.number_to_point(number)
|
||||
|
||||
def point_to_number(self, point):
|
||||
x, y = self.point_to_coords(point)
|
||||
return complex(x, y)
|
||||
|
||||
def p2n(self, point):
|
||||
return self.point_to_number(point)
|
||||
|
||||
def get_default_coordinate_values(self):
|
||||
x_numbers = self.get_x_axis().default_numbers_to_display()
|
||||
y_numbers = self.get_y_axis().default_numbers_to_display()
|
||||
|
|
|
|||
|
|
@ -494,7 +494,7 @@ class Line(TipableVMobject):
|
|||
self.start = start
|
||||
self.end = end
|
||||
self.generate_points()
|
||||
super().put_start_and_end_on(start, end)
|
||||
return super().put_start_and_end_on(start, end)
|
||||
|
||||
def get_vector(self):
|
||||
return self.get_end() - self.get_start()
|
||||
|
|
@ -619,7 +619,6 @@ class Arrow(Line):
|
|||
"max_tip_length_to_length_ratio": 0.25,
|
||||
"max_stroke_width_to_length_ratio": 5,
|
||||
"preserve_tip_size_when_scaling": True,
|
||||
"rectangular_stem_width": 0.05,
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -136,7 +136,10 @@ class NumberLine(Line):
|
|||
def default_numbers_to_display(self):
|
||||
if self.numbers_to_show is not None:
|
||||
return self.numbers_to_show
|
||||
numbers = np.arange(int(self.leftmost_tick), int(self.x_max))
|
||||
numbers = np.arange(
|
||||
np.floor(self.leftmost_tick),
|
||||
np.ceil(self.x_max),
|
||||
)
|
||||
if self.exclude_zero_from_default_numbers:
|
||||
numbers = numbers[numbers != 0]
|
||||
return numbers
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ class Bubble(SVGMobject):
|
|||
self.stretch_to_fit_height(self.height)
|
||||
self.stretch_to_fit_width(self.width)
|
||||
if self.direction[0] > 0:
|
||||
Mobject.flip(self)
|
||||
self.flip()
|
||||
self.direction_was_specified = ("direction" in kwargs)
|
||||
self.content = Mobject()
|
||||
|
||||
|
|
@ -457,7 +457,7 @@ class Bubble(SVGMobject):
|
|||
|
||||
def flip(self, axis=UP):
|
||||
Mobject.flip(self, axis=axis)
|
||||
if abs(axis[0]) > 0:
|
||||
if abs(axis[1]) > 0:
|
||||
self.direction = -np.array(self.direction)
|
||||
return self
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ class ParametricSurface(VGroup):
|
|||
|
||||
def __init__(self, func, **kwargs):
|
||||
VGroup.__init__(self, **kwargs)
|
||||
self.func = func
|
||||
self.setup_in_uv_space()
|
||||
self.apply_function(lambda p: func(p[0], p[1]))
|
||||
if self.should_make_jagged:
|
||||
|
|
|
|||
|
|
@ -313,18 +313,9 @@ class SceneFileWriter(object):
|
|||
'-safe', '0',
|
||||
'-i', file_list,
|
||||
'-loglevel', 'error',
|
||||
|
||||
'-c', 'copy',
|
||||
movie_file_path
|
||||
]
|
||||
if not self.save_as_gif:
|
||||
commands +=[
|
||||
'-c', 'copy',
|
||||
movie_file_path
|
||||
]
|
||||
if self.save_as_gif:
|
||||
movie_file_path=self.gif_file_path
|
||||
commands +=[
|
||||
movie_file_path,
|
||||
]
|
||||
if not self.includes_sound:
|
||||
commands.insert(-1, '-an')
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,9 @@ def stage_scenes(module_name):
|
|||
# }
|
||||
# TODO, fix this
|
||||
animation_dir = os.path.join(
|
||||
consts.VIDEO_DIR, "ode", "part3", "1440p60"
|
||||
os.path.expanduser('~'),
|
||||
"Dropbox (3Blue1Brown)/3Blue1Brown Team Folder/videos",
|
||||
"diffyq", "part5", "1440p60"
|
||||
)
|
||||
#
|
||||
files = os.listdir(animation_dir)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue