diff --git a/hilbert/section1.py b/hilbert/section1.py index 045e5736..508bdf4f 100644 --- a/hilbert/section1.py +++ b/hilbert/section1.py @@ -1,26 +1,46 @@ from mobject import Mobject, Point -from mobject.tex_mobject import TexMobject, TextMobject, Brace -from mobject.image_mobject import ImageMobject +from mobject.tex_mobject import \ + TexMobject, TextMobject, Brace +from mobject.image_mobject import \ + ImageMobject, MobjectFromRegion from scene import Scene from animation import Animation -from animation.transform import Transform, CounterclockwiseTransform, \ - ApplyMethod, GrowFromCenter -from animation.simple_animations import ShowCreation, ShimmerIn -from animation.meta_animations import DelayByOrder, TransformAnimations -from animation.playground import VibratingString +from animation.transform import \ + Transform, CounterclockwiseTransform, ApplyMethod,\ + GrowFromCenter, ClockwiseTransform +from animation.simple_animations import \ + ShowCreation, ShimmerIn, FadeOut, FadeIn +from animation.meta_animations import \ + DelayByOrder, TransformAnimations +from animation.playground import Vibrate -from topics.geometry import Line, Dot, Arrow +from topics.geometry import \ + Line, Dot, Arrow, Grid, Square, Point from topics.characters import ThoughtBubble from topics.number_line import UnitInterval +from topics.three_dimensions import Stars + +from region import region_from_polygon_vertices + +import displayer as disp + +from hilbert.curves import \ + TransformOverIncreasingOrders, FlowSnake from helpers import * -from hilbert.curves import TransformOverIncreasingOrders, FlowSnake +def get_grid(): + return Grid(64, 64) + +def get_freq_line(): + return UnitInterval().shift(2*DOWN) ##Change? + + class AboutSpaceFillingCurves(TransformOverIncreasingOrders): @staticmethod def args_to_string(): @@ -131,7 +151,7 @@ class WriteSomeSoftware(Scene): class ImageToSound(Scene): def construct(self): - string = VibratingString(color = BLUE_D, run_time = 5) + string = Vibrate(color = BLUE_D, run_time = 5) picture = ImageMobject("lion", invert = False) picture.scale(0.8) picture_copy = picture.copy() @@ -181,11 +201,11 @@ class SoundDataIsOneDimensional(Scene): def construct(self): overtones = 5 floor = 2*DOWN - main_string = VibratingString(color = BLUE_D) + main_string = Vibrate(color = BLUE_D) component_strings = [ - VibratingString( + Vibrate( num_periods = k+1, - overtones = 2, + overtones = 1, color = color, center = 2*DOWN + UP*k ) @@ -202,7 +222,7 @@ class SoundDataIsOneDimensional(Scene): for string in component_strings ] - freq_line = UnitInterval() + freq_line = get_freq_line() freq_line.shift(floor) freq_line.sort_points(np.linalg.norm) brace = Brace(freq_line, UP) @@ -242,7 +262,243 @@ class SoundDataIsOneDimensional(Scene): ) self.dither(0.5) - +class GridOfPixels(Scene): + def construct(self): + low_res = ImageMobject("low_resolution_lion", invert = False) + high_res = ImageMobject("Lion", invert = False) + grid = get_grid() + for mob in low_res, high_res: + mob.replace(grid, stretch = True) + for mob in low_res, high_res, grid: + mob.sort_points(np.linalg.norm) + side_brace = Brace(grid, LEFT) + top_brace = Brace(grid, UP) + top_words = TextMobject("256 Px", size = "\\normal") + side_words = top_words.copy().rotate(np.pi/2) + top_words.next_to(top_brace, UP) + side_words.next_to(side_brace, LEFT) + + self.add(high_res) + self.dither() + self.play(DelayByOrder(Transform(high_res, low_res))) + self.dither() + self.play(DelayByOrder(Transform(high_res, grid))) + self.clear() + self.add(grid) + self.play( + GrowFromCenter(top_brace), + GrowFromCenter(side_brace), + ShimmerIn(top_words), + ShimmerIn(side_words) + ) + self.dither() + + +class ShowFrequencySpace(Scene): + def construct(self): + freq_line = get_freq_line() + + self.add(freq_line) + self.dither() + for tex, vect in zip(["20 Hz", "20{,}000 Hz"], [LEFT, RIGHT]): + tex_mob = TextMobject(tex) + tex_mob.to_edge(vect) + tex_mob.shift(UP) + arrow = Arrow(tex_mob, freq_line.get_edge_center(vect)) + self.play( + ShimmerIn(tex_mob), + ShowCreation(arrow) + ) + self.dither() + + + +class AssociatePixelWithFrequency(Scene): + def construct(self): + big_grid_dim = 20. + small_grid_dim = 6. + big_grid = Grid(64, 64, height = big_grid_dim, width = big_grid_dim) + big_grid.to_corner(UP+RIGHT, buff = 2) + small_grid = big_grid.copy() + small_grid.scale(small_grid_dim/big_grid_dim) + small_grid.center() + pixel = MobjectFromRegion( + region_from_polygon_vertices(*0.2*np.array([ + RIGHT+DOWN, + RIGHT+UP, + LEFT+UP, + LEFT+DOWN + ])) + ) + pixel.set_color(WHITE) + pixel_width = big_grid.width/big_grid.columns + pixel.scale_to_fit_width(pixel_width) + pixel.to_corner(UP+RIGHT, buff = 2) + pixel.shift(5*pixel_width*(2*LEFT+DOWN)) + + freq_line = get_freq_line() + dot = Dot() + dot.shift(freq_line.get_center() + 2*RIGHT) + string = Line(LEFT, RIGHT, color = GREEN) + arrow = Arrow( + dot, string.get_center(), + color = YELLOW_C + ) + vibration_config = { + "overtones" : 1, + "spatial_period" : 2, + } + vibration, loud_vibration, quiet_vibration = [ + Vibrate(string.copy(), amplitude = a, **vibration_config) + for a in [0.5, 1., 0.25] + ] + + self.add(small_grid) + self.dither() + self.play( + Transform(small_grid, big_grid) + ) + self.play(FadeIn(pixel)) + self.dither() + self.play( + FadeOut(small_grid), + ShowCreation(freq_line) + ) + self.remove(small_grid) + self.play( + Transform(pixel, dot), + ) + self.dither() + self.play(ShowCreation(arrow)) + self.play(loud_vibration) + self.play( + TransformAnimations(loud_vibration, quiet_vibration), + ApplyMethod(dot.fade, 0.1) + ) + self.clear() + self.add(freq_line, dot, arrow) + self.play(quiet_vibration) + + +class ListenToAllPixels(Scene): + def construct(self): + grid = get_grid() + grid.sort_points(np.linalg.norm) + freq_line = get_freq_line() + freq_line.sort_points(lambda p : p[0]) + red, blue = Color(RED), Color(BLUE) + freq_line.gradient_highlight(red, blue) + + colors = [ + Color(rgb = interpolate( + np.array(red.rgb), + np.array(blue.rgb), + alpha + )) + for alpha in np.arange(4)/3. + ] + string = Line(3*LEFT, 3*RIGHT, color = colors[1]) + vibration = Vibrate(string) + vibration_copy = vibration.copy() + vibration_copy.mobject.point_thickness = 1 + sub_vibrations = [ + Vibrate( + string.copy().shift((n-1)*UP).highlight(colors[n]), + overtones = 1, + spatial_period = 6./(n+1), + temporal_period = 1./(n+1), + amplitude = 0.5/(n+1) + ) + for n in range(4) + ] + words = TexMobject("&\\vdots \\\\ \\text{thousands }& \\text{of frequencies} \\\\ &\\vdots") + words.to_edge(UP, buff = 0.1) + + self.add(grid) + self.dither() + self.play(DelayByOrder(ApplyMethod( + grid.gradient_highlight, red, blue + ))) + self.play(Transform(grid, freq_line)) + self.dither() + self.play( + ShimmerIn( + words, + alpha_func = squish_alpha_func(smooth, 0, 0.2) + ), + *sub_vibrations, + run_time = 5 + ) + self.play( + *[ + TransformAnimations( + sub_vib, vibration + ) + for sub_vib in sub_vibrations + ]+[FadeOut(words)] + ) + self.clear() + self.add(freq_line) + self.play(vibration) + + +class LayAsideSpeculation(Scene): + def construct(self): + words = TextMobject("Would this actually work?") + grid = get_grid() + grid.scale_to_fit_width(6) + grid.to_edge(LEFT) + freq_line = get_freq_line() + freq_line.scale_to_fit_width(6) + freq_line.center().to_edge(RIGHT) + mapping = Mobject( + grid, freq_line, Arrow(grid, freq_line) + ) + mapping.ingest_sub_mobjects() + lower_left = Point().to_corner(DOWN+LEFT, buff = 0) + lower_right = Point().to_corner(DOWN+RIGHT, buff = 0) + + self.add(words) + self.dither() + self.play( + Transform(words, lower_right), + Transform(lower_left, mapping) + ) + self.dither() + + +class RandomMapping(Scene): + def construct(self): + grid = get_grid() + grid.scale_to_fit_width(6) + grid.to_edge(LEFT) + freq_line = get_freq_line() + freq_line.scale_to_fit_width(6) + freq_line.center().to_edge(RIGHT) + # for mob in grid, freq_line: + # indices = np.arange(mob.get_num_points()) + # random.shuffle(indices) + # mob.points = mob.points[indices] + stars = Stars(point_thickness = grid.point_thickness) + + self.add(grid) + targets = [stars, freq_line] + alphas = [not_quite_there(rush_into), rush_from] + for target, alpha_func in zip(targets, alphas): + self.play(Transform( + grid, target, + run_time = 3, + alpha_func = alpha_func, + interpolation_function = path_along_arc(-np.pi/2) + )) + self.dither() + + + +class LeverageExistingIntuitions(Scene): + def construct(self): + self.add(TextMobject("Leverage existing intuitions")) + self.dither()