Starting chapter 4

This commit is contained in:
Grant Sanderson
2016-07-27 13:10:45 -07:00
parent 983f895f11
commit ef8461bc73
7 changed files with 475 additions and 31 deletions

View File

@ -137,9 +137,9 @@ COLOR_MAP = {
"GREEN_SCREEN": "#00FF00",
}
PALETTE = COLOR_MAP.values()
globals().update(COLOR_MAP)
locals().update(COLOR_MAP)
for name in filter(lambda s : s.endswith("_C"), COLOR_MAP.keys()):
globals()[name.replace("_C", "")] = globals()[name]
locals()[name.replace("_C", "")] = locals()[name]

View File

@ -35,7 +35,7 @@ class OpeningQuote(Scene):
words.scale_to_fit_width(2*SPACE_WIDTH - 2)
words.to_edge(UP)
words.split()[1].highlight(GREEN)
words.split()[3].highlight(GREEN)
words.split()[3].highlight(BLUE)
author = TextMobject("-Morpheus")
author.highlight(YELLOW)
author.next_to(words, DOWN, buff = 0.5)
@ -43,7 +43,6 @@ class OpeningQuote(Scene):
(Surprisingly apt words on the importance
of understanding matrix operations visually.)
""")
comment.scale(0.7)
comment.next_to(author, DOWN, buff = 1)
self.play(FadeIn(words))
@ -173,9 +172,25 @@ class WhyConfuseWithTerminology(TeacherStudentsScene):
def construct(self):
self.setup()
self.student_says("Why confuse us with \\\\ redundant terminology?")
other_students = [self.get_students()[i] for i in 0, 2]
self.play(*[
ApplyMethod(self.get_students()[i].change_mode, "confused")
for i in 0, 2
ApplyMethod(student.change_mode, "confused")
for student in other_students
])
self.random_blink()
self.dither()
statement = TextMobject([
"The word",
"``transformation''",
"suggests \\\\ that you think using",
"movement",
])
statement.split()[1].highlight(BLUE)
statement.split()[-1].highlight(YELLOW)
self.teacher_says(statement, width = 10)
self.play(*[
ApplyMethod(student.change_mode, "happy")
for student in other_students
])
self.random_blink()
self.dither()
@ -242,7 +257,7 @@ class TransformJustOneVector(VectorScene):
)
self.dither()
class TransformManyVectors(VectorScene):
class TransformManyVectors(LinearTransformationScene):
CONFIG = {
"transposed_matrix" : [[2, 1], [1, 2]],
"use_dots" : False,
@ -546,10 +561,11 @@ class YetAnotherLinearTransformation(SimpleLinearTransformationScene):
words.add_background_rectangle()
words.to_edge(UP)
words.highlight(GREEN)
formula = TexMobject(
matrix_to_tex_string(["x", "y"]) + "\\rightarrow" + \
matrix_to_tex_string(["-1x+3y", "1x + 2y"])
)
formula = TexMobject([
matrix_to_tex_string(["x_\\text{in}", "y_\\text{in}"]),
"\\rightarrow ???? \\rightarrow",
matrix_to_tex_string(["x_\\text{out}", "y_{\\text{out}}"])
])
formula.add_background_rectangle()
self.play(Write(words))
@ -569,9 +585,17 @@ class FollowIHatJHat(LinearTransformationScene):
def construct(self):
self.setup()
i_hat = self.add_vector([1, 0], color = X_COLOR)
i_label = self.label_vector(i_hat, "\\hat{\\imath}")
i_label = self.label_vector(
i_hat, "\\hat{\\imath}",
color = X_COLOR,
label_scale_val = 1
)
j_hat = self.add_vector([0, 1], color = Y_COLOR)
j_label = self.label_vector(j_hat, "\\hat{\\jmath}")
j_label = self.label_vector(
j_hat, "\\hat{\\jmath}",
color = Y_COLOR,
label_scale_val = 1
)
self.dither()
self.play(*map(FadeOut, [i_label, j_label]))
@ -742,17 +766,91 @@ class TrackBasisVectorsExample(LinearTransformationScene):
self.play(Write(result))
self.dither()
class TrackBasisVectorsExampleGenerally(TrackBasisVectorsExample):
CONFIG = {
"v_coord_strings" : ["x", "y"],
"result_coords_string" : """
=
\\left[ \\begin{array}{c}
1x + 3y \\\\
-2x + 0y
\\end{arary}\\right]
"""
}
class WatchManyVectorsMove(TransformManyVectors):
def construct(self):
self.setup()
vectors = VMobject(*[
Vector([x, y])
for x in np.arange(-int(SPACE_WIDTH)+0.5, int(SPACE_WIDTH)+0.5)
for y in np.arange(-int(SPACE_HEIGHT)+0.5, int(SPACE_HEIGHT)+0.5)
])
vectors.submobject_gradient_highlight(PINK, YELLOW)
dots = self.vectors_to_dots(vectors)
self.play(ShowCreation(dots, submobject_mode = "lagged_start"))
self.play(Transform(
dots, vectors,
submobject_mode = "lagged_start",
run_time = 2
))
self.remove(dots)
for v in vectors.split():
self.add_vector(v, animate = False)
self.apply_transposed_matrix([[1, -2], [3, 0]])
self.dither()
self.play(
ApplyMethod(self.plane.fade),
FadeOut(vectors),
Animation(self.i_hat),
Animation(self.j_hat),
)
self.dither()
class NowWithoutWatching(Scene):
def construct(self):
text = TextMobject("Now without watching...")
text.to_edge(UP)
randy = Randolph(mode = "pondering")
self.add(randy)
self.play(Write(text, run_time = 1))
self.play(ApplyMethod(randy.blink))
self.dither(2)
class DeduceResultWithGeneralCoordinates(Scene):
def construct(self):
i_hat_to = TexMobject("\\hat{\\imath} \\rightarrow")
j_hat_to = TexMobject("\\hat{\\jmath} \\rightarrow")
i_coords = Matrix([1, -2])
j_coords = Matrix([3, 0])
i_coords.next_to(i_hat_to, RIGHT, buff = 0.1)
j_coords.next_to(j_hat_to, RIGHT, buff = 0.1)
i_group = VMobject(i_hat_to, i_coords)
j_group = VMobject(j_hat_to, j_coords)
i_group.highlight(X_COLOR)
j_group.highlight(Y_COLOR)
i_group.next_to(ORIGIN, LEFT, buff = 1).to_edge(UP)
j_group.next_to(ORIGIN, RIGHT, buff = 1).to_edge(UP)
vect = Matrix(["x", "y"])
x, y = vect.get_mob_matrix().flatten()
VMobject(x, y).highlight(YELLOW)
rto = TexMobject("\\rightarrow")
equals = TexMobject("=")
plus = TexMobject("+")
row1 = TexMobject("1x + 3y")
row2 = TexMobject("-2x + 0y")
VMobject(
row1.split()[0], row2.split()[0], row2.split()[1]
).highlight(X_COLOR)
VMobject(
row1.split()[1], row1.split()[4], row2.split()[2], row2.split()[5]
).highlight(YELLOW)
VMobject(
row1.split()[3], row2.split()[4]
).highlight(Y_COLOR)
result = Matrix([row1, row2])
result.show()
vect_group = VMobject(
vect, rto,
x.copy(), i_coords.copy(), plus,
y.copy(), j_coords.copy(), equals,
result
)
vect_group.arrange_submobjects(RIGHT, buff = 0.1)
self.add(i_group, j_group)
for mob in vect_group.split():
self.play(Write(mob))
self.dither()
class MatrixVectorMultiplication(LinearTransformationScene):
CONFIG = {
@ -774,8 +872,8 @@ class MatrixVectorMultiplication(LinearTransformationScene):
if self.abstract:
new_i_coords = Matrix(["a", "c"])
new_j_coords = Matrix(["b", "d"])
new_i_coords.scale(0.7).move_to(i_coords)
new_j_coords.scale(0.7).move_to(j_coords)
new_i_coords.move_to(i_coords)
new_j_coords.move_to(j_coords)
i_coords = new_i_coords
j_coords = new_j_coords
i_coords.highlight(X_COLOR)
@ -796,6 +894,9 @@ class MatrixVectorMultiplication(LinearTransformationScene):
add_background_rectangles = True
)
concrete_matrix.to_edge(UP)
if self.abstract:
m = concrete_matrix.get_mob_matrix()[1, 0]
m.shift(m.get_height()*DOWN/2)
matrix_brackets = concrete_matrix.get_brackets()
self.play(ShowCreation(i_coords.rect), Write(i_coords))
@ -916,7 +1017,6 @@ class MatrixVectorMultiplication(LinearTransformationScene):
row2 = VMobject(*map(TexMobject, row2))
for row in row1, row2:
row.arrange_submobjects(RIGHT, buff = 0.1)
row.scale(0.7)
final_sum = Matrix([row1, row2])
row1, row2 = final_sum.get_mob_matrix().flatten()
row1.split()[0].highlight(X_COLOR)
@ -933,6 +1033,7 @@ class MatrixVectorMultiplication(LinearTransformationScene):
)
self.dither()
def reposition_matrix_and_vector(self, matrix, vector, formula):
start_state = VMobject(matrix, vector)
end_state = start_state.copy()
@ -940,6 +1041,10 @@ class MatrixVectorMultiplication(LinearTransformationScene):
equals = TexMobject("=")
equals.next_to(formula, LEFT)
end_state.next_to(equals, LEFT)
brace = Brace(formula, DOWN)
brace_words = TextMobject("Where all the intuition is")
brace_words.next_to(brace, DOWN)
brace_words.highlight(YELLOW)
self.play(
Transform(
@ -949,6 +1054,12 @@ class MatrixVectorMultiplication(LinearTransformationScene):
Write(equals, run_time = 1)
)
self.dither()
self.play(
FadeIn(brace),
FadeIn(brace_words),
submobject_mode = "lagged_start"
)
self.dither()
class MatrixVectorMultiplicationAbstract(MatrixVectorMultiplication):
CONFIG = {
@ -1128,6 +1239,11 @@ class DescribeShear(Describe90DegreeRotation):
"title" : "``Shear''",
}
class OtherWayAround(Scene):
def construct(self):
self.play(Write("What about the other way around?"))
self.dither(2)
class DeduceTransformationFromMatrix(ColumnsToBasisVectors):
def construct(self):
self.setup()
@ -1159,7 +1275,6 @@ class NextVideo(Scene):
self.play(ShowCreation(rect))
self.dither()
class FinalSlide(Scene):
def construct(self):
text = TextMobject("""

311
eola/chapter4.py Normal file
View File

@ -0,0 +1,311 @@
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 OpeningQuote(Scene):
def construct(self):
words = TextMobject([
"It is my experience that proofs involving",
"matrices",
"can be shortened by 50\\% if one",
"throws the matrices out."
])
words.scale_to_fit_width(2*SPACE_WIDTH - 2)
words.to_edge(UP)
words.split()[1].highlight(GREEN)
words.split()[3].highlight(BLUE)
author = TextMobject("-Emil Artin")
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 MatrixToBlank(Scene):
def construct(self):
matrix = Matrix([[3, 1], [0, 2]])
arrow = Arrow(LEFT, RIGHT)
matrix.to_edge(LEFT)
arrow.next_to(matrix, LEFT)
matrix.add(arrow)
self.play(Write(matrix))
self.dither()
class RecapTime(TeacherStudentsScene):
def construct(self):
self.setup()
self.teacher_says("Quick recap time!")
self.random_blink()
self.dither()
student = self.get_students()[0]
everyone = self.get_mobjects()
everyone.remove(student)
everyone = VMobject(*everyone)
self.play(
ApplyMethod(everyone.fade, 0.7),
ApplyMethod(student.change_mode, "confused")
)
self.play(Blink(student))
self.dither()
self.play(ApplyFunction(
lambda m : m.change_mode("pondering").look(LEFT),
student
))
self.play(Blink(student))
self.dither()
class DeterminedByTwoBasisVectors(LinearTransformationScene):
CONFIG = {
"show_basis_vectors" : False
}
def construct(self):
self.setup()
i_hat = self.add_vector([1, 0], color = X_COLOR)
self.add_transformable_label(
i_hat, "\\hat{\\imath}", "\\hat{\\imath}",
color = X_COLOR
)
j_hat = self.add_vector([0, 1], color = Y_COLOR)
self.add_transformable_label(
j_hat, "\\hat{\\jmath}", "\\hat{\\jmath}",
color = Y_COLOR
)
t_matrix = np.array([[2, 2], [-2, 1]])
matrix = t_matrix.transpose()
matrix1 = np.array(matrix)
matrix1[:,1] = [0, 1]
matrix2 = np.dot(matrix, np.linalg.inv(matrix1))
self.dither()
self.apply_transposed_matrix(matrix1.transpose())
self.apply_transposed_matrix(matrix2.transpose())
self.dither()
class FollowLinearCombination(LinearTransformationScene):
def construct(self):
vect_coords = [-1, 2]
t_matrix = np.array([[2, 2], [-2, 1]])
#Draw vectors
self.setup()
i_label = self.add_transformable_label(
self.i_hat, "\\hat{\\imath}", animate = False,
direction = "right", color = X_COLOR
)
j_label = self.add_transformable_label(
self.j_hat, "\\hat{\\jmath}", animate = False,
direction = "right", color = Y_COLOR
)
vect = self.add_vector(vect_coords)
vect_array = Matrix(["x", "y"], add_background_rectangles = True)
v_equals = TexMobject(["\\vec{\\textbf{v}}", "="])
v_equals.split()[0].highlight(YELLOW)
v_equals.next_to(vect_array, LEFT)
vect_array.add(v_equals)
vect_array.to_edge(UP, buff = 0.2)
background_rect = BackgroundRectangle(vect_array)
vect_array.get_entries().highlight(YELLOW)
self.play(ShowCreation(background_rect), Write(vect_array))
self.add_foreground_mobject(background_rect, vect_array)
#Show scaled vectors
x, y = vect_array.get_entries().split()
scaled_i_label = VMobject(x.copy(), i_label)
scaled_j_label = VMobject(y.copy(), j_label)
scaled_i = self.i_hat.copy().scale(vect_coords[0])
scaled_j = self.j_hat.copy().scale(vect_coords[1])
for mob in scaled_i, scaled_j:
mob.fade(0.3)
scaled_i_label_target = scaled_i_label.copy()
scaled_i_label_target.arrange_submobjects(buff = 0.1)
scaled_i_label_target.next_to(scaled_i, DOWN)
scaled_j_label_target = scaled_j_label.copy()
scaled_j_label_target.arrange_submobjects(buff = 0.1)
scaled_j_label_target.next_to(scaled_j, LEFT)
self.show_scaled_vectors(vect_array, vect_coords, i_label, j_label)
self.apply_transposed_matrix(t_matrix)
self.show_scaled_vectors(vect_array, vect_coords, i_label, j_label)
self.record_basis_coordinates(vect_array, vect)
def show_scaled_vectors(self, vect_array, vect_coords, i_label, j_label):
x, y = vect_array.get_entries().split()
scaled_i_label = VMobject(x.copy(), i_label.copy())
scaled_j_label = VMobject(y.copy(), j_label.copy())
scaled_i = self.i_hat.copy().scale(vect_coords[0])
scaled_j = self.j_hat.copy().scale(vect_coords[1])
for mob in scaled_i, scaled_j:
mob.fade(0.3)
scaled_i_label_target = scaled_i_label.copy()
scaled_i_label_target.arrange_submobjects(buff = 0.1)
scaled_i_label_target.next_to(scaled_i.get_center(), DOWN)
scaled_j_label_target = scaled_j_label.copy()
scaled_j_label_target.arrange_submobjects(buff = 0.1)
scaled_j_label_target.next_to(scaled_j.get_center(), LEFT)
self.play(
Transform(self.i_hat.copy(), scaled_i),
Transform(scaled_i_label, scaled_i_label_target)
)
scaled_i = self.get_mobjects_from_last_animation()[0]
self.play(
Transform(self.j_hat.copy(), scaled_j),
Transform(scaled_j_label, scaled_j_label_target)
)
scaled_j = self.get_mobjects_from_last_animation()[0]
self.play(*[
ApplyMethod(mob.shift, scaled_i.get_end())
for mob in scaled_j, scaled_j_label
])
self.dither()
self.play(*map(FadeOut, [
scaled_i, scaled_j, scaled_i_label, scaled_j_label,
]))
def record_basis_coordinates(self, vect_array, vect):
i_label = vector_coordinate_label(self.i_hat)
i_label.highlight(X_COLOR)
j_label = vector_coordinate_label(self.j_hat)
j_label.highlight(Y_COLOR)
for mob in i_label, j_label:
mob.scale_in_place(0.8)
background = BackgroundRectangle(mob)
self.play(ShowCreation(background), Write(mob))
self.dither()
x, y = vect_array.get_entries().split()
pre_formula = VMobject(
x, i_label, TexMobject("+"),
y, j_label
)
post_formula = pre_formula.copy()
pre_formula.split()[2].fade(1)
post_formula.arrange_submobjects(buff = 0.1)
post_formula.next_to(vect, DOWN)
background = BackgroundRectangle(post_formula)
everything = self.get_mobjects()
everything.remove(vect)
self.play(*[
ApplyMethod(m.fade) for m in everything
] + [
ShowCreation(background, run_time = 2, rate_func = squish_rate_func(smooth, 0.5, 1)),
Transform(pre_formula.copy(), post_formula, run_time = 2),
ApplyMethod(vect.set_stroke, width = 7)
])
self.dither()
class MatrixVectorMultiplicationCopy(MatrixVectorMultiplicationAbstract):
pass ## Here just for stage_animations.py purposes
class RecapOver(TeacherStudentsScene):
def construct(self):
self.setup()
self.teacher_says("Recap over!")
class TwoSuccessiveTransformations(LinearTransformationScene):
def construct(self):
self.setup()
self.apply_transposed_matrix([[2, 1],[1, 2]])
self.apply_transposed_matrix([[-1, -0.5],[0, -0.5]])
self.dither()
class RotationThenShear(LinearTransformationScene):
CONFIG = {
"foreground_plane_kwargs" : {
"x_radius" : SPACE_WIDTH,
"y_radius" : 2*SPACE_WIDTH,
"secondary_line_ratio" : 0
},
}
def construct(self):
self.setup()
rot_words = TextMobject("$90^\\circ$ rotation counterclockwise")
shear_words = TextMobject("followed by a shear")
rot_words.highlight(YELLOW)
shear_words.highlight(PINK)
VMobject(rot_words, shear_words).arrange_submobjects(DOWN).to_edge(UP)
for words in rot_words, shear_words:
words.add_background_rectangle()
self.play(Write(rot_words, run_time = 1))
self.add_foreground_mobject(rot_words)
self.apply_transposed_matrix([[0, 1], [-1, 0]])
self.play(Write(shear_words, run_time = 1))
self.add_foreground_mobject(shear_words)
self.apply_transposed_matrix([[1, 0], [1, 1]])
self.dither()
class IntroduceIdeaOfComposition(RotationThenShear):
def construct(self):
self.setup()
self.show_composition()
self.track_basis_vectors()
def show_composition(self):
words = TextMobject([
"``Composition''",
"of a",
"rotation",
"and a",
"shear"
])
words.split()[0].submobject_gradient_highlight(YELLOW, PINK, use_color_range_to = False)
words.split()[2].highlight(YELLOW)
words.split()[4].highlight(PINK)
words.add_background_rectangle()
words.to_edge(UP)
self.apply_transposed_matrix([[0, 1], [-1, 0]], run_time = 2)
self.apply_transposed_matrix([[1, 0], [1, 1]], run_time = 2)
self.play(Write(words))
self.dither()
def track_basis_vectors(self):
pass

View File

@ -12,7 +12,7 @@ from topics.geometry import Vector, Line, Circle, Arrow, Dot
from helpers import *
VECTOR_LABEL_SCALE_VAL = 0.7
VECTOR_LABEL_SCALE_VAL = 1.0
def matrix_to_tex_string(matrix):
matrix = np.array(matrix).astype("string")
@ -107,6 +107,9 @@ class Matrix(VMobject):
def get_mob_matrix(self):
return self.mob_matrix
def get_entries(self):
return VMobject(*self.get_mob_matrix().flatten())
def get_brackets(self):
return self.brackets

View File

@ -311,6 +311,8 @@ class LinearTransformationScene(VectorScene):
label_mob.target_text = "L(%s)"%label_mob.expression
label_mob.vector = vector
label_mob.kwargs = kwargs
if "animate" in label_mob.kwargs:
label_mob.kwargs.pop("animate")
self.transformable_labels.append(label_mob)
return label_mob

View File

@ -297,9 +297,16 @@ class Mobject(object):
def gradient_highlight(self, start_color, end_color):
raise Exception("Not implemented")
def submobject_gradient_highlight(self, start_color, end_color):
def submobject_gradient_highlight(self, start_color, end_color, use_color_range_to = False):
mobs = self.family_members_with_points()
if use_color_range_to:
colors = Color(start_color).range_to(end_color, len(mobs))
else:
rgb1, rgb2 = map(color_to_rgb, [start_color, end_color])
colors = [
Color(rgb = interpolate(rgb1, rgb2, alpha))
for alpha in np.linspace(0, 1, len(mobs))
]
for mob, color in zip(mobs, colors):
mob.highlight(color, family = False)
return self

View File

@ -286,6 +286,12 @@ class BackgroundRectangle(Rectangle):
self.lock_style = True
return self
def fade_to(self, *args, **kwargs):
self.lock_style = False
Rectangle.fade_to(self, *args, **kwargs)
self.lock_style = True
return self
def set_style_data(self, *args, **kwargs):
if self.lock_style:
return self #Do nothing