mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Finished initial animations for chapter 5
This commit is contained in:
parent
4f42f62b3c
commit
f52179c3d9
5 changed files with 760 additions and 15 deletions
|
@ -35,6 +35,8 @@ class Animation(object):
|
|||
|
||||
def update_config(self, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
if "rate_func" in kwargs and kwargs["rate_func"] is None:
|
||||
self.rate_func = (lambda x : x)
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -137,7 +137,8 @@ class Rotate(ApplyMethod):
|
|||
"in_place" : False,
|
||||
}
|
||||
def __init__(self, mobject, angle = np.pi, axis = OUT, **kwargs):
|
||||
kwargs["path_arc"] = angle
|
||||
if "path_arc" not in kwargs:
|
||||
kwargs["path_arc"] = angle
|
||||
digest_config(self, kwargs, locals())
|
||||
if self.in_place:
|
||||
method = mobject.rotate_in_place
|
||||
|
|
746
eola/chapter5.py
746
eola/chapter5.py
|
@ -21,6 +21,24 @@ from eola.matrix import *
|
|||
from eola.two_d_space import *
|
||||
from eola.chapter3 import MatrixVectorMultiplicationAbstract
|
||||
|
||||
def get_det_text(matrix, determinant = None):
|
||||
parens = TexMobject(["(", ")"])
|
||||
parens.scale(2)
|
||||
parens.stretch_to_fit_height(matrix.get_height())
|
||||
l_paren, r_paren = parens.split()
|
||||
l_paren.next_to(matrix, LEFT, buff = 0.1)
|
||||
r_paren.next_to(matrix, RIGHT, buff = 0.1)
|
||||
det = TextMobject("det").next_to(l_paren, LEFT, buff = 0.1)
|
||||
det.add_background_rectangle()
|
||||
det_text = VMobject(det, l_paren, r_paren)
|
||||
if determinant is not None:
|
||||
eq = TexMobject("=")
|
||||
eq.next_to(r_paren, RIGHT, buff = 0.1)
|
||||
result = TexMobject(str(determinant))
|
||||
result.next_to(eq, RIGHT, buff = 0.2)
|
||||
det_text.add(eq, result)
|
||||
return det_text
|
||||
|
||||
class Blob(Circle):
|
||||
CONFIG = {
|
||||
"stroke_color" : TEAL,
|
||||
|
@ -49,6 +67,15 @@ class Blob(Circle):
|
|||
)
|
||||
return sum(in_center_direction) <= 2
|
||||
|
||||
class RightHand(VMobject):
|
||||
def __init__(self, **kwargs):
|
||||
hand = SVGMobject("RightHandOutline")
|
||||
self.inlines = VMobject(*hand.split()[:-4])
|
||||
self.outline = VMobject(*hand.split()[-4:])
|
||||
self.outline.set_stroke(color = WHITE, width = 5)
|
||||
self.inlines.set_stroke(color = DARK_GREY, width = 3)
|
||||
VMobject.__init__(self, self.outline, self.inlines)
|
||||
self.center().scale_to_fit_height(3)
|
||||
|
||||
class OpeningQuote(Scene):
|
||||
def construct(self):
|
||||
|
@ -378,20 +405,15 @@ class NameDeterminant(LinearTransformationScene):
|
|||
matrix.next_to(self.title, DOWN, buff = 0.5)
|
||||
matrix.shift(2*LEFT)
|
||||
matrix_background = BackgroundRectangle(matrix)
|
||||
|
||||
braces = TexMobject("()")
|
||||
braces.scale(2)
|
||||
braces.stretch_to_fit_height(matrix.get_height())
|
||||
l_brace, r_brace = braces.split()
|
||||
l_brace.next_to(matrix, LEFT, buff = 0.1)
|
||||
r_brace.next_to(matrix, RIGHT, buff = 0.1)
|
||||
det = TextMobject("det").next_to(l_brace, LEFT, buff = 0.1)
|
||||
det.add_background_rectangle()
|
||||
eq = TexMobject("=").next_to(r_brace, RIGHT, buff = 0.1)
|
||||
|
||||
det_text = VMobject(det, l_brace, r_brace, eq)
|
||||
det_text = get_det_text(matrix, 0)
|
||||
det_text.remove(det_text.split()[-1])
|
||||
return matrix_background, matrix, det_text
|
||||
|
||||
class DeterminantIsThree(NameDeterminant):
|
||||
CONFIG = {
|
||||
"t_matrix" : [[0, -1.5], [2, 1]]
|
||||
}
|
||||
|
||||
class DeterminantIsOneHalf(NameDeterminant):
|
||||
CONFIG = {
|
||||
"t_matrix" : [[0.5, -0.5], [0.5, 0.5]],
|
||||
|
@ -404,9 +426,707 @@ class DeterminantIsOneHalf(NameDeterminant):
|
|||
|
||||
class DeterminantIsZero(NameDeterminant):
|
||||
CONFIG = {
|
||||
"t_matrix" : [[2, 1], [2, 1]],
|
||||
"t_matrix" : [[4, 2], [2, 1]],
|
||||
}
|
||||
|
||||
class NextFewVideos(Scene):
|
||||
def construct(self):
|
||||
icon = SVGMobject("video_icon")
|
||||
icon.center()
|
||||
icon.scale_to_fit_width(2*SPACE_WIDTH/12.)
|
||||
icon.set_stroke(color = WHITE, width = 0)
|
||||
icon.set_fill(WHITE, opacity = 1)
|
||||
icons = VMobject(*[icon.copy() for x in range(10)])
|
||||
icons.submobject_gradient_highlight(BLUE_A, BLUE_D)
|
||||
icons.arrange_submobjects(RIGHT)
|
||||
icons.to_edge(LEFT)
|
||||
|
||||
self.play(
|
||||
FadeIn(icons, submobject_mode = "lagged_start"),
|
||||
run_time = 3
|
||||
)
|
||||
self.dither()
|
||||
|
||||
class WhatIveSaidSoFar(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.teacher_says("""
|
||||
What I've said so far
|
||||
is not quite right...
|
||||
""")
|
||||
self.dither()
|
||||
|
||||
class NegativeDeterminant(Scene):
|
||||
def construct(self):
|
||||
numerical_matrix = [[1, 2], [3, 4]]
|
||||
matrix = Matrix(numerical_matrix)
|
||||
matrix.highlight_columns(X_COLOR, Y_COLOR)
|
||||
det_text = get_det_text(matrix, np.linalg.det(numerical_matrix))
|
||||
words = TextMobject("""
|
||||
How can you scale area
|
||||
by a negative number?
|
||||
""")
|
||||
words.highlight(YELLOW)
|
||||
words.to_corner(UP+RIGHT)
|
||||
det_num = det_text.split()[-1]
|
||||
arrow = Arrow(words.get_bottom(), det_num)
|
||||
|
||||
self.add(matrix)
|
||||
self.play(Write(det_text))
|
||||
self.dither()
|
||||
self.play(
|
||||
Write(words, run_time = 2),
|
||||
ShowCreation(arrow)
|
||||
)
|
||||
self.play(det_num.highlight, YELLOW)
|
||||
self.dither()
|
||||
|
||||
class FlipSpaceOver(Scene):
|
||||
def construct(self):
|
||||
plane1 = NumberPlane(y_radius = SPACE_WIDTH)
|
||||
plane2 = NumberPlane(
|
||||
y_radius = SPACE_WIDTH,
|
||||
color = RED_D, secondary_color = RED_E
|
||||
)
|
||||
axis = UP
|
||||
for word, plane in ("Front", plane1), ("Back", plane2):
|
||||
text = TextMobject(word)
|
||||
if word == "Back":
|
||||
text.rotate(np.pi, axis = axis)
|
||||
text.scale(2)
|
||||
text.next_to(ORIGIN, RIGHT).to_edge(UP)
|
||||
text.add_background_rectangle()
|
||||
plane.add(text)
|
||||
|
||||
self.play(ShowCreation(
|
||||
plane1, submobject_mode = "lagged_start",
|
||||
run_time = 1
|
||||
))
|
||||
self.dither()
|
||||
self.play(Rotate(
|
||||
plane1, axis = axis,
|
||||
rate_func = lambda t : smooth(t/2),
|
||||
run_time = 1.5,
|
||||
path_arc = np.pi/2,
|
||||
))
|
||||
self.remove(plane1)
|
||||
self.play(Rotate(
|
||||
plane2, axis = axis,
|
||||
rate_func = lambda t : smooth((t+1)/2),
|
||||
run_time = 1.5,
|
||||
path_arc = np.pi/2,
|
||||
))
|
||||
self.dither()
|
||||
|
||||
class RandyThinking(Scene):
|
||||
def construct(self):
|
||||
randy = Randolph().to_corner()
|
||||
bubble = randy.get_bubble()
|
||||
bubble.make_green_screen()
|
||||
|
||||
self.play(
|
||||
randy.change_mode, "pondering",
|
||||
ShowCreation(bubble)
|
||||
)
|
||||
self.dither()
|
||||
self.play(Blink(randy))
|
||||
self.dither(2)
|
||||
self.play(Blink(randy))
|
||||
|
||||
class NegativeDeterminantTransformation(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"t_matrix" : [[1, 1], [2, -1]],
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.add_title("Feels like flipping space")
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(self.t_matrix)
|
||||
self.dither()
|
||||
|
||||
class ThinkAboutFlippingPaper(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
class NegativeDeterminantTransformation2(NegativeDeterminantTransformation):
|
||||
CONFIG ={
|
||||
"t_matrix" : [[-2, 1], [2, 1]]
|
||||
}
|
||||
|
||||
class IHatJHatOrientation(NegativeDeterminantTransformation):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
i_label, j_label = self.get_basis_vector_labels()
|
||||
self.add_transformable_label(self.i_hat, i_label, color = X_COLOR)
|
||||
self.add_transformable_label(self.j_hat, j_label, color = Y_COLOR)
|
||||
|
||||
arc = Arc(start_angle = 0, angle = np.pi/2, color = YELLOW)
|
||||
arc.shift(0.5*(RIGHT+UP)).scale(1/1.6)
|
||||
arc.add_tip()
|
||||
words1 = TextMobject([
|
||||
"$\\hat{\\jmath}$",
|
||||
"is to the",
|
||||
"left",
|
||||
"of",
|
||||
"$\\hat{\\imath}$",
|
||||
])
|
||||
words1.split()[0].highlight(Y_COLOR)
|
||||
words1.split()[2].highlight(YELLOW)
|
||||
words1.split()[-1].highlight(X_COLOR)
|
||||
words1.add_background_rectangle()
|
||||
words1.next_to(arc, UP+RIGHT)
|
||||
|
||||
words2 = TextMobject([
|
||||
"$L(\\hat{\\jmath})$",
|
||||
"is to the \\\\",
|
||||
"\\emph{right}",
|
||||
"of",
|
||||
"$L(\\hat{\\imath})$",
|
||||
])
|
||||
words2.split()[0].highlight(Y_COLOR)
|
||||
words2.split()[2].highlight(YELLOW)
|
||||
words2.split()[-1].highlight(X_COLOR)
|
||||
words2.add_background_rectangle()
|
||||
|
||||
|
||||
self.play(ShowCreation(arc))
|
||||
self.play(Write(words1))
|
||||
self.dither()
|
||||
self.remove(words1, arc)
|
||||
self.apply_transposed_matrix(self.t_matrix)
|
||||
arc.submobjects = []
|
||||
arc.apply_function(self.get_matrix_transformation(self.t_matrix))
|
||||
arc.add_tip()
|
||||
words2.next_to(arc, RIGHT)
|
||||
self.play(
|
||||
ShowCreation(arc),
|
||||
Write(words2, run_time = 2),
|
||||
)
|
||||
self.dither()
|
||||
title = TextMobject("Orientation has been reversed")
|
||||
title.to_edge(UP)
|
||||
title.add_background_rectangle()
|
||||
self.play(Write(title, run_time = 1))
|
||||
self.dither()
|
||||
|
||||
class WriteNegativeDeterminant(NegativeDeterminantTransformation):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.add_unit_square()
|
||||
matrix = Matrix(np.array(self.t_matrix).transpose())
|
||||
matrix.next_to(ORIGIN, LEFT)
|
||||
matrix.to_edge(UP)
|
||||
matrix.highlight_columns(X_COLOR, Y_COLOR)
|
||||
|
||||
det_text = get_det_text(
|
||||
matrix, determinant = np.linalg.det(self.t_matrix)
|
||||
)
|
||||
three = VMobject(*det_text.split()[-1].split()[1:])
|
||||
for mob in det_text.split():
|
||||
if isinstance(mob, TexMobject):
|
||||
mob.add_background_rectangle()
|
||||
matrix_background = BackgroundRectangle(matrix)
|
||||
self.play(
|
||||
ShowCreation(matrix_background),
|
||||
Write(matrix),
|
||||
Write(det_text),
|
||||
)
|
||||
self.add_foreground_mobject(matrix_background, matrix, det_text)
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(self.t_matrix)
|
||||
|
||||
self.play(three.copy().move_to, self.square)
|
||||
self.dither()
|
||||
|
||||
class AltWriteNegativeDeterminant(WriteNegativeDeterminant):
|
||||
CONFIG = {
|
||||
"t_matrix" : [[2, -1], [1, -3]]
|
||||
}
|
||||
|
||||
class WhyNegativeScaling(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.student_says("""
|
||||
Why does negative area
|
||||
relate to orientation-flipping?
|
||||
""")
|
||||
other_students = np.array(self.get_students())[[0, 2]]
|
||||
self.play(*[
|
||||
ApplyMethod(student.change_mode, "confused")
|
||||
for student in other_students
|
||||
])
|
||||
self.random_blink()
|
||||
self.dither()
|
||||
self.random_blink()
|
||||
|
||||
class SlowlyRotateIHat(LinearTransformationScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.add_unit_square()
|
||||
self.apply_transposed_matrix(
|
||||
[[-1, 0], [0, 1]],
|
||||
path_arc = np.pi,
|
||||
run_time = 30,
|
||||
rate_func = None,
|
||||
)
|
||||
|
||||
class DeterminantGraphForRotatingIHat(Scene):
|
||||
def construct(self):
|
||||
t_axis = NumberLine(
|
||||
numbers_with_elongated_ticks = [],
|
||||
x_min = 0,
|
||||
x_max = 10,
|
||||
color = WHITE,
|
||||
)
|
||||
det_axis = NumberLine(
|
||||
numbers_with_elongated_ticks = [],
|
||||
x_min = -2,
|
||||
x_max = 2,
|
||||
color = WHITE
|
||||
)
|
||||
det_axis.rotate(np.pi/2)
|
||||
t_axis.next_to(ORIGIN, RIGHT, buff = 0)
|
||||
det_axis.move_to(t_axis.get_left())
|
||||
axes = VMobject(det_axis, t_axis)
|
||||
graph = FunctionGraph(np.cos, x_min = 0, x_max = np.pi)
|
||||
graph.next_to(det_axis, RIGHT, buff = 0)
|
||||
graph.highlight(YELLOW)
|
||||
det_word = TextMobject("Det")
|
||||
det_word.next_to(det_axis, RIGHT, aligned_edge = UP)
|
||||
time_word = TextMobject("time")
|
||||
time_word.next_to(t_axis, UP)
|
||||
time_word.to_edge(RIGHT)
|
||||
everything = VMobject(axes, det_word, time_word, graph)
|
||||
everything.scale(1.5)
|
||||
|
||||
self.add(axes, det_word, time_word)
|
||||
self.play(ShowCreation(
|
||||
graph, rate_func = None, run_time = 10
|
||||
))
|
||||
|
||||
class WhatAboutThreeDimensions(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.student_says("""
|
||||
What about 3D
|
||||
transformations?
|
||||
""")
|
||||
self.random_blink()
|
||||
self.dither()
|
||||
self.random_blink()
|
||||
|
||||
class Transforming3DCube(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
class NameParallelepiped(Scene):
|
||||
def construct(self):
|
||||
word = TextMobject("``Parallelepiped''")
|
||||
word.scale(2)
|
||||
pp_part1 = VMobject(*word.split()[:len(word.split())/2])
|
||||
pp_part2 = VMobject(*word.split()[len(word.split())/2:])
|
||||
pp_part1.submobject_gradient_highlight(X_COLOR, Y_COLOR)
|
||||
pp_part2.submobject_gradient_highlight(Y_COLOR, Z_COLOR)
|
||||
self.play(Write(word))
|
||||
self.dither(2)
|
||||
|
||||
class DeterminantIsVolumeOfParallelepiped(Scene):
|
||||
def construct(self):
|
||||
matrix = Matrix([[1, 0, 0.5], [0.5, 1, 0], [1, 0, 1]])
|
||||
matrix.shift(3*LEFT)
|
||||
matrix.highlight_columns(X_COLOR, Y_COLOR, Z_COLOR)
|
||||
det_text = get_det_text(matrix)
|
||||
eq = TexMobject("=")
|
||||
eq.next_to(det_text, RIGHT)
|
||||
words = TextMobject([
|
||||
"Volume of this\\\\",
|
||||
"parallelepiped"
|
||||
])
|
||||
pp = words.split()[1]
|
||||
pp_part1 = VMobject(*pp.split()[:len(pp.split())/2])
|
||||
pp_part2 = VMobject(*pp.split()[len(pp.split())/2:])
|
||||
pp_part1.submobject_gradient_highlight(X_COLOR, Y_COLOR)
|
||||
pp_part2.submobject_gradient_highlight(Y_COLOR, Z_COLOR)
|
||||
|
||||
words.next_to(eq, RIGHT)
|
||||
|
||||
self.play(Write(matrix))
|
||||
self.dither()
|
||||
self.play(Write(det_text), Write(words), Write(eq))
|
||||
self.dither()
|
||||
|
||||
class Degenerate3DTransformation(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
class WriteZeroDeterminant(Scene):
|
||||
def construct(self):
|
||||
matrix = Matrix([[1, 0, 1], [0.5, 1, 1.5], [1, 0, 1]])
|
||||
matrix.shift(2*LEFT)
|
||||
matrix.highlight_columns(X_COLOR, Y_COLOR, Z_COLOR)
|
||||
det_text = get_det_text(matrix, 0)
|
||||
brace = Brace(matrix, DOWN)
|
||||
words = TextMobject("""
|
||||
Columns must be
|
||||
linearly dependent
|
||||
""")
|
||||
words.highlight(YELLOW)
|
||||
words.next_to(brace, DOWN)
|
||||
|
||||
self.play(Write(matrix))
|
||||
self.dither()
|
||||
self.play(Write(det_text))
|
||||
self.dither()
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(words, run_time = 2)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
class AskAboutNegaive3DDeterminant(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.student_says("""
|
||||
What would det$(M) < 0$ mean?
|
||||
""")
|
||||
self.random_blink()
|
||||
self.play(self.teacher.change_mode, "pondering")
|
||||
self.dither()
|
||||
self.random_blink()
|
||||
|
||||
class OrientationReversing3DTransformation(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
class RightHandRule(Scene):
|
||||
CONFIG = {
|
||||
"flip" : False
|
||||
}
|
||||
def construct(self):
|
||||
hand = RightHand()
|
||||
i_hat = Vector([-1.75, 0.5])
|
||||
j_hat = Vector([-1.4, -0.7])
|
||||
k_hat = Vector([0, 1.7])
|
||||
i_label, j_label, k_label = [
|
||||
TexMobject("\\hat{%s}"%s).scale(1.5)
|
||||
for s in "\\imath", "\\jmath", "k"
|
||||
]
|
||||
i_label.next_to(i_hat.get_end(), UP)
|
||||
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(
|
||||
ShowCreation(hand.outline, run_time = 2, rate_func = None),
|
||||
FadeIn(hand.inlines)
|
||||
)
|
||||
self.dither()
|
||||
for vect, label, color in zip(vects, labels, colors):
|
||||
vect.highlight(color)
|
||||
label.highlight(color)
|
||||
vect.set_stroke(width = 8)
|
||||
self.play(ShowCreation(vect))
|
||||
self.play(Write(label))
|
||||
self.dither()
|
||||
|
||||
class LeftHandRule(RightHandRule):
|
||||
CONFIG = {
|
||||
"flip" : True
|
||||
}
|
||||
|
||||
class TwoDDeterminantFormula(Scene):
|
||||
def construct(self):
|
||||
eq = TextMobject("=")
|
||||
matrix = Matrix([["a", "b"], ["c", "d"]])
|
||||
matrix.highlight_columns(X_COLOR, Y_COLOR)
|
||||
ma, mb, mc, md = matrix.get_entries().split()
|
||||
ma.shift(0.1*DOWN)
|
||||
mc.shift(0.7*mc.get_height()*DOWN)
|
||||
det_text = get_det_text(matrix)
|
||||
VMobject(matrix, det_text).next_to(eq, LEFT)
|
||||
formula = TexMobject(list("ad-bc"))
|
||||
formula.next_to(eq, RIGHT)
|
||||
formula.shift(0.2*UP)
|
||||
|
||||
a, d, minus, b, c = formula.split()
|
||||
VMobject(a, c).highlight(X_COLOR)
|
||||
VMobject(b, d).highlight(Y_COLOR)
|
||||
|
||||
for mob in mb, mc, b, c:
|
||||
if mob is c:
|
||||
mob.zero = TexMobject("\\cdot 0")
|
||||
else:
|
||||
mob.zero = TexMobject("0")
|
||||
mob.zero.move_to(mob, side_to_align = DOWN+LEFT)
|
||||
mob.zero.highlight(mob.get_color())
|
||||
mob.original = mob.copy()
|
||||
c.zero.shift(0.1*RIGHT)
|
||||
|
||||
self.add(matrix)
|
||||
self.play(Write(det_text, run_time = 1))
|
||||
self.play(Write(eq), Write(formula))
|
||||
self.dither()
|
||||
self.play(*[
|
||||
Transform(m, m.zero)
|
||||
for m in mb, mc, b, c
|
||||
])
|
||||
self.dither()
|
||||
for pair in (mc, c), (mb, b):
|
||||
self.play(*[
|
||||
Transform(m, m.original)
|
||||
for m in pair
|
||||
])
|
||||
self.dither()
|
||||
|
||||
class TwoDDeterminantFormulaIntuition(LinearTransformationScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.add_unit_square()
|
||||
a, b, c, d = 3, 2, 3.5, 2
|
||||
|
||||
self.dither()
|
||||
self.apply_transposed_matrix([[a, 0], [0, 1]])
|
||||
i_brace = Brace(self.i_hat, DOWN)
|
||||
width = TexMobject("a").scale(1.5)
|
||||
i_brace.put_at_tip(width)
|
||||
width.highlight(X_COLOR)
|
||||
width.add_background_rectangle()
|
||||
self.play(GrowFromCenter(i_brace), Write(width))
|
||||
self.dither()
|
||||
|
||||
self.apply_transposed_matrix([[1, 0], [0, d]])
|
||||
side_brace = Brace(self.square, RIGHT)
|
||||
height = TexMobject("d").scale(1.5)
|
||||
side_brace.put_at_tip(height)
|
||||
height.highlight(Y_COLOR)
|
||||
height.add_background_rectangle()
|
||||
self.play(GrowFromCenter(side_brace), Write(height))
|
||||
self.dither()
|
||||
|
||||
self.apply_transposed_matrix(
|
||||
[[1, 0], [float(b)/d, 1]],
|
||||
added_anims = [
|
||||
ApplyMethod(m.shift, b*RIGHT)
|
||||
for m in side_brace, height
|
||||
]
|
||||
)
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, [i_brace, side_brace, width, height]))
|
||||
matrix1 = np.dot(
|
||||
[[a, b], [c, d]],
|
||||
np.linalg.inv([[a, b], [0, d]])
|
||||
)
|
||||
matrix2 = np.dot(
|
||||
[[a, b], [-c, d]],
|
||||
np.linalg.inv([[a, b], [c, d]])
|
||||
)
|
||||
self.apply_transposed_matrix(matrix1.transpose(), path_arc = 0)
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(matrix2.transpose(), path_arc = 0)
|
||||
self.dither()
|
||||
|
||||
class FullFormulaExplanation(LinearTransformationScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.add_unit_square()
|
||||
self.apply_transposed_matrix([[3, 1], [1, 2]], run_time = 0)
|
||||
self.add_braces()
|
||||
self.add_polygons()
|
||||
self.show_formula()
|
||||
|
||||
def get_matrix(self):
|
||||
matrix = Matrix([["a", "b"], ["c", "d"]])
|
||||
matrix.highlight_columns(X_COLOR, Y_COLOR)
|
||||
ma, mb, mc, md = matrix.get_entries().split()
|
||||
ma.shift(0.1*DOWN)
|
||||
mc.shift(0.7*mc.get_height()*DOWN)
|
||||
matrix.shift(2*DOWN+4*LEFT)
|
||||
return matrix
|
||||
|
||||
def add_polygons(self):
|
||||
a = self.i_hat.get_end()[0]*RIGHT
|
||||
b = self.j_hat.get_end()[0]*RIGHT
|
||||
c = self.i_hat.get_end()[1]*UP
|
||||
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(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"),
|
||||
]
|
||||
everyone = VMobject()
|
||||
for shape, color, tex in shapes_colors_and_tex:
|
||||
shape.set_stroke(width = 0)
|
||||
shape.set_fill(color = color, opacity = 0.7)
|
||||
tex_mob = TexMobject(tex)
|
||||
tex_mob.scale(0.7)
|
||||
tex_mob.move_to(shape.get_center_of_mass())
|
||||
everyone.add(shape, tex_mob)
|
||||
self.play(FadeIn(
|
||||
everyone,
|
||||
submobject_mode = "lagged_start",
|
||||
run_time = 1
|
||||
))
|
||||
|
||||
|
||||
|
||||
def add_braces(self):
|
||||
a = self.i_hat.get_end()[0]*RIGHT
|
||||
b = self.j_hat.get_end()[0]*RIGHT
|
||||
c = self.i_hat.get_end()[1]*UP
|
||||
d = self.j_hat.get_end()[1]*UP
|
||||
|
||||
quads = [
|
||||
(ORIGIN, a, DOWN, "a"),
|
||||
(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"),
|
||||
(d+c, d, LEFT, "c"),
|
||||
(d, ORIGIN, LEFT, "d"),
|
||||
]
|
||||
everyone = VMobject()
|
||||
for p1, p2, direction, char in quads:
|
||||
line = Line(p1, p2)
|
||||
brace = Brace(line, direction, buff = 0)
|
||||
text = brace.get_text(char)
|
||||
text.add_background_rectangle()
|
||||
if char in ["a", "c"]:
|
||||
text.highlight(X_COLOR)
|
||||
else:
|
||||
text.highlight(Y_COLOR)
|
||||
everyone.add(brace, text)
|
||||
self.play(Write(everyone), run_time = 1)
|
||||
|
||||
|
||||
def show_formula(self):
|
||||
matrix = self.get_matrix()
|
||||
det_text = get_det_text(matrix)
|
||||
f_str = "=(a+b)(c+d)-ac-bd-2bc=ad-bc"
|
||||
formula = TexMobject(f_str)
|
||||
|
||||
formula.next_to(det_text, RIGHT)
|
||||
everyone = VMobject(det_text, matrix, formula)
|
||||
everyone.scale_to_fit_width(2*SPACE_WIDTH - 1)
|
||||
everyone.next_to(DOWN, DOWN)
|
||||
background_rect = BackgroundRectangle(everyone)
|
||||
self.play(
|
||||
ShowCreation(background_rect),
|
||||
Write(everyone)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
class ThreeDDetFormula(Scene):
|
||||
def construct(self):
|
||||
matrix = Matrix([list("abc"), list("def"), list("ghi")])
|
||||
matrix.highlight_columns(X_COLOR, Y_COLOR, Z_COLOR)
|
||||
m1 = Matrix([["e", "f"], ["h", "i"]])
|
||||
m1.highlight_columns(Y_COLOR, Z_COLOR)
|
||||
m2 = Matrix([["d", "f"], ["g", "i"]])
|
||||
m2.highlight_columns(X_COLOR, Z_COLOR)
|
||||
m3 = Matrix([["d", "e"], ["g", "h"]])
|
||||
m3.highlight_columns(X_COLOR, Y_COLOR)
|
||||
|
||||
for m in matrix, m1, m2, m3:
|
||||
m.add(get_det_text(m))
|
||||
a, b, c = matrix.get_entries().split()[:3]
|
||||
parts = it.starmap(VMobject, [
|
||||
[matrix],
|
||||
[TexMobject("="), a.copy(), m1],
|
||||
[TexMobject("-"), b.copy(), m2],
|
||||
[TexMobject("+"), c.copy(), m3],
|
||||
])
|
||||
parts = list(parts)
|
||||
for part in parts:
|
||||
part.arrange_submobjects(RIGHT, buff = 0.2)
|
||||
parts[1].next_to(parts[0], RIGHT)
|
||||
parts[2].next_to(parts[1], DOWN, aligned_edge = LEFT)
|
||||
parts[3].next_to(parts[2], DOWN, aligned_edge = LEFT)
|
||||
everyone = VMobject(*parts)
|
||||
everyone.center().to_edge(UP)
|
||||
for part in parts:
|
||||
self.play(Write(part))
|
||||
self.dither(2)
|
||||
|
||||
class QuizTime(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.teacher_says("Quiz time!")
|
||||
self.random_blink()
|
||||
self.dither()
|
||||
self.random_blink()
|
||||
|
||||
class ProductProperty(Scene):
|
||||
def construct(self):
|
||||
lhs = TexMobject([
|
||||
"\\text{det}(",
|
||||
"M_1",
|
||||
"M_2",
|
||||
")"
|
||||
])
|
||||
det, m1, m2, rp = lhs.split()
|
||||
m1.highlight(TEAL)
|
||||
m2.highlight(PINK)
|
||||
|
||||
rhs = TexMobject([
|
||||
"=\\text{det}(",
|
||||
"M_1",
|
||||
")\\text{det}(",
|
||||
"M_2",
|
||||
")"
|
||||
])
|
||||
rhs.split()[1].highlight(TEAL)
|
||||
rhs.split()[3].highlight(PINK)
|
||||
|
||||
rhs.next_to(lhs, RIGHT)
|
||||
formula = VMobject(lhs, rhs)
|
||||
formula.center()
|
||||
|
||||
title = TextMobject("Explain in one sentence")
|
||||
title.highlight(YELLOW)
|
||||
title.next_to(formula, UP, buff = 0.5)
|
||||
|
||||
self.play(Write(m1))
|
||||
self.play(Write(m2))
|
||||
self.dither()
|
||||
self.play(Write(det), Write(rp))
|
||||
self.play(Write(rhs))
|
||||
self.dither(2)
|
||||
self.play(Write(title))
|
||||
self.dither(2)
|
||||
|
||||
class NextVideo(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("""
|
||||
Next video: Inverse matrices, column space and null space
|
||||
""")
|
||||
title.scale_to_fit_width(2*SPACE_WIDTH - 2)
|
||||
title.to_edge(UP)
|
||||
rect = Rectangle(width = 16, height = 9, color = BLUE)
|
||||
rect.scale_to_fit_height(6)
|
||||
rect.next_to(title, DOWN)
|
||||
|
||||
self.add(title)
|
||||
self.play(ShowCreation(rect))
|
||||
self.dither()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -103,7 +103,10 @@ class TexMobject(SVGMobject):
|
|||
)
|
||||
|
||||
def add_background_rectangle(self, color = BLACK, opacity = 0.75):
|
||||
rect = BackgroundRectangle(self, color = color, opacity = opacity)
|
||||
rect = BackgroundRectangle(
|
||||
self, color = color,
|
||||
fill_opacity = opacity
|
||||
)
|
||||
letters = VMobject(*self.submobjects)
|
||||
self.submobjects = [rect, letters]
|
||||
return self
|
||||
|
@ -123,6 +126,7 @@ class Brace(TexMobject):
|
|||
}
|
||||
TEX_STRING = "\\underbrace{%s}"%(3*"\\qquad")
|
||||
def __init__(self, mobject, direction = DOWN, **kwargs):
|
||||
digest_config(self, kwargs, locals())
|
||||
TexMobject.__init__(self, self.TEX_STRING, **kwargs)
|
||||
angle = -np.arctan2(*direction[:2]) + np.pi
|
||||
mobject.rotate(-angle)
|
||||
|
@ -133,6 +137,16 @@ class Brace(TexMobject):
|
|||
for mob in mobject, self:
|
||||
mob.rotate(angle)
|
||||
|
||||
def put_at_tip(self, mob, **kwargs):
|
||||
mob.next_to(self, self.direction, **kwargs)
|
||||
return self
|
||||
|
||||
def get_text(self, text, **kwargs):
|
||||
text_mob = TextMobject(text)
|
||||
self.put_at_tip(text_mob, **kwargs)
|
||||
return text_mob
|
||||
|
||||
|
||||
|
||||
def tex_hash(expression, template_tex_file):
|
||||
return str(hash(expression + template_tex_file))
|
||||
|
|
|
@ -31,6 +31,14 @@ class Arc(VMobject):
|
|||
)
|
||||
]
|
||||
|
||||
def add_tip(self):
|
||||
#TODO, do this a better way
|
||||
arrow = Arrow(*self.points[-2:])
|
||||
self.add(arrow.split()[-1])
|
||||
self.highlight(self.get_color())
|
||||
return self
|
||||
|
||||
|
||||
class Circle(Arc):
|
||||
CONFIG = {
|
||||
"color" : RED,
|
||||
|
|
Loading…
Add table
Reference in a new issue