3b1b-manim/hilbert/section1.py

1041 lines
30 KiB
Python

from mobject import Mobject, Point
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, ClockwiseTransform, ApplyPointwiseFunction
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, Grid, Square, Point
from topics.characters import \
ThoughtBubble, SpeechBubble, Mathematician
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, HilbertCurve, \
SnakeCurve
from helpers import *
def get_grid():
return Grid(64, 64)
def get_freq_line():
return UnitInterval().shift(2*DOWN) ##Change?
def get_mathy_and_bubble():
mathy = Mathematician()
mathy.to_edge(DOWN).shift(4*LEFT)
bubble = SpeechBubble(initial_width = 8)
bubble.pin_to(mathy)
return mathy, bubble
class AboutSpaceFillingCurves(TransformOverIncreasingOrders):
@staticmethod
def args_to_string():
return ""
@staticmethod
def string_to_args(arg_str):
return ()
def construct(self):
self.bubble = ThoughtBubble().ingest_sub_mobjects()
self.bubble.scale(1.5)
TransformOverIncreasingOrders.construct(self, FlowSnake, 7)
self.play(Transform(self.curve, self.bubble))
self.show_infinite_objects()
self.pose_question()
self.dither()
def show_infinite_objects(self):
sigma, summand, equals, result = TexMobject([
"\\sum_{n = 1}^{\\infty}",
"\\dfrac{1}{n^2}",
"=",
"\\dfrac{\pi^2}{6}"
]).split()
alt_summand = TexMobject("n").replace(summand)
alt_result = TexMobject("-\\dfrac{1}{12}").replace(result)
rationals, other_equals, naturals = TexMobject([
"|\\mathds{Q}|",
"=",
"|\\mathds{N}|"
]).scale(2).split()
infinity = TexMobject("\\infty").scale(2)
local_mobjects = filter(
lambda m : isinstance(m, Mobject),
locals().values(),
)
for mob in local_mobjects:
mob.sort_points(np.linalg.norm)
self.play(ShimmerIn(infinity))
self.dither()
self.play(
ShimmerIn(summand),
ShimmerIn(equals),
ShimmerIn(result),
DelayByOrder(Transform(infinity, sigma))
)
self.dither()
self.play(
Transform(summand, alt_summand),
Transform(result, alt_result),
)
self.dither()
self.remove(infinity)
self.play(*[
CounterclockwiseTransform(
Mobject(summand, equals, result, sigma),
Mobject(rationals, other_equals, naturals)
)
])
self.dither()
self.clear()
self.add(self.bubble)
def pose_question(self):
infinity, rightarrow, N = TexMobject([
"\\infty", "\\rightarrow", "N"
]).scale(2).split()
question_mark = TextMobject("?").scale(2)
self.add(question_mark)
self.dither()
self.play(*[
ShimmerIn(mob)
for mob in infinity, rightarrow, N
] + [
ApplyMethod(question_mark.next_to, rightarrow, UP),
])
self.dither()
class PostponePhilosophizing(Scene):
def construct(self):
abstract, arrow, concrete = TextMobject([
"Abstract", " $\\rightarrow$ ", "Concrete"
]).scale(2).split()
self.add(abstract, arrow, concrete)
self.dither()
self.play(*[
ApplyMethod(
word1.replace, word2,
path_func = path_along_arc(np.pi/2)
)
for word1, word2 in it.permutations([abstract, concrete])
])
self.dither()
class SectionOne(Scene):
def construct(self):
self.add(TextMobject("Section 1: Seeing with your ears"))
self.dither()
class WriteSomeSoftware(Scene):
pass #Done viea screen capture, written here for organization
class ImageToSound(Scene):
def construct(self):
string = Vibrate(color = BLUE_D, run_time = 5)
picture = ImageMobject("lion", invert = False)
picture.scale(0.8)
picture_copy = picture.copy()
picture.sort_points(np.linalg.norm)
string.mobject.sort_points(lambda p : -np.linalg.norm(p))
self.add(picture)
self.dither()
self.play(Transform(
picture, string.mobject,
run_time = 3,
rate_func = rush_into
))
self.remove(picture)
self.play(string)
for mob in picture_copy, string.mobject:
mob.sort_points(lambda p : np.linalg.norm(p)%1)
self.play(Transform(
string.mobject, picture_copy,
run_time = 5,
rate_func = rush_from
))
class ImageDataIsTwoDimensional(Scene):
def construct(self):
image = ImageMobject("lion", invert = False)
image.scale(0.5)
image.shift(2*LEFT)
self.add(image)
for vect, num in zip([DOWN, RIGHT], [1, 2]):
brace = Brace(image, vect)
words_mob = TextMobject("Dimension %d"%num)
words_mob.next_to(image, vect, buff = 1)
self.play(
Transform(Point(brace.get_center()), brace),
ShimmerIn(words_mob),
run_time = 2
)
self.dither()
class SoundDataIsOneDimensional(Scene):
def construct(self):
overtones = 5
floor = 2*DOWN
main_string = Vibrate(color = BLUE_D)
component_strings = [
Vibrate(
num_periods = k+1,
overtones = 1,
color = color,
center = 2*DOWN + UP*k
)
for k, color in zip(
range(overtones),
Color(BLUE_E).range_to(WHITE, overtones)
)
]
dots = [
Dot(
string.mobject.get_center(),
color = string.mobject.get_color()
)
for string in component_strings
]
freq_line = get_freq_line()
freq_line.shift(floor)
freq_line.sort_points(np.linalg.norm)
brace = Brace(freq_line, UP)
words = TextMobject("Range of frequency values")
words.next_to(brace, UP)
self.play(*[
TransformAnimations(
main_string.copy(),
string,
run_time = 5
)
for string in component_strings
])
self.clear()
self.play(*[
TransformAnimations(
string,
Animation(dot)
)
for string, dot in zip(component_strings, dots)
])
self.clear()
self.play(
ShowCreation(freq_line),
GrowFromCenter(brace),
ShimmerIn(words),
*[
Transform(
dot,
dot.copy().scale(2).rotate(-np.pi/2).shift(floor),
path_func = path_along_arc(np.pi/3)
)
for dot in dots
]
)
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().scale(0.8)
for mob in low_res, high_res:
mob.replace(grid, stretch = True)
side_brace = Brace(low_res, LEFT)
top_brace = Brace(low_res, 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(
GrowFromCenter(top_brace),
GrowFromCenter(side_brace),
ShimmerIn(top_words),
ShimmerIn(side_words)
)
self.dither()
for mob in grid, high_res:
mob.sort_points(np.linalg.norm)
self.play(DelayByOrder(Transform(high_res, grid)))
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())
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.9)
)
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,
rate_func = squish_rate_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, rate_func in zip(targets, alphas):
self.play(Transform(
grid, target,
run_time = 3,
rate_func = rate_func,
path_func = path_along_arc(-np.pi/2)
))
self.dither()
class LeverageExistingIntuitions(Scene):
def construct(self):
self.add(TextMobject("Leverage existing intuitions"))
self.dither()
class ThinkInTermsOfReverseMapping(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)
arrow = Arrow(grid, freq_line)
color1, color2 = YELLOW_C, RED
square_length = 0.01
dot1 = Dot(color = color1)
dot1.shift(3*RIGHT)
dot2 = Dot(color = color2)
dot2.shift(3.1*RIGHT)
arrow1 = Arrow(2*RIGHT+UP, dot1, color = color1, buff = 0.1)
arrow2 = Arrow(4*RIGHT+UP, dot2, color = color2, buff = 0.1)
dot3, arrow3 = [
mob.copy().shift(5*LEFT+UP)
for mob in dot1, arrow1
]
dot4, arrow4 = [
mob.copy().shift(5*LEFT+0.9*UP)
for mob in dot2, arrow2
]
self.add(grid, freq_line, arrow)
self.dither()
self.play(ApplyMethod(
arrow.rotate, np.pi,
path_func = clockwise_path()
))
self.dither()
self.play(ShowCreation(arrow1))
self.add(dot1)
self.play(ShowCreation(arrow2))
self.add(dot2)
self.dither()
self.remove(arrow1, arrow2)
self.play(
Transform(dot1, dot3),
Transform(dot2, dot4)
)
self.play(
ApplyMethod(grid.fade, 0.8),
Animation(Mobject(dot3, dot4))
)
self.play(ShowCreation(arrow3))
self.play(ShowCreation(arrow4))
self.dither()
class WeaveLineThroughPixels(Scene):
@staticmethod
def args_to_string(order):
return str(order)
@staticmethod
def string_to_args(order_str):
return int(order_str)
def construct(self, order):
start_color, end_color = RED, GREEN
curve = HilbertCurve(order = order)
line = Line(5*LEFT, 5*RIGHT)
for mob in curve, line:
mob.gradient_highlight(start_color, end_color)
freq_line = get_freq_line()
freq_line.replace(line, stretch = True)
unit = 6./(2**order) #sidelength of pixel
up = unit*UP
right = unit*RIGHT
lower_left = 3*(LEFT+DOWN)
squares = Mobject(*[
Square(
side_length = unit,
color = WHITE
).shift(x*right+y*up)
for x, y in it.product(range(2**order), range(2**order))
])
squares.center()
targets = Mobject()
for square in squares.sub_mobjects:
center = square.get_center()
distances = np.apply_along_axis(
lambda p : np.linalg.norm(p-center),
1,
curve.points
)
index_along_curve = np.argmin(distances)
fraction_along_curve = index_along_curve/float(curve.get_num_points())
target = square.copy().center().scale(0.8/(2**order))
line_index = int(fraction_along_curve*line.get_num_points())
target.shift(line.points[line_index])
targets.add(target)
self.add(squares)
self.play(ShowCreation(
curve,
run_time = 5,
rate_func = None
))
self.dither()
self.play(
Transform(curve, line),
Transform(squares, targets),
run_time = 3
)
self.dither()
self.play(ShowCreation(freq_line))
self.dither()
class WellPlayedGameOfSnake(Scene):
def construct(self):
grid = Grid(16, 16).fade()
snake_curve = SnakeCurve(order = 4)
words = TextMobject("``Snake Curve''")
words.next_to(grid, UP)
self.add(grid)
self.play(ShowCreation(
snake_curve,
run_time = 7,
rate_func = None
))
self.dither()
self.play(ShimmerIn(words))
self.dither()
class TellMathematicianFriend(Scene):
def construct(self):
mathy, bubble = get_mathy_and_bubble()
squiggle_mouth = mathy.mouth.copy()
squiggle_mouth.apply_function(
lambda (x, y, z) : (x, y+0.02*np.sin(50*x), z)
)
bubble.ingest_sub_mobjects()
bubble.write("Why not use a Hilbert curve \\textinterrobang ")
words1 = bubble.content
bubble.write("So, it's not one curve but an infinite family of curves \\dots")
words2 = bubble.content
bubble.write("Well, no, it \\emph{is} just one thing, but I need \\\\ \
to tell you about a certain infinite family first.")
words3 = bubble.content
description = TextMobject("Mathematician friend", size = "\\small")
description.next_to(mathy, buff = 2)
arrow = Arrow(description, mathy)
self.add(mathy)
self.play(
ShowCreation(arrow),
ShimmerIn(description)
)
self.dither()
point = Point(bubble.get_tip())
self.play(
Transform(point, bubble),
)
self.remove(point)
self.add(bubble)
self.play(ShimmerIn(words1))
self.dither()
self.remove(description, arrow)
self.play(
Transform(mathy.mouth, squiggle_mouth),
ApplyMethod(mathy.arm.wag, 0.2*RIGHT, LEFT),
)
self.remove(words1)
self.add(words2)
self.dither(2)
self.remove(words2)
self.add(words3)
self.dither(2)
self.play(
ApplyPointwiseFunction(
lambda p : 15*p/np.linalg.norm(p),
bubble
),
ApplyMethod(mathy.shift, 5*(DOWN+LEFT)),
FadeOut(words3),
run_time = 3
)
class Order1PseudoHilbertCurve(Scene):
def construct(self):
words, s = TextMobject(["Pseudo-Hilbert Curve", "s"]).split()
pre_words = TextMobject("Order 1")
pre_words.next_to(words, LEFT, buff = 0.5)
s.next_to(words, RIGHT, buff = 0.05, aligned_edge = DOWN)
cluster = Mobject(pre_words, words, s)
cluster.center()
cluster.scale(0.7)
cluster.to_edge(UP, buff = 0.3)
cluster.highlight(GREEN)
grid1 = Grid(1, 1)
grid2 = Grid(2, 2)
curve = HilbertCurve(order = 1)
self.add(words, s)
self.dither()
self.play(Transform(
s, pre_words,
path_func = path_along_arc(-np.pi/3)
))
self.dither()
self.play(ShowCreation(grid1))
self.dither()
self.play(ShowCreation(grid2))
self.dither()
kwargs = {
"run_time" : 5,
"rate_func" : None
}
self.play(ShowCreation(curve, **kwargs))
self.dither()
class Order2PseudoHilbertCurve(Scene):
def construct(self):
words = TextMobject("Order 2 Pseudo-Hilbert Curve")
words.to_edge(UP, buff = 0.3)
words.highlight(GREEN)
grid2 = Grid(2, 2)
grid4 = Grid(4, 4, point_thickness = 2)
# order_1_curve = HilbertCurve(order = 1)
# squaggle_curve = order_1_curve.copy().apply_function(
# lambda (x, y, z) : (x + np.cos(3*y), y + np.sin(3*x), z)
# )
# squaggle_curve.show()
mini_curves = [
HilbertCurve(order = 1).scale(0.5).shift(1.5*vect)
for vect in [
LEFT+DOWN,
LEFT+UP,
RIGHT+UP,
RIGHT+DOWN
]
]
last_curve = mini_curves[0]
naive_curve = Mobject(last_curve)
for mini_curve in mini_curves[1:]:
line = Line(last_curve.points[-1], mini_curve.points[0])
naive_curve.add(line, mini_curve)
last_curve = mini_curve
naive_curve.ingest_sub_mobjects()
naive_curve.gradient_highlight(RED, GREEN)
order_2_curve = HilbertCurve(order = 2)
self.add(words, grid2)
self.dither()
self.play(ShowCreation(grid4))
self.play(*[
ShowCreation(mini_curve)
for mini_curve in mini_curves
])
self.dither()
self.play(ShowCreation(naive_curve, run_time = 5))
self.remove(*mini_curves)
self.dither()
self.play(Transform(naive_curve, order_2_curve))
self.dither()
class Order3PseudoHilbertCurve(Scene):
def construct(self):
words = TextMobject("Order 3 Pseudo-Hilbert Curve")
words.highlight(GREEN)
words.to_edge(UP)
grid4 = Mobject(
Grid(2, 2),
Grid(4, 4, point_thickness = 2)
)
grid8 = Grid(8, 8, point_thickness = 1)
order_3_curve = HilbertCurve(order = 3)
mini_curves = [
HilbertCurve(order = 2).scale(0.5).shift(1.5*vect)
for vect in [
LEFT+DOWN,
LEFT+UP,
RIGHT+UP,
RIGHT+DOWN
]
]
self.add(words, grid4)
self.dither()
self.play(ShowCreation(grid8))
self.dither()
self.play(*map(GrowFromCenter, mini_curves))
self.dither()
self.clear()
self.add(words, grid8, *mini_curves)
self.play(*[
ApplyMethod(curve.rotate_in_place, np.pi, axis)
for curve, axis in [
(mini_curves[0], UP+RIGHT),
(mini_curves[3], UP+LEFT)
]
])
self.play(ShowCreation(order_3_curve, run_time = 5))
self.dither()
class GrowToOrder8PseudoHilbertCurve(Scene):
def construct(self):
self.curve = HilbertCurve(order = 1)
self.add(self.curve)
self.dither()
while self.curve.order < 8:
self.increase_order()
def increase_order(self):
mini_curves = [
self.curve.copy().scale(0.5).shift(1.5*vect)
for vect in [
LEFT+DOWN,
LEFT+UP,
RIGHT+UP,
RIGHT+DOWN
]
]
self.remove(self.curve)
self.play(
Transform(self.curve.copy(), mini_curves[0])
)
self.play(*[
GrowFromCenter(mini_curve)
for mini_curve in mini_curves[1:]
])
self.dither()
self.clear()
self.add(*mini_curves)
self.play(*[
ApplyMethod(curve.rotate_in_place, np.pi, axis)
for curve, axis in [
(mini_curves[0], UP+RIGHT),
(mini_curves[3], UP+LEFT)
]
])
self.curve = HilbertCurve(order = self.curve.order+1)
self.play(ShowCreation(self.curve, run_time = 2))
self.remove(*mini_curves)
self.dither()
class UseOrder8(Scene):
def construct(self):
mathy, bubble = get_mathy_and_bubble()
bubble.write("For a 256x256 pixel array...")
words = TextMobject("Order 8 Pseudo-Hilbert Curve")
words.highlight(GREEN)
words.to_edge(UP, buff = 0.3)
curve = HilbertCurve(order = 8)
self.add(mathy, bubble)
self.play(ShimmerIn(bubble.content))
self.dither()
self.clear()
self.add(words)
self.play(ShowCreation(
curve, run_time = 7, rate_func = None
))
self.dither()
class HilbertBetterThanSnakeQ(Scene):
def construct(self):
hilbert_curves, snake_curves = [
[
CurveClass(order = n)
for n in range(2, 7)
]
for CurveClass in HilbertCurve, SnakeCurve
]
for curve in hilbert_curves+snake_curves:
curve.scale(0.8)
for curve in hilbert_curves:
curve.to_edge(LEFT)
for curve in snake_curves:
curve.to_edge(RIGHT)
greater_than = TexMobject(">")
question_mark = TextMobject("?")
question_mark.next_to(greater_than, UP)
self.add(greater_than, question_mark)
hilbert_curve = hilbert_curves[0]
snake_curve = snake_curves[0]
for new_hc, new_sc in zip(hilbert_curves[1:], snake_curves[1:]):
self.play(*[
Transform(hilbert_curve, new_hc),
Transform(snake_curve, new_sc)
])
self.dither()
class ImagineItWorks(Scene):
def construct(self):
self.add(TextMobject("Image your project succeeds..."))
self.dither()
class IncreaseResolution(Scene):
def construct(self):
grids = [
Grid(
2**order, 2**order,
point_thickness = 1
).shift(0.3*DOWN)
for order in 6, 7
]
grid = grids[0]
side_brace = Brace(grid, LEFT)
top_brace = Brace(grid, UP)
top_words = TextMobject("256")
new_top_words = TextMobject("512")
side_words = top_words.copy()
new_side_words = new_top_words.copy()
for words in top_words, new_top_words:
words.next_to(top_brace, UP, buff = 0.1)
for words in side_words, new_side_words:
words.next_to(side_brace, LEFT)
self.add(grid)
self.play(
GrowFromCenter(side_brace),
GrowFromCenter(top_brace),
ShimmerIn(top_words),
ShimmerIn(side_words)
)
self.dither()
self.play(
DelayByOrder(Transform(*grids)),
Transform(top_words, new_top_words),
Transform(side_words, new_side_words)
)
self.dither()
class IncreasingResolutionWithSnakeCurve(Scene):
def construct(self):
start_curve = SnakeCurve(order = 6)
end_curve = SnakeCurve(order = 7)
start_dots, end_dots = [
Mobject(*[
Dot(
curve.points[int(x*curve.get_num_points())],
color = color
)
for x, color in [
(0.202, GREEN),
(0.48, BLUE),
(0.7, RED)
]
])
for curve in start_curve, end_curve
]
self.add(start_curve)
self.dither()
self.play(
ShowCreation(start_dots, run_time = 2),
ApplyMethod(start_curve.fade)
)
end_curve.fade()
self.play(
Transform(start_curve, end_curve),
Transform(start_dots, end_dots)
)
self.dither()
class TrackSpecificCurvePoint(Scene):
CURVE_CLASS = None #Fillin
def construct(self):
line = get_freq_line().center()
line.sort_points(lambda p : p[0])
curves = [
self.CURVE_CLASS(order = order)
for order in range(3, 10)
]
alpha = 0.48
dot = Dot(UP)
start_dot = Dot(0.1*LEFT)
dots = [
Dot(curve.points[alpha*curve.get_num_points()])
for curve in curves
]
self.play(ShowCreation(line))
self.play(Transform(dot, start_dot))
self.dither()
for new_dot, curve in zip(dots, curves):
self.play(
Transform(line, curve),
Transform(dot, new_dot)
)
self.dither()
class TrackSpecificSnakeCurvePoint(TrackSpecificCurvePoint):
CURVE_CLASS = SnakeCurve
class NeedToRelearn(Scene):
def construct(self):
top_words = TextMobject("Different pixel-frequency association")
bottom_words = TextMobject("Need to relearn synesthesia")
top_words.shift(UP)
bottom_words.shift(DOWN)
arrow = Arrow(top_words, bottom_words)
self.play(ShimmerIn(top_words))
self.dither()
self.play(ShowCreation(arrow))
self.play(ShimmerIn(bottom_words))
self.dither()
class TrackSpecificHilbertCurvePoint(TrackSpecificCurvePoint):
CURVE_CLASS = HilbertCurve