mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 21:44:19 +08:00
3/4 Dot products
This commit is contained in:
@ -1598,7 +1598,7 @@ class AdditivityProperty(LinearTransformationScene):
|
||||
if self.proclaim_sum:
|
||||
text = TextMobject("It's still their sum!")
|
||||
text.add_background_rectangle()
|
||||
text.move_to(new_w.get_end(), side_to_align = -new_w.get_end())
|
||||
text.move_to(new_w.get_end(), aligned_edge = -new_w.get_end())
|
||||
text.shift_onto_screen()
|
||||
self.play(Write(text))
|
||||
self.dither()
|
||||
|
@ -901,7 +901,7 @@ class TwoDDeterminantFormula(Scene):
|
||||
mob.zero = TexMobject("\\cdot 0")
|
||||
else:
|
||||
mob.zero = TexMobject("0")
|
||||
mob.zero.move_to(mob, side_to_align = DOWN+LEFT)
|
||||
mob.zero.move_to(mob, aligned_edge = DOWN+LEFT)
|
||||
mob.zero.highlight(mob.get_color())
|
||||
mob.original = mob.copy()
|
||||
c.zero.shift(0.1*RIGHT)
|
||||
|
@ -192,7 +192,7 @@ class StockPrices(Scene):
|
||||
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)
|
||||
sl.move_to(y_axis.get_center(), aligned_edge = LEFT)
|
||||
everyone.add(sl)
|
||||
stock_lines.append(sl)
|
||||
everyone.center()
|
||||
@ -814,7 +814,7 @@ class DescribeInverse(LinearTransformationScene):
|
||||
neg_1 = TexMobject("-1")
|
||||
neg_1.move_to(
|
||||
inv_matrix.get_corner(UP+RIGHT),
|
||||
side_to_align = LEFT
|
||||
aligned_edge = LEFT
|
||||
)
|
||||
neg_1.shift(0.1*RIGHT)
|
||||
inv_matrix.add(neg_1)
|
||||
@ -1480,7 +1480,7 @@ class NameColumnSpace(Scene):
|
||||
two_d_span[index].scale(0)
|
||||
two_d_span.arrange_submobjects(RIGHT, buff = 0.2)
|
||||
two_d_span[-1].next_to(two_d_span[4], RIGHT, buff = 0.2)
|
||||
two_d_span.move_to(span_text, side_to_align = RIGHT)
|
||||
two_d_span.move_to(span_text, aligned_edge = RIGHT)
|
||||
mob_matrix = np.array([
|
||||
two_d_span[i].get_entries().split()
|
||||
for i in 2, 4
|
||||
@ -1676,7 +1676,7 @@ class NameNullSpace(LinearTransformationScene):
|
||||
line.highlight(YELLOW)
|
||||
null_space_label = TextMobject("``Null space''")
|
||||
kernel_label = TextMobject("``Kernel''")
|
||||
null_space_label.move_to(vectors[13].get_end(), side_to_align = UP+LEFT)
|
||||
null_space_label.move_to(vectors[13].get_end(), aligned_edge = UP+LEFT)
|
||||
kernel_label.next_to(null_space_label, DOWN)
|
||||
for mob in null_space_label, kernel_label:
|
||||
mob.highlight(YELLOW)
|
||||
@ -1743,7 +1743,7 @@ class NullSpaceSolveForVEqualsZero(NameNullSpace):
|
||||
zero_vector = Matrix([0, 0])
|
||||
zero_vector.highlight(YELLOW)
|
||||
zero_vector.scale(0.7)
|
||||
zero_vector.move_to(v, side_to_align = LEFT)
|
||||
zero_vector.move_to(v, aligned_edge = LEFT)
|
||||
VMobject(equation, zero_vector).next_to(ORIGIN, LEFT).to_edge(UP)
|
||||
zero_vector_rect = BackgroundRectangle(zero_vector)
|
||||
equation.add_background_rectangle()
|
||||
|
627
eola/chapter7.py
627
eola/chapter7.py
@ -27,18 +27,19 @@ V_COLOR = YELLOW
|
||||
W_COLOR = MAROON_B
|
||||
SUM_COLOR = PINK
|
||||
|
||||
def get_projection(stable_vector, vector_to_project):
|
||||
dot_product = np.dot(*[
|
||||
v.get_end()
|
||||
for v in stable_vector, vector_to_project
|
||||
])
|
||||
stable_square_norm = stable_vector.get_length()**2
|
||||
result = Vector(
|
||||
stable_vector.get_end()*dot_product/stable_square_norm,
|
||||
|
||||
def get_projection(vector_to_project, stable_vector):
|
||||
v1, v2 = stable_vector, vector_to_project
|
||||
return v1*np.dot(v1, v2)/(np.linalg.norm(v1)**2)
|
||||
|
||||
def get_vect_mob_projection(vector_to_project, stable_vector):
|
||||
return Vector(
|
||||
get_projection(
|
||||
vector_to_project.get_end(),
|
||||
stable_vector.get_end()
|
||||
),
|
||||
color = vector_to_project.get_color()
|
||||
)
|
||||
result.fade()
|
||||
return result
|
||||
).fade()
|
||||
|
||||
class OpeningQuote(Scene):
|
||||
def construct(self):
|
||||
@ -515,7 +516,7 @@ class SymmetricVAndW(VectorScene):
|
||||
vect.label.highlight(vect.get_color())
|
||||
vect.label.next_to(vect.get_end(), DOWN+RIGHT)
|
||||
for v1, v2 in (v, w), (w, v):
|
||||
v1.proj = get_projection(v2, v1)
|
||||
v1.proj = get_vect_mob_projection(v1, v2)
|
||||
v1.proj_line = Line(
|
||||
v1.get_end(), v1.proj.get_end(), color = GREY
|
||||
)
|
||||
@ -1061,32 +1062,23 @@ class FollowVectorViaCoordinatesConcrete(FollowVectorViaCoordinates):
|
||||
}
|
||||
|
||||
class TwoDOneDMatrixMultiplication(Scene):
|
||||
CONFIG = {
|
||||
"matrix" : [[1, -2]],
|
||||
"vector" : [4, 3],
|
||||
"order_left_to_right" : False,
|
||||
}
|
||||
def construct(self):
|
||||
matrix = Matrix([[1, -2]])
|
||||
matrix = Matrix(self.matrix)
|
||||
matrix.label = "Transform"
|
||||
vector = Matrix([4, 3])
|
||||
vector = Matrix(self.vector)
|
||||
vector.label = "Vector"
|
||||
matrix.next_to(vector, LEFT, buff = 0.2)
|
||||
self.color_matrix_and_vector(matrix, vector)
|
||||
for m, vect in zip([matrix, vector], [UP, DOWN]):
|
||||
x, y = m.get_entries()
|
||||
x.highlight(X_COLOR)
|
||||
y.highlight(Y_COLOR)
|
||||
m.brace = Brace(m, vect)
|
||||
m.label = m.brace.get_text(m.label)
|
||||
matrix.label.highlight(BLUE)
|
||||
vector.label.highlight(YELLOW)
|
||||
|
||||
starter_pairs = zip(vector.get_entries(), matrix.get_entries())
|
||||
pairs = [
|
||||
VMobject(
|
||||
e1.copy(), TexMobject("\\cdot"), e2.copy()
|
||||
).arrange_submobjects()
|
||||
for e1, e2 in starter_pairs
|
||||
]
|
||||
symbols = map(TexMobject, ["=", "+"])
|
||||
equation = VMobject(*it.chain(*zip(symbols, pairs)))
|
||||
equation.arrange_submobjects()
|
||||
equation.next_to(vector, RIGHT)
|
||||
vector.label.highlight(MAROON_B)
|
||||
|
||||
for m in vector, matrix:
|
||||
self.play(Write(m))
|
||||
@ -1096,6 +1088,23 @@ class TwoDOneDMatrixMultiplication(Scene):
|
||||
run_time = 1
|
||||
)
|
||||
self.dither()
|
||||
self.show_product(matrix, vector)
|
||||
|
||||
def show_product(self, matrix, vector):
|
||||
starter_pairs = zip(vector.get_entries(), matrix.get_entries())
|
||||
pairs = [
|
||||
VMobject(
|
||||
e1.copy(), TexMobject("\\cdot"), e2.copy()
|
||||
).arrange_submobjects(
|
||||
LEFT if self.order_left_to_right else RIGHT,
|
||||
)
|
||||
for e1, e2 in starter_pairs
|
||||
]
|
||||
symbols = map(TexMobject, ["=", "+"])
|
||||
equation = VMobject(*it.chain(*zip(symbols, pairs)))
|
||||
equation.arrange_submobjects(align_using_submobjects = True)
|
||||
equation.next_to(vector, RIGHT)
|
||||
|
||||
self.play(Write(VMobject(*symbols)))
|
||||
for starter_pair, pair in zip(starter_pairs, pairs):
|
||||
self.play(Transform(
|
||||
@ -1105,6 +1114,12 @@ class TwoDOneDMatrixMultiplication(Scene):
|
||||
))
|
||||
self.dither()
|
||||
|
||||
def color_matrix_and_vector(self, matrix, vector):
|
||||
for m in matrix, vector:
|
||||
x, y = m.get_entries()
|
||||
x.highlight(X_COLOR)
|
||||
y.highlight(Y_COLOR)
|
||||
|
||||
class AssociationBetweenMatricesAndVectors(Scene):
|
||||
def construct(self):
|
||||
matrices_words = TextMobject("$1\\times 2$ matrices")
|
||||
@ -1174,26 +1189,540 @@ class ImagineYouDontKnowThis(Scene):
|
||||
self.dither()
|
||||
|
||||
class ProjectOntoUnitVectorNumberline(VectorScene):
|
||||
def construct(self):
|
||||
self.lock_in_faded_grid()
|
||||
u_hat = Vector([1, 0], color = PINK)
|
||||
u_hat.rotate(np.pil/6)
|
||||
number_line = NumberLine()
|
||||
CONFIG = {
|
||||
"randomize_dots" : True,
|
||||
"animate_setup" : True,
|
||||
"zoom_factor" : 1,
|
||||
"u_hat_color" : YELLOW,
|
||||
"tilt_angle" : np.pi/6,
|
||||
}
|
||||
def setup(self):
|
||||
plane = self.add_plane()
|
||||
plane.fade()
|
||||
|
||||
u_hat = Vector([1, 0], color = self.u_hat_color)
|
||||
u_brace = Brace(u_hat)
|
||||
u_hat.rotate(self.tilt_angle)
|
||||
u_hat.label = TexMobject("\\hat{\\textbf{u}}")
|
||||
u_hat.label.highlight(u_hat.get_color())
|
||||
u_hat.label.next_to(u_hat.get_end(), UP+LEFT)
|
||||
u_brace.rotate(u_hat.get_angle())
|
||||
one = TexMobject("1").add_background_rectangle()
|
||||
one.next_to(u_brace.get_center(), DOWN+RIGHT, buff = MED_BUFF/2)
|
||||
|
||||
number_line = NumberLine(x_min = -9, x_max = 9)
|
||||
numbers = number_line.get_numbers()
|
||||
VMobject(number_line, numbers).rotate(u_hat.get_angle())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Group(number_line, numbers).rotate(u_hat.get_angle())
|
||||
if self.animate_setup:
|
||||
self.play(ShowCreation(u_hat))
|
||||
self.play(Write(u_hat.label))
|
||||
self.play(
|
||||
GrowFromCenter(u_brace),
|
||||
Write(one)
|
||||
)
|
||||
self.dither()
|
||||
self.play(
|
||||
ShowCreation(number_line),
|
||||
Write(numbers),
|
||||
Animation(u_hat),
|
||||
*map(FadeOut, [u_brace, one]),
|
||||
run_time = 3
|
||||
)
|
||||
else:
|
||||
self.add(number_line, numbers, u_hat)
|
||||
|
||||
if self.zoom_factor != 1:
|
||||
for mob in plane, u_hat:
|
||||
mob.target = mob.copy().scale(self.zoom_factor)
|
||||
number_line.target = number_line.copy()
|
||||
number_line.target.rotate(-u_hat.get_angle())
|
||||
number_line.target.stretch(self.zoom_factor, 0)
|
||||
numbers.target = number_line.target.get_numbers()
|
||||
number_line.target.rotate(u_hat.get_angle())
|
||||
numbers.target.rotate(u_hat.get_angle())
|
||||
self.play(*[
|
||||
Transform(mob, mob.target)
|
||||
for mob in self.get_mobjects()
|
||||
])
|
||||
self.dither()
|
||||
self.number_line, self.numbers, self.u_hat = number_line, numbers, u_hat
|
||||
|
||||
|
||||
def construct(self):
|
||||
vectors = self.get_vectors(randomize = self.randomize_dots)
|
||||
dots = self.get_dots(vectors)
|
||||
proj_dots = self.get_proj_dots(dots)
|
||||
proj_lines = self.get_proj_lines(dots, proj_dots)
|
||||
|
||||
self.dither()
|
||||
self.play(FadeIn(vectors, submobject_mode = "lagged_start"))
|
||||
self.dither()
|
||||
self.play(Transform(vectors, dots))
|
||||
self.dither()
|
||||
self.play(ShowCreation(proj_lines))
|
||||
self.dither()
|
||||
self.play(
|
||||
self.number_line.set_stroke, None, 2,
|
||||
Transform(vectors, proj_dots),
|
||||
Transform(proj_lines, proj_dots),
|
||||
Animation(self.u_hat),
|
||||
submobject_mode = "lagged_start",
|
||||
run_time = 2
|
||||
)
|
||||
self.dither()
|
||||
|
||||
|
||||
def get_vectors(self, num_vectors = 10, randomize = True):
|
||||
x_max = SPACE_WIDTH - 1
|
||||
y_max = SPACE_HEIGHT - 1
|
||||
x_vals = np.linspace(-x_max, x_max, num_vectors)
|
||||
y_vals = np.linspace(y_max, -y_max, num_vectors)
|
||||
if randomize:
|
||||
random.shuffle(y_vals)
|
||||
vectors = Group(*[
|
||||
Vector(x*RIGHT + y*UP)
|
||||
for x, y in zip(x_vals, y_vals)
|
||||
])
|
||||
vectors.gradient_highlight(PINK, MAROON_B)
|
||||
return vectors
|
||||
|
||||
def get_dots(self, vectors):
|
||||
return Group(*[
|
||||
Dot(v.get_end(), color = v.get_color(), radius = 0.075)
|
||||
for v in vectors
|
||||
])
|
||||
|
||||
def get_proj_dots(self, dots):
|
||||
return Group(*[
|
||||
dot.copy().move_to(get_projection(
|
||||
dot.get_center(), self.u_hat.get_end()
|
||||
))
|
||||
for dot in dots
|
||||
])
|
||||
|
||||
def get_proj_lines(self, dots, proj_dots):
|
||||
return Group(*[
|
||||
DashedLine(
|
||||
d1.get_center(), d2.get_center(),
|
||||
buff = 0, color = d1.get_color(),
|
||||
dashed_segment_length = 0.15
|
||||
)
|
||||
for d1, d2 in zip(dots, proj_dots)
|
||||
])
|
||||
|
||||
class ProjectionFunctionSymbol(Scene):
|
||||
def construct(self):
|
||||
v_tex = "\\vec{\\textbf{v}}"
|
||||
equation = TexMobject(
|
||||
"P(", v_tex, ")=",
|
||||
"\\text{number }", v_tex, "\\text{ lands on}"
|
||||
)
|
||||
equation.highlight_by_tex(v_tex, YELLOW)
|
||||
equation.shift(2*UP)
|
||||
words = TextMobject(
|
||||
"This projection function is", "linear"
|
||||
)
|
||||
words.highlight_by_tex("linear", BLUE)
|
||||
arrow = Arrow(
|
||||
words.get_top(), equation[0].get_bottom(),
|
||||
color = BLUE
|
||||
)
|
||||
|
||||
self.add(Group(*equation[:3]))
|
||||
self.play(Write(Group(*equation[3:])))
|
||||
self.dither()
|
||||
self.play(Write(words), ShowCreation(arrow))
|
||||
self.dither()
|
||||
|
||||
class ProjectLineOfDots(ProjectOntoUnitVectorNumberline):
|
||||
CONFIG = {
|
||||
"randomize_dots" : False,
|
||||
"animate_setup" : False,
|
||||
}
|
||||
|
||||
class AskAboutProjectionMatrix(Scene):
|
||||
def construct(self):
|
||||
matrix = Matrix([["?", "?"]])
|
||||
matrix.highlight_columns(X_COLOR, Y_COLOR)
|
||||
words = TextMobject("Projection matrix:")
|
||||
VMobject(words, matrix).arrange_submobjects(buff = MED_BUFF).shift(UP)
|
||||
basis_words = [
|
||||
TextMobject("Where", "$\\hat{\\%smath}$"%char, "lands")
|
||||
for char in "i", "j"
|
||||
]
|
||||
for b_words, q_mark, direction in zip(basis_words, matrix.get_entries(), [UP, DOWN]):
|
||||
b_words.next_to(q_mark, direction, buff = 1.5)
|
||||
b_words.arrow = Arrow(b_words, q_mark, color = q_mark.get_color())
|
||||
b_words.highlight(q_mark.get_color())
|
||||
|
||||
self.play(
|
||||
Write(words),
|
||||
Write(matrix)
|
||||
)
|
||||
self.dither()
|
||||
for b_words in basis_words:
|
||||
self.play(
|
||||
Write(b_words),
|
||||
ShowCreation(b_words.arrow)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
class ProjectBasisVectors(ProjectOntoUnitVectorNumberline):
|
||||
CONFIG = {
|
||||
"animate_setup" : False,
|
||||
"zoom_factor" : 3,
|
||||
"u_hat_color" : YELLOW,
|
||||
"tilt_angle" : np.pi/5,
|
||||
}
|
||||
def construct(self):
|
||||
basis_vectors = self.get_basis_vectors()
|
||||
i_hat, j_hat = basis_vectors
|
||||
for vect in basis_vectors:
|
||||
vect.scale(self.zoom_factor)
|
||||
dots = self.get_dots(basis_vectors)
|
||||
proj_dots = self.get_proj_dots(dots)
|
||||
proj_lines = self.get_proj_lines(dots, proj_dots)
|
||||
for dot in proj_dots:
|
||||
dot.scale_in_place(0.1)
|
||||
proj_basis = Group(*[
|
||||
get_vect_mob_projection(vector, self.u_hat)
|
||||
for vector in basis_vectors
|
||||
])
|
||||
|
||||
i_tex, j_tex = ["$\\hat{\\%smath}$"%char for char in "i", "j"]
|
||||
question = TextMobject(
|
||||
"Where do", i_tex, "and", j_tex, "land?"
|
||||
)
|
||||
question.highlight_by_tex(i_tex, X_COLOR)
|
||||
question.highlight_by_tex(j_tex, Y_COLOR)
|
||||
question.add_background_rectangle()
|
||||
matrix = Matrix([["u_x", "u_y"]])
|
||||
Group(question, matrix).arrange_submobjects(DOWN).to_corner(
|
||||
UP+LEFT, buff = MED_BUFF/2
|
||||
)
|
||||
matrix_rect = BackgroundRectangle(matrix)
|
||||
|
||||
|
||||
i_label = TexMobject(i_tex[1:-1])
|
||||
j_label = TexMobject(j_tex[1:-1])
|
||||
u_label = TexMobject("\\vec{\\textbf{u}}")
|
||||
trips = zip(
|
||||
(i_label, j_label, u_label),
|
||||
(i_hat, j_hat, self.u_hat),
|
||||
(DOWN+RIGHT, UP+LEFT, UP),
|
||||
)
|
||||
for label, vect, direction in trips:
|
||||
label.highlight(vect.get_color())
|
||||
label.scale(1.2)
|
||||
label.next_to(vect.get_end(), direction, buff = MED_BUFF/2)
|
||||
|
||||
self.play(Write(u_label, run_time = 1))
|
||||
self.play(*map(ShowCreation, basis_vectors))
|
||||
self.play(*map(Write, [i_label, j_label]), run_time = 1)
|
||||
self.play(ShowCreation(proj_lines))
|
||||
self.play(
|
||||
Write(question),
|
||||
ShowCreation(matrix_rect),
|
||||
Write(matrix.get_brackets()),
|
||||
run_time = 2,
|
||||
)
|
||||
to_remove = [proj_lines]
|
||||
quads = zip(basis_vectors, proj_basis, proj_lines, proj_dots)
|
||||
for vect, proj_vect, proj_line, proj_dot in quads:
|
||||
self.play(Transform(vect.copy(), proj_vect))
|
||||
to_remove += self.get_mobjects_from_last_animation()
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, to_remove))
|
||||
|
||||
# self.show_u_coords(u_label)
|
||||
u_x, u_y = [
|
||||
TexMobject("u_%s"%c).highlight(self.u_hat.get_color())
|
||||
for c in "x", "y"
|
||||
]
|
||||
matrix_x, matrix_y = matrix.get_entries()
|
||||
self.remove(j_hat, j_label)
|
||||
self.show_symmetry(i_hat, u_x, matrix_x)
|
||||
self.add(j_hat, j_label)
|
||||
self.remove(i_hat, i_label)
|
||||
self.show_symmetry(j_hat, u_y, matrix_y)
|
||||
|
||||
# def show_u_coords(self, u_label):
|
||||
# coords = Matrix(["u_x", "u_y"])
|
||||
# x, y = coords.get_entries()
|
||||
# x.highlight(X_COLOR)
|
||||
# y.highlight(Y_COLOR)
|
||||
# coords.add_to_back(BackgroundRectangle(coords))
|
||||
# eq = TexMobject("=")
|
||||
# eq.next_to(u_label, RIGHT)
|
||||
# coords.next_to(eq, RIGHT)
|
||||
# self.play(*map(FadeIn, [eq, coords]))
|
||||
# self.dither()
|
||||
# self.u_coords = coords
|
||||
|
||||
def show_symmetry(self, vect, coord, coord_landing_spot):
|
||||
starting_mobjects = list(self.get_mobjects())
|
||||
line = DashedLine(SPACE_WIDTH*LEFT, SPACE_WIDTH*RIGHT)
|
||||
words = TextMobject("Line of symmetry")
|
||||
words.next_to(ORIGIN, UP+LEFT)
|
||||
words.shift(LEFT)
|
||||
words.add_background_rectangle()
|
||||
angle = np.mean([vect.get_angle(), self.u_hat.get_angle()])
|
||||
Group(line, words).rotate(angle)
|
||||
|
||||
self.play(ShowCreation(line))
|
||||
if vect.get_end()[0] > 0.1:#is ihat
|
||||
self.play(Write(words, run_time = 1))
|
||||
|
||||
vect.proj = get_vect_mob_projection(vect, self.u_hat)
|
||||
self.u_hat.proj = get_vect_mob_projection(self.u_hat, vect)
|
||||
for v in vect, self.u_hat:
|
||||
v.proj_line = DashedLine(
|
||||
v.get_end(), v.proj.get_end(),
|
||||
color = v.get_color()
|
||||
)
|
||||
v.proj_line.fade()
|
||||
v.tick = Line(0.1*DOWN, 0.1*UP, color = WHITE)
|
||||
v.tick.rotate(v.proj.get_angle())
|
||||
v.tick.shift(v.proj.get_end())
|
||||
v.q_mark = TextMobject("?")
|
||||
v.q_mark.next_to(v.tick, v.proj.get_end()-v.get_end())
|
||||
|
||||
self.play(ShowCreation(v.proj_line))
|
||||
self.play(Transform(v.copy(), v.proj))
|
||||
self.remove(*self.get_mobjects_from_last_animation())
|
||||
self.add(v.proj)
|
||||
self.dither()
|
||||
for v in vect, self.u_hat:
|
||||
self.play(
|
||||
ShowCreation(v.tick),
|
||||
Write(v.q_mark)
|
||||
)
|
||||
self.dither()
|
||||
for v in self.u_hat, vect:
|
||||
coord_copy = coord.copy().move_to(v.q_mark)
|
||||
self.play(Transform(v.q_mark, coord_copy))
|
||||
self.dither()
|
||||
final_coord = coord_copy.copy()
|
||||
self.play(final_coord.move_to, coord_landing_spot)
|
||||
|
||||
added_mobjects = [
|
||||
mob
|
||||
for mob in self.get_mobjects()
|
||||
if mob not in starting_mobjects + [final_coord]
|
||||
]
|
||||
self.play(*map(FadeOut, added_mobjects))
|
||||
|
||||
class ShowSingleProjection(ProjectBasisVectors):
|
||||
CONFIG = {
|
||||
"zoom_factor" : 1
|
||||
}
|
||||
def construct(self):
|
||||
vector = Vector([5, - 1], color = MAROON_B)
|
||||
proj = get_vect_mob_projection(vector, self.u_hat)
|
||||
proj_line = DashedLine(
|
||||
vector.get_end(), proj.get_end(),
|
||||
color = vector.get_color()
|
||||
)
|
||||
coords = Matrix(["x", "y"])
|
||||
coords.get_entries().highlight(vector.get_color())
|
||||
coords.add_to_back(BackgroundRectangle(coords))
|
||||
coords.next_to(vector.get_end(), RIGHT)
|
||||
|
||||
u_label = TexMobject("\\hat{\\textbf{u}}")
|
||||
u_label.next_to(self.u_hat.get_end(), UP)
|
||||
u_label.add_background_rectangle()
|
||||
self.add(u_label)
|
||||
|
||||
self.play(ShowCreation(vector))
|
||||
self.play(Write(coords))
|
||||
self.dither()
|
||||
self.play(ShowCreation(proj_line))
|
||||
self.play(
|
||||
Transform(vector.copy(), proj),
|
||||
Animation(self.u_hat)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
class GeneralTwoDOneDMatrixMultiplication(TwoDOneDMatrixMultiplication):
|
||||
CONFIG = {
|
||||
"matrix" : [["u_x", "u_y"]],
|
||||
"vector" : ["x", "y"],
|
||||
"order_left_to_right" : True,
|
||||
}
|
||||
def construct(self):
|
||||
TwoDOneDMatrixMultiplication.construct(self)
|
||||
everything = Group(*self.get_mobjects())
|
||||
to_fade = filter(
|
||||
lambda m : isinstance(m, Brace) or isinstance(m, TextMobject),
|
||||
everything
|
||||
)
|
||||
|
||||
u = Matrix(self.matrix[0])
|
||||
v = Matrix(self.vector)
|
||||
self.color_matrix_and_vector(u, v)
|
||||
dot_product = Group(u, TexMobject("\\cdot"), v)
|
||||
dot_product.arrange_submobjects()
|
||||
dot_product.shift(2*RIGHT+DOWN)
|
||||
words = Group(
|
||||
TextMobject("Matrix-vector product"),
|
||||
TexMobject("\\Updownarrow"),
|
||||
TextMobject("Dot product")
|
||||
)
|
||||
words[0].highlight(BLUE)
|
||||
words[2].highlight(GREEN)
|
||||
words.arrange_submobjects(DOWN)
|
||||
words.to_edge(LEFT)
|
||||
|
||||
|
||||
|
||||
self.play(
|
||||
everything.to_corner, UP+RIGHT,
|
||||
*map(FadeOut, to_fade)
|
||||
)
|
||||
self.remove(everything)
|
||||
self.add(*everything)
|
||||
self.remove(*to_fade)
|
||||
|
||||
self.play(Write(words, run_time = 2))
|
||||
self.play(ShowCreation(dot_product))
|
||||
self.show_product(u, v)
|
||||
|
||||
|
||||
|
||||
def color_matrix_and_vector(self, matrix, vector):
|
||||
colors = [X_COLOR, Y_COLOR]
|
||||
for coord, color in zip(matrix.get_entries(), colors):
|
||||
coord[0].highlight(YELLOW)
|
||||
coord[1].highlight(color)
|
||||
vector.get_entries().highlight(MAROON_B)
|
||||
|
||||
class UHatIsTransformInDisguise(Scene):
|
||||
def construct(self):
|
||||
u_tex = "$\\hat{\\textbf{u}}$"
|
||||
words = TextMobject(
|
||||
u_tex,
|
||||
"is secretly a \\\\",
|
||||
"transform",
|
||||
"in disguise",
|
||||
)
|
||||
words.highlight_by_tex(u_tex, YELLOW)
|
||||
words.highlight_by_tex("transform", BLUE)
|
||||
words.scale(2)
|
||||
|
||||
self.play(Write(words))
|
||||
self.dither()
|
||||
|
||||
class ScaleUpUHat(ProjectOntoUnitVectorNumberline) :
|
||||
CONFIG = {
|
||||
"animate_setup" : False,
|
||||
"u_hat_color" : YELLOW,
|
||||
"tilt_angle" : np.pi/6,
|
||||
"scalar" : 3,
|
||||
}
|
||||
def construct(self):
|
||||
self.scale_u_hat()
|
||||
self.show_matrix()
|
||||
self.transform_basis_vectors()
|
||||
self.transform_some_vector()
|
||||
|
||||
def scale_u_hat(self):
|
||||
self.u_hat.coords = Matrix(["u_x", "u_y"])
|
||||
new_u = self.u_hat.copy().scale(self.scalar)
|
||||
new_u.coords = Matrix([
|
||||
"%du_x"%self.scalar,
|
||||
"%du_y"%self.scalar,
|
||||
])
|
||||
for v in self.u_hat, new_u:
|
||||
v.coords.get_entries().highlight(YELLOW)
|
||||
v.coords.add_to_back(BackgroundRectangle(v.coords))
|
||||
v.coords.next_to(v.get_end(), UP+LEFT)
|
||||
|
||||
self.play(Write(self.u_hat.coords))
|
||||
self.play(Transform(self.u_hat, new_u))
|
||||
self.play(Transform(self.u_hat.coords, new_u.coords))
|
||||
self.dither()
|
||||
|
||||
def show_matrix(self):
|
||||
matrix = Matrix([list(self.u_hat.coords.get_entries().copy())])
|
||||
matrix.highlight_columns(X_COLOR, Y_COLOR)
|
||||
matrix.add_to_back(BackgroundRectangle(matrix))
|
||||
brace = Brace(matrix)
|
||||
words = TextMobject(
|
||||
"\\centering Associated\\\\",
|
||||
"transformation"
|
||||
)
|
||||
words.highlight_by_tex("transformation", BLUE)
|
||||
words.add_background_rectangle()
|
||||
brace.put_at_tip(words)
|
||||
Group(matrix, brace, words).to_corner(UP+LEFT)
|
||||
|
||||
self.play(Transform(
|
||||
self.u_hat.coords, matrix
|
||||
))
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(words, run_time = 2)
|
||||
)
|
||||
self.dither()
|
||||
self.matrix_words = words
|
||||
|
||||
def transform_basis_vectors(self):
|
||||
start_state = list(self.get_mobjects())
|
||||
bases = self.get_basis_vectors()
|
||||
for b, char in zip(bases, ["x", "y"]):
|
||||
b.proj = get_vect_mob_projection(b, self.u_hat)
|
||||
b.proj_line = DashedLine(
|
||||
b.get_end(), b.proj.get_end(),
|
||||
dashed_segment_length = 0.75
|
||||
)
|
||||
b.proj.label = TexMobject("u_%s"%char)
|
||||
b.proj.label.highlight(b.get_color())
|
||||
b.scaled_proj = b.proj.copy().scale(self.scalar)
|
||||
b.scaled_proj.label = Group(
|
||||
TexMobject(str(self.scalar)).highlight(b.get_color()),
|
||||
b.proj.label.copy()
|
||||
).arrange_submobjects(aligned_edge = DOWN)
|
||||
for v in b.proj, b.scaled_proj:
|
||||
v.label.next_to(v.get_end(), UP+LEFT)
|
||||
|
||||
self.play(*map(ShowCreation, bases))
|
||||
for b in bases:
|
||||
mover = b.copy()
|
||||
self.play(ShowCreation(b.proj_line))
|
||||
self.play(Transform(mover, b.proj))
|
||||
self.play(Write(b.proj.label))
|
||||
self.dither()
|
||||
self.play(
|
||||
Transform(mover, b.scaled_proj),
|
||||
Transform(b.proj.label, b.scaled_proj.label)
|
||||
)
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, [
|
||||
mob
|
||||
for mob in self.get_mobjects()
|
||||
if mob not in start_state
|
||||
]))
|
||||
|
||||
def transform_some_vector(self):
|
||||
words = TextMobject(
|
||||
"\\centering Project",
|
||||
"then scale"
|
||||
)
|
||||
words.move_to(self.matrix_words, aligned_edge = UP)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# get_proj_lines(self, dots, proj_dots)
|
||||
# get_proj_dots(self, dots)
|
||||
# get_dots(self, vectors)
|
||||
# get_vectors(self, num_vectors = 10, randomize = True)
|
||||
|
||||
|
||||
|
||||
|
@ -302,7 +302,7 @@ class MatrixInTheWild(Scene):
|
||||
self.play(Blink(randy))
|
||||
self.dither(2)
|
||||
new_matrix = Matrix([[3, 1, 4], [1, 5, 9]])
|
||||
new_matrix.move_to(matrix, side_to_align = UP+LEFT)
|
||||
new_matrix.move_to(matrix, aligned_edge = UP+LEFT)
|
||||
self.play(
|
||||
Transform(matrix, new_matrix),
|
||||
FadeOut(bubble)
|
||||
|
@ -216,19 +216,28 @@ class Mobject(object):
|
||||
def to_edge(self, edge = LEFT, buff = DEFAULT_MOBJECT_TO_EDGE_BUFFER):
|
||||
return self.align_on_border(edge, buff)
|
||||
|
||||
def next_to(self, mobject_or_point,
|
||||
def next_to(self, mobject_or_point,
|
||||
direction = RIGHT,
|
||||
buff = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
||||
aligned_edge = ORIGIN):
|
||||
aligned_edge = ORIGIN,
|
||||
align_using_submobjects = False,
|
||||
):
|
||||
if isinstance(mobject_or_point, Mobject):
|
||||
mob = mobject_or_point
|
||||
target_point = mob.get_critical_point(aligned_edge+direction)
|
||||
target_point = mob.get_critical_point(
|
||||
aligned_edge+direction,
|
||||
use_submobject = align_using_submobjects
|
||||
)
|
||||
else:
|
||||
target_point = mobject_or_point
|
||||
point_to_align = self.get_critical_point(aligned_edge-direction)
|
||||
point_to_align = self.get_critical_point(
|
||||
aligned_edge-direction,
|
||||
use_submobject = align_using_submobjects
|
||||
)
|
||||
self.shift(target_point - point_to_align + buff*direction)
|
||||
return self
|
||||
|
||||
|
||||
def shift_onto_screen(self, **kwargs):
|
||||
space_lengths = [SPACE_WIDTH, SPACE_HEIGHT]
|
||||
for vect in UP, DOWN, LEFT, RIGHT:
|
||||
@ -258,12 +267,12 @@ class Mobject(object):
|
||||
def scale_to_fit_height(self, height):
|
||||
return self.stretch_to_fit(height, 1, stretch = False)
|
||||
|
||||
def move_to(self, point_or_mobject, side_to_align = ORIGIN):
|
||||
def move_to(self, point_or_mobject, aligned_edge = ORIGIN):
|
||||
if isinstance(point_or_mobject, Mobject):
|
||||
target = point_or_mobject.get_critical_point(side_to_align)
|
||||
target = point_or_mobject.get_critical_point(aligned_edge)
|
||||
else:
|
||||
target = point_or_mobject
|
||||
point_to_align = self.get_critical_point(side_to_align)
|
||||
point_to_align = self.get_critical_point(aligned_edge)
|
||||
self.shift(target - point_to_align)
|
||||
return self
|
||||
|
||||
@ -398,7 +407,9 @@ class Mobject(object):
|
||||
def get_num_points(self):
|
||||
return len(self.points)
|
||||
|
||||
def get_critical_point(self, direction):
|
||||
def get_critical_point(self, direction, use_submobject = False):
|
||||
if use_submobject:
|
||||
return self.get_submobject_critical_point(direction)
|
||||
result = np.zeros(self.dim)
|
||||
for dim in [0, 1]:
|
||||
if direction[dim] <= 0:
|
||||
@ -414,6 +425,17 @@ class Mobject(object):
|
||||
result[dim] = max_point
|
||||
return result
|
||||
|
||||
def get_submobject_critical_point(self, direction):
|
||||
if len(self.split()) == 1:
|
||||
return self.get_critical_point(direction)
|
||||
index = np.argmax([
|
||||
np.dot(submob.get_center(), direction)
|
||||
for submob in self
|
||||
])
|
||||
return self[index].get_critical_point(
|
||||
direction, use_submobject = True
|
||||
)
|
||||
|
||||
# Pseudonyms for more general get_critical_point method
|
||||
def get_edge_center(self, direction):
|
||||
return self.get_critical_point(direction)
|
||||
|
@ -94,7 +94,7 @@ class PiCreature(SVGMobject):
|
||||
def look(self, direction):
|
||||
x, y = direction[:2]
|
||||
for pupil, eye in zip(self.pupils.split(), self.eyes.split()):
|
||||
pupil.move_to(eye, side_to_align = direction)
|
||||
pupil.move_to(eye, aligned_edge = direction)
|
||||
#Some hacky nudging is required here
|
||||
if y > 0 and x != 0: # Look up and to a side
|
||||
nudge_size = pupil.get_height()/4.
|
||||
|
@ -135,7 +135,7 @@ class Line(VMobject):
|
||||
|
||||
class DashedLine(Line):
|
||||
CONFIG = {
|
||||
"dashed_segment_length" : 0.25
|
||||
"dashed_segment_length" : 0.15
|
||||
}
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.init_kwargs = kwargs
|
||||
|
Reference in New Issue
Block a user