mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 22:03:01 +08:00
Up to ShowInfiniteSum in diffyq part 4 animations
This commit is contained in:
@ -225,7 +225,39 @@ class FourierSeriesExampleWithRectForZoom(ComplexFourierSeriesExample):
|
||||
def get_rect(self):
|
||||
return ScreenRectangle(
|
||||
color=BLUE,
|
||||
stroke_width=2,
|
||||
stroke_width=1,
|
||||
)
|
||||
|
||||
def get_path_end(self, vectors, stroke_width=None, **kwargs):
|
||||
if stroke_width is None:
|
||||
stroke_width = self.drawn_path_st
|
||||
full_path = self.get_vector_sum_path(vectors, **kwargs)
|
||||
path = VMobject()
|
||||
path.set_stroke(
|
||||
self.drawn_path_color,
|
||||
stroke_width
|
||||
)
|
||||
|
||||
def update_path(p):
|
||||
alpha = self.get_vector_time() % 1
|
||||
p.pointwise_become_partial(
|
||||
full_path,
|
||||
np.clip(alpha - 0.01, 0, 1),
|
||||
np.clip(alpha, 0, 1),
|
||||
)
|
||||
p.points[-1] = vectors[-1].get_end()
|
||||
|
||||
path.add_updater(update_path)
|
||||
return path
|
||||
|
||||
def get_drawn_path_alpha(self):
|
||||
return super().get_drawn_path_alpha() - 0.002
|
||||
|
||||
def get_drawn_path(self, vectors, stroke_width=2, **kwargs):
|
||||
odp = super().get_drawn_path(vectors, stroke_width, **kwargs)
|
||||
return VGroup(
|
||||
odp,
|
||||
self.get_path_end(vectors, stroke_width, **kwargs),
|
||||
)
|
||||
|
||||
|
||||
@ -251,31 +283,6 @@ class ZoomedInFourierSeriesExample(FourierSeriesExampleWithRectForZoom, MovingCa
|
||||
if v.get_stroke_width() < 1:
|
||||
v.set_stroke(width=1)
|
||||
|
||||
def get_path_end(self, vectors, stroke_width=2, **kwargs):
|
||||
full_path = self.get_vector_sum_path(vectors, **kwargs)
|
||||
path = VMobject()
|
||||
path.set_stroke(YELLOW, stroke_width)
|
||||
|
||||
def update_path(p):
|
||||
alpha = self.get_vector_time() % 1
|
||||
p.pointwise_become_partial(
|
||||
full_path, 0, np.clip(alpha, 0, 1),
|
||||
)
|
||||
p.points[-1] = vectors[-1].get_end()
|
||||
|
||||
path.add_updater(update_path)
|
||||
return path
|
||||
|
||||
def get_drawn_path_alpha(self):
|
||||
return super().get_drawn_path_alpha() - 0.002
|
||||
|
||||
def get_drawn_path(self, vectors, stroke_width=2, **kwargs):
|
||||
odp = super().get_drawn_path(vectors, stroke_width, **kwargs)
|
||||
return VGroup(
|
||||
odp,
|
||||
self.get_path_end(vectors, stroke_width, **kwargs),
|
||||
)
|
||||
|
||||
|
||||
class ZoomedInFourierSeriesExample10xMore(ZoomedInFourierSeriesExample):
|
||||
CONFIG = {
|
||||
@ -297,13 +304,48 @@ class ZoomedInFourierSeriesExample10xMore(ZoomedInFourierSeriesExample):
|
||||
# return self.get_path_end(vectors, stroke_width, **kwargs)
|
||||
|
||||
|
||||
class FourierSeriesExampleWithRectForZoomTrebleClef(FourierSeriesExampleWithRectForZoom):
|
||||
class TrebleClefFourierSeriesExampleWithRectForZoom(FourierSeriesExampleWithRectForZoom):
|
||||
CONFIG = {
|
||||
"file_name": "TrebleClef",
|
||||
}
|
||||
|
||||
|
||||
class ZoomedInFourierSeriesExampleTrebleClef(ZoomedInFourierSeriesExample):
|
||||
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,
|
||||
}
|
||||
|
||||
def get_shape(self):
|
||||
return TexMobject("\\Sigma")
|
||||
|
||||
def get_rect(self):
|
||||
result = super().get_rect()
|
||||
result.set_opacity(0)
|
||||
return result
|
||||
|
||||
|
||||
class SigmaZoomedInFourierSeriesExample(SigmaFourierSeriesExampleWithRectForZoom, ZoomedInFourierSeriesExample):
|
||||
pass
|
||||
|
@ -20,3 +20,120 @@ class WhyWouldYouCare(TeacherStudentsScene):
|
||||
)
|
||||
self.look_at(self.screen)
|
||||
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)
|
||||
|
@ -1,4 +1,19 @@
|
||||
from manimlib.imports import *
|
||||
from active_projects.diffyq.part3.staging import FourierSeriesIllustraiton
|
||||
|
||||
|
||||
class FourierSeriesFormula(Scene):
|
||||
def construct(self):
|
||||
formula = TexMobject(
|
||||
"c_{n} = \\int_0^1 e^{-2\\pi i {n} {t}}f({t})d{t}",
|
||||
tex_to_color_map={
|
||||
"{n}": RED,
|
||||
"{t}": YELLOW,
|
||||
}
|
||||
)
|
||||
|
||||
self.play(Write(formula))
|
||||
self.wait()
|
||||
|
||||
|
||||
class RelationToOtherVideos(Scene):
|
||||
@ -179,5 +194,835 @@ class FourierGainsImmortality(Scene):
|
||||
|
||||
|
||||
class WhichWavesAreAvailable(Scene):
|
||||
CONFIG = {
|
||||
"axes_config": {
|
||||
"x_min": 0,
|
||||
"x_max": TAU,
|
||||
"y_min": -1.5,
|
||||
"y_max": 1.5,
|
||||
"x_axis_config": {
|
||||
"tick_frequency": PI / 2,
|
||||
"unit_size": 1,
|
||||
"include_tip": False,
|
||||
},
|
||||
"y_axis_config": {
|
||||
"unit_size": 1,
|
||||
"tick_frequency": 0.5,
|
||||
"include_tip": False,
|
||||
},
|
||||
},
|
||||
"n_axes": 5,
|
||||
"trig_func": np.cos,
|
||||
"trig_func_tex": "\\cos",
|
||||
"bc_words": "Restricted by\\\\boundary conditions",
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
pass
|
||||
self.setup_little_axes()
|
||||
self.show_cosine_waves()
|
||||
|
||||
def setup_little_axes(self):
|
||||
axes_group = VGroup(*[
|
||||
Axes(**self.axes_config)
|
||||
for n in range(self.n_axes)
|
||||
])
|
||||
axes_group.set_stroke(width=2)
|
||||
axes_group.arrange(DOWN, buff=1)
|
||||
axes_group.set_height(FRAME_HEIGHT - 1.25)
|
||||
axes_group.to_edge(RIGHT)
|
||||
axes_group.to_edge(UP, buff=MED_SMALL_BUFF)
|
||||
dots = TextMobject("\\vdots")
|
||||
dots.next_to(axes_group, DOWN)
|
||||
dots.shift_onto_screen()
|
||||
|
||||
self.add(axes_group)
|
||||
self.add(dots)
|
||||
|
||||
self.axes_group = axes_group
|
||||
|
||||
def show_cosine_waves(self):
|
||||
axes_group = self.axes_group
|
||||
colors = [BLUE, GREEN, RED, YELLOW, PINK]
|
||||
|
||||
graphs = VGroup()
|
||||
h_lines = VGroup()
|
||||
func_labels = VGroup()
|
||||
for k, axes, color in zip(it.count(1), axes_group, colors):
|
||||
L = axes.x_max
|
||||
graph = axes.get_graph(
|
||||
lambda x: self.trig_func(x * k * PI / L),
|
||||
color=color
|
||||
)
|
||||
graph.set_stroke(width=2)
|
||||
graphs.add(graph)
|
||||
|
||||
func_label = TexMobject(
|
||||
self.trig_func_tex + "\\left(",
|
||||
str(k),
|
||||
"(\\pi / L)x\\right)",
|
||||
tex_to_color_map={
|
||||
str(k): color,
|
||||
}
|
||||
)
|
||||
func_label.scale(0.7)
|
||||
func_label.next_to(axes, LEFT)
|
||||
func_labels.add(func_label)
|
||||
|
||||
hl1 = DashedLine(LEFT, RIGHT)
|
||||
hl1.set_width(0.5)
|
||||
hl1.set_stroke(WHITE, 2)
|
||||
hl1.move_to(graph.get_start())
|
||||
hl2 = hl1.copy()
|
||||
hl2.move_to(graph.get_end())
|
||||
h_lines.add(hl1, hl2)
|
||||
|
||||
words = TextMobject(self.bc_words)
|
||||
words.next_to(axes_group, LEFT)
|
||||
words.to_edge(UP)
|
||||
|
||||
self.play(
|
||||
FadeIn(words),
|
||||
LaggedStartMap(
|
||||
ShowCreation, graphs,
|
||||
)
|
||||
)
|
||||
self.play(Write(h_lines))
|
||||
self.play(FadeOut(h_lines))
|
||||
self.wait()
|
||||
self.play(
|
||||
words.next_to, func_labels, LEFT,
|
||||
words.to_edge, UP,
|
||||
LaggedStartMap(
|
||||
FadeInFrom, func_labels,
|
||||
lambda m: (m, RIGHT)
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class AlternateBoundaryConditions(WhichWavesAreAvailable):
|
||||
CONFIG = {
|
||||
"trig_func": np.sin,
|
||||
"trig_func_tex": "\\sin",
|
||||
"bc_words": "Alternate\\\\boundary condition"
|
||||
}
|
||||
|
||||
|
||||
class AskQuestionOfGraph(PiCreatureScene):
|
||||
def construct(self):
|
||||
randy = self.pi_creature
|
||||
|
||||
self.pi_creature_says(
|
||||
randy,
|
||||
"What sine waves\\\\are you made of?",
|
||||
target_mode="sassy",
|
||||
)
|
||||
self.wait(2)
|
||||
self.play(
|
||||
randy.change, "pondering",
|
||||
randy.bubble.get_right()
|
||||
)
|
||||
self.wait(2)
|
||||
|
||||
|
||||
class CommentOnFouriersImmortality(FourierGainsImmortality):
|
||||
def construct(self):
|
||||
immortals = self.get_immortals()
|
||||
immortals.to_edge(LEFT)
|
||||
fourier = immortals.fourier
|
||||
name = TextMobject("Joseph", "Fourier")
|
||||
name.scale(1.5)
|
||||
name.move_to(FRAME_WIDTH * RIGHT / 4)
|
||||
name.to_edge(DOWN)
|
||||
|
||||
fourier_things = VGroup(
|
||||
TextMobject("Fourier transform"),
|
||||
TextMobject("Fourier series"),
|
||||
TextMobject("Complex Fourier series"),
|
||||
TextMobject("Discrete Fourier transform"),
|
||||
TextMobject("Fractional Fourier transform"),
|
||||
TextMobject("Fast Fourier transform"),
|
||||
TextMobject("Quantum Fourier transform"),
|
||||
TextMobject("Fourier transform spectroscopy"),
|
||||
TexMobject("\\vdots"),
|
||||
)
|
||||
fourier_things.arrange(
|
||||
DOWN,
|
||||
aligned_edge=LEFT,
|
||||
buff=MED_LARGE_BUFF
|
||||
)
|
||||
fourier_things.to_corner(UL)
|
||||
fourier_things[-1].shift(RIGHT + 0.25 * UP)
|
||||
|
||||
self.add(immortals)
|
||||
immortals.remove(immortals.fourier)
|
||||
self.play(
|
||||
fourier.set_height, 6,
|
||||
fourier.next_to, name, UP,
|
||||
FadeInFromDown(name),
|
||||
)
|
||||
self.play(FadeOut(immortals))
|
||||
self.wait(2)
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
FadeInFrom, fourier_things,
|
||||
lambda m: (m, UP),
|
||||
run_time=5,
|
||||
lag_ratio=0.3,
|
||||
)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
|
||||
class ShowInfiniteSum(FourierSeriesIllustraiton):
|
||||
CONFIG = {
|
||||
"n_range": range(1, 101, 2),
|
||||
"colors": [BLUE, GREEN, RED, YELLOW, PINK],
|
||||
"axes_config": {
|
||||
"y_max": 1.5,
|
||||
"y_min": -1.5,
|
||||
"y_axis_config": {
|
||||
"tick_frequency": 0.5,
|
||||
"unit_size": 1.0,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
"x_axis_config": {
|
||||
"tick_frequency": 0.1,
|
||||
"stroke_width": 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def construct(self):
|
||||
self.add_equation()
|
||||
self.add_graphs()
|
||||
self.show_to_infinity()
|
||||
self.walk_through_constants()
|
||||
|
||||
self.ask_about_infinite_sum()
|
||||
self.show_inf_sum_of_numbers()
|
||||
self.show_many_inputs_in_parallel()
|
||||
self.follow_single_inputs()
|
||||
|
||||
def add_equation(self):
|
||||
inf_sum = self.get_infinite_sum()
|
||||
step_func_def = self.get_step_func_definition()
|
||||
step_func_def.next_to(inf_sum, RIGHT)
|
||||
equation = VGroup(inf_sum, step_func_def)
|
||||
equation.set_width(FRAME_WIDTH - 1)
|
||||
equation.center().to_edge(UP)
|
||||
|
||||
self.add(equation)
|
||||
|
||||
self.equation = equation
|
||||
self.inf_sum = inf_sum
|
||||
self.inf_sum = inf_sum
|
||||
self.step_func_def = step_func_def
|
||||
|
||||
def add_graphs(self):
|
||||
aaa_group = self.get_axes_arrow_axes()
|
||||
aaa_group.next_to(self.equation, DOWN, buff=1.5)
|
||||
axes1, arrow, axes2 = aaa_group
|
||||
|
||||
tfg = self.get_target_func_graph(axes2)
|
||||
tfg.set_color(WHITE)
|
||||
axes2.add(tfg)
|
||||
|
||||
sine_graphs = self.get_sine_graphs(axes1)
|
||||
partial_sums = self.get_partial_sums(axes1, sine_graphs)
|
||||
partial_sums.set_stroke(width=0.5)
|
||||
partial_sums[-1].set_stroke(width=2)
|
||||
colors = self.colors
|
||||
partial_sums[len(colors):].set_color_by_gradient(*colors)
|
||||
|
||||
self.add(aaa_group)
|
||||
self.add(partial_sums)
|
||||
|
||||
self.partial_sums = partial_sums
|
||||
self.sine_graphs = sine_graphs
|
||||
self.aaa_group = aaa_group
|
||||
|
||||
def show_to_infinity(self):
|
||||
dots = self.inf_sum.dots
|
||||
arrow = Vector(1.5 * RIGHT)
|
||||
arrow.next_to(
|
||||
dots, DOWN, MED_LARGE_BUFF,
|
||||
aligned_edge=RIGHT
|
||||
)
|
||||
words = TextMobject("Sum to $\\infty$")
|
||||
words.next_to(arrow, DOWN)
|
||||
|
||||
self.play(
|
||||
FadeInFrom(words, LEFT),
|
||||
GrowArrow(arrow)
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.inf_words = VGroup(arrow, words)
|
||||
|
||||
def walk_through_constants(self):
|
||||
inf_sum = self.inf_sum
|
||||
terms = self.inf_sum.terms
|
||||
sine_graphs = self.sine_graphs
|
||||
partial_sums = self.partial_sums
|
||||
|
||||
rects = VGroup(*[
|
||||
SurroundingRectangle(
|
||||
term,
|
||||
color=term[-1].get_color(),
|
||||
stroke_width=2
|
||||
)
|
||||
for term in terms
|
||||
])
|
||||
dots_rect = SurroundingRectangle(inf_sum.dots)
|
||||
dots_rect.set_stroke(width=2)
|
||||
|
||||
curr_rect = rects[0].copy()
|
||||
curr_partial_sum = partial_sums[0]
|
||||
curr_partial_sum.set_stroke(width=3)
|
||||
|
||||
self.play(
|
||||
FadeOut(partial_sums[1:]),
|
||||
FadeIn(curr_rect),
|
||||
FadeIn(curr_partial_sum),
|
||||
)
|
||||
|
||||
for sg, ps, rect in zip(sine_graphs[1:], partial_sums[1:], rects[1:]):
|
||||
self.play(
|
||||
FadeOut(curr_rect),
|
||||
FadeIn(rect),
|
||||
FadeIn(sg),
|
||||
)
|
||||
curr_rect.become(rect)
|
||||
self.remove(rect)
|
||||
self.add(curr_rect)
|
||||
ps.set_stroke(width=3)
|
||||
self.play(
|
||||
curr_partial_sum.set_stroke, {"width": 0.5},
|
||||
ReplacementTransform(sg, ps),
|
||||
)
|
||||
curr_partial_sum = ps
|
||||
self.play(
|
||||
Transform(curr_rect, dots_rect),
|
||||
curr_partial_sum.set_stroke, {"width": 0.5},
|
||||
LaggedStart(
|
||||
*[
|
||||
UpdateFromAlphaFunc(
|
||||
ps,
|
||||
lambda m, a: m.set_stroke(
|
||||
width=(3 * there_and_back(a) + 0.5 * a)
|
||||
),
|
||||
)
|
||||
for ps in partial_sums[4:]
|
||||
],
|
||||
run_time=3,
|
||||
lag_ratio=0.2,
|
||||
),
|
||||
)
|
||||
self.play(partial_sums[-1].set_stroke, {"width": 2})
|
||||
self.play(
|
||||
FadeOut(curr_rect),
|
||||
ShowCreationThenFadeAround(inf_sum.four_over_pi),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
def ask_about_infinite_sum(self):
|
||||
inf_words = self.inf_words
|
||||
randy = Randolph(mode="confused")
|
||||
randy.set_height(1.5)
|
||||
|
||||
outline = inf_words[1].copy()
|
||||
outline.set_stroke(YELLOW, 1)
|
||||
outline.set_fill(opacity=0)
|
||||
|
||||
question = TextMobject(
|
||||
"What$\\dots$\\\\ does this mean?"
|
||||
)
|
||||
question.scale(0.7)
|
||||
question.next_to(inf_words, LEFT)
|
||||
randy.next_to(question, DOWN, aligned_edge=RIGHT)
|
||||
|
||||
self.play(FadeIn(question))
|
||||
self.play(FadeIn(randy))
|
||||
self.play(
|
||||
Blink(randy),
|
||||
ShowCreationThenFadeOut(outline)
|
||||
)
|
||||
self.wait()
|
||||
self.play(FadeOut(randy), FadeOut(question))
|
||||
|
||||
def show_inf_sum_of_numbers(self):
|
||||
inf_sum = self.inf_sum
|
||||
graph_group = VGroup(
|
||||
self.aaa_group, self.partial_sums
|
||||
)
|
||||
|
||||
number_line = NumberLine(
|
||||
x_min=0,
|
||||
x_max=1,
|
||||
tick_frequency=0.1,
|
||||
numbers_with_elongated_ticks=[0, 0.5, 1],
|
||||
unit_size=8,
|
||||
# line_to_number_buff=0.4,
|
||||
)
|
||||
number_line.set_stroke(LIGHT_GREY, 2)
|
||||
number_line.move_to(2 * DOWN)
|
||||
number_line.add_numbers(
|
||||
*np.arange(0, 1.5, 0.5),
|
||||
number_config={
|
||||
"num_decimal_places": 1,
|
||||
},
|
||||
)
|
||||
|
||||
num_inf_sum = TexMobject(
|
||||
"{1 \\over 1}",
|
||||
"-{1 \\over 3}",
|
||||
"+{1 \\over 5}",
|
||||
"-{1 \\over 7}",
|
||||
"+{1 \\over 9}",
|
||||
"-{1 \\over 11}",
|
||||
"+\\cdots",
|
||||
"= {\\pi \\over 4}"
|
||||
)
|
||||
num_inf_sum.move_to(UP)
|
||||
|
||||
self.play(
|
||||
FadeOutAndShift(graph_group, DOWN),
|
||||
FadeInFrom(number_line, UP),
|
||||
FadeOut(self.inf_words),
|
||||
*[
|
||||
TransformFromCopy(t1[-1:], t2)
|
||||
for t1, t2 in zip(
|
||||
inf_sum.terms,
|
||||
num_inf_sum,
|
||||
)
|
||||
],
|
||||
TransformFromCopy(
|
||||
inf_sum.dots,
|
||||
num_inf_sum[-2],
|
||||
),
|
||||
TransformFromCopy(
|
||||
inf_sum.dots,
|
||||
num_inf_sum[-4:-2]
|
||||
),
|
||||
self.equation.set_opacity, 0.5,
|
||||
)
|
||||
self.play(Write(num_inf_sum[-1]))
|
||||
|
||||
# Show sums
|
||||
terms = [
|
||||
u / n
|
||||
for u, n in zip(
|
||||
it.cycle([1, -1]),
|
||||
range(1, 1001, 2)
|
||||
)
|
||||
]
|
||||
partial_sums = np.cumsum(terms)
|
||||
tip = ArrowTip(start_angle=-TAU / 4)
|
||||
value_tracker = ValueTracker(1)
|
||||
get_value = value_tracker.get_value
|
||||
tip.add_updater(
|
||||
lambda t: t.move_to(
|
||||
number_line.n2p(get_value()),
|
||||
DOWN,
|
||||
)
|
||||
)
|
||||
n_braces = 7
|
||||
braces = VGroup(*[
|
||||
Brace(num_inf_sum[:n], DOWN)
|
||||
for n in range(1, n_braces + 1)
|
||||
])
|
||||
brace = braces[0].copy()
|
||||
decimal = DecimalNumber(
|
||||
0, num_decimal_places=6,
|
||||
)
|
||||
decimal.add_updater(lambda d: d.set_value(get_value()))
|
||||
decimal.add_updater(lambda d: d.next_to(tip, UP, SMALL_BUFF))
|
||||
|
||||
term_count = VGroup(
|
||||
Integer(1), TextMobject("terms")
|
||||
)
|
||||
term_count_tracker = ValueTracker(1)
|
||||
term_count[0].set_color(YELLOW)
|
||||
term_count.add_updater(
|
||||
lambda m: m[0].set_value(term_count_tracker.get_value())
|
||||
)
|
||||
term_count.add_updater(lambda m: m.arrange(
|
||||
RIGHT, aligned_edge=DOWN
|
||||
))
|
||||
term_count.add_updater(lambda m: m.next_to(brace, DOWN))
|
||||
|
||||
pi_fourths_tip = ArrowTip(start_angle=90 * DEGREES)
|
||||
pi_fourths_tip.set_color(WHITE)
|
||||
pi_fourths_tip.move_to(
|
||||
number_line.n2p(PI / 4), UP,
|
||||
)
|
||||
pi_fourths_label = TexMobject(
|
||||
"{\\pi \\over 4} ="
|
||||
)
|
||||
pi_fourths_value = DecimalNumber(
|
||||
PI / 4, num_decimal_places=4
|
||||
)
|
||||
pi_fourths_value.scale(0.8)
|
||||
pi_fourths_value.next_to(pi_fourths_label, RIGHT, buff=0.2)
|
||||
pi_fourths_label.add(pi_fourths_value)
|
||||
# pi_fourths_label.scale(0.7)
|
||||
pi_fourths_label.next_to(
|
||||
pi_fourths_tip, DOWN, MED_SMALL_BUFF,
|
||||
aligned_edge=LEFT,
|
||||
)
|
||||
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
FadeIn, VGroup(
|
||||
brace, tip, decimal,
|
||||
term_count,
|
||||
)
|
||||
),
|
||||
FadeIn(pi_fourths_tip),
|
||||
FadeIn(pi_fourths_label),
|
||||
)
|
||||
for ps, new_brace in zip(partial_sums[1:], braces[1:]):
|
||||
term_count_tracker.increment_value(1)
|
||||
self.play(
|
||||
Transform(brace, new_brace),
|
||||
value_tracker.set_value, ps,
|
||||
run_time=0.2,
|
||||
)
|
||||
self.leave_mark(number_line, ps)
|
||||
self.wait(0.8)
|
||||
|
||||
count = 0
|
||||
num_moving_values = n_braces + 8
|
||||
for ps in partial_sums[n_braces:num_moving_values]:
|
||||
value_tracker.set_value(ps)
|
||||
self.leave_mark(number_line, ps)
|
||||
count += 1
|
||||
term_count_tracker.increment_value(1)
|
||||
self.wait(0.5)
|
||||
decimal.remove_updater(decimal.updaters[-1])
|
||||
decimal.match_x(pi_fourths_tip)
|
||||
|
||||
new_marks = VGroup(*[
|
||||
self.leave_mark(number_line, ps)
|
||||
for ps in partial_sums[num_moving_values:]
|
||||
])
|
||||
number_line.remove(*new_marks)
|
||||
term_count_tracker.increment_value(1)
|
||||
self.play(
|
||||
UpdateFromAlphaFunc(
|
||||
value_tracker,
|
||||
lambda m, a: m.set_value(
|
||||
partial_sums[integer_interpolate(
|
||||
num_moving_values,
|
||||
len(partial_sums) - 1,
|
||||
a,
|
||||
)[0]]
|
||||
),
|
||||
),
|
||||
ShowIncreasingSubsets(new_marks),
|
||||
term_count_tracker.set_value, len(partial_sums),
|
||||
run_time=10,
|
||||
rate_func=linear,
|
||||
)
|
||||
self.play(LaggedStartMap(
|
||||
FadeOut, VGroup(
|
||||
num_inf_sum,
|
||||
brace,
|
||||
decimal,
|
||||
term_count,
|
||||
tip,
|
||||
number_line,
|
||||
new_marks,
|
||||
pi_fourths_tip,
|
||||
pi_fourths_label,
|
||||
),
|
||||
lag_ratio=0.3,
|
||||
))
|
||||
self.play(
|
||||
FadeInFromDown(graph_group),
|
||||
self.equation.set_opacity, 1,
|
||||
)
|
||||
|
||||
def show_many_inputs_in_parallel(self):
|
||||
aaa_group = self.aaa_group
|
||||
axes1, arrow, axes2 = aaa_group
|
||||
partial_sums = self.partial_sums
|
||||
|
||||
inputs = np.linspace(0, 1, 21)
|
||||
n_iterations = 100
|
||||
|
||||
values = np.array([
|
||||
[
|
||||
(4 / PI) * (u / n) * np.cos(n * PI * x)
|
||||
for x in inputs
|
||||
]
|
||||
for u, n in zip(
|
||||
it.cycle([1, -1]),
|
||||
range(1, 2 * n_iterations + 1, 2),
|
||||
)
|
||||
])
|
||||
p_sums = np.apply_along_axis(np.cumsum, 0, values)
|
||||
|
||||
dots = VGroup(*[Dot() for x in inputs])
|
||||
dots.scale(0.5)
|
||||
dots.set_color_by_gradient(BLUE, YELLOW)
|
||||
n_tracker = ValueTracker(0)
|
||||
|
||||
def update_dots(dots):
|
||||
n = int(n_tracker.get_value())
|
||||
outputs = p_sums[n]
|
||||
for dot, x, y in zip(dots, inputs, outputs):
|
||||
dot.move_to(axes1.c2p(x, y))
|
||||
dots.add_updater(update_dots)
|
||||
|
||||
lines = VGroup(*[
|
||||
self.get_dot_line(dot, axes1.x_axis)
|
||||
for dot in dots
|
||||
])
|
||||
|
||||
self.remove(*self.inf_words)
|
||||
self.play(
|
||||
FadeOut(partial_sums),
|
||||
FadeIn(dots),
|
||||
FadeIn(lines),
|
||||
)
|
||||
self.play(
|
||||
n_tracker.set_value, len(p_sums) - 1,
|
||||
run_time=5,
|
||||
)
|
||||
dots.clear_updaters()
|
||||
|
||||
index = 4
|
||||
self.input_dot = dots[index]
|
||||
self.input_line = lines[index]
|
||||
self.partial_sum_values = p_sums[:, index]
|
||||
self.cosine_values = values[:, index]
|
||||
|
||||
dots.remove(self.input_dot)
|
||||
lines.remove(self.input_line)
|
||||
self.add(self.input_line)
|
||||
self.add(self.input_dot)
|
||||
|
||||
self.play(
|
||||
FadeOut(dots),
|
||||
FadeOut(lines),
|
||||
)
|
||||
|
||||
def follow_single_inputs(self):
|
||||
aaa_group = self.aaa_group
|
||||
inf_sum = self.inf_sum
|
||||
axes1, arrow, axes2 = aaa_group
|
||||
x_axis = axes1.x_axis
|
||||
dot = self.input_dot
|
||||
partial_sums = self.partial_sums
|
||||
partial_sums.set_stroke(width=2)
|
||||
|
||||
input_tracker = ValueTracker(
|
||||
x_axis.p2n(dot.get_center())
|
||||
)
|
||||
get_input = input_tracker.get_value
|
||||
|
||||
input_label = TexMobject("x =", "0.2")
|
||||
input_decimal = DecimalNumber(get_input())
|
||||
input_decimal.replace(input_label[1])
|
||||
input_decimal.set_color(BLUE)
|
||||
input_label.remove(input_label[1])
|
||||
input_label.add(input_decimal)
|
||||
input_label.next_to(dot, UR, SMALL_BUFF)
|
||||
|
||||
def get_brace_value_label(brace, u, n):
|
||||
result = DecimalNumber()
|
||||
result.scale(0.7)
|
||||
result.next_to(brace, DOWN, SMALL_BUFF)
|
||||
result.add_updater(lambda d: d.set_value(
|
||||
(u / n) * np.cos(PI * n * get_input())
|
||||
))
|
||||
return result
|
||||
|
||||
braces = VGroup(*[
|
||||
Brace(term, DOWN)
|
||||
for term in inf_sum.terms
|
||||
])
|
||||
brace_value_labels = VGroup(*[
|
||||
get_brace_value_label(brace, u, n)
|
||||
for brace, u, n in zip(
|
||||
braces,
|
||||
it.cycle([1, -1]),
|
||||
it.count(1, 2),
|
||||
)
|
||||
])
|
||||
bv_rects = VGroup(*[
|
||||
SurroundingRectangle(
|
||||
brace_value_labels[:n],
|
||||
color=BLUE,
|
||||
stroke_width=1,
|
||||
)
|
||||
for n in range(1, len(braces) + 1)
|
||||
])
|
||||
|
||||
bv_rect = bv_rects[0].copy()
|
||||
partial_sum = partial_sums[0].copy()
|
||||
|
||||
dot.add_updater(
|
||||
lambda d: d.move_to(partial_sum.point_from_proportion(
|
||||
inverse_interpolate(
|
||||
x_axis.x_min,
|
||||
x_axis.x_max,
|
||||
get_input(),
|
||||
)
|
||||
))
|
||||
)
|
||||
|
||||
n_waves_label = TextMobject(
|
||||
"Sum of", "10", "waves"
|
||||
)
|
||||
n_waves_label.next_to(axes1.c2p(0.5, 1), UR)
|
||||
n_tracker = ValueTracker(1)
|
||||
n_dec = Integer(1)
|
||||
n_dec.set_color(YELLOW)
|
||||
n_dec.move_to(n_waves_label[1])
|
||||
n_waves_label[1].set_opacity(0)
|
||||
n_waves_label.add(n_dec)
|
||||
n_dec.add_updater(lambda n: n.set_value(
|
||||
n_tracker.get_value()
|
||||
))
|
||||
n_dec.add_updater(lambda m: m.move_to(
|
||||
n_waves_label[1]
|
||||
))
|
||||
|
||||
self.play(
|
||||
FadeInFrom(input_label, LEFT),
|
||||
dot.scale, 1.5,
|
||||
)
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStartMap(GrowFromCenter, braces),
|
||||
LaggedStartMap(GrowFromCenter, brace_value_labels),
|
||||
*[
|
||||
TransformFromCopy(
|
||||
input_label[0][0],
|
||||
term[n][1],
|
||||
)
|
||||
for i, term in enumerate(inf_sum.terms)
|
||||
for n in [2 if i == 0 else 4]
|
||||
]
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.add(partial_sum, dot)
|
||||
dot.set_stroke(BLACK, 1, background=True)
|
||||
self.play(
|
||||
FadeOut(input_label),
|
||||
FadeIn(n_waves_label),
|
||||
FadeIn(bv_rect),
|
||||
FadeIn(partial_sum),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
ps_iter = iter(partial_sums[1:])
|
||||
|
||||
def get_ps_anim():
|
||||
return AnimationGroup(
|
||||
Transform(partial_sum, next(ps_iter)),
|
||||
ApplyMethod(n_tracker.increment_value, 1),
|
||||
)
|
||||
|
||||
for i in range(1, 4):
|
||||
self.play(
|
||||
Transform(bv_rect, bv_rects[i]),
|
||||
get_ps_anim(),
|
||||
)
|
||||
self.wait()
|
||||
|
||||
self.play(
|
||||
FadeOut(bv_rect),
|
||||
get_ps_anim()
|
||||
)
|
||||
for x in range(3):
|
||||
self.play(get_ps_anim())
|
||||
self.play(
|
||||
input_tracker.set_value, 0.7,
|
||||
)
|
||||
for x in range(6):
|
||||
self.play(get_ps_anim())
|
||||
self.play(input_tracker.set_value, 0.5)
|
||||
for x in range(10):
|
||||
self.play(get_ps_anim())
|
||||
|
||||
#
|
||||
def get_dot_line(self, dot, axis, line_class=Line):
|
||||
def get_line():
|
||||
p = dot.get_center()
|
||||
lp = axis.n2p(axis.p2n(p))
|
||||
return line_class(lp, p, stroke_width=1)
|
||||
return always_redraw(get_line)
|
||||
|
||||
def leave_mark(self, number_line, value):
|
||||
tick = number_line.get_tick(value)
|
||||
tick.set_color(BLUE)
|
||||
number_line.add(tick)
|
||||
return tick
|
||||
|
||||
def get_infinite_sum(self):
|
||||
colors = self.colors
|
||||
inf_sum = TexMobject(
|
||||
"{4 \\over \\pi}", "\\left(",
|
||||
"{\\cos\\left({1}\\pi x\\right) \\over {1}}",
|
||||
"-",
|
||||
"{\\cos\\left({3}\\pi x\\right) \\over {3}}",
|
||||
"+",
|
||||
"{\\cos\\left({5}\\pi x\\right) \\over {5}}",
|
||||
"-",
|
||||
"{\\cos\\left({7}\\pi x\\right) \\over {7}}",
|
||||
"+",
|
||||
"\\cdots",
|
||||
"\\right)",
|
||||
tex_to_color_map={
|
||||
"{1}": colors[0],
|
||||
"{-1 \\over 3}": colors[1],
|
||||
"{3}": colors[1],
|
||||
"{1 \\over 5}": colors[2],
|
||||
"{5}": colors[2],
|
||||
"{-1 \\over 7}": colors[3],
|
||||
"{7}": colors[3],
|
||||
"{1 \\over 9}": colors[4],
|
||||
"{9}": colors[4],
|
||||
}
|
||||
)
|
||||
inf_sum.get_parts_by_tex("-")[0].set_color(colors[1])
|
||||
inf_sum.get_parts_by_tex("-")[1].set_color(colors[3])
|
||||
inf_sum.get_parts_by_tex("+")[0].set_color(colors[2])
|
||||
|
||||
inf_sum.terms = VGroup(
|
||||
inf_sum[2:6],
|
||||
inf_sum[6:12],
|
||||
inf_sum[12:18],
|
||||
inf_sum[18:24],
|
||||
)
|
||||
inf_sum.dots = inf_sum.get_part_by_tex("\\cdots")
|
||||
inf_sum.four_over_pi = inf_sum.get_part_by_tex(
|
||||
"{4 \\over \\pi}"
|
||||
)
|
||||
|
||||
return inf_sum
|
||||
|
||||
def get_step_func_definition(self):
|
||||
values = VGroup(*map(Integer, [1, 0, -1]))
|
||||
conditions = VGroup(*map(TextMobject, [
|
||||
"if $x < 0.5$",
|
||||
"if $x = 0.5$",
|
||||
"if $x > 0.5$",
|
||||
]))
|
||||
values.arrange(DOWN, buff=MED_LARGE_BUFF)
|
||||
for condition, value in zip(conditions, values):
|
||||
condition.move_to(value)
|
||||
condition.align_to(conditions[0], LEFT)
|
||||
conditions.next_to(values, RIGHT, LARGE_BUFF)
|
||||
brace = Brace(values, LEFT)
|
||||
|
||||
eq = TexMobject("=")
|
||||
eq.scale(1.5)
|
||||
eq.next_to(brace, LEFT)
|
||||
|
||||
return VGroup(eq, brace, values, conditions)
|
||||
|
@ -132,6 +132,7 @@ class StepFunctionExample(BringTwoRodsTogether, FourierSeriesIllustraiton):
|
||||
graph.restore,
|
||||
time_label.set_value, 0,
|
||||
)
|
||||
rods.clear_updaters()
|
||||
self.wait()
|
||||
|
||||
def add_labels(self):
|
||||
@ -146,16 +147,15 @@ class StepFunctionExample(BringTwoRodsTogether, FourierSeriesIllustraiton):
|
||||
}
|
||||
)
|
||||
x_numbers = x_axis.get_number_mobjects(
|
||||
*np.arange(0.25, 1.25, 0.25),
|
||||
*np.arange(0.2, 1.2, 0.2),
|
||||
number_config={
|
||||
"num_decimal_places": 2,
|
||||
"num_decimal_places": 1,
|
||||
},
|
||||
)
|
||||
|
||||
self.play(FadeIn(y_numbers))
|
||||
self.play(ShowCreationThenFadeAround(y_numbers[-1]))
|
||||
self.play(ShowCreationThenFadeAround(y_numbers[0]))
|
||||
self.wait()
|
||||
self.play(
|
||||
LaggedStartMap(
|
||||
FadeInFrom, x_numbers,
|
||||
@ -185,14 +185,12 @@ class StepFunctionExample(BringTwoRodsTogether, FourierSeriesIllustraiton):
|
||||
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,
|
||||
k_tracker.set_value, 3 * TAU,
|
||||
)
|
||||
self.wait()
|
||||
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, 1,
|
||||
A_tracker.set_value, 4 / PI,
|
||||
run_time=3
|
||||
)
|
||||
self.wait()
|
||||
@ -206,13 +204,15 @@ class StepFunctionExample(BringTwoRodsTogether, FourierSeriesIllustraiton):
|
||||
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(partial_sums[0])
|
||||
FadeIn(curr_partial_sum),
|
||||
FadeOut(self.rods),
|
||||
)
|
||||
# Copy-pasting from superclass...in theory,
|
||||
# this should be better abstracted, but eh.
|
||||
curr_partial_sum = partial_sums[0]
|
||||
pairs = list(zip(sine_graphs, partial_sums))[1:]
|
||||
for sine_graph, partial_sum in pairs:
|
||||
anims1 = [
|
||||
@ -239,3 +239,8 @@ class StepFunctionExample(BringTwoRodsTogether, FourierSeriesIllustraiton):
|
||||
self.axes.shift(
|
||||
self.axes.c2p(0, 0)[1] * DOWN
|
||||
)
|
||||
|
||||
|
||||
class NewSceneName(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
Reference in New Issue
Block a user