mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 12:07:45 +00:00
A few more Fourier series scenes
This commit is contained in:
parent
200c479759
commit
247c440d05
5 changed files with 417 additions and 47 deletions
|
|
@ -1,7 +1,19 @@
|
||||||
from active_projects.ode.part2.staging import *
|
from active_projects.ode.part2.staging import *
|
||||||
from active_projects.ode.part2.fourier_series import *
|
from active_projects.ode.part2.fourier_series import *
|
||||||
|
from active_projects.ode.part2.heat_equation import *
|
||||||
|
|
||||||
OUTPUT_DIRECTORY = "ode/part2"
|
OUTPUT_DIRECTORY = "ode/part2"
|
||||||
ALL_SCENE_CLASSES = [
|
ALL_SCENE_CLASSES = [
|
||||||
CirclesDrawingWave,
|
# Tests
|
||||||
|
FourierOfPiSymbol,
|
||||||
|
FourierOfPiSymbol5,
|
||||||
|
FourierOfTrebleClef,
|
||||||
|
# CirclesDrawingWave,
|
||||||
|
# Scenes for video
|
||||||
|
ExplainCircleAnimations,
|
||||||
|
FourierSeriesIntro,
|
||||||
|
FourierSeriesIntroBackground4,
|
||||||
|
FourierSeriesIntroBackground8,
|
||||||
|
FourierSeriesIntroBackground12,
|
||||||
|
FourierSeriesIntroBackground20,
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -2012,19 +2012,25 @@ class ManyStepsFromDifferentStartingPoints(TakeManyTinySteps):
|
||||||
class Thumbnail(IntroduceVectorField):
|
class Thumbnail(IntroduceVectorField):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"vector_field_config": {
|
"vector_field_config": {
|
||||||
"delta_x": 1,
|
"delta_x": 0.5,
|
||||||
"delta_y": 1,
|
"delta_y": 0.5,
|
||||||
"max_magnitude": 5,
|
"max_magnitude": 5,
|
||||||
"length_func": lambda norm: 0.75 * sigmoid(norm),
|
"length_func": lambda norm: 0.5 * sigmoid(norm),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.initialize_plane()
|
self.initialize_plane()
|
||||||
|
self.plane.axes.set_stroke(width=0.5)
|
||||||
self.initialize_vector_field()
|
self.initialize_vector_field()
|
||||||
|
|
||||||
field = self.vector_field
|
field = self.vector_field
|
||||||
field.set_stroke(width=5)
|
field.set_stroke(width=5)
|
||||||
|
for vector in field:
|
||||||
|
vector.set_stroke(width=3)
|
||||||
|
vector.tip.set_stroke(width=0)
|
||||||
|
vector.tip.scale(1.5, about_point=vector.get_last_point())
|
||||||
|
vector.set_opacity(1)
|
||||||
|
|
||||||
title = TextMobject("Differential\\\\", "equations")
|
title = TextMobject("Differential\\\\", "equations")
|
||||||
title.space_out_submobjects(0.8)
|
title.space_out_submobjects(0.8)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
from big_ol_pile_of_manim_imports import *
|
from big_ol_pile_of_manim_imports import *
|
||||||
|
# import scipy
|
||||||
|
|
||||||
|
|
||||||
class CirclesDrawing(Scene):
|
class FourierCirclesScene(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"n_circles": 4,
|
"n_circles": 10,
|
||||||
"big_radius": 2,
|
"big_radius": 2,
|
||||||
"colors": [
|
"colors": [
|
||||||
BLUE_D,
|
BLUE_D,
|
||||||
|
|
@ -14,38 +15,54 @@ class CirclesDrawing(Scene):
|
||||||
"circle_style": {
|
"circle_style": {
|
||||||
"stroke_width": 2,
|
"stroke_width": 2,
|
||||||
},
|
},
|
||||||
"base_frequency": 0.25 * TAU,
|
"base_frequency": 1,
|
||||||
|
"slow_factor": 0.25,
|
||||||
"center_point": ORIGIN,
|
"center_point": ORIGIN,
|
||||||
|
"parametric_function_step_size": 0.001,
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
def get_freqs_and_radii(self):
|
def get_freqs(self):
|
||||||
raise Exception("Not implemented")
|
n = self.n_circles
|
||||||
|
all_freqs = list(range(n // 2, -n // 2, -1))
|
||||||
|
all_freqs.sort(key=abs)
|
||||||
|
return all_freqs
|
||||||
|
|
||||||
|
def get_coefficients(self):
|
||||||
|
return [complex(0) for x in range(self.n_circles)]
|
||||||
|
|
||||||
def get_color_iterator(self):
|
def get_color_iterator(self):
|
||||||
return it.cycle(self.colors)
|
return it.cycle(self.colors)
|
||||||
|
|
||||||
def get_circles(self):
|
def get_circles(self, freqs=None, coefficients=None):
|
||||||
circles = VGroup()
|
circles = VGroup()
|
||||||
color_iterator = self.get_color_iterator()
|
color_iterator = self.get_color_iterator()
|
||||||
self.center_tracker = VectorizedPoint(self.center_point)
|
self.center_tracker = VectorizedPoint(self.center_point)
|
||||||
|
|
||||||
|
if freqs is None:
|
||||||
|
freqs = self.get_freqs()
|
||||||
|
if coefficients is None:
|
||||||
|
coefficients = self.get_coefficients()
|
||||||
|
|
||||||
last_circle = None
|
last_circle = None
|
||||||
for freq, radius in self.get_freqs_and_radii():
|
for freq, coefficient in zip(freqs, coefficients):
|
||||||
if last_circle:
|
if last_circle:
|
||||||
center_func = last_circle.get_start
|
center_func = last_circle.get_start
|
||||||
else:
|
else:
|
||||||
center_func = self.center_tracker.get_location
|
center_func = self.center_tracker.get_location
|
||||||
circle = self.get_circle(
|
circle = self.get_circle(
|
||||||
radius=radius,
|
coefficient=coefficient,
|
||||||
color=next(color_iterator),
|
|
||||||
freq=freq,
|
freq=freq,
|
||||||
center_func=center_func
|
color=next(color_iterator),
|
||||||
|
center_func=center_func,
|
||||||
)
|
)
|
||||||
circles.add(circle)
|
circles.add(circle)
|
||||||
last_circle = circle
|
last_circle = circle
|
||||||
return circles
|
return circles
|
||||||
|
|
||||||
def get_circle(self, radius, color, freq, center_func):
|
def get_circle(self, coefficient, freq, color, center_func):
|
||||||
|
radius = abs(coefficient)
|
||||||
|
phase = np.log(coefficient).imag
|
||||||
circle = Circle(
|
circle = Circle(
|
||||||
radius=radius,
|
radius=radius,
|
||||||
color=color,
|
color=color,
|
||||||
|
|
@ -59,41 +76,60 @@ class CirclesDrawing(Scene):
|
||||||
)
|
)
|
||||||
circle.add(circle.radial_line)
|
circle.add(circle.radial_line)
|
||||||
circle.freq = freq
|
circle.freq = freq
|
||||||
|
circle.phase = phase
|
||||||
|
circle.rotate(phase)
|
||||||
|
circle.coefficient = coefficient
|
||||||
circle.center_func = center_func
|
circle.center_func = center_func
|
||||||
circle.add_updater(self.update_circle)
|
circle.add_updater(self.update_circle)
|
||||||
return circle
|
return circle
|
||||||
|
|
||||||
def update_circle(self, circle, dt):
|
def update_circle(self, circle, dt):
|
||||||
circle.rotate(circle.freq * dt)
|
circle.rotate(
|
||||||
|
self.slow_factor * circle.freq * dt * TAU
|
||||||
|
)
|
||||||
circle.move_to(circle.center_func())
|
circle.move_to(circle.center_func())
|
||||||
return circle
|
return circle
|
||||||
|
|
||||||
|
def get_rotating_vectors(self, circles):
|
||||||
|
return VGroup(*[
|
||||||
|
self.get_rotating_vector(circle)
|
||||||
|
for circle in circles
|
||||||
|
])
|
||||||
|
|
||||||
|
def get_rotating_vector(self, circle):
|
||||||
|
vector = Vector(RIGHT, color=WHITE)
|
||||||
|
vector.add_updater(lambda v: v.put_start_and_end_on(
|
||||||
|
*circle.radial_line.get_start_and_end()
|
||||||
|
))
|
||||||
|
return vector
|
||||||
|
|
||||||
def get_circle_end_path(self, circles, color=YELLOW):
|
def get_circle_end_path(self, circles, color=YELLOW):
|
||||||
|
coefs = [c.coefficient for c in circles]
|
||||||
freqs = [c.freq for c in circles]
|
freqs = [c.freq for c in circles]
|
||||||
radii = [c.radius for c in circles]
|
|
||||||
total_time = TAU / self.base_frequency
|
|
||||||
center = circles[0].get_center()
|
center = circles[0].get_center()
|
||||||
|
|
||||||
return ParametricFunction(
|
path = ParametricFunction(
|
||||||
lambda t: center + reduce(op.add, [
|
lambda t: center + reduce(op.add, [
|
||||||
radius * rotate_vector(RIGHT, freq * t)
|
complex_to_R3(
|
||||||
for freq, radius in zip(freqs, radii)
|
coef * np.exp(TAU * 1j * freq * t)
|
||||||
|
)
|
||||||
|
for coef, freq in zip(coefs, freqs)
|
||||||
]),
|
]),
|
||||||
t_min=0,
|
t_min=0,
|
||||||
t_max=total_time,
|
t_max=1,
|
||||||
color=color,
|
color=color,
|
||||||
step_size=0.005,
|
step_size=self.parametric_function_step_size,
|
||||||
)
|
)
|
||||||
|
return path
|
||||||
|
|
||||||
# TODO, this should be a general animated mobect
|
# TODO, this should be a general animated mobect
|
||||||
def get_drawn_path(self, circles, **kwargs):
|
def get_drawn_path(self, circles, **kwargs):
|
||||||
path = self.get_circle_end_path(circles, **kwargs)
|
path = self.get_circle_end_path(circles, **kwargs)
|
||||||
total_time = path.t_max
|
|
||||||
broken_path = CurvesAsSubmobjects(path)
|
broken_path = CurvesAsSubmobjects(path)
|
||||||
broken_path.curr_time = 0
|
broken_path.curr_time = 0
|
||||||
|
|
||||||
def update_path(path, dt):
|
def update_path(path, dt):
|
||||||
alpha = (path.curr_time / total_time)
|
alpha = path.curr_time * self.slow_factor
|
||||||
n_curves = len(path)
|
n_curves = len(path)
|
||||||
for a, sp in zip(np.linspace(0, 1, n_curves), path):
|
for a, sp in zip(np.linspace(0, 1, n_curves), path):
|
||||||
b = alpha - a
|
b = alpha - a
|
||||||
|
|
@ -111,9 +147,9 @@ class CirclesDrawing(Scene):
|
||||||
def get_y_component_wave(self,
|
def get_y_component_wave(self,
|
||||||
circles,
|
circles,
|
||||||
left_x=1,
|
left_x=1,
|
||||||
color=BLUE,
|
color=PINK,
|
||||||
n_copies=2,
|
n_copies=2,
|
||||||
right_shift_rate=1.5):
|
right_shift_rate=5):
|
||||||
path = self.get_circle_end_path(circles)
|
path = self.get_circle_end_path(circles)
|
||||||
wave = ParametricFunction(
|
wave = ParametricFunction(
|
||||||
lambda t: op.add(
|
lambda t: op.add(
|
||||||
|
|
@ -132,7 +168,7 @@ class CirclesDrawing(Scene):
|
||||||
top_point = wave_copies.get_top()
|
top_point = wave_copies.get_top()
|
||||||
wave.creation = ShowCreation(
|
wave.creation = ShowCreation(
|
||||||
wave,
|
wave,
|
||||||
run_time=wave.t_max,
|
run_time=(1 / self.slow_factor),
|
||||||
rate_func=linear,
|
rate_func=linear,
|
||||||
)
|
)
|
||||||
cycle_animation(wave.creation)
|
cycle_animation(wave.creation)
|
||||||
|
|
@ -141,7 +177,9 @@ class CirclesDrawing(Scene):
|
||||||
))
|
))
|
||||||
|
|
||||||
def update_wave_copies(wcs):
|
def update_wave_copies(wcs):
|
||||||
index = int(np.ceil(wave.creation.total_time / wave.t_max)) - 1
|
index = int(
|
||||||
|
wave.creation.total_time * self.slow_factor
|
||||||
|
)
|
||||||
wcs[:index].match_style(wave)
|
wcs[:index].match_style(wave)
|
||||||
wcs[index:].set_stroke(width=0)
|
wcs[index:].set_stroke(width=0)
|
||||||
wcs.next_to(wave, RIGHT, buff=0)
|
wcs.next_to(wave, RIGHT, buff=0)
|
||||||
|
|
@ -154,35 +192,327 @@ class CirclesDrawing(Scene):
|
||||||
return DashedLine(
|
return DashedLine(
|
||||||
circles[-1].get_start(),
|
circles[-1].get_start(),
|
||||||
wave[0].get_end(),
|
wave[0].get_end(),
|
||||||
|
stroke_width=1,
|
||||||
|
dash_length=DEFAULT_DASH_LENGTH * 0.5,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Computing Fourier series
|
||||||
|
def get_coefficients_of_path(self, path, n_samples=10000, freqs=None):
|
||||||
|
if freqs is None:
|
||||||
|
freqs = self.get_freqs()
|
||||||
|
dt = 1 / n_samples
|
||||||
|
ts = np.arange(0, 1, dt)
|
||||||
|
samples = np.array([
|
||||||
|
path.point_from_proportion(t)
|
||||||
|
for t in ts
|
||||||
|
])
|
||||||
|
samples -= self.center_point
|
||||||
|
complex_samples = samples[:, 0] + 1j * samples[:, 1]
|
||||||
|
|
||||||
class CirclesDrawingWave(CirclesDrawing):
|
result = []
|
||||||
|
for freq in freqs:
|
||||||
|
riemann_sum = np.array([
|
||||||
|
np.exp(-TAU * 1j * freq * t) * cs
|
||||||
|
for t, cs in zip(ts, complex_samples)
|
||||||
|
]).sum() * dt
|
||||||
|
result.append(riemann_sum)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class FourierSeriesIntroBackground4(FourierCirclesScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"n_circles": 4,
|
"n_circles": 4,
|
||||||
"center_point": 3 * LEFT,
|
"center_point": 4 * LEFT,
|
||||||
|
"run_time": 30,
|
||||||
|
"big_radius": 1.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
circles = self.get_circles()
|
circles = self.get_circles()
|
||||||
path = self.get_drawn_path(circles)
|
path = self.get_drawn_path(circles)
|
||||||
wave = self.get_y_component_wave(circles)
|
wave = self.get_y_component_wave(circles)
|
||||||
|
|
||||||
# small_path = self.get_drawn_path(circles[:1])
|
|
||||||
wave1 = self.get_y_component_wave(circles[:1], color=PINK)
|
|
||||||
wave2 = self.get_y_component_wave(circles[:2], color=RED)
|
|
||||||
# Why?
|
|
||||||
circles.update(-1 / self.camera.frame_rate)
|
|
||||||
#
|
|
||||||
h_line = always_redraw(
|
h_line = always_redraw(
|
||||||
lambda: self.get_wave_y_line(circles, wave)
|
lambda: self.get_wave_y_line(circles, wave)
|
||||||
)
|
)
|
||||||
self.add(circles, path, wave, h_line)
|
|
||||||
self.add(wave1, wave2)
|
|
||||||
self.wait(10)
|
|
||||||
|
|
||||||
def get_freqs_and_radii(self):
|
# Why?
|
||||||
return [
|
circles.update(-1 / self.camera.frame_rate)
|
||||||
(k * self.base_frequency, self.big_radius / k)
|
#
|
||||||
for k in range(1, 2 * self.n_circles + 1, 2)
|
self.add(circles, path, wave, h_line)
|
||||||
|
self.wait(self.run_time)
|
||||||
|
|
||||||
|
def get_ks(self):
|
||||||
|
return np.arange(1, 2 * self.n_circles + 1, 2)
|
||||||
|
|
||||||
|
def get_freqs(self):
|
||||||
|
return self.base_frequency * self.get_ks()
|
||||||
|
|
||||||
|
def get_coefficients(self):
|
||||||
|
return self.big_radius / self.get_ks()
|
||||||
|
|
||||||
|
|
||||||
|
class FourierSeriesIntroBackground8(FourierSeriesIntroBackground4):
|
||||||
|
CONFIG = {
|
||||||
|
"n_circles": 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FourierSeriesIntroBackground12(FourierSeriesIntroBackground4):
|
||||||
|
CONFIG = {
|
||||||
|
"n_circles": 12,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FourierSeriesIntroBackground20(FourierSeriesIntroBackground4):
|
||||||
|
CONFIG = {
|
||||||
|
"n_circles": 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FourierOfPiSymbol(FourierCirclesScene):
|
||||||
|
CONFIG = {
|
||||||
|
"n_circles": 50,
|
||||||
|
"center_point": ORIGIN,
|
||||||
|
"slow_factor": 0.1,
|
||||||
|
"run_time": 30,
|
||||||
|
"tex": "\\pi",
|
||||||
|
"start_drawn": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
path = self.get_path()
|
||||||
|
coefs = self.get_coefficients_of_path(path)
|
||||||
|
|
||||||
|
circles = self.get_circles(coefficients=coefs)
|
||||||
|
for k, circle in zip(it.count(1), circles):
|
||||||
|
circle.set_stroke(width=max(
|
||||||
|
1 / np.sqrt(k),
|
||||||
|
1,
|
||||||
|
))
|
||||||
|
|
||||||
|
# approx_path = self.get_circle_end_path(circles)
|
||||||
|
drawn_path = self.get_drawn_path(circles)
|
||||||
|
if self.start_drawn:
|
||||||
|
drawn_path.curr_time = 1 / self.slow_factor
|
||||||
|
|
||||||
|
self.add(path)
|
||||||
|
self.add(circles)
|
||||||
|
self.add(drawn_path)
|
||||||
|
self.wait(self.run_time)
|
||||||
|
|
||||||
|
def get_path(self):
|
||||||
|
tex_mob = TexMobject(self.tex)
|
||||||
|
tex_mob.set_height(6)
|
||||||
|
path = tex_mob.family_members_with_points()[0]
|
||||||
|
path.set_fill(opacity=0)
|
||||||
|
path.set_stroke(WHITE, 1)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
class FourierOfPiSymbol5(FourierOfPiSymbol):
|
||||||
|
CONFIG = {
|
||||||
|
"n_circles": 5,
|
||||||
|
"run_time": 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FourierOfTrebleClef(FourierOfPiSymbol):
|
||||||
|
CONFIG = {
|
||||||
|
"n_circles": 100,
|
||||||
|
"run_time": 10,
|
||||||
|
"start_drawn": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_path(self):
|
||||||
|
path = SVGMobject("TrebleClef")
|
||||||
|
path = path.family_members_with_points()[0]
|
||||||
|
path.set_height(7.5)
|
||||||
|
path.set_fill(opacity=0)
|
||||||
|
path.set_stroke(WHITE, 0)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
class ExplainCircleAnimations(FourierCirclesScene):
|
||||||
|
CONFIG = {
|
||||||
|
# "n_circles": 100,
|
||||||
|
"n_circles": 20,
|
||||||
|
"center_point": 2 * DOWN,
|
||||||
|
"n_top_circles": 9,
|
||||||
|
# "slow_factor": 0.1,
|
||||||
|
"path_height": 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.add_path()
|
||||||
|
self.add_circles()
|
||||||
|
self.organize_circles_in_a_row()
|
||||||
|
self.show_frequencies()
|
||||||
|
self.show_examples_for_frequencies()
|
||||||
|
self.show_as_vectors()
|
||||||
|
self.show_vector_sum()
|
||||||
|
self.moons_of_moons_of_moons()
|
||||||
|
self.tweak_starting_vectors()
|
||||||
|
|
||||||
|
def add_path(self):
|
||||||
|
self.path = self.get_path()
|
||||||
|
self.add(self.path)
|
||||||
|
|
||||||
|
def add_circles(self):
|
||||||
|
coefs = self.get_coefficients_of_path(self.path)
|
||||||
|
self.circles = self.get_circles(coefficients=coefs)
|
||||||
|
|
||||||
|
self.add(self.circles)
|
||||||
|
self.drawn_path = self.get_drawn_path(self.circles)
|
||||||
|
self.add(self.drawn_path)
|
||||||
|
|
||||||
|
self.wait(8)
|
||||||
|
|
||||||
|
def organize_circles_in_a_row(self):
|
||||||
|
circles = self.circles
|
||||||
|
top_circles = circles[:self.n_top_circles].deepcopy()
|
||||||
|
|
||||||
|
center_trackers = VGroup()
|
||||||
|
for circle in top_circles:
|
||||||
|
tracker = VectorizedPoint(circle.center_func())
|
||||||
|
circle.center_func = tracker.get_location
|
||||||
|
center_trackers.add(tracker)
|
||||||
|
tracker.freq = circle.freq
|
||||||
|
tracker.circle = circle
|
||||||
|
|
||||||
|
center_trackers.submobjects.sort(
|
||||||
|
key=lambda m: m.freq
|
||||||
|
)
|
||||||
|
center_trackers.generate_target()
|
||||||
|
right_buff = 1.45
|
||||||
|
center_trackers.target.arrange(RIGHT, buff=right_buff)
|
||||||
|
center_trackers.target.to_edge(UP, buff=1.25)
|
||||||
|
|
||||||
|
self.add(top_circles)
|
||||||
|
self.play(
|
||||||
|
MoveToTarget(center_trackers),
|
||||||
|
run_time=2
|
||||||
|
)
|
||||||
|
self.wait(4)
|
||||||
|
|
||||||
|
self.top_circles = top_circles
|
||||||
|
self.center_trackers = center_trackers
|
||||||
|
|
||||||
|
def show_frequencies(self):
|
||||||
|
center_trackers = self.center_trackers
|
||||||
|
|
||||||
|
freq_numbers = VGroup()
|
||||||
|
for ct in center_trackers:
|
||||||
|
number = Integer(ct.freq)
|
||||||
|
number.next_to(ct, DOWN, buff=1)
|
||||||
|
freq_numbers.add(number)
|
||||||
|
ct.circle.number = number
|
||||||
|
|
||||||
|
ld, rd = [
|
||||||
|
TexMobject("\\dots")
|
||||||
|
for x in range(2)
|
||||||
]
|
]
|
||||||
|
ld.next_to(freq_numbers, LEFT, MED_LARGE_BUFF)
|
||||||
|
rd.next_to(freq_numbers, RIGHT, MED_LARGE_BUFF)
|
||||||
|
freq_numbers.add_to_back(ld)
|
||||||
|
freq_numbers.add(rd)
|
||||||
|
|
||||||
|
freq_word = TextMobject("Frequencies")
|
||||||
|
freq_word.scale(1.5)
|
||||||
|
freq_word.set_color(YELLOW)
|
||||||
|
freq_word.next_to(freq_numbers, DOWN, MED_LARGE_BUFF)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
LaggedStartMap(
|
||||||
|
FadeInFromDown, freq_numbers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
Write(freq_word),
|
||||||
|
LaggedStartMap(
|
||||||
|
ShowCreationThenFadeAround, freq_numbers,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.wait(2)
|
||||||
|
|
||||||
|
def show_examples_for_frequencies(self):
|
||||||
|
top_circles = self.top_circles
|
||||||
|
c1, c2, c3 = [
|
||||||
|
list(filter(
|
||||||
|
lambda c: c.freq == k,
|
||||||
|
top_circles
|
||||||
|
))[0]
|
||||||
|
for k in (1, 2, 3)
|
||||||
|
]
|
||||||
|
|
||||||
|
neg_circles = VGroup(*filter(
|
||||||
|
lambda c: c.freq < 0,
|
||||||
|
top_circles
|
||||||
|
))
|
||||||
|
|
||||||
|
for c in [c1, c2, c3, *neg_circles]:
|
||||||
|
c.rect = SurroundingRectangle(c)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ShowCreation(c2.rect),
|
||||||
|
WiggleOutThenIn(c2.number),
|
||||||
|
)
|
||||||
|
self.wait(2)
|
||||||
|
self.play(
|
||||||
|
ReplacementTransform(c2.rect, c1.rect),
|
||||||
|
)
|
||||||
|
self.play(FadeOut(c1.rect))
|
||||||
|
self.wait()
|
||||||
|
self.play(
|
||||||
|
ShowCreation(c3.rect),
|
||||||
|
WiggleOutThenIn(c3.number),
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
FadeOut(c3.rect),
|
||||||
|
)
|
||||||
|
self.wait(2)
|
||||||
|
self.play(
|
||||||
|
LaggedStart(*[
|
||||||
|
ShowCreationThenFadeOut(c.rect)
|
||||||
|
for c in neg_circles
|
||||||
|
])
|
||||||
|
)
|
||||||
|
self.wait(3)
|
||||||
|
|
||||||
|
def show_as_vectors(self):
|
||||||
|
top_circles = self.top_circles
|
||||||
|
top_vectors = self.get_rotating_vectors(top_circles)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
top_circles.set_stroke, {"width": 0.5},
|
||||||
|
FadeIn(top_vectors),
|
||||||
|
)
|
||||||
|
self.wait(3)
|
||||||
|
|
||||||
|
self.top_vectors = top_vectors
|
||||||
|
|
||||||
|
def show_vector_sum(self):
|
||||||
|
top_circles = self.top_circles
|
||||||
|
top_vectors = self.top_vectors
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeOut(self.path),
|
||||||
|
FadeOut(self.circles),
|
||||||
|
)
|
||||||
|
|
||||||
|
def moons_of_moons_of_moons(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def tweak_starting_vectors(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
#
|
||||||
|
def get_path(self):
|
||||||
|
tex = TexMobject("f")
|
||||||
|
path = tex.family_members_with_points()[0]
|
||||||
|
path.set_stroke(WHITE, 1)
|
||||||
|
path.set_fill(opacity=0)
|
||||||
|
path.set_height(self.path_height)
|
||||||
|
path.move_to(self.center_point)
|
||||||
|
return path
|
||||||
|
# return Square().set_height(3)
|
||||||
|
|
|
||||||
6
active_projects/ode/part2/heat_equation.py
Normal file
6
active_projects/ode/part2/heat_equation.py
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
from big_ol_pile_of_manim_imports import *
|
||||||
|
|
||||||
|
|
||||||
|
class NewSceneName(Scene):
|
||||||
|
def construct(self):
|
||||||
|
pass
|
||||||
|
|
@ -1,6 +1,22 @@
|
||||||
from big_ol_pile_of_manim_imports import *
|
from big_ol_pile_of_manim_imports import *
|
||||||
|
|
||||||
|
|
||||||
class NewSceneName(Scene):
|
class FourierSeriesIntro(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
pass
|
title = TextMobject(
|
||||||
|
"Fourier ", "Series", ":",
|
||||||
|
" An origin story",
|
||||||
|
arg_separator="",
|
||||||
|
)
|
||||||
|
title.scale(2)
|
||||||
|
title.to_edge(UP)
|
||||||
|
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.add(title)
|
||||||
|
self.add(image)
|
||||||
|
self.add(name)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue