From b3673e93d779969001c48d9d8dbac9ea3f7e751f Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Wed, 3 Jul 2019 11:08:39 -0700 Subject: [PATCH] Final animations for Fourier montage video --- active_projects/diffyq/all_part4_scenes.py | 1 + .../diffyq/fourier_montage_scenes.py | 23 ++ .../diffyq/part4/fourier_series_scenes.py | 170 +----------- .../diffyq/part4/long_fourier_scenes.py | 242 ++++++++++++++++++ 4 files changed, 272 insertions(+), 164 deletions(-) create mode 100644 active_projects/diffyq/fourier_montage_scenes.py create mode 100644 active_projects/diffyq/part4/long_fourier_scenes.py diff --git a/active_projects/diffyq/all_part4_scenes.py b/active_projects/diffyq/all_part4_scenes.py index 9a729a8e..21ff9510 100644 --- a/active_projects/diffyq/all_part4_scenes.py +++ b/active_projects/diffyq/all_part4_scenes.py @@ -4,6 +4,7 @@ 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 * from active_projects.diffyq.part3.staging import * diff --git a/active_projects/diffyq/fourier_montage_scenes.py b/active_projects/diffyq/fourier_montage_scenes.py new file mode 100644 index 00000000..27d028c8 --- /dev/null +++ b/active_projects/diffyq/fourier_montage_scenes.py @@ -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, +] diff --git a/active_projects/diffyq/part4/fourier_series_scenes.py b/active_projects/diffyq/part4/fourier_series_scenes.py index f42addc0..e346cf16 100644 --- a/active_projects/diffyq/part4/fourier_series_scenes.py +++ b/active_projects/diffyq/part4/fourier_series_scenes.py @@ -1840,6 +1840,7 @@ class DE4Thumbnail(ComplexFourierSeriesExample): subname = TextMobject("a.k.a ``everything is rotations''") subname.match_width(name) subname.next_to(name, DOWN) + VGroup(name, subname).to_edge(DOWN) self.add(name) self.add(subname) @@ -1858,18 +1859,19 @@ class DE4Thumbnail(ComplexFourierSeriesExample): for n in ns ]) approxs.arrange(RIGHT, buff=2.5) - approxs.set_height(4) - approxs.to_edge(DOWN, buff=LARGE_BUFF) + approxs.set_height(3.75) + approxs.to_edge(UP, buff=1.25) for a, c, w in zip(approxs, [BLUE, GREEN, YELLOW], [4, 3, 2]): a.set_stroke(c, w) + a.set_stroke(WHITE, w + w / 2, background=True) labels = VGroup() for n, approx in zip(ns, approxs): label = TexMobject("n = ", str(n)) label[1].match_color(approx) label.scale(2) - label.next_to(approx, DOWN) - label.to_edge(DOWN, buff=MED_SMALL_BUFF) + label.next_to(approx, UP) + label.to_edge(UP, buff=MED_SMALL_BUFF) labels.add(label) self.add(approxs) @@ -1889,163 +1891,3 @@ class DE4Thumbnail(ComplexFourierSeriesExample): self.add(path, self.circles, self.vectors) self.update_mobjects(0) - -# Pure fourier series with zooming. -# Note to self, put out a single video with nothing -# but these? - -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.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", - } - - -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 FourierOfFourierOneLineArtsy(FourierSeriesExampleWithRectForZoom): - CONFIG = { - "file_name": "JosephFourierOneLineArtsy", - "n_vectors": 100, - "rect_stroke_width": 1, - } diff --git a/active_projects/diffyq/part4/long_fourier_scenes.py b/active_projects/diffyq/part4/long_fourier_scenes.py new file mode 100644 index 00000000..9fae0ec0 --- /dev/null +++ b/active_projects/diffyq/part4/long_fourier_scenes.py @@ -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)