Halfway through chapter 6

This commit is contained in:
Grant Sanderson 2016-08-09 14:07:23 -07:00
parent f52179c3d9
commit e5747b3f3b
9 changed files with 1061 additions and 46 deletions

View file

@ -441,6 +441,22 @@ class IntroduceLinearTransformations(LinearTransformationScene):
)
self.dither()
class ToThePedants(Scene):
def construct(self):
words = TextMobject([
"To the pedants:\\\\",
"""
Yeah yeah, I know that's not the formal definition
for linear transformations, as seen in textbooks,
but I'm building visual intuition here, and what
I've said is equivalent to the formal definition
(which I'll get to later in the series).
"""])
words.split()[0].highlight(RED)
words.to_edge(UP)
self.add(words)
self.dither()
class SimpleLinearTransformationScene(LinearTransformationScene):
CONFIG = {
"show_basis_vectors" : False,
@ -1138,13 +1154,13 @@ class ColumnsToBasisVectors(LinearTransformationScene):
self.apply_transposed_matrix(
transform_matrix1.transpose(),
added_anims = [Transform(i_coords_start, i_coords_end)],
path_arc = np.pi/2
path_arc = np.pi/2,
)
self.add_foreground_mobject(i_coords_start)
self.apply_transposed_matrix(
transform_matrix2.transpose(),
added_anims = [Transform(j_coords_start, j_coords_end) ],
path_arc = np.pi/2
path_arc = np.pi/2,
)
self.add_foreground_mobject(j_coords_start)
self.dither()

View file

@ -687,7 +687,7 @@ class GeneralMultiplication(MoreComplicatedExampleNumerically):
for entry, char in zip(m1_entries.split(), "efgh")
])
words = TextMobject("This method works genearlly")
words = TextMobject("This method works generally")
self.play(Write(words, run_time = 2))
self.play(Transform(
m1_entries, m1_entries_target,

View file

@ -348,6 +348,11 @@ class BreakBlobIntoGridSquaresGranular(BreakBlobIntoGridSquares):
"square_size" : 0.25
}
class BreakBlobIntoGridSquaresMoreGranular(BreakBlobIntoGridSquares):
CONFIG = {
"square_size" : 0.15
}
class BreakBlobIntoGridSquaresVeryGranular(BreakBlobIntoGridSquares):
CONFIG = {
"square_size" : 0.1
@ -409,6 +414,11 @@ class NameDeterminant(LinearTransformationScene):
det_text.remove(det_text.split()[-1])
return matrix_background, matrix, det_text
class SecondDeterminantExample(NameDeterminant):
CONFIG = {
"t_matrix" : [[-1, -1], [1, -1]]
}
class DeterminantIsThree(NameDeterminant):
CONFIG = {
"t_matrix" : [[0, -1.5], [2, 1]]
@ -429,6 +439,12 @@ class DeterminantIsZero(NameDeterminant):
"t_matrix" : [[4, 2], [2, 1]],
}
class SecondDeterminantIsZeroExamlpe(NameDeterminant):
CONFIG = {
"t_matrix" : [[0, 0], [0, 0]],
"show_basis_vectors" : False
}
class NextFewVideos(Scene):
def construct(self):
icon = SVGMobject("video_icon")
@ -447,6 +463,16 @@ class NextFewVideos(Scene):
)
self.dither()
class UnderstandingBeforeApplication(TeacherStudentsScene):
def construct(self):
self.setup()
self.teacher_says("""
Just the visual
understanding for now
""")
self.random_blink()
self.dither()
class WhatIveSaidSoFar(TeacherStudentsScene):
def construct(self):
self.setup()
@ -807,6 +833,10 @@ class RightHandRule(Scene):
i_hat = Vector([-1.75, 0.5])
j_hat = Vector([-1.4, -0.7])
k_hat = Vector([0, 1.7])
vects = [i_hat, j_hat, k_hat]
if self.flip:
VMobject(hand, *vects).flip()
i_label, j_label, k_label = [
TexMobject("\\hat{%s}"%s).scale(1.5)
for s in "\\imath", "\\jmath", "k"
@ -815,12 +845,9 @@ class RightHandRule(Scene):
j_label.next_to(j_hat.get_end(), DOWN)
k_label.next_to(k_hat.get_end(), UP)
vects = [i_hat, j_hat, k_hat]
labels = [i_label, j_label, k_label]
colors = [X_COLOR, Y_COLOR, Z_COLOR]
if self.flip:
VMobject(hand, *vects+labels).flip()
# self.add(NumberPlane())
self.play(
@ -841,6 +868,16 @@ class LeftHandRule(RightHandRule):
"flip" : True
}
class AskHowToCompute(TeacherStudentsScene):
def construct(self):
self.setup()
student = self.get_students()[1]
self.student_says("How do you \\\\ compute this?")
self.play(student.change_mode, "confused")
self.random_blink()
self.dither()
self.random_blink()
class TwoDDeterminantFormula(Scene):
def construct(self):
eq = TextMobject("=")
@ -853,7 +890,7 @@ class TwoDDeterminantFormula(Scene):
VMobject(matrix, det_text).next_to(eq, LEFT)
formula = TexMobject(list("ad-bc"))
formula.next_to(eq, RIGHT)
formula.shift(0.2*UP)
formula.shift(0.1*UP)
a, d, minus, b, c = formula.split()
VMobject(a, c).highlight(X_COLOR)
@ -878,7 +915,7 @@ class TwoDDeterminantFormula(Scene):
for m in mb, mc, b, c
])
self.dither()
for pair in (mc, c), (mb, b):
for pair in (mb, b), (mc, c):
self.play(*[
Transform(m, m.original)
for m in pair
@ -957,9 +994,9 @@ class FullFormulaExplanation(LinearTransformationScene):
d = self.j_hat.get_end()[1]*UP
shapes_colors_and_tex = [
(Polygon(ORIGIN, a, a+c), TEAL, "bd/2"),
(Polygon(ORIGIN, d+b, d), TEAL, "\\dfrac{bd}{2}"),
(Polygon(a+c, a+b+c, a+b+c+d), MAROON, "\\dfrac{ac}{2}"),
(Polygon(ORIGIN, a, a+c), MAROON, "ac/2"),
(Polygon(ORIGIN, d+b, d, d), TEAL, "\\dfrac{bd}{2}"),
(Polygon(a+c, a+b+c, a+b+c, a+b+c+d), TEAL, "\\dfrac{bd}{2}"),
(Polygon(b+d, a+b+c+d, b+c+d), MAROON, "ac/2"),
(Polygon(a, a+b, a+b+c, a+c), PINK, "bc"),
(Polygon(d, d+b, d+b+c, d+c), PINK, "bc"),
@ -991,8 +1028,8 @@ class FullFormulaExplanation(LinearTransformationScene):
(a, a+b, DOWN, "b"),
(a+b, a+b+c, RIGHT, "c"),
(a+b+c, a+b+c+d, RIGHT, "d"),
(a+b+c+d, a+c+d, UP, "a"),
(a+c+d, d+c, UP, "b"),
(a+b+c+d, b+c+d, UP, "a"),
(b+c+d, d+c, UP, "b"),
(d+c, d, LEFT, "c"),
(d, ORIGIN, LEFT, "d"),
]

814
eola/chapter6.py Normal file
View file

@ -0,0 +1,814 @@
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 ka_playgrounds.circuits import Resistor, Source, LongResistor
class OpeningQuote(Scene):
def construct(self):
words = TextMobject([
"The question you raise, ",
"``how can such a formulation lead to computations?''",
"doesn't bother me in the least! Throughout my whole life "
"as a mathematician, the possibility of making explicit, "
"elegant computations has always come out by itself, as a "
"byproduct of a ",
"thorough conceptual understanding."
], 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(["-Grothendieck", "(a hero of mine)"])
author.split()[0].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 ListTerms(Scene):
def construct(self):
title = TextMobject("Under the light of linear transformations")
title.highlight(YELLOW)
title.to_edge(UP)
randy = Randolph().to_corner()
words = VMobject(*map(TextMobject, [
"Inverse matrices",
"Column space",
"Rank",
"Null space",
]))
words.arrange_submobjects(DOWN, aligned_edge = LEFT)
words.next_to(title, DOWN, aligned_edge = LEFT)
words.shift(RIGHT)
self.add(title, randy)
for i, word in enumerate(words.split()):
self.play(Write(word), run_time = 1)
if i%2 == 0:
self.play(Blink(randy))
else:
self.dither()
self.dither()
class NoComputations(TeacherStudentsScene):
def construct(self):
self.setup()
self.student_says(
"Will you cover \\\\ computations?",
pi_creature_target_mode = "raise_left_hand"
)
self.random_blink()
self.teacher_says(
"Well...uh...no",
pi_creature_target_mode = "guilty",
)
self.play(*[
ApplyMethod(student.change_mode, mode)
for student, mode in zip(
self.get_students(),
["dejected", "confused", "angry"]
)
])
self.random_blink()
self.dither()
new_words = self.teacher.bubble.position_mobject_inside(
TextMobject([
"Search",
"``Gaussian elimination'' \\\\",
"and",
"``Row echelon form''",
])
)
new_words.split()[1].highlight(YELLOW)
new_words.split()[3].highlight(GREEN)
self.play(
Transform(self.teacher.bubble.content, new_words),
self.teacher.change_mode, "speaking"
)
self.play(*[
ApplyMethod(student.change_mode, "pondering")
for student in self.get_students()
])
self.random_blink()
class UsefulnessOfMatrices(Scene):
def construct(self):
title = TextMobject("Usefulness of matrices")
title.highlight(YELLOW)
title.to_edge(UP)
self.add(title)
self.dither(3) #Play some 3d linear transform over this
equations = TexMobject("""
6x - 3y + 2z &= 7 \\\\
x + 2y + 5z &= 0 \\\\
2x - 8y - z &= -2 \\\\
""")
equations.to_edge(RIGHT, buff = 2)
syms = VMobject(*np.array(equations.split())[[1, 4, 7]])
new_syms = VMobject(*[
m.copy().highlight(c)
for m, c in zip(syms.split(), [X_COLOR, Y_COLOR, Z_COLOR])
])
new_syms.arrange_submobjects(RIGHT, buff = 0.5)
new_syms.next_to(equations, LEFT, buff = 3)
sym_brace = Brace(new_syms, DOWN)
unknowns = sym_brace.get_text("Unknown variables")
eq_brace = Brace(equations, DOWN)
eq_words = eq_brace.get_text("Equations")
self.play(Write(equations))
self.dither()
self.play(Transform(syms.copy(), new_syms, path_arc = np.pi/2))
for brace, words in (sym_brace, unknowns), (eq_brace, eq_words):
self.play(
GrowFromCenter(brace),
Write(words)
)
self.dither()
class CircuitDiagram(Scene):
def construct(self):
self.add(TextMobject("Voltages").to_edge(UP))
source = Source()
p1, p2 = source.get_top(), source.get_bottom()
r1 = Resistor(p1, p1+2*RIGHT)
r2 = LongResistor(p1+2*RIGHT, p2+2*RIGHT)
r3 = Resistor(p1+2*RIGHT, p1+2*2*RIGHT)
l1 = Line(p1+2*2*RIGHT, p2+2*2*RIGHT)
l2 = Line(p2+2*2*RIGHT, p2)
circuit = VMobject(source, r1, r2, r3, l1, l2)
circuit.center()
v1 = TexMobject("v_1").next_to(r1, UP)
v2 = TexMobject("v_2").next_to(r2, RIGHT)
v3 = TexMobject("v_3").next_to(r3, UP)
unknowns = VMobject(v1, v2, v3)
unknowns.highlight(BLUE)
self.play(ShowCreation(circuit))
self.dither()
self.play(Write(unknowns))
self.dither()
class StockLine(VMobject):
CONFIG = {
"num_points" : 15,
"step_range" : 2
}
def generate_points(self):
points = [ORIGIN]
for x in range(self.num_points):
step_size = self.step_range*(random.random() - 0.5)
points.append(points[-1] + 0.5*RIGHT + step_size*UP)
self.set_anchor_points(points, mode = "corners")
class StockPrices(Scene):
def construct(self):
self.add(TextMobject("Stock prices").to_edge(UP))
x_axis = Line(ORIGIN, SPACE_WIDTH*RIGHT)
y_axis = Line(ORIGIN, SPACE_HEIGHT*UP)
everyone = VMobject(x_axis, y_axis)
stock_lines = []
for color in TEAL, PINK, YELLOW, RED, BLUE:
sl = StockLine(color = color)
sl.move_to(y_axis.get_center(), side_to_align = LEFT)
everyone.add(sl)
stock_lines.append(sl)
everyone.center()
self.add(x_axis, y_axis)
self.play(ShowCreation(
VMobject(*stock_lines),
run_time = 3,
submobject_mode = "lagged_start"
))
self.dither()
class MachineLearningNetwork(Scene):
def construct(self):
self.add(TextMobject("Machine learning parameters").to_edge(UP))
layers = []
for i, num_nodes in enumerate([3, 4, 4, 1]):
layer = VMobject(*[
Circle(radius = 0.5, color = YELLOW)
for x in range(num_nodes)
])
for j, mob in enumerate(layer.split()):
sym = TexMobject("x_{%d, %d}"%(i, j))
sym.move_to(mob)
mob.add(sym)
layer.arrange_submobjects(DOWN, buff = 0.5)
layer.center()
layers.append(layer)
VMobject(*layers).arrange_submobjects(RIGHT, buff = 1.5)
lines = VMobject()
for l_layer, r_layer in zip(layers, layers[1:]):
for l_node, r_node in it.product(l_layer.split(), r_layer.split()):
lines.add(Line(l_node, r_node))
lines.submobject_gradient_highlight(BLUE_E, BLUE_A)
for mob in VMobject(*layers), lines:
self.play(Write(mob), run_time = 2)
self.dither()
class SystemOfEquations(Scene):
def construct(self):
equations = self.get_equations()
self.show_linearity_rules(equations)
self.describe_organization(equations)
self.factor_into_matrix(equations)
def get_equations(self):
matrix = Matrix([
[2, 5, 3],
[4, 0, 8],
[1, 3, 0]
])
mob_matrix = matrix.get_mob_matrix()
rhs = map(TexMobject, map(str, [-3, 0, 2]))
variables = map(TexMobject, list("xyz"))
for v, color in zip(variables, [X_COLOR, Y_COLOR, Z_COLOR]):
v.highlight(color)
equations = VMobject()
for row in mob_matrix:
equation = VMobject(*it.chain(*zip(
row,
[v.copy() for v in variables],
map(TexMobject, list("++="))
)))
equation.arrange_submobjects(
RIGHT, buff = 0.1,
aligned_edge = DOWN
)
equation.split()[4].shift(0.1*DOWN)
equation.split()[-1].next_to(equation.split()[-2], RIGHT)
equations.add(equation)
equations.arrange_submobjects(DOWN, aligned_edge = RIGHT)
for eq, rhs_elem in zip(equations.split(), rhs):
rhs_elem.next_to(eq, RIGHT)
eq.add(rhs_elem)
equations.center()
self.play(Write(equations))
self.add(equations)
return equations
def show_linearity_rules(self, equations):
top_equation = equations.split()[0]
other_equations = VMobject(*equations.split()[1:])
other_equations.save_state()
scaled_vars = VMobject(*[
VMobject(*top_equation.split()[3*i:3*i+2])
for i in range(3)
])
scaled_vars.save_state()
isolated_scaled_vars = scaled_vars.copy()
isolated_scaled_vars.scale(1.5)
isolated_scaled_vars.next_to(top_equation, UP)
scalars = VMobject(*[m.split()[0] for m in scaled_vars.split()])
plusses = np.array(top_equation.split())[[2, 5]]
self.play(other_equations.fade, 0.7)
self.play(Transform(scaled_vars, isolated_scaled_vars))
self.play(scalars.highlight, YELLOW, submobject_mode = "lagged_start")
self.play(*[
ApplyMethod(m.scale_in_place, 1.2, rate_func = there_and_back)
for m in scalars.split()
])
self.dither()
self.remove(scalars)
self.play(scaled_vars.restore)
self.play(*[
ApplyMethod(p.scale_in_place, 1.5, rate_func = there_and_back)
for p in plusses
])
self.dither()
self.show_nonlinearity_examples()
self.play(other_equations.restore)
def show_nonlinearity_examples(self):
squared = TexMobject("x^2")
squared.split()[0].highlight(X_COLOR)
sine = TexMobject("\\sin(x)")
sine.split()[-2].highlight(X_COLOR)
product = TexMobject("xy")
product.split()[0].highlight(X_COLOR)
product.split()[1].highlight(Y_COLOR)
words = TextMobject("Not allowed!")
words.highlight(RED)
words.to_corner(UP+LEFT, buff = 1)
arrow = Vector(RIGHT, color = RED)
arrow.next_to(words, RIGHT)
for mob in squared, sine, product:
mob.scale(1.7)
mob.next_to(arrow.get_end(), RIGHT, buff = 0.5)
circle_slash = Circle(color = RED)
line = Line(LEFT, RIGHT, color = RED)
line.rotate(np.pi/4)
circle_slash.add(line)
circle_slash.next_to(arrow, RIGHT)
def draw_circle_slash(mob):
circle_slash.replace(mob)
circle_slash.scale_in_place(1.4)
self.play(ShowCreation(circle_slash), run_time = 0.5)
self.dither(0.5)
self.play(FadeOut(circle_slash), run_time = 0.5)
self.play(
Write(squared),
Write(words, run_time = 1),
ShowCreation(arrow),
)
draw_circle_slash(squared)
for mob in sine, product:
self.play(Transform(squared, mob))
draw_circle_slash(mob)
self.play(*map(FadeOut, [words, arrow, squared]))
self.dither()
def describe_organization(self, equations):
variables = VMobject(*it.chain(*[
eq.split()[:-2]
for eq in equations.split()
]))
variables.words = "Throw variables on the left"
constants = VMobject(*[
eq.split()[-1]
for eq in equations.split()
])
constants.words = "Lingering constants on the right"
xs, ys, zs = [
VMobject(*[
eq.split()[i]
for eq in equations.split()
])
for i in 1, 4, 7
]
ys.words = "Vertically align variables"
colors = [PINK, YELLOW, BLUE_B, BLUE_C, BLUE_D]
for mob, color in zip([variables, constants, xs, ys, zs], colors):
mob.square = Square(color = color)
mob.square.replace(mob, stretch = True)
mob.square.scale_in_place(1.1)
if hasattr(mob, "words"):
mob.words = TextMobject(mob.words)
mob.words.highlight(color)
mob.words.next_to(mob.square, UP)
ys.square.add(xs.square, zs.square)
zero_circles = VMobject(*[
Circle().replace(mob).scale_in_place(1.3)
for mob in [
VMobject(*equations.split()[i].split()[j:j+2])
for i, j in (1, 3), (2, 6)
]
])
zero_circles.highlight(PINK)
zero_circles.words = TextMobject("Add zeros as needed")
zero_circles.words.highlight(zero_circles.get_color())
zero_circles.words.next_to(equations, UP)
for mob in variables, constants, ys:
self.play(
FadeIn(mob.square),
FadeIn(mob.words)
)
self.dither()
self.play(*map(FadeOut, [mob.square, mob.words]))
self.play(
ShowCreation(zero_circles),
Write(zero_circles.words, run_time = 1)
)
self.dither()
self.play(*map(FadeOut, [zero_circles, zero_circles.words]))
self.dither()
title = TextMobject("``Linear system of equations''")
title.scale(1.5)
title.to_edge(UP)
self.play(Write(title))
self.dither()
self.play(FadeOut(title))
def factor_into_matrix(self, equations):
coefficients = np.array([
np.array(eq.split())[[0, 3, 6]]
for eq in equations.split()
])
variable_arrays = np.array([
np.array(eq.split())[[1, 4, 7]]
for eq in equations.split()
])
rhs_entries = np.array([
eq.split()[-1]
for eq in equations.split()
])
matrix = Matrix(copy.deepcopy(coefficients))
x_array = Matrix(copy.deepcopy(variable_arrays[0]))
v_array = Matrix(copy.deepcopy(rhs_entries))
equals = TexMobject("=")
ax_equals_v = VMobject(matrix, x_array, equals, v_array)
ax_equals_v.arrange_submobjects(RIGHT)
ax_equals_v.to_edge(RIGHT)
all_brackets = [
mob.get_brackets()
for mob in matrix, x_array, v_array
]
self.play(equations.to_edge, LEFT)
arrow = Vector(RIGHT, color = YELLOW)
arrow.next_to(ax_equals_v, LEFT)
self.play(ShowCreation(arrow))
self.play(*it.chain(*[
[
Transform(
m1.copy(), m2,
run_time = 2,
path_arc = -np.pi/2
)
for m1, m2 in zip(
start_array.flatten(),
matrix_mobject.get_entries().split()
)
]
for start_array, matrix_mobject in [
(coefficients, matrix),
(variable_arrays[0], x_array),
(variable_arrays[1], x_array),
(variable_arrays[2], x_array),
(rhs_entries, v_array)
]
]))
self.play(*[
Write(mob)
for mob in all_brackets + [equals]
])
self.dither()
self.label_matrix_product(matrix, x_array, v_array)
def label_matrix_product(self, matrix, x_array, v_array):
matrix.words = "Coefficients"
matrix.symbol = "A"
x_array.words = "Variables"
x_array.symbol = "\\vec{\\textbf{x}}"
v_array.words = "Constants"
v_array.symbol = "\\vec{\\textbf{v}}"
parts = matrix, x_array, v_array
for mob in parts:
mob.brace = Brace(mob, UP)
mob.words = mob.brace.get_text(mob.words)
mob.words.shift_onto_screen()
mob.symbol = TexMobject(mob.symbol)
mob.brace.put_at_tip(mob.symbol)
x_array.words.submobject_gradient_highlight(
X_COLOR, Y_COLOR, Z_COLOR
)
x_array.symbol.highlight(PINK)
v_array.symbol.highlight(YELLOW)
for mob in parts:
self.play(
GrowFromCenter(mob.brace),
FadeIn(mob.words)
)
self.dither()
self.play(*map(FadeOut, [mob.brace, mob.words]))
self.dither()
for mob in parts:
self.play(
FadeIn(mob.brace),
Write(mob.symbol)
)
compact_equation = VMobject(*[
mob.symbol for mob in parts
])
compact_equation.submobjects.insert(
2, TexMobject("=").next_to(x_array, RIGHT)
)
compact_equation.target = compact_equation.copy()
compact_equation.target.arrange_submobjects(buff = 0.1)
compact_equation.target.to_edge(UP)
self.play(Transform(
compact_equation.copy(),
compact_equation.target
))
self.dither()
class LinearSystemTransformationScene(LinearTransformationScene):
def setup(self):
LinearTransformationScene.setup(self)
equation = TexMobject([
"A",
"\\vec{\\textbf{x}}",
"=",
"\\vec{\\textbf{v}}",
])
equation.scale(1.5)
equation.next_to(ORIGIN, LEFT).to_edge(UP)
equation.add_background_rectangle()
self.add_foreground_mobject(equation)
self.equation = equation
self.A, self.x, eq, self.v = equation.split()[1].split()
self.x.highlight(PINK)
self.v.highlight(YELLOW)
class MentionThatItsATransformation(LinearSystemTransformationScene):
CONFIG = {
"t_matrix" : np.array([[2, 1], [2, 3]])
}
def construct(self):
self.setup()
brace = Brace(self.A)
words = brace.get_text("Transformation")
words.add_background_rectangle()
self.play(GrowFromCenter(brace), Write(words, run_time = 1))
self.add_foreground_mobject(words, brace)
self.apply_transposed_matrix(self.t_matrix)
self.dither()
class LookForX(MentionThatItsATransformation):
CONFIG = {
"show_basis_vectors" : False
}
def construct(self):
self.setup()
v = [-4, - 1]
x = np.linalg.solve(self.t_matrix.T, v)
v = Vector(v, color = YELLOW)
x = Vector(x, color = PINK)
v_label = self.get_vector_label(v, "v", color = YELLOW)
x_label = self.get_vector_label(x, "x", color = PINK)
for label in x_label, v_label:
label.add_background_rectangle()
self.play(
ShowCreation(v),
Write(v_label)
)
self.add_foreground_mobject(v_label)
x = self.add_vector(x, animate = False)
self.play(
ShowCreation(x),
Write(x_label)
)
self.dither()
self.add(VMobject(x, x_label).copy().fade())
self.apply_transposed_matrix(self.t_matrix)
self.dither()
class SystemOfTwoEquationsTwoUnknowns(Scene):
def construct(self):
system = TexMobject("""
2x + 2y &= -4 \\\\
1x + 3y &= -1
""")
system.to_edge(UP)
for indices, color in ((1, 9), X_COLOR), ((4, 12), Y_COLOR):
for i in indices:
system.split()[i].highlight(color)
matrix = Matrix([[2, 2], [1, 3]])
v = Matrix([-4, -1])
x = Matrix(["x", "y"])
x.get_entries().submobject_gradient_highlight(X_COLOR, Y_COLOR)
matrix_system = VMobject(
matrix, x, TexMobject("="), v
)
matrix_system.arrange_submobjects(RIGHT)
matrix_system.next_to(system, DOWN, buff = 1)
self.add(system)
self.play(Write(matrix_system))
self.dither()
class ShowBijectivity(LinearTransformationScene):
CONFIG = {
"show_basis_vectors" : False,
"t_matrix" : np.array([[0, -1], [2, 1]])
}
def construct(self):
self.setup()
vectors = VMobject(*[
Vector([x, y])
for x, y in it.product(*[
np.arange(-int(val)+0.5, int(val)+0.5)
for val in SPACE_WIDTH, SPACE_HEIGHT
])
])
vectors.submobject_gradient_highlight(BLUE_E, PINK)
dots = VMobject(*[
Dot(v.get_end(), color = v.get_color())
for v in vectors.split()
])
titles = [
TextMobject([
"Each vector lands on\\\\",
"exactly one vector"
]),
TextMobject([
"Every vector has \\\\",
"been landed on"
])
]
for title in titles:
title.to_edge(UP)
background = BackgroundRectangle(VMobject(*titles))
self.add_foreground_mobject(background, titles[0])
kwargs = {
"submobject_mode" : "lagged_start",
"run_time" : 2
}
anims = map(Animation, self.foreground_mobjects)
self.play(ShowCreation(vectors, **kwargs), *anims)
self.play(Transform(vectors, dots, **kwargs), *anims)
self.dither()
self.add_transformable_mobject(vectors)
self.apply_transposed_matrix(self.t_matrix)
self.dither()
self.play(Transform(*titles))
self.dither()
self.apply_transposed_matrix(
np.linalg.inv(self.t_matrix.T).T
)
self.dither()
class LabeledExample(LinearSystemTransformationScene):
CONFIG = {
"title" : "",
"t_matrix" : [[0, 0], [0, 0]],
}
def setup(self):
LinearSystemTransformationScene.setup(self)
title = TextMobject(self.title)
title.scale(1.5)
title.next_to(self.equation, DOWN)
title.add_background_rectangle()
self.add_foreground_mobject(title)
self.title = title
def construct(self):
self.setup()
self.dither()
self.apply_transposed_matrix(self.t_matrix)
self.dither()
class SquishExmapleWithWords(LabeledExample):
CONFIG = {
"title" : "$A$ squishes things to a lower dimension",
"t_matrix" : [[-2, -1], [2, 1]]
}
class FullRankExmapleWithWords(LabeledExample):
CONFIG = {
"title" : "$A$ keeps things 2D",
"t_matrix" : [[3, 0], [2, 1]]
}
class SquishExmapleDet(SquishExmapleWithWords):
CONFIG = {
"title" : "$\\det(A) = 0$",
}
class FullRankExmapleDet(FullRankExmapleWithWords):
CONFIG = {
"title" : "$\\det(A) \\ne 0$",
}
class PlayInReverse(FullRankExmapleDet):
CONFIG = {
"show_basis_vectors" : False
}
def construct(self):
FullRankExmapleDet.construct(self)
v = self.add_vector([-2, -2], color = YELLOW)
v_label = self.label_vector(v, "v", color = YELLOW)
self.add(v.copy())
self.apply_inverse_transpose(self.t_matrix)
self.play(v.highlight, PINK)
self.label_vector(v, "x", color = PINK)
self.dither()
class DescribeInverse(LinearTransformationScene):
CONFIG = {
"show_matrix" : False
}
def construct(self):
self.setup()
title = TextMobject("Transformation:")
new_title = TextMobject("Inverse transformation:")
if self.show_matrix:
matrix = Matrix(self.t_matrix.T)
inv_matrix = Matrix(np.linalg.inv(self.t_matrix.T).astype('int'))
else:
matrix, inv_matrix = map(TexMobject, ["A", "A^{-1}"])
for m, text in (matrix, title), (inv_matrix, new_title):
m.rect = BackgroundRectangle(m)
m = VMobject(m.rect, m)
text.add_background_rectangle()
m.next_to(text, RIGHT)
text.add(m)
if text.get_width() > 2*SPACE_WIDTH-1:
text.scale_to_fit_width(2*SPACE_WIDTH-1)
text.center().to_edge(UP)
self.add_foreground_mobject(title)
self.apply_transposed_matrix(self.t_matrix)
self.dither()
self.play(Transform(title, new_title))
self.apply_inverse_transpose(self.t_matrix)
self.dither()
class ClockwiseCounterclockwise(DescribeInverse):
CONFIG = {
"t_matrix" : [[0, 1], [-1, 0]],
"show_matrix" : True,
}
class ShearInverseShear(DescribeInverse):
CONFIG = {
"t_matrix" : [[1, 0], [1, 1]],
"show_matrix" : True,
}
class MultiplyToIdentity(LinearTransformationScene):
def construct(self):
self.setup()
lhs = TexMobject("A", "A^{-1}", "=")
lhs.scale(1.5)
A, A_inv, eq = lhs.split()
identity = Matrix([[1, 0], [0, 1]])
identity.highlight_columns(X_COLOR, Y_COLOR)
identity.next_to(eq, RIGHT)
VMobject(lhs, identity).center().to_edge(UP)
lhs.add_background_rectangle()
identity.add_to_back(BackgroundRectangle(identity))
col1 = VMobject(*identity.get_mob_matrix[:,0])
col2 = VMobject(*identity.get_mob_matrix[:,1])
A.text = "Transformation"
A_inv.text = "Inverse transformation"
product = VMobject(A, A_inv)
product.text = "Matrix multiplication"
identity.text = "The transformation that does nothing"
for mob in A, A_inv, product, identity:
mob.brace = Brace(mob)
mob.text = mob.brace.get_text(mob.text)
mob.text.add_background_rectangle()
self.add(A, A_inv)

96
eola/thumbnails.py Normal file
View file

@ -0,0 +1,96 @@
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 *
class Chapter0(LinearTransformationScene):
CONFIG = {
"include_background_plane" : False,
"t_matrix" : [[3, 1], [2, -1]]
}
def construct(self):
self.setup()
self.plane.fade()
for mob in self.get_mobjects():
mob.set_stroke(width = 6)
self.apply_transposed_matrix(self.t_matrix, run_time = 0)
class Chapter1(Scene):
def construct(self):
arrow = Vector(2*UP+RIGHT)
vs = TextMobject("vs.")
array = Matrix([1, 2])
array.highlight(TEAL)
everyone = VMobject(arrow, vs, array)
everyone.arrange_submobjects(RIGHT, buff = 0.5)
everyone.scale_to_fit_height(4)
self.add(everyone)
class Chapter2(LinearTransformationScene):
def construct(self):
self.lock_in_faded_grid()
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, BLUE_E)
words = TextMobject("Span")
words.scale(3)
words.to_edge(UP)
words.add_background_rectangle()
self.add(vectors, words)
class Chapter3(Chapter0):
CONFIG = {
"t_matrix" : [[3, 0], [2, -1]]
}
class Chapter4p1(Chapter0):
CONFIG = {
"t_matrix" : [[1, 0], [1, 1]]
}
class Chapter4p2(Chapter0):
CONFIG = {
"t_matrix" : [[1, 2], [-1, 1]]
}

View file

@ -257,6 +257,7 @@ class LinearTransformationScene(VectorScene):
"i_hat_color" : X_COLOR,
"j_hat_color" : Y_COLOR,
"leave_ghost_vectors" : False,
"t_matrix" : np.array([[3, 0], [1, 2]]),
}
def setup(self):
self.background_mobjects = []
@ -266,7 +267,7 @@ class LinearTransformationScene(VectorScene):
self.transformable_labels = []
self.moving_mobjects = []
self.t_matrix = np.array(self.t_matrix)
self.background_plane = NumberPlane(
**self.background_plane_kwargs
)
@ -289,6 +290,7 @@ class LinearTransformationScene(VectorScene):
]
]
def add_special_mobjects(self, mob_list, *mobs_to_add):
for mobject in mobs_to_add:
if mobject not in mob_list:
@ -405,6 +407,10 @@ class LinearTransformationScene(VectorScene):
kwargs["path_arc"] = net_rotation
self.apply_function(func, **kwargs)
def apply_inverse_transpose(self, t_matrix, **kwargs):
t_inv = np.linalg.inv(np.array(t_matrix).T).T
self.apply_transposed_matrix(t_inv, **kwargs)
def apply_nonlinear_transformation(self, function, **kwargs):
self.plane.prepare_for_nonlinear_transform()
self.apply_function(function, **kwargs)

View file

@ -51,6 +51,11 @@ class Mobject(object):
self.submobjects = list_update(self.submobjects, mobjects)
return self
def add_to_back(self, *mobjects):
self.remove(*mobjects)
self.submobjects = list(mobjects) + self.submobjects
return self
def remove(self, *mobjects):
for mobject in mobjects:
if mobject in self.submobjects:
@ -298,17 +303,25 @@ class Mobject(object):
def gradient_highlight(self, start_color, end_color):
raise Exception("Not implemented")
def submobject_gradient_highlight(self, start_color, end_color, use_color_range_to = False):
def submobject_gradient_highlight(self, *colors):
if len(colors) == 0:
raise Exception("Need at least one color")
elif len(colors) == 1:
return self.highlight(*colors)
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):
rgbs = map(color_to_rgb, colors)
alphas = np.linspace(0, (len(rgbs) - 1), len(mobs))
floors = alphas.astype('int')
alphas_mod1 = alphas % 1
#End edge case
alphas_mod1[-1] = 1
floors[-1] = len(rgbs) - 2
new_colors = [
Color(rgb = interpolate(rgbs[i], rgbs[i+1], alpha))
for i, alpha in zip(floors, alphas_mod1)
]
for mob, color in zip(mobs, new_colors):
mob.highlight(color, family = False)
return self
@ -337,6 +350,15 @@ class Mobject(object):
return self.color
##
def save_state(self):
self.saved_state = self.copy()
return self
def restore(self):
if not hasattr(self, "saved_state"):
raise Exception("Trying to restore without having saved")
self.__dict__.update(self.saved_state.__dict__)
return self
def apply_complex_function(self, function):
return self.apply_function(

View file

@ -39,26 +39,18 @@ class TexMobject(SVGMobject):
"organize_left_to_right" : False,
"propogate_style_to_family" : True,
}
def __init__(self, expression, **kwargs):
def __init__(self, *args, **kwargs):
digest_config(self, kwargs, locals())
self.is_input_a_list = isinstance(expression, list)
##TODO, Eventually remove this
if len(args) == 1 and isinstance(args[0], list):
args = args[0]
##
assert(all([isinstance(a, str) for a in args]))
VMobject.__init__(self, **kwargs)
self.move_into_position()
if self.organize_left_to_right:
self.organize_submobjects_left_to_right()
def handle_input_type(self):
if isinstance(self.expression, str):
self.is_input_a_list = False
elif isinstance(self.expression, collections.Iterable):
self.is_input_a_list = True
self.expression = list(self.expression)
else:
raise Exception(
"TexMobject was expecting string or list, got " + \
str(type(self.expression)) + \
" instead."
)
def path_string_to_mobject(self, path_string):
#Overwrite superclass default to use
@ -72,22 +64,22 @@ class TexMobject(SVGMobject):
self.template_tex_file
)
SVGMobject.generate_points(self)
if self.is_input_a_list:
self.handle_list_expression(self.expression)
if len(self.args) > 1:
self.handle_multiple_args()
def get_modified_expression(self):
separator = ""
if self.is_input_a_list and self.separate_list_arg_with_spaces:
if self.separate_list_arg_with_spaces:
separator = " "
result = separator.join(self.expression)
result = separator.join(self.args)
if self.enforce_new_line_structure:
result = result.replace("\n", " \\\\ \n ")
return result
def handle_list_expression(self, list_expression):
def handle_multiple_args(self):
new_submobjects = []
curr_index = 0
for expr in list_expression:
for expr in self.args:
model = TexMobject(expr, **self.CONFIG)
new_index = curr_index + len(model.submobjects)
new_submobjects.append(VMobject(
@ -108,7 +100,7 @@ class TexMobject(SVGMobject):
fill_opacity = opacity
)
letters = VMobject(*self.submobjects)
self.submobjects = [rect, letters]
self.add_to_back(rect)
return self
class TextMobject(TexMobject):

View file

@ -5,6 +5,7 @@ from mobject.svg_mobject import SVGMobject
from mobject.vectorized_mobject import VMobject
from mobject.tex_mobject import TextMobject
from animation import Animation
from animation.transform import Transform, ApplyMethod, FadeOut, FadeIn
from animation.simple_animations import Write
from scene import Scene
@ -107,6 +108,7 @@ class PiCreature(SVGMobject):
pupil.shift(nudge_size*UP)
return self
def get_looking_direction(self):
return np.sign(np.round(
self.pupils.get_center() - self.eyes.get_center(),
@ -166,6 +168,35 @@ class Blink(ApplyMethod):
def __init__(self, pi_creature, **kwargs):
ApplyMethod.__init__(self, pi_creature.blink, **kwargs)
class DoTheWave(Transform):
CONFIG = {
"run_time" : 2
}
def __init__(self, pi_creature, **kwargs):
start_state = pi_creature.copy()
self.target_states = [
pi_creature.copy().change_mode("wave_%d"%x)
for x in 1, 2, 3
] + [
pi_creature.copy()
]
Transform.__init__(self, pi_creature, self.target_states[0], **kwargs)
def update_mobject(self, alpha):
scaled = alpha*len(self.target_states)
try:
if scaled-1 > 0:
self.starting_mobject = self.target_states[int(scaled)-1]
self.ending_mobject = self.target_states[int(scaled)]
except IndexError:
self.ending_mobject = self.target_states[-1]
Transform.update_mobject(self, scaled%1)
return self
class Bubble(SVGMobject):
CONFIG = {
"direction" : LEFT,
@ -275,6 +306,7 @@ class TeacherStudentsScene(Scene):
self.students.arrange_submobjects(RIGHT)
self.students.scale(0.8)
self.students.to_corner(DOWN+LEFT)
self.students = self.students.split()
for pi_creature in self.get_everyone():
pi_creature.bubble = None
@ -284,7 +316,7 @@ class TeacherStudentsScene(Scene):
return self.teacher
def get_students(self):
return self.students.split()
return self.students
def get_everyone(self):
return [self.get_teacher()] + self.get_students()