3b1b-manim/eola/chapter5.py

415 lines
13 KiB
Python
Raw Normal View History

2016-08-02 12:26:15 -07:00
from mobject.tex_mobject import TexMobject
from mobject import Mobject
from mobject.image_mobject import ImageMobject
from mobject.vectorized_mobject import VMobject
from animation.animation import Animation
from animation.transform import *
from animation.simple_animations import *
from topics.geometry import *
from topics.characters import *
from topics.functions import *
from topics.number_line import *
from topics.numerals import *
from scene import Scene
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
from mobject.vectorized_mobject import *
from eola.matrix import *
from eola.two_d_space import *
from eola.chapter3 import MatrixVectorMultiplicationAbstract
class Blob(Circle):
CONFIG = {
"stroke_color" : TEAL,
"fill_color" : BLUE_E,
"fill_opacity" : 1,
"random_seed" : 1,
"random_nudge_size" : 0.5,
"height" : 2,
}
def __init__(self, **kwargs):
Circle.__init__(self, **kwargs)
random.seed(self.random_seed)
self.apply_complex_function(
lambda z : z*(1+self.random_nudge_size*(random.random()-0.5))
)
self.scale_to_fit_height(self.height).center()
def probably_contains(self, point):
border_points = np.array(self.get_anchors_and_handles()[0])
distances = map(lambda p : np.linalg.norm(p-point), border_points)
min3 = border_points[np.argsort(distances)[:3]]
center_direction = self.get_center() - point
in_center_direction = map(
lambda p : np.dot(p-point, center_direction) > 0,
min3
)
return sum(in_center_direction) <= 2
class OpeningQuote(Scene):
def construct(self):
words = TextMobject([
"``The purpose of computation is \\\\",
"insight",
", not ",
"numbers.",
"''",
], separate_list_arg_with_spaces = False)
# words.scale_to_fit_width(2*SPACE_WIDTH - 2)
words.to_edge(UP)
words.split()[1].highlight(BLUE)
words.split()[3].highlight(GREEN)
author = TextMobject("-Richard Hamming")
author.highlight(YELLOW)
author.next_to(words, DOWN, buff = 0.5)
self.play(FadeIn(words))
self.dither(2)
self.play(Write(author, run_time = 3))
self.dither()
class MovingForward(TeacherStudentsScene):
def construct(self):
self.setup()
student = self.get_students()[1]
bubble = student.get_bubble(direction = RIGHT, width = 5)
bubble.rotate(-np.pi/12)
bubble.next_to(student, UP, aligned_edge = RIGHT)
bubble.shift(0.5*LEFT)
bubble.make_green_screen()
self.teacher_says("""
Y'all know about linear
transformations, right?
""", width = 7)
self.play(
ShowCreation(bubble),
student.change_mode, "pondering"
)
self.dither(2)
class StretchingTransformation(LinearTransformationScene):
def construct(self):
self.setup()
self.add_title("Generally stretches space")
self.apply_transposed_matrix([[3, 1], [-1, 2]])
self.dither()
class SquishingTransformation(LinearTransformationScene):
CONFIG = {
"foreground_plane_kwargs" : {
"x_radius" : 3*SPACE_WIDTH,
"y_radius" : 3*SPACE_WIDTH,
"secondary_line_ratio" : 0
},
}
def construct(self):
self.setup()
self.add_title("Generally squishes space")
self.apply_transposed_matrix([[1./2, -0.5], [1, 1./3]])
self.dither()
class AskAboutStretching(LinearTransformationScene):
def construct(self):
self.setup()
words = TextMobject("""
Exactly how much are
things being stretched?
""")
words.add_background_rectangle()
words.to_corner(UP+RIGHT)
words.highlight(YELLOW)
self.apply_transposed_matrix(
[[2, 1], [-1, 3]],
added_anims = [Write(words)]
)
self.dither()
class AskAboutStretchingSpecifically(LinearTransformationScene):
def construct(self):
self.setup()
self.add_title(["How much are", "areas", "scaled?"])
hma, areas, scaled = self.title.split()[1].split()
areas.highlight(YELLOW)
blob = Blob().shift(UP+RIGHT)
label = TextMobject("Area")
label.highlight(YELLOW)
label = VMobject(VectorizedPoint(label.get_left()), label)
label.move_to(blob)
target_label = TexMobject(["c \\cdot", "\\text{Area}"])
target_label.split()[1].highlight(YELLOW)
self.add_transformable_mobject(blob)
self.add_moving_mobject(label, target_label)
self.dither()
self.apply_transposed_matrix([[2, -1], [1, 1]])
arrow = Arrow(scaled, label.target.split()[0])
self.play(ShowCreation(arrow))
self.dither()
class BeautyNowUsesLater(TeacherStudentsScene):
def construct(self):
self.setup()
self.teacher_says("Beauty now, uses later")
self.dither()
class DiagonalExample(LinearTransformationScene):
CONFIG = {
"show_square" : False,
"show_coordinates" : True,
"transposed_matrix" : [[3, 0], [0, 2]]
}
def construct(self):
self.setup()
matrix = Matrix(np.array(self.transposed_matrix).transpose())
matrix.highlight_columns(X_COLOR, Y_COLOR)
matrix.next_to(ORIGIN, LEFT).to_edge(UP)
matrix_background = BackgroundRectangle(matrix)
self.play(ShowCreation(matrix_background), Write(matrix))
if self.show_square:
self.add_unit_square(animate = True)
self.add_foreground_mobject(matrix_background, matrix)
self.dither()
self.apply_transposed_matrix([self.transposed_matrix[0], [0, 1]])
self.apply_transposed_matrix([[1, 0], self.transposed_matrix[1]])
self.dither()
if self.show_square:
bottom_brace = Brace(self.i_hat, DOWN)
right_brace = Brace(self.square, RIGHT)
width = TexMobject(str(self.transposed_matrix[0][0]))
height = TexMobject(str(self.transposed_matrix[1][1]))
width.next_to(bottom_brace, DOWN)
height.next_to(right_brace, RIGHT)
for mob in bottom_brace, width, right_brace, height:
mob.add_background_rectangle()
self.play(Write(mob, run_time = 0.5))
self.dither()
width_target, height_target = width.copy(), height.copy()
det = np.linalg.det(self.transposed_matrix)
times, eq_det = map(TexMobject, ["\\times", "=%d"%det])
words = TextMobject("New area $=$")
equation = VMobject(
words, width_target, times, height_target, eq_det
)
equation.arrange_submobjects(RIGHT, buff = 0.2)
equation.next_to(self.square, UP, aligned_edge = LEFT)
equation.shift(0.5*RIGHT)
background_rect = BackgroundRectangle(equation)
self.play(
ShowCreation(background_rect),
Transform(width.copy(), width_target),
Transform(height.copy(), height_target),
*map(Write, [words, times, eq_det])
)
self.dither()
class DiagonalExampleWithSquare(DiagonalExample):
CONFIG = {
"show_square" : True
}
class ShearExample(DiagonalExample):
CONFIG = {
"show_square" : False,
"show_coordinates" : True,
"transposed_matrix" : [[1, 0], [1, 1]]
}
class ShearExampleWithSquare(DiagonalExample):
CONFIG = {
"show_square" : True,
"show_coordinates" : True,
"show_coordinates" : False,
"transposed_matrix" : [[1, 0], [1, 1]]
}
class ThisSquareTellsEverything(LinearTransformationScene):
def construct(self):
self.setup()
self.add_unit_square()
words = TextMobject("""
This square gives you
everything you need.
""")
words.to_corner(UP+RIGHT)
words.highlight(YELLOW)
words.add_background_rectangle()
arrow = Arrow(
words.get_bottom(), self.square.get_right(),
color = WHITE
)
self.play(Write(words, run_time = 2))
self.play(ShowCreation(arrow))
self.add_foreground_mobject(words, arrow)
self.dither()
self.apply_transposed_matrix([[1.5, -0.5], [1, 1.5]])
self.dither()
class WhatHappensToOneSquareHappensToAll(LinearTransformationScene):
def construct(self):
self.setup()
self.add_unit_square()
pairs = [
(2*RIGHT+UP, 1),
(3*LEFT, 2),
(2*LEFT+DOWN, 0.5),
(3.5*RIGHT+2.5*UP, 1.5),
(RIGHT+2*DOWN, 0.25),
(3*LEFT+3*DOWN, 1),
]
squares = VMobject()
for position, side_length in pairs:
square = self.square.copy()
square.scale(side_length)
square.shift(position)
squares.add(square)
self.play(FadeIn(
squares, submobject_mode = "lagged_start",
run_time = 3
))
self.add_transformable_mobject(squares)
self.apply_transposed_matrix([[1, -1], [0.5, 1]])
self.dither()
class BreakBlobIntoGridSquares(LinearTransformationScene):
CONFIG = {
"square_size" : 0.5,
"blob_height" : 3,
}
def construct(self):
self.setup()
blob = Blob(
height = self.blob_height,
random_seed = 5,
random_nudge_size = 0.2,
)
blob.next_to(ORIGIN, UP+RIGHT)
self.add_transformable_mobject(blob)
arange = np.arange(
0, self.blob_height + self.square_size,
self.square_size
)
square = Square(side_length = self.square_size)
square.set_stroke(YELLOW, width = 2)
square.set_fill(YELLOW, opacity = 0.3)
squares = VMobject()
for x, y in it.product(*[arange]*2):
point = x*RIGHT + y*UP
if blob.probably_contains(point):
squares.add(square.copy().shift(point))
self.play(ShowCreation(
squares, submobject_mode = "lagged_start",
run_time = 2,
))
self.add_transformable_mobject(squares)
self.dither()
self.apply_transposed_matrix([[1, -1], [0.5, 1]])
self.dither()
class BreakBlobIntoGridSquaresGranular(BreakBlobIntoGridSquares):
CONFIG = {
"square_size" : 0.25
}
class BreakBlobIntoGridSquaresVeryGranular(BreakBlobIntoGridSquares):
CONFIG = {
"square_size" : 0.1
}
class NameDeterminant(LinearTransformationScene):
CONFIG = {
2016-08-02 15:50:32 -07:00
"t_matrix" : [[3, 0], [2, 2]]
2016-08-02 12:26:15 -07:00
}
def construct(self):
self.setup()
2016-08-02 15:50:32 -07:00
self.plane.fade(0.3)
self.add_unit_square(color = YELLOW_E, opacity = 0.5)
self.add_title(
["The", "``determinant''", "of a transformation"],
scale_factor = 1
)
2016-08-02 12:26:15 -07:00
self.title.split()[1].split()[1].highlight(YELLOW)
2016-08-02 15:50:32 -07:00
matrix_background, matrix, det_text = self.get_matrix()
self.add_foreground_mobject(matrix_background, matrix)
A = TexMobject("A")
area_label = VMobject(A.copy(), A.copy(), A)
area_label.move_to(self.square)
2016-08-02 12:26:15 -07:00
det = np.linalg.det(self.t_matrix)
2016-08-02 15:50:32 -07:00
if np.round(det) == det:
det = int(det)
area_label_target = VMobject(
TexMobject(str(det)), TexMobject("\\cdot"), A.copy()
)
if det < 1 and det > 0:
area_label_target.scale(det)
area_label_target.arrange_submobjects(RIGHT, buff = 0.1)
self.add_moving_mobject(area_label, area_label_target)
self.dither()
self.apply_transposed_matrix(self.t_matrix)
self.dither()
det_mob_copy = area_label.split()[0].copy()
new_det_mob = det_mob_copy.copy().scale_to_fit_height(
det_text.split()[0].get_height()
)
new_det_mob.next_to(det_text, RIGHT, buff = 0.2)
new_det_mob.add_background_rectangle()
det_mob_copy.add_background_rectangle(opacity = 0)
self.play(Write(det_text))
self.play(Transform(det_mob_copy, new_det_mob))
self.dither()
2016-08-02 12:26:15 -07:00
2016-08-02 15:50:32 -07:00
def get_matrix(self):
matrix = Matrix(np.array(self.t_matrix).transpose())
matrix.highlight_columns(X_COLOR, Y_COLOR)
matrix.next_to(self.title, DOWN, buff = 0.5)
matrix.shift(2*LEFT)
matrix_background = BackgroundRectangle(matrix)
2016-08-02 12:26:15 -07:00
2016-08-02 15:50:32 -07:00
braces = TexMobject("()")
braces.scale(2)
braces.stretch_to_fit_height(matrix.get_height())
l_brace, r_brace = braces.split()
l_brace.next_to(matrix, LEFT, buff = 0.1)
r_brace.next_to(matrix, RIGHT, buff = 0.1)
det = TextMobject("det").next_to(l_brace, LEFT, buff = 0.1)
det.add_background_rectangle()
eq = TexMobject("=").next_to(r_brace, RIGHT, buff = 0.1)
2016-08-02 12:26:15 -07:00
2016-08-02 15:50:32 -07:00
det_text = VMobject(det, l_brace, r_brace, eq)
return matrix_background, matrix, det_text
2016-08-02 12:26:15 -07:00
2016-08-02 15:50:32 -07:00
class DeterminantIsOneHalf(NameDeterminant):
CONFIG = {
"t_matrix" : [[0.5, -0.5], [0.5, 0.5]],
"foreground_plane_kwargs" : {
"x_radius" : 2*SPACE_WIDTH,
"y_radius" : 2*SPACE_WIDTH,
"secondary_line_ratio" : 0
},
}
2016-08-02 12:26:15 -07:00
2016-08-02 15:50:32 -07:00
class DeterminantIsZero(NameDeterminant):
CONFIG = {
"t_matrix" : [[2, 1], [2, 1]],
}
2016-08-02 12:26:15 -07:00