mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 02:07:45 +00:00
Up to associativity in EoLA chapter 4
This commit is contained in:
parent
418e11fd66
commit
8e48140961
5 changed files with 766 additions and 11 deletions
727
eola/chapter4.py
727
eola/chapter4.py
|
|
@ -263,7 +263,8 @@ class IntroduceIdeaOfComposition(RotationThenShear):
|
|||
def construct(self):
|
||||
self.setup()
|
||||
self.show_composition()
|
||||
self.track_basis_vectors()
|
||||
matrix = self.track_basis_vectors()
|
||||
self.show_overall_effect(matrix)
|
||||
|
||||
def show_composition(self):
|
||||
words = TextMobject([
|
||||
|
|
@ -281,12 +282,730 @@ class IntroduceIdeaOfComposition(RotationThenShear):
|
|||
|
||||
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.play(
|
||||
ApplyMethod(self.plane.fade),
|
||||
Write(words),
|
||||
Animation(self.i_hat),
|
||||
Animation(self.j_hat),
|
||||
)
|
||||
self.dither()
|
||||
|
||||
def track_basis_vectors(self):
|
||||
pass
|
||||
|
||||
last_words = self.get_mobjects_from_last_animation()[1]
|
||||
words = TextMobject([
|
||||
"Record where",
|
||||
"$\\hat{\\imath}$",
|
||||
"and",
|
||||
"$\\hat{\\jmath}$",
|
||||
"land:"
|
||||
])
|
||||
rw, i_hat, a, j_hat, l = words.split()
|
||||
i_hat.highlight(X_COLOR)
|
||||
j_hat.highlight(Y_COLOR)
|
||||
words.add_background_rectangle()
|
||||
words.next_to(last_words, DOWN)
|
||||
|
||||
i_coords = vector_coordinate_label(self.i_hat)
|
||||
j_coords = vector_coordinate_label(self.j_hat)
|
||||
i_coords.highlight(X_COLOR)
|
||||
j_coords.highlight(Y_COLOR)
|
||||
i_background = BackgroundRectangle(i_coords)
|
||||
j_background = BackgroundRectangle(j_coords)
|
||||
|
||||
matrix = Matrix(np.append(
|
||||
i_coords.copy().get_mob_matrix(),
|
||||
j_coords.copy().get_mob_matrix(),
|
||||
axis = 1
|
||||
))
|
||||
matrix.next_to(words, RIGHT, aligned_edge = UP)
|
||||
col1, col2 = [
|
||||
VMobject(*matrix.get_mob_matrix()[:,i])
|
||||
for i in 0, 1
|
||||
]
|
||||
matrix_background = BackgroundRectangle(matrix)
|
||||
|
||||
self.play(Write(words))
|
||||
self.dither()
|
||||
self.play(ShowCreation(i_background), Write(i_coords), run_time = 2)
|
||||
self.dither()
|
||||
self.play(
|
||||
Transform(i_background.copy(), matrix_background),
|
||||
Transform(i_coords.copy().get_brackets(), matrix.get_brackets()),
|
||||
ApplyMethod(i_coords.copy().get_entries().move_to, col1)
|
||||
)
|
||||
self.dither()
|
||||
self.play(ShowCreation(j_background), Write(j_coords), run_time = 2)
|
||||
self.dither()
|
||||
self.play(
|
||||
ApplyMethod(j_coords.copy().get_entries().move_to, col2)
|
||||
)
|
||||
self.dither()
|
||||
matrix = VMobject(matrix_background, matrix)
|
||||
return matrix
|
||||
|
||||
def show_overall_effect(self, matrix):
|
||||
everything = self.get_mobjects()
|
||||
everything = list_difference_update(
|
||||
everything, matrix.submobject_family()
|
||||
)
|
||||
self.play(*map(FadeOut, everything) + [Animation(matrix)])
|
||||
new_matrix = matrix.copy()
|
||||
new_matrix.center().to_edge(UP)
|
||||
self.play(Transform(matrix, new_matrix))
|
||||
self.dither()
|
||||
self.remove(matrix)
|
||||
|
||||
self.setup()
|
||||
everything = self.get_mobjects()
|
||||
self.play(*map(FadeIn, everything) + [Animation(matrix)])
|
||||
func = self.get_matrix_transformation([[1, 1], [-1, 0]])
|
||||
bases = VMobject(self.i_hat, self.j_hat)
|
||||
new_bases = VMobject(*[
|
||||
Vector(func(v.get_end()), color = v.get_color())
|
||||
for v in bases.split()
|
||||
])
|
||||
self.play(
|
||||
ApplyPointwiseFunction(func, self.plane),
|
||||
Transform(bases, new_bases),
|
||||
Animation(matrix),
|
||||
run_time = 3
|
||||
)
|
||||
self.dither()
|
||||
|
||||
class PumpVectorThroughRotationThenShear(RotationThenShear):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.add_vector([2, 3])
|
||||
self.apply_transposed_matrix([[0, 1], [-1, 0]], run_time = 2)
|
||||
self.apply_transposed_matrix([[1, 0], [1, 1]], run_time = 2)
|
||||
self.dither()
|
||||
|
||||
class ExplainWhyItsMatrixMultiplication(Scene):
|
||||
def construct(self):
|
||||
vect = Matrix(["x", "y"])
|
||||
vect.get_entries().highlight(YELLOW)
|
||||
|
||||
rot_matrix = Matrix([[0, -1], [1, 0]])
|
||||
rot_matrix.highlight(TEAL)
|
||||
shear_matrix = Matrix([[1, 1], [0, 1]])
|
||||
shear_matrix.highlight(PINK)
|
||||
l_paren, r_paren = map(TexMobject, ["\\Big(", "\\Big)"])
|
||||
for p in l_paren, r_paren:
|
||||
p.scale_to_fit_height(1.4*vect.get_height())
|
||||
long_way = VMobject(
|
||||
shear_matrix, l_paren, rot_matrix, vect, r_paren
|
||||
)
|
||||
long_way.arrange_submobjects(buff = 0.1)
|
||||
long_way.to_edge(LEFT).shift(UP)
|
||||
|
||||
equals = TexMobject("=").next_to(long_way, RIGHT)
|
||||
|
||||
comp_matrix = Matrix([[1, -1], [1, 0]])
|
||||
comp_matrix.highlight_columns(X_COLOR, Y_COLOR)
|
||||
vect_copy = vect.copy()
|
||||
short_way = VMobject(comp_matrix, vect_copy)
|
||||
short_way.arrange_submobjects(buff = 0.1)
|
||||
short_way.next_to(equals, RIGHT)
|
||||
|
||||
pairs = [
|
||||
(rot_matrix, "Rotation"),
|
||||
(shear_matrix, "Shear"),
|
||||
(comp_matrix, "Composition"),
|
||||
]
|
||||
for matrix, word in pairs:
|
||||
brace = Brace(matrix)
|
||||
text = TextMobject(word).next_to(brace, DOWN)
|
||||
brace.highlight(matrix.get_color())
|
||||
text.highlight(matrix.get_color())
|
||||
matrix.add(brace, text)
|
||||
comp_matrix.split()[-1].submobject_gradient_highlight(TEAL, PINK)
|
||||
|
||||
self.add(vect)
|
||||
groups = [
|
||||
[rot_matrix],
|
||||
[l_paren, r_paren, shear_matrix],
|
||||
[equals, comp_matrix, vect_copy],
|
||||
]
|
||||
for group in groups:
|
||||
self.play(*map(Write, group))
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, [l_paren, r_paren, vect, vect_copy]))
|
||||
comp_matrix.add(equals)
|
||||
matrices = VMobject(shear_matrix, rot_matrix, comp_matrix)
|
||||
self.play(ApplyMethod(
|
||||
matrices.arrange_submobjects, buff = 0.1,
|
||||
aligned_edge = UP
|
||||
))
|
||||
self.dither()
|
||||
|
||||
arrow = Arrow(rot_matrix.get_right(), shear_matrix.get_left())
|
||||
arrow.shift((rot_matrix.get_top()[1]+0.2)*UP)
|
||||
words = TextMobject("Read right to left")
|
||||
words.submobjects.reverse()
|
||||
words.next_to(arrow, UP)
|
||||
functions = TexMobject("f(g(x))")
|
||||
functions.next_to(words, UP)
|
||||
|
||||
self.play(ShowCreation(arrow))
|
||||
self.play(Write(words))
|
||||
self.dither()
|
||||
self.play(Write(functions))
|
||||
self.dither()
|
||||
|
||||
class MoreComplicatedExampleVisually(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"t_matrix1" : [[1, 1], [-2, 0]],
|
||||
"t_matrix2" : [[0, 1], [2, 0]],
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
t_matrix1 = np.array(self.t_matrix1)
|
||||
t_matrix2 = np.array(self.t_matrix2)
|
||||
t_m1_inv = np.linalg.inv(t_matrix1.transpose()).transpose()
|
||||
t_m2_inv = np.linalg.inv(t_matrix2.transpose()).transpose()
|
||||
|
||||
m1_mob, m2_mob, comp_matrix = self.get_matrices()
|
||||
|
||||
self.play(Write(m1_mob))
|
||||
self.add_foreground_mobject(m1_mob)
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(t_matrix1)
|
||||
self.dither()
|
||||
self.play(Write(m1_mob.label))
|
||||
self.add_foreground_mobject(m1_mob.label)
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(t_m1_inv, run_time = 0)
|
||||
self.dither()
|
||||
|
||||
self.play(Write(m2_mob))
|
||||
self.add_foreground_mobject(m2_mob)
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(t_matrix2)
|
||||
self.dither()
|
||||
self.play(Write(m2_mob.label))
|
||||
self.add_foreground_mobject(m2_mob.label)
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(t_m2_inv, run_time = 0)
|
||||
self.dither()
|
||||
|
||||
for matrix in t_matrix1, t_matrix2:
|
||||
self.apply_transposed_matrix(matrix, run_time = 1)
|
||||
self.play(Write(comp_matrix))
|
||||
self.add_foreground_mobject(comp_matrix)
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, [
|
||||
self.background_plane,
|
||||
self.plane,
|
||||
self.i_hat,
|
||||
self.j_hat,
|
||||
]) + [
|
||||
Animation(m) for m in self.foreground_mobjects
|
||||
])
|
||||
self.remove(self.i_hat, self.j_hat)
|
||||
self.dither()
|
||||
|
||||
def get_matrices(self):
|
||||
m1_mob = Matrix(np.array(self.t_matrix1).transpose())
|
||||
m2_mob = Matrix(np.array(self.t_matrix2).transpose())
|
||||
comp_matrix = Matrix([["?", "?"], ["?", "?"]])
|
||||
m1_mob.highlight(YELLOW)
|
||||
m2_mob.highlight(PINK)
|
||||
comp_matrix.get_entries().submobject_gradient_highlight(YELLOW, PINK)
|
||||
|
||||
equals = TexMobject("=")
|
||||
equals.next_to(comp_matrix, LEFT)
|
||||
comp_matrix.add(equals)
|
||||
m1_mob = VMobject(BackgroundRectangle(m1_mob), m1_mob)
|
||||
m2_mob = VMobject(BackgroundRectangle(m2_mob), m2_mob)
|
||||
comp_matrix = VMobject(BackgroundRectangle(comp_matrix), comp_matrix)
|
||||
VMobject(
|
||||
m2_mob, m1_mob, comp_matrix
|
||||
).arrange_submobjects(buff = 0.1).to_corner(UP+LEFT).shift(DOWN)
|
||||
|
||||
for i, mob in enumerate([m1_mob, m2_mob]):
|
||||
brace = Brace(mob, UP)
|
||||
text = TexMobject("M_%d"%(i+1))
|
||||
text.next_to(brace, UP)
|
||||
brace.add_background_rectangle()
|
||||
text.add_background_rectangle()
|
||||
brace.add(text)
|
||||
mob.label = brace
|
||||
return m1_mob, m2_mob, comp_matrix
|
||||
|
||||
class MoreComplicatedExampleNumerically(MoreComplicatedExampleVisually):
|
||||
def get_result(self):
|
||||
return np.dot(self.t_matrix1, self.t_matrix2).transpose()
|
||||
|
||||
def construct(self):
|
||||
m1_mob, m2_mob, comp_matrix = self.get_matrices()
|
||||
self.add(m1_mob, m2_mob, m1_mob.label, m2_mob.label, comp_matrix)
|
||||
result = self.get_result()
|
||||
|
||||
col1, col2 = [
|
||||
VMobject(*m1_mob.split()[1].get_mob_matrix()[:,i])
|
||||
for i in 0, 1
|
||||
]
|
||||
col1.target_color = X_COLOR
|
||||
col2.target_color = Y_COLOR
|
||||
for col in col1, col2:
|
||||
circle = Circle()
|
||||
circle.stretch_to_fit_height(m1_mob.get_height())
|
||||
circle.stretch_to_fit_width(m1_mob.get_width()/2.5)
|
||||
circle.highlight(col.target_color)
|
||||
circle.move_to(col)
|
||||
col.circle = circle
|
||||
|
||||
triplets = [
|
||||
(col1, "i", X_COLOR),
|
||||
(col2, "j", Y_COLOR),
|
||||
]
|
||||
for i, (col, char, color) in enumerate(triplets):
|
||||
self.add(col)
|
||||
start_state = self.get_mobjects()
|
||||
question = TextMobject(
|
||||
"Where does $\\hat{\\%smath}$ go?"%char
|
||||
)
|
||||
question.split()[-4].highlight(color)
|
||||
question.split()[-5].highlight(color)
|
||||
question.scale(1.2)
|
||||
question.shift(DOWN)
|
||||
first = TextMobject("First here")
|
||||
first.highlight(color)
|
||||
first.shift(DOWN+LEFT)
|
||||
first_arrow = Arrow(
|
||||
first, col.circle.get_bottom(), color = color
|
||||
)
|
||||
second = TextMobject("Then to whatever this is")
|
||||
second.highlight(color)
|
||||
second.to_edge(RIGHT).shift(DOWN)
|
||||
|
||||
m2_copy = m2_mob.copy()
|
||||
m2_target = m2_mob.copy()
|
||||
m2_target.next_to(m2_mob, DOWN, buff = 1)
|
||||
col_vect = Matrix(col.copy().split())
|
||||
col_vect.highlight(color)
|
||||
col_vect.next_to(m2_target, RIGHT, buff = 0.1)
|
||||
second_arrow = Arrow(second, col_vect, color = color)
|
||||
|
||||
new_m2_copy = m2_mob.copy().split()[1]
|
||||
intermediate = VMobject(
|
||||
TexMobject("="),
|
||||
col_vect.copy().get_entries().split()[0],
|
||||
Matrix(new_m2_copy.get_mob_matrix()[:,0]),
|
||||
TexMobject("+"),
|
||||
col_vect.copy().get_entries().split()[1],
|
||||
Matrix(new_m2_copy.get_mob_matrix()[:,1]),
|
||||
TexMobject("=")
|
||||
)
|
||||
intermediate.arrange_submobjects(buff = 0.1)
|
||||
intermediate.next_to(col_vect, RIGHT)
|
||||
|
||||
product = Matrix(result[:,i])
|
||||
product.next_to(intermediate, RIGHT)
|
||||
|
||||
comp_col = VMobject(*comp_matrix.split()[1].get_mob_matrix()[:,i])
|
||||
|
||||
self.play(Write(question, run_time = 1 ))
|
||||
self.dither()
|
||||
self.play(
|
||||
Transform(question, first),
|
||||
ShowCreation(first_arrow),
|
||||
ShowCreation(col.circle),
|
||||
ApplyMethod(col.highlight, col.target_color)
|
||||
)
|
||||
self.dither()
|
||||
self.play(
|
||||
Transform(m2_copy, m2_target, run_time = 2),
|
||||
ApplyMethod(col.copy().move_to, col_vect, run_time = 2),
|
||||
Write(col_vect.get_brackets()),
|
||||
Transform(first_arrow, second_arrow),
|
||||
Transform(question, second),
|
||||
)
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, [question, first_arrow]))
|
||||
self.play(Write(intermediate))
|
||||
self.dither()
|
||||
self.play(Write(product))
|
||||
self.dither()
|
||||
product_entries = product.get_entries()
|
||||
self.play(
|
||||
ApplyMethod(comp_col.highlight, BLACK),
|
||||
ApplyMethod(product_entries.move_to, comp_col)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
start_state.append(product_entries)
|
||||
self.play(*[
|
||||
FadeOut(mob)
|
||||
for mob in self.get_mobjects()
|
||||
if mob not in start_state
|
||||
] + [
|
||||
Animation(product_entries)
|
||||
])
|
||||
self.dither()
|
||||
|
||||
class GeneralMultiplication(MoreComplicatedExampleNumerically):
|
||||
def get_result(self):
|
||||
entries = map(TexMobject, [
|
||||
"ae+bg", "af+bh", "ce+dg", "cf+dh"
|
||||
])
|
||||
for mob in entries:
|
||||
mob.split()[0].highlight(PINK)
|
||||
mob.split()[3].highlight(PINK)
|
||||
for mob in entries[0], entries[2]:
|
||||
mob.split()[1].highlight(X_COLOR)
|
||||
mob.split()[4].highlight(X_COLOR)
|
||||
for mob in entries[1], entries[3]:
|
||||
mob.split()[1].highlight(Y_COLOR)
|
||||
mob.split()[4].highlight(Y_COLOR)
|
||||
return np.array(entries).reshape((2, 2))
|
||||
|
||||
def get_matrices(self):
|
||||
m1, m2, comp = MoreComplicatedExampleNumerically.get_matrices(self)
|
||||
self.add(m1, m2, m1.label, m2.label, comp)
|
||||
m1_entries = m1.split()[1].get_entries()
|
||||
m2_entries = m2.split()[1].get_entries()
|
||||
m2_entries_target = VMobject(*[
|
||||
TexMobject(char).move_to(entry).highlight(entry.get_color())
|
||||
for entry, char in zip(m2_entries.split(), "abcd")
|
||||
])
|
||||
m1_entries_target = VMobject(*[
|
||||
TexMobject(char).move_to(entry).highlight(entry.get_color())
|
||||
for entry, char in zip(m1_entries.split(), "efgh")
|
||||
])
|
||||
|
||||
words = TextMobject("This method works genearlly")
|
||||
self.play(Write(words, run_time = 2))
|
||||
self.play(Transform(
|
||||
m1_entries, m1_entries_target,
|
||||
submobject_mode = "lagged_start"
|
||||
))
|
||||
self.play(Transform(
|
||||
m2_entries, m2_entries_target,
|
||||
submobject_mode = "lagged_start"
|
||||
))
|
||||
self.dither()
|
||||
|
||||
new_comp = Matrix(self.get_result())
|
||||
new_comp.next_to(comp.split()[1].submobjects[-1], RIGHT)
|
||||
new_comp.get_entries().highlight(BLACK)
|
||||
self.play(
|
||||
Transform(comp.split()[1].get_brackets(), new_comp.get_brackets()),
|
||||
*[
|
||||
ApplyMethod(q_mark.move_to, entry)
|
||||
for q_mark, entry in zip(
|
||||
comp.split()[1].get_entries().split(),
|
||||
new_comp.get_entries().split()
|
||||
)
|
||||
]
|
||||
)
|
||||
self.dither()
|
||||
self.play(FadeOut(words))
|
||||
return m1, m2, comp
|
||||
|
||||
class MoreComplicatedExampleWithJustIHat(MoreComplicatedExampleVisually):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False,
|
||||
"v_coords" : [1, 0],
|
||||
"v_color" : X_COLOR,
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.add_vector(self.v_coords, self.v_color)
|
||||
self.apply_transposed_matrix(self.t_matrix1)
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(self.t_matrix2)
|
||||
self.dither()
|
||||
|
||||
class MoreComplicatedExampleWithJustJHat(MoreComplicatedExampleWithJustIHat):
|
||||
CONFIG = {
|
||||
"v_coords" : [0, 1],
|
||||
"v_color" : Y_COLOR,
|
||||
}
|
||||
|
||||
class RoteMatrixMultiplication(NumericalMatrixMultiplication):
|
||||
CONFIG = {
|
||||
"left_matrix" : [[-3, 1], [2, 5]],
|
||||
"right_matrix" : [[5, 3], [7, -3]]
|
||||
}
|
||||
|
||||
class NeverForget(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.teacher_says("Never forget what \\\\ this represents!")
|
||||
self.random_blink()
|
||||
self.student_thinks("", student_index = 0)
|
||||
def warp(point):
|
||||
point += 2*DOWN+RIGHT
|
||||
return 20*point/np.linalg.norm(point)
|
||||
self.play(ApplyPointwiseFunction(
|
||||
warp,
|
||||
VMobject(*self.get_mobjects())
|
||||
))
|
||||
|
||||
class AskAboutCommutativity(Scene):
|
||||
def construct(self):
|
||||
l_m1, l_m2, eq, r_m2, r_m1 = TexMobject([
|
||||
"M_1", "M_2", "=", "M_2", "M_1"
|
||||
]).scale(1.5).split()
|
||||
VMobject(l_m1, r_m1).highlight(YELLOW)
|
||||
VMobject(l_m2, r_m2).highlight(PINK)
|
||||
q_marks = TextMobject("???")
|
||||
q_marks.highlight(TEAL)
|
||||
q_marks.next_to(eq, UP)
|
||||
neq = TexMobject("\\neq")
|
||||
neq.move_to(eq)
|
||||
|
||||
self.play(*map(Write, [l_m1, l_m2, eq]))
|
||||
self.play(
|
||||
Transform(l_m1.copy(), r_m1),
|
||||
Transform(l_m2.copy(), r_m2),
|
||||
path_arc = -np.pi,
|
||||
run_time = 2
|
||||
)
|
||||
self.play(Write(q_marks))
|
||||
self.dither()
|
||||
self.play(Transform(
|
||||
VMobject(eq, q_marks),
|
||||
VMobject(neq),
|
||||
submobject_mode = "lagged_start"
|
||||
))
|
||||
self.dither()
|
||||
|
||||
class ShowShear(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"title" : "Shear",
|
||||
"title_color" : PINK,
|
||||
"t_matrix" : [[1, 0], [1, 1]]
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
title = TextMobject(self.title)
|
||||
title.scale(1.5).to_edge(UP)
|
||||
title.highlight(self.title_color)
|
||||
title.add_background_rectangle()
|
||||
self.add_foreground_mobject(title)
|
||||
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(self.t_matrix)
|
||||
self.dither()
|
||||
|
||||
class ShowRotation(ShowShear):
|
||||
CONFIG = {
|
||||
"title" : "$90^\\circ$ rotation",
|
||||
"title_color" : YELLOW,
|
||||
"t_matrix" : [[0, 1], [-1, 0]]
|
||||
}
|
||||
|
||||
class FirstShearThenRotation(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"title" : "First shear then rotation",
|
||||
"t_matrix1" : [[1, 0], [1, 1]],
|
||||
"t_matrix2" : [[0, 1], [-1, 0]],
|
||||
"foreground_plane_kwargs" : {
|
||||
"x_radius" : 2*SPACE_WIDTH,
|
||||
"y_radius" : 2*SPACE_WIDTH,
|
||||
"secondary_line_ratio" : 0
|
||||
},
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
title_parts = self.title.split(" ")
|
||||
title = TextMobject(title_parts)
|
||||
for i, part in enumerate(title_parts):
|
||||
if part == "rotation":
|
||||
title.split()[i].highlight(YELLOW)
|
||||
elif part == "shear":
|
||||
title.split()[i].highlight(PINK)
|
||||
title.scale(1.5)
|
||||
self.add_title(title)
|
||||
|
||||
self.apply_transposed_matrix(self.t_matrix1)
|
||||
self.apply_transposed_matrix(self.t_matrix2)
|
||||
self.i_hat.rotate(-0.01)##Laziness
|
||||
self.dither()
|
||||
self.write_vector_coordinates(self.i_hat, color = X_COLOR)
|
||||
self.dither()
|
||||
self.write_vector_coordinates(self.j_hat, color = Y_COLOR)
|
||||
self.dither()
|
||||
|
||||
class RotationThenShear(FirstShearThenRotation):
|
||||
CONFIG = {
|
||||
"title" : "First rotation then shear",
|
||||
"t_matrix1" : [[0, 1], [-1, 0]],
|
||||
"t_matrix2" : [[1, 0], [1, 1]],
|
||||
}
|
||||
|
||||
class NoticeTheLackOfComputations(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.teacher_says("""
|
||||
Notice the lack
|
||||
of computations!
|
||||
""")
|
||||
self.random_blink()
|
||||
|
||||
students = self.get_students()
|
||||
random.shuffle(students)
|
||||
unit = np.array([-0.5, 0.5])
|
||||
self.play(*[
|
||||
ApplyMethod(
|
||||
pi.change_mode, "pondering",
|
||||
rate_func = squish_rate_func(smooth, *np.clip(unit+0.5*i, 0, 1))
|
||||
)
|
||||
for i, pi in enumerate(students)
|
||||
])
|
||||
self.random_blink()
|
||||
self.dither()
|
||||
|
||||
class AskAssociativityQuestion(Scene):
|
||||
def construct(self):
|
||||
morty = Mortimer()
|
||||
morty.scale(0.8)
|
||||
morty.to_corner(DOWN+RIGHT)
|
||||
morty.shift(0.5*LEFT)
|
||||
title = TextMobject("Associativity:")
|
||||
title.to_corner(UP+LEFT)
|
||||
|
||||
lhs = TexMobject(list("(AB)C"))
|
||||
lp, a, b, rp, c = lhs.split()
|
||||
rhs = VMobject(*[m.copy() for m in a, lp, b, c, rp])
|
||||
point = VectorizedPoint()
|
||||
start = VMobject(*[m.copy() for m in point, a, b, point, c])
|
||||
for mob in lhs, rhs, start:
|
||||
mob.arrange_submobjects(buff = 0.1)
|
||||
a, lp, b, c, rp = rhs.split()
|
||||
rhs = VMobject(lp, a, b, rp, c)##Align order to lhs
|
||||
eq = TexMobject("=")
|
||||
q_marks = TextMobject("???")
|
||||
q_marks.submobject_gradient_highlight(TEAL_B, TEAL_D)
|
||||
q_marks.next_to(eq, UP)
|
||||
lhs.next_to(eq, LEFT)
|
||||
rhs.next_to(eq, RIGHT)
|
||||
start.move_to(lhs)
|
||||
|
||||
|
||||
self.add(morty, title)
|
||||
self.dither()
|
||||
self.play(Blink(morty))
|
||||
self.play(Write(start))
|
||||
self.dither()
|
||||
self.play(Transform(start, lhs))
|
||||
self.dither()
|
||||
self.play(
|
||||
Transform(lhs, rhs, path_arc = -np.pi),
|
||||
Write(eq)
|
||||
)
|
||||
self.play(Write(q_marks))
|
||||
self.play(Blink(morty))
|
||||
self.play(morty.change_mode, "pondering")
|
||||
|
||||
lp, a, b, rp, c = start.split()
|
||||
self.show_full_matrices(morty, a, b, c, title)
|
||||
|
||||
def show_full_matrices(self, morty, a, b, c, title):
|
||||
everything = self.get_mobjects()
|
||||
everything.remove(morty)
|
||||
everything.remove(title)
|
||||
everything = VMobject(*everything)
|
||||
|
||||
matrices = map(matrix_to_mobject, [
|
||||
np.array(list(m)).reshape((2, 2))
|
||||
for m in "abcd", "efgh", "ijkl"
|
||||
])
|
||||
VMobject(*matrices).arrange_submobjects()
|
||||
|
||||
self.play(everything.to_edge, UP)
|
||||
for letter, matrix in zip([a, b, c], matrices):
|
||||
self.play(Transform(
|
||||
letter.copy(), matrix,
|
||||
submobject_mode = "lagged_start"
|
||||
))
|
||||
self.remove(*self.get_mobjects_from_last_animation())
|
||||
self.add(matrix)
|
||||
self.dither()
|
||||
self.move_matrix_parentheses(morty, matrices)
|
||||
|
||||
def move_matrix_parentheses(self, morty, matrices):
|
||||
m1, m2, m3 = matrices
|
||||
parens = TexMobject(["(", ")"])
|
||||
parens.scale_to_fit_height(1.2*m1.get_height())
|
||||
lp, rp = parens.split()
|
||||
state1 = VMobject(
|
||||
VectorizedPoint(m1.get_left()),
|
||||
m1, m2,
|
||||
VectorizedPoint(m2.get_right()),
|
||||
m3
|
||||
)
|
||||
state2 = VMobject(*[
|
||||
m.copy() for m in lp, m1, m2, rp, m3
|
||||
])
|
||||
state3 = VMobject(*[
|
||||
m.copy() for m in m1, lp, m2, m3, rp
|
||||
])
|
||||
for state in state2, state3:
|
||||
state.arrange_submobjects(RIGHT, buff = 0.1)
|
||||
m1, lp, m2, m3, rp = state3.split()
|
||||
state3 = VMobject(lp, m1, m2, rp, m3)
|
||||
|
||||
self.play(morty.change_mode, "angry")
|
||||
for state in state2, state3:
|
||||
self.play(Transform(state1, state))
|
||||
self.dither()
|
||||
self.play(morty.change_mode, "confused")
|
||||
self.dither()
|
||||
|
||||
class ThreeSuccessiveTransformations(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"t_matrices" : [
|
||||
[[2, 1], [1, 2]],
|
||||
[[np.cos(-np.pi/6), np.sin(-np.pi/6)], [-np.sin(-np.pi/6), np.cos(-np.pi/6)]],
|
||||
[[1, 0], [1, 1]]
|
||||
],
|
||||
"symbols_str" : "A(BC)",
|
||||
"include_background_plane" : False,
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
symbols = TexMobject(list(self.symbols_str))
|
||||
symbols.scale(1.5)
|
||||
symbols.to_edge(UP)
|
||||
a, b, c = None, None, None
|
||||
for mob, letter in zip(symbols.split(), self.symbols_str):
|
||||
if letter == "A":
|
||||
a = mob
|
||||
elif letter == "B":
|
||||
b = mob
|
||||
elif letter == "C":
|
||||
c = mob
|
||||
|
||||
symbols.add_background_rectangle()
|
||||
self.add_foreground_mobject(symbols)
|
||||
|
||||
brace = Brace(c, DOWN)
|
||||
words = TextMobject("Apply this transformation")
|
||||
words.add_background_rectangle()
|
||||
words.next_to(brace, DOWN)
|
||||
brace.add(words)
|
||||
|
||||
self.play(Write(brace, run_time = 1))
|
||||
self.add_foreground_mobject(brace)
|
||||
|
||||
last = VectorizedPoint()
|
||||
for t_matrix, sym in zip(self.t_matrices, [c, b, a]):
|
||||
self.play(
|
||||
brace.next_to, sym, DOWN,
|
||||
sym.highlight, YELLOW,
|
||||
last.highlight, WHITE
|
||||
)
|
||||
self.apply_transposed_matrix(t_matrix, run_time = 1)
|
||||
last = sym
|
||||
self.dither()
|
||||
|
||||
class ThreeSuccessiveTransformationsAltParens(ThreeSuccessiveTransformations):
|
||||
CONFIG = {
|
||||
"symbols_str" : "(AB)C"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ from animation.transform import ApplyPointwiseFunction, Transform, \
|
|||
ApplyMethod, FadeOut, ApplyFunction
|
||||
from animation.simple_animations import ShowCreation, Write
|
||||
from topics.number_line import NumberPlane, Axes
|
||||
from topics.geometry import Vector, Line, Circle, Arrow, Dot
|
||||
from topics.geometry import Vector, Line, Circle, Arrow, Dot, BackgroundRectangle
|
||||
|
||||
from helpers import *
|
||||
|
||||
VECTOR_LABEL_SCALE_VAL = 1.0
|
||||
VECTOR_LABEL_SCALE_VAL = 0.8
|
||||
|
||||
def matrix_to_tex_string(matrix):
|
||||
matrix = np.array(matrix).astype("string")
|
||||
|
|
@ -31,7 +31,8 @@ def matrix_to_tex_string(matrix):
|
|||
def matrix_to_mobject(matrix):
|
||||
return TexMobject(matrix_to_tex_string(matrix))
|
||||
|
||||
def vector_coordinate_label(vector_mob, integer_labels = True, n_dim = 2):
|
||||
def vector_coordinate_label(vector_mob, integer_labels = True,
|
||||
n_dim = 2, color = WHITE):
|
||||
vect = np.array(vector_mob.get_end())
|
||||
if integer_labels:
|
||||
vect = np.round(vect).astype(int)
|
||||
|
|
@ -41,11 +42,14 @@ def vector_coordinate_label(vector_mob, integer_labels = True, n_dim = 2):
|
|||
label.scale(VECTOR_LABEL_SCALE_VAL)
|
||||
|
||||
shift_dir = np.array(vector_mob.get_end())
|
||||
if shift_dir[0] > 0: #Pointing right
|
||||
if shift_dir[0] >= 0: #Pointing right
|
||||
shift_dir -= label.get_left() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER*LEFT
|
||||
else: #Pointing left
|
||||
shift_dir -= label.get_right() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER*RIGHT
|
||||
label.shift(shift_dir)
|
||||
label.highlight(color)
|
||||
background = BackgroundRectangle(label)
|
||||
label.submobjects = [background] + label.submobjects
|
||||
return label
|
||||
|
||||
class Matrix(VMobject):
|
||||
|
|
@ -104,9 +108,15 @@ class Matrix(VMobject):
|
|||
self.brackets = VMobject(l_bracket, r_bracket)
|
||||
return self
|
||||
|
||||
def highlight_columns(self, *colors):
|
||||
for i, color in enumerate(colors):
|
||||
VMobject(*self.mob_matrix[:,i]).highlight(color)
|
||||
return self
|
||||
|
||||
def get_mob_matrix(self):
|
||||
return self.mob_matrix
|
||||
|
||||
|
||||
def get_entries(self):
|
||||
return VMobject(*self.get_mob_matrix().flatten())
|
||||
|
||||
|
|
@ -117,7 +127,8 @@ class Matrix(VMobject):
|
|||
class NumericalMatrixMultiplication(Scene):
|
||||
CONFIG = {
|
||||
"left_matrix" : [[1, 2], [3, 4]],
|
||||
"right_matrix" : [[5, 6], [7, 8]]
|
||||
"right_matrix" : [[5, 6], [7, 8]],
|
||||
"use_parens" : True,
|
||||
}
|
||||
def construct(self):
|
||||
left_string_matrix, right_string_matrix = [
|
||||
|
|
@ -143,8 +154,9 @@ class NumericalMatrixMultiplication(Scene):
|
|||
mob_matrix = np.array([VMobject()]).repeat(m*n).reshape((m, n))
|
||||
for a in range(m):
|
||||
for b in range(n):
|
||||
template = "(%s)(%s)" if self.use_parens else "%s%s"
|
||||
parts = [
|
||||
prefix + "(%s)(%s)"%(left[a][c], right[c][b])
|
||||
prefix + template%(left[a][c], right[c][b])
|
||||
for c in range(k)
|
||||
for prefix in ["" if c == 0 else "+"]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from animation.transform import ApplyPointwiseFunction, Transform, \
|
|||
ApplyMethod, FadeOut, ApplyFunction
|
||||
from animation.simple_animations import ShowCreation, Write
|
||||
from topics.number_line import NumberPlane, Axes
|
||||
from topics.geometry import Vector, Line, Circle, Arrow, Dot
|
||||
from topics.geometry import Vector, Line, Circle, Arrow, Dot, BackgroundRectangle
|
||||
|
||||
from helpers import *
|
||||
from eola.matrix import Matrix, VECTOR_LABEL_SCALE_VAL, vector_coordinate_label
|
||||
|
|
@ -55,6 +55,11 @@ class VectorScene(Scene):
|
|||
self.add(vector)
|
||||
return vector
|
||||
|
||||
def write_vector_coordinates(self, vector, **kwargs):
|
||||
coords = vector_coordinate_label(vector, **kwargs)
|
||||
self.play(Write(coords))
|
||||
return coords
|
||||
|
||||
def get_basis_vectors(self):
|
||||
return [
|
||||
Vector(
|
||||
|
|
@ -303,6 +308,11 @@ class LinearTransformationScene(VectorScene):
|
|||
self.moving_vectors.append(vector)
|
||||
return vector
|
||||
|
||||
def write_vector_coordinates(self, vector, **kwargs):
|
||||
coords = VectorScene.write_vector_coordinates(self, vector, **kwargs)
|
||||
self.add_foreground_mobject(coords)
|
||||
return coords
|
||||
|
||||
def add_transformable_label(self, vector, label, new_label = None, **kwargs):
|
||||
label_mob = self.label_vector(vector, label, **kwargs)
|
||||
if new_label:
|
||||
|
|
@ -316,6 +326,16 @@ class LinearTransformationScene(VectorScene):
|
|||
self.transformable_labels.append(label_mob)
|
||||
return label_mob
|
||||
|
||||
def add_title(self, title, scale_val = 1.5, animate = False):
|
||||
if not isinstance(title, Mobject):
|
||||
title = TextMobject(title).scale(scale_val)
|
||||
title.to_edge(UP)
|
||||
title.add_background_rectangle()
|
||||
if animate:
|
||||
self.play(Write(title))
|
||||
self.add_foreground_mobject(title)
|
||||
return self
|
||||
|
||||
def get_matrix_transformation(self, transposed_matrix):
|
||||
transposed_matrix = np.array(transposed_matrix)
|
||||
if transposed_matrix.shape == (2, 2):
|
||||
|
|
|
|||
|
|
@ -133,6 +133,9 @@ def list_update(l1, l2):
|
|||
"""
|
||||
return filter(lambda e : e not in l2, l1) + list(l2)
|
||||
|
||||
def list_difference_update(l1, l2):
|
||||
return filter(lambda e : e not in l2, l1)
|
||||
|
||||
def all_elements_are_instances(iterable, Class):
|
||||
return all(map(lambda e : isinstance(e, Class), iterable))
|
||||
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ class Mobject(object):
|
|||
|
||||
def flip(self, axis = UP):
|
||||
self.rotate_in_place(np.pi, axis)
|
||||
return self
|
||||
|
||||
def scale_in_place(self, scale_factor):
|
||||
self.do_in_place(self.scale, scale_factor)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue