mirror of
https://github.com/3b1b/manim.git
synced 2025-08-02 19:46:21 +08:00
0
active_projects/eola2/__init__.py
Normal file
0
active_projects/eola2/__init__.py
Normal file
286
active_projects/eola2/determinant_puzzle.py
Normal file
286
active_projects/eola2/determinant_puzzle.py
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
from big_ol_pile_of_manim_imports import *
|
||||||
|
|
||||||
|
|
||||||
|
class WorkOutNumerically(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"M1_COLOR": TEAL,
|
||||||
|
"M2_COLOR": PINK,
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.add_question()
|
||||||
|
self.add_example()
|
||||||
|
self.compute_rhs()
|
||||||
|
self.compute_lhs()
|
||||||
|
|
||||||
|
def add_question(self):
|
||||||
|
equation = self.original_equation = TexMobject(
|
||||||
|
"\\det(", "M_1", "M_2", ")", "=",
|
||||||
|
"\\det(", "M_1", ")",
|
||||||
|
"\\det(", "M_2", ")",
|
||||||
|
)
|
||||||
|
equation.set_color_by_tex_to_color_map({
|
||||||
|
"M_1": self.M1_COLOR,
|
||||||
|
"M_2": self.M2_COLOR,
|
||||||
|
})
|
||||||
|
challenge = TextMobject("Explain in one sentence")
|
||||||
|
challenge.set_color(YELLOW)
|
||||||
|
group = VGroup(challenge, equation)
|
||||||
|
group.arrange_submobjects(DOWN)
|
||||||
|
group.to_edge(UP)
|
||||||
|
|
||||||
|
self.add(equation)
|
||||||
|
self.play(Write(challenge))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
def add_example(self):
|
||||||
|
M1 = self.M1 = Matrix([[2, -1], [1, 1]])
|
||||||
|
M1.set_color(self.M1_COLOR)
|
||||||
|
self.M1_copy = M1.copy()
|
||||||
|
M2 = self.M2 = Matrix([[-1, 4], [1, 1]])
|
||||||
|
M2.set_color(self.M2_COLOR)
|
||||||
|
self.M2_copy = M2.copy()
|
||||||
|
eq_parts = TexMobject(
|
||||||
|
"\\det", "\\big(", "\\big)", "=",
|
||||||
|
"\\det", "\\big(", "\\big)",
|
||||||
|
"\\det", "\\big(", "\\big)",
|
||||||
|
)
|
||||||
|
for part in eq_parts.get_parts_by_tex("\\big"):
|
||||||
|
part.scale(2)
|
||||||
|
part.stretch(1.5, 1)
|
||||||
|
i1, i2, i3 = [
|
||||||
|
eq_parts.index_of_part(part) + 1
|
||||||
|
for part in eq_parts.get_parts_by_tex("\\big(")
|
||||||
|
]
|
||||||
|
equation = self.equation_with_numbers = VGroup(*it.chain(
|
||||||
|
eq_parts[:i1], [M1, M2],
|
||||||
|
eq_parts[i1:i2], [self.M1_copy],
|
||||||
|
eq_parts[i2:i3], [self.M2_copy],
|
||||||
|
eq_parts[i3:],
|
||||||
|
))
|
||||||
|
equation.arrange_submobjects(RIGHT, buff=SMALL_BUFF)
|
||||||
|
eq_parts.get_part_by_tex("=").shift(0.2 * SMALL_BUFF * DOWN)
|
||||||
|
equation.scale_to_fit_width(FRAME_WIDTH - 2 * LARGE_BUFF)
|
||||||
|
equation.next_to(self.original_equation, DOWN, MED_LARGE_BUFF)
|
||||||
|
|
||||||
|
self.play(LaggedStart(FadeIn, equation))
|
||||||
|
|
||||||
|
def compute_rhs(self):
|
||||||
|
M1, M2 = self.M1_copy, self.M2_copy
|
||||||
|
|
||||||
|
line1 = VGroup(
|
||||||
|
TexMobject(
|
||||||
|
"\\big(", "2", "\\cdot", "2", "-",
|
||||||
|
"(-1)", "\\cdot", "1", "\\big)"
|
||||||
|
),
|
||||||
|
TexMobject(
|
||||||
|
"\\big(", "-1", "\\cdot", "1", "-",
|
||||||
|
"4", "\\cdot", "1", "\\big)"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
line1.arrange_submobjects(RIGHT, buff=SMALL_BUFF)
|
||||||
|
line1[0].set_color(self.M1_COLOR)
|
||||||
|
line1[1].set_color(self.M2_COLOR)
|
||||||
|
indices = [1, 3, 5, 7]
|
||||||
|
|
||||||
|
line2 = TexMobject("(3)", "(-5)")
|
||||||
|
line2.match_style(line1)
|
||||||
|
line3 = TexMobject("-15")
|
||||||
|
arrows = [TexMobject("\\downarrow") for x in range(2)]
|
||||||
|
lines = VGroup(line1, arrows[0], line2, arrows[1], line3)
|
||||||
|
lines.arrange_submobjects(DOWN, buff=MED_SMALL_BUFF)
|
||||||
|
lines.next_to(self.equation_with_numbers, DOWN, buff=MED_LARGE_BUFF)
|
||||||
|
lines.to_edge(RIGHT)
|
||||||
|
|
||||||
|
for matrix, det in zip([M1, M2], line1):
|
||||||
|
numbers = VGroup(*[det[i] for i in indices])
|
||||||
|
numbers_iter = iter(numbers)
|
||||||
|
non_numbers = VGroup(*filter(
|
||||||
|
lambda m: m not in numbers,
|
||||||
|
det
|
||||||
|
))
|
||||||
|
matrix_numbers = VGroup(*[
|
||||||
|
matrix.mob_matrix[i][j].copy()
|
||||||
|
for i, j in (0, 0), (1, 1), (0, 1), (1, 0)
|
||||||
|
])
|
||||||
|
self.play(
|
||||||
|
LaggedStart(FadeIn, non_numbers, run_time=1),
|
||||||
|
LaggedStart(
|
||||||
|
ReplacementTransform,
|
||||||
|
matrix_numbers,
|
||||||
|
lambda m: (m, numbers_iter.next()),
|
||||||
|
path_arc=TAU / 6
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.play(LaggedStart(FadeIn, lines[1:], run_time=3))
|
||||||
|
|
||||||
|
def compute_lhs(self):
|
||||||
|
matrix = Matrix([[-3, 7], [0, 5]])
|
||||||
|
matrix.set_color(BLUE)
|
||||||
|
matrix.scale(0.8)
|
||||||
|
empty_det_tex = TexMobject("\\det", "\\big(", "\\big)")
|
||||||
|
empty_det_tex[1:].scale(1.5)
|
||||||
|
empty_det_tex[1:].match_height(matrix, stretch=True)
|
||||||
|
det_tex = VGroup(empty_det_tex[:2], matrix, *empty_det_tex[2:])
|
||||||
|
det_tex.arrange_submobjects(RIGHT, buff=SMALL_BUFF)
|
||||||
|
|
||||||
|
group = VGroup(
|
||||||
|
det_tex,
|
||||||
|
TexMobject("\\downarrow"),
|
||||||
|
TexMobject("(-3)(5) - (7)(0)").scale(0.8),
|
||||||
|
TexMobject("\\downarrow"),
|
||||||
|
TexMobject("-15"),
|
||||||
|
)
|
||||||
|
group.arrange_submobjects(DOWN, buff=2 * SMALL_BUFF)
|
||||||
|
# group.scale_to_fit_height(0.4*FRAME_HEIGHT)
|
||||||
|
group.next_to(self.equation_with_numbers, DOWN)
|
||||||
|
group.shift(FRAME_WIDTH * LEFT / 4)
|
||||||
|
|
||||||
|
self.play(FadeIn(empty_det_tex))
|
||||||
|
self.play(*[
|
||||||
|
ReplacementTransform(M.copy(), matrix)
|
||||||
|
for M in self.M1, self.M2
|
||||||
|
])
|
||||||
|
self.play(LaggedStart(FadeIn, group[1:]))
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
|
||||||
|
class LetsGoInOneSentence(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
self.teacher_says(
|
||||||
|
"Here we go, \\\\", "one sentence!"
|
||||||
|
)
|
||||||
|
self.change_all_student_modes("hooray")
|
||||||
|
self.teacher_says(
|
||||||
|
"Or three...", "",
|
||||||
|
target_mode="guilty"
|
||||||
|
)
|
||||||
|
self.change_all_student_modes("sassy")
|
||||||
|
self.wait(4)
|
||||||
|
|
||||||
|
|
||||||
|
class SuccessiveLinearTransformations(LinearTransformationScene):
|
||||||
|
CONFIG = {
|
||||||
|
"matrix_2": [[3, -1], [0, 1]],
|
||||||
|
"matrix_1": [[2, 3], [-1. / 3, 2]],
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.create_product_and_inverse()
|
||||||
|
self.scale_area_successively()
|
||||||
|
self.apply_transformations_successively()
|
||||||
|
self.scale_area_successively(
|
||||||
|
"\\det(M_2)", "\\det(M_1)", "\\det(M_1 M_2)",
|
||||||
|
reset=False
|
||||||
|
)
|
||||||
|
# self.show_det_as_scaling_factor()
|
||||||
|
|
||||||
|
def create_product_and_inverse(self):
|
||||||
|
self.matrix_product = np.dot(self.matrix_1, self.matrix_2)
|
||||||
|
self.matrix_product_inverse = np.linalg.inv(self.matrix_product)
|
||||||
|
|
||||||
|
def scale_area_successively(self, tex2="3", tex1="5", tex_prod="15", reset=True):
|
||||||
|
self.add_unit_square()
|
||||||
|
t1 = "$%s \\, \\cdot $" % tex1
|
||||||
|
t2 = "$%s \\, \\cdot $" % tex2
|
||||||
|
t3 = "Area"
|
||||||
|
areas = VGroup(
|
||||||
|
TextMobject("", "", t3),
|
||||||
|
TextMobject("", t2, t3),
|
||||||
|
TextMobject(t1, t2, t3),
|
||||||
|
)
|
||||||
|
areas.scale(0.8)
|
||||||
|
areas.move_to(self.square)
|
||||||
|
area = areas[0]
|
||||||
|
self.add_moving_mobject(area, areas[1])
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeIn(self.square),
|
||||||
|
Write(area),
|
||||||
|
Animation(self.basis_vectors)
|
||||||
|
)
|
||||||
|
self.apply_matrix(self.matrix_2)
|
||||||
|
self.wait()
|
||||||
|
self.add_moving_mobject(area, areas[2])
|
||||||
|
self.apply_matrix(self.matrix_1)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
product = VGroup(area[:2])
|
||||||
|
brace = Brace(product, DOWN, buff=SMALL_BUFF)
|
||||||
|
brace_tex = brace.get_tex(tex_prod, buff=SMALL_BUFF)
|
||||||
|
brace_tex.scale(0.8, about_edge=UP)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
GrowFromCenter(brace),
|
||||||
|
Write(brace_tex)
|
||||||
|
)
|
||||||
|
self.wait()
|
||||||
|
if reset:
|
||||||
|
self.play(
|
||||||
|
FadeOut(VGroup(self.square, area, brace, brace_tex)),
|
||||||
|
Animation(self.plane),
|
||||||
|
Animation(self.basis_vectors)
|
||||||
|
)
|
||||||
|
self.transformable_mobjects.remove(self.square)
|
||||||
|
self.moving_mobjects = []
|
||||||
|
self.reset_plane()
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
def apply_transformations_successively(self):
|
||||||
|
M1, M2, all_space = expression = TexMobject(
|
||||||
|
"M_1", "M_2", "\\text{(All 2d space)}"
|
||||||
|
)
|
||||||
|
expression.set_color_by_tex_to_color_map({
|
||||||
|
"M_1": TEAL,
|
||||||
|
"M_2": PINK,
|
||||||
|
})
|
||||||
|
expression.shift(FRAME_WIDTH * LEFT / 4)
|
||||||
|
expression.to_edge(UP)
|
||||||
|
for part in expression:
|
||||||
|
part.add_background_rectangle()
|
||||||
|
part.background_rectangle.stretch(1.05, 0)
|
||||||
|
M1.save_state()
|
||||||
|
M1.move_to(ORIGIN)
|
||||||
|
M1.fade(1)
|
||||||
|
|
||||||
|
# Apply one after the other
|
||||||
|
self.play(
|
||||||
|
FocusOn(M2, run_time=1),
|
||||||
|
FadeIn(VGroup(M2, all_space))
|
||||||
|
)
|
||||||
|
self.add_foreground_mobjects(M2, all_space)
|
||||||
|
self.apply_matrix(self.matrix_2)
|
||||||
|
self.wait()
|
||||||
|
self.play(M1.restore)
|
||||||
|
self.add_foreground_mobjects(M1)
|
||||||
|
self.apply_matrix(self.matrix_1)
|
||||||
|
self.wait()
|
||||||
|
|
||||||
|
# Show full composition
|
||||||
|
rp, lp = parens = TexMobject("()")
|
||||||
|
matrices = VGroup(M1, M2)
|
||||||
|
matrices.generate_target()
|
||||||
|
parens.match_height(matrices)
|
||||||
|
lp.move_to(matrices, RIGHT)
|
||||||
|
matrices.target.next_to(lp, LEFT, SMALL_BUFF)
|
||||||
|
rp.next_to(matrices.target, LEFT, SMALL_BUFF)
|
||||||
|
|
||||||
|
self.reset_plane()
|
||||||
|
self.play(
|
||||||
|
MoveToTarget(matrices),
|
||||||
|
*map(GrowFromCenter, parens)
|
||||||
|
)
|
||||||
|
self.apply_matrix(self.matrix_product)
|
||||||
|
self.wait()
|
||||||
|
self.reset_plane()
|
||||||
|
|
||||||
|
def show_det_as_scaling_factor(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
def reset_plane(self):
|
||||||
|
plane_and_bases = VGroup(self.plane, self.basis_vectors)
|
||||||
|
self.play(FadeOut(plane_and_bases))
|
||||||
|
self.apply_matrix(self.matrix_product_inverse, run_time=0)
|
||||||
|
self.play(FadeIn(plane_and_bases))
|
@ -15,7 +15,8 @@ from utils.paths import counterclockwise_path
|
|||||||
from utils.rate_functions import double_smooth
|
from utils.rate_functions import double_smooth
|
||||||
from utils.rate_functions import smooth
|
from utils.rate_functions import smooth
|
||||||
|
|
||||||
#Drawing
|
# Drawing
|
||||||
|
|
||||||
|
|
||||||
class ShowPartial(Animation):
|
class ShowPartial(Animation):
|
||||||
def update_submobject(self, submobject, starting_submobject, alpha):
|
def update_submobject(self, submobject, starting_submobject, alpha):
|
||||||
@ -26,24 +27,29 @@ class ShowPartial(Animation):
|
|||||||
def get_bounds(self, alpha):
|
def get_bounds(self, alpha):
|
||||||
raise Exception("Not Implemented")
|
raise Exception("Not Implemented")
|
||||||
|
|
||||||
|
|
||||||
class ShowCreation(ShowPartial):
|
class ShowCreation(ShowPartial):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"submobject_mode" : "one_at_a_time",
|
"submobject_mode": "one_at_a_time",
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_bounds(self, alpha):
|
def get_bounds(self, alpha):
|
||||||
return (0, alpha)
|
return (0, alpha)
|
||||||
|
|
||||||
|
|
||||||
class Uncreate(ShowCreation):
|
class Uncreate(ShowCreation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"rate_func" : lambda t : smooth(1-t),
|
"rate_func": lambda t: smooth(1 - t),
|
||||||
"remover" : True
|
"remover": True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Write(ShowCreation):
|
class Write(ShowCreation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"rate_func" : None,
|
"rate_func": None,
|
||||||
"submobject_mode" : "lagged_start",
|
"submobject_mode": "lagged_start",
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, mob_or_text, **kwargs):
|
def __init__(self, mob_or_text, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
if isinstance(mob_or_text, str):
|
if isinstance(mob_or_text, str):
|
||||||
@ -67,13 +73,15 @@ class Write(ShowCreation):
|
|||||||
else:
|
else:
|
||||||
self.run_time = 2
|
self.run_time = 2
|
||||||
|
|
||||||
|
|
||||||
class DrawBorderThenFill(Animation):
|
class DrawBorderThenFill(Animation):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"run_time" : 2,
|
"run_time": 2,
|
||||||
"stroke_width" : 2,
|
"stroke_width": 2,
|
||||||
"stroke_color" : None,
|
"stroke_color": None,
|
||||||
"rate_func" : double_smooth,
|
"rate_func": double_smooth,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, vmobject, **kwargs):
|
def __init__(self, vmobject, **kwargs):
|
||||||
if not isinstance(vmobject, VMobject):
|
if not isinstance(vmobject, VMobject):
|
||||||
raise Exception("DrawBorderThenFill only works for VMobjects")
|
raise Exception("DrawBorderThenFill only works for VMobjects")
|
||||||
@ -82,7 +90,7 @@ class DrawBorderThenFill(Animation):
|
|||||||
|
|
||||||
def update_submobject(self, submobject, starting_submobject, alpha):
|
def update_submobject(self, submobject, starting_submobject, alpha):
|
||||||
submobject.pointwise_become_partial(
|
submobject.pointwise_become_partial(
|
||||||
starting_submobject, 0, min(2*alpha, 1)
|
starting_submobject, 0, min(2 * alpha, 1)
|
||||||
)
|
)
|
||||||
if alpha < 0.5:
|
if alpha < 0.5:
|
||||||
if self.stroke_color:
|
if self.stroke_color:
|
||||||
@ -91,50 +99,55 @@ class DrawBorderThenFill(Animation):
|
|||||||
color = starting_submobject.get_stroke_color()
|
color = starting_submobject.get_stroke_color()
|
||||||
else:
|
else:
|
||||||
color = starting_submobject.get_color()
|
color = starting_submobject.get_color()
|
||||||
submobject.set_stroke(color, width = self.stroke_width)
|
submobject.set_stroke(color, width=self.stroke_width)
|
||||||
submobject.set_fill(opacity = 0)
|
submobject.set_fill(opacity=0)
|
||||||
else:
|
else:
|
||||||
if not self.reached_halfway_point_before:
|
if not self.reached_halfway_point_before:
|
||||||
self.reached_halfway_point_before = True
|
self.reached_halfway_point_before = True
|
||||||
submobject.points = np.array(starting_submobject.points)
|
submobject.points = np.array(starting_submobject.points)
|
||||||
width, opacity = [
|
width, opacity = [
|
||||||
interpolate(start, end, 2*alpha - 1)
|
interpolate(start, end, 2 * alpha - 1)
|
||||||
for start, end in [
|
for start, end in [
|
||||||
(self.stroke_width, starting_submobject.get_stroke_width()),
|
(self.stroke_width, starting_submobject.get_stroke_width()),
|
||||||
(0, starting_submobject.get_fill_opacity())
|
(0, starting_submobject.get_fill_opacity())
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
submobject.set_stroke(width = width)
|
submobject.set_stroke(width=width)
|
||||||
submobject.set_fill(opacity = opacity)
|
submobject.set_fill(opacity=opacity)
|
||||||
|
|
||||||
|
# Fading
|
||||||
|
|
||||||
#Fading
|
|
||||||
|
|
||||||
class FadeOut(Transform):
|
class FadeOut(Transform):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"remover" : True,
|
"remover": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, mobject, **kwargs):
|
def __init__(self, mobject, **kwargs):
|
||||||
target = mobject.copy()
|
target = mobject.copy()
|
||||||
target.fade(1)
|
target.fade(1)
|
||||||
Transform.__init__(self, mobject, target, **kwargs)
|
Transform.__init__(self, mobject, target, **kwargs)
|
||||||
|
|
||||||
def clean_up(self, surrounding_scene = None):
|
def clean_up(self, surrounding_scene=None):
|
||||||
Transform.clean_up(self, surrounding_scene)
|
Transform.clean_up(self, surrounding_scene)
|
||||||
self.update(0)
|
self.update(0)
|
||||||
|
|
||||||
|
|
||||||
class FadeIn(Transform):
|
class FadeIn(Transform):
|
||||||
def __init__(self, mobject, **kwargs):
|
def __init__(self, mobject, **kwargs):
|
||||||
target = mobject.copy()
|
target = mobject.copy()
|
||||||
Transform.__init__(self, mobject, target, **kwargs)
|
Transform.__init__(self, mobject, target, **kwargs)
|
||||||
self.starting_mobject.fade(1)
|
self.starting_mobject.fade(1)
|
||||||
if isinstance(self.starting_mobject, VMobject):
|
if isinstance(self.starting_mobject, VMobject):
|
||||||
self.starting_mobject.set_stroke(width = 0)
|
self.starting_mobject.set_stroke(width=0)
|
||||||
self.starting_mobject.set_fill(opacity = 0)
|
self.starting_mobject.set_fill(opacity=0)
|
||||||
|
|
||||||
|
|
||||||
class FadeInAndShiftFromDirection(Transform):
|
class FadeInAndShiftFromDirection(Transform):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"direction" : DOWN,
|
"direction": DOWN,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, mobject, **kwargs):
|
def __init__(self, mobject, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
target = mobject.copy()
|
target = mobject.copy()
|
||||||
@ -142,19 +155,23 @@ class FadeInAndShiftFromDirection(Transform):
|
|||||||
mobject.fade(1)
|
mobject.fade(1)
|
||||||
Transform.__init__(self, mobject, target, **kwargs)
|
Transform.__init__(self, mobject, target, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class FadeInFromDown(FadeInAndShiftFromDirection):
|
class FadeInFromDown(FadeInAndShiftFromDirection):
|
||||||
"""
|
"""
|
||||||
Essential a more convenient form of FadeInAndShiftFromDirection
|
Essential a more convenient form of FadeInAndShiftFromDirection
|
||||||
"""
|
"""
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"direction" : DOWN,
|
"direction": DOWN,
|
||||||
}
|
}
|
||||||
|
|
||||||
#Growing
|
# Growing
|
||||||
|
|
||||||
|
|
||||||
class GrowFromPoint(Transform):
|
class GrowFromPoint(Transform):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"point_color" : None,
|
"point_color": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, mobject, point, **kwargs):
|
def __init__(self, mobject, point, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
target = mobject.copy()
|
target = mobject.copy()
|
||||||
@ -165,19 +182,23 @@ class GrowFromPoint(Transform):
|
|||||||
mobject.set_color(point_mob.get_color())
|
mobject.set_color(point_mob.get_color())
|
||||||
Transform.__init__(self, mobject, target, **kwargs)
|
Transform.__init__(self, mobject, target, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class GrowFromCenter(GrowFromPoint):
|
class GrowFromCenter(GrowFromPoint):
|
||||||
def __init__(self, mobject, **kwargs):
|
def __init__(self, mobject, **kwargs):
|
||||||
GrowFromPoint.__init__(self, mobject, mobject.get_center(), **kwargs)
|
GrowFromPoint.__init__(self, mobject, mobject.get_center(), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class GrowArrow(GrowFromPoint):
|
class GrowArrow(GrowFromPoint):
|
||||||
def __init__(self, arrow, **kwargs):
|
def __init__(self, arrow, **kwargs):
|
||||||
GrowFromPoint.__init__(self, arrow, arrow.get_start(), **kwargs)
|
GrowFromPoint.__init__(self, arrow, arrow.get_start(), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class SpinInFromNothing(GrowFromCenter):
|
class SpinInFromNothing(GrowFromCenter):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"path_func" : counterclockwise_path()
|
"path_func": counterclockwise_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ShrinkToCenter(Transform):
|
class ShrinkToCenter(Transform):
|
||||||
def __init__(self, mobject, **kwargs):
|
def __init__(self, mobject, **kwargs):
|
||||||
Transform.__init__(
|
Transform.__init__(
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
# import getopt
|
|
||||||
import argparse
|
import argparse
|
||||||
import imp
|
import imp
|
||||||
import imp
|
import imp
|
||||||
@ -11,8 +10,9 @@ import os
|
|||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from camera.camera import Camera
|
|
||||||
from constants import *
|
from constants import *
|
||||||
|
|
||||||
|
from camera.camera import Camera
|
||||||
from scene.scene import Scene
|
from scene.scene import Scene
|
||||||
from utils.sounds import play_error_sound
|
from utils.sounds import play_error_sound
|
||||||
from utils.sounds import play_finish_sound
|
from utils.sounds import play_finish_sound
|
||||||
|
@ -25,17 +25,19 @@ from scene.scene import Scene
|
|||||||
from utils.rate_functions import squish_rate_func
|
from utils.rate_functions import squish_rate_func
|
||||||
from utils.rate_functions import there_and_back
|
from utils.rate_functions import there_and_back
|
||||||
|
|
||||||
|
|
||||||
class PiCreatureScene(Scene):
|
class PiCreatureScene(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"total_wait_time" : 0,
|
"total_wait_time": 0,
|
||||||
"seconds_to_blink" : 3,
|
"seconds_to_blink": 3,
|
||||||
"pi_creatures_start_on_screen" : True,
|
"pi_creatures_start_on_screen": True,
|
||||||
"default_pi_creature_kwargs" : {
|
"default_pi_creature_kwargs": {
|
||||||
"color" : GREY_BROWN,
|
"color": GREY_BROWN,
|
||||||
"flip_at_start" : True,
|
"flip_at_start": True,
|
||||||
},
|
},
|
||||||
"default_pi_creature_start_corner" : DOWN+LEFT,
|
"default_pi_creature_start_corner": DOWN + LEFT,
|
||||||
}
|
}
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self.pi_creatures = self.create_pi_creatures()
|
self.pi_creatures = self.create_pi_creatures()
|
||||||
self.pi_creature = self.get_primary_pi_creature()
|
self.pi_creature = self.get_primary_pi_creature()
|
||||||
@ -66,7 +68,7 @@ class PiCreatureScene(Scene):
|
|||||||
def get_on_screen_pi_creatures(self):
|
def get_on_screen_pi_creatures(self):
|
||||||
mobjects = self.get_mobjects()
|
mobjects = self.get_mobjects()
|
||||||
return VGroup(*filter(
|
return VGroup(*filter(
|
||||||
lambda pi : pi in mobjects,
|
lambda pi: pi in mobjects,
|
||||||
self.get_pi_creatures()
|
self.get_pi_creatures()
|
||||||
))
|
))
|
||||||
|
|
||||||
@ -91,6 +93,7 @@ class PiCreatureScene(Scene):
|
|||||||
on_screen_mobjects = self.camera.extract_mobject_family_members(
|
on_screen_mobjects = self.camera.extract_mobject_family_members(
|
||||||
self.get_mobjects()
|
self.get_mobjects()
|
||||||
)
|
)
|
||||||
|
|
||||||
def has_bubble(pi):
|
def has_bubble(pi):
|
||||||
return hasattr(pi, "bubble") and \
|
return hasattr(pi, "bubble") and \
|
||||||
pi.bubble is not None and \
|
pi.bubble is not None and \
|
||||||
@ -102,7 +105,7 @@ class PiCreatureScene(Scene):
|
|||||||
old_bubble = pi_creature.bubble
|
old_bubble = pi_creature.bubble
|
||||||
bubble = pi_creature.get_bubble(
|
bubble = pi_creature.get_bubble(
|
||||||
*content,
|
*content,
|
||||||
bubble_class = bubble_class,
|
bubble_class=bubble_class,
|
||||||
**bubble_kwargs
|
**bubble_kwargs
|
||||||
)
|
)
|
||||||
anims += [
|
anims += [
|
||||||
@ -114,9 +117,9 @@ class PiCreatureScene(Scene):
|
|||||||
anims.append(PiCreatureBubbleIntroduction(
|
anims.append(PiCreatureBubbleIntroduction(
|
||||||
pi_creature,
|
pi_creature,
|
||||||
*content,
|
*content,
|
||||||
bubble_class = bubble_class,
|
bubble_class=bubble_class,
|
||||||
bubble_kwargs = bubble_kwargs,
|
bubble_kwargs=bubble_kwargs,
|
||||||
target_mode = target_mode,
|
target_mode=target_mode,
|
||||||
**kwargs
|
**kwargs
|
||||||
))
|
))
|
||||||
anims += [
|
anims += [
|
||||||
@ -130,22 +133,24 @@ class PiCreatureScene(Scene):
|
|||||||
def pi_creature_says(self, *args, **kwargs):
|
def pi_creature_says(self, *args, **kwargs):
|
||||||
self.introduce_bubble(
|
self.introduce_bubble(
|
||||||
*args,
|
*args,
|
||||||
bubble_class = SpeechBubble,
|
bubble_class=SpeechBubble,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
def pi_creature_thinks(self, *args, **kwargs):
|
def pi_creature_thinks(self, *args, **kwargs):
|
||||||
self.introduce_bubble(
|
self.introduce_bubble(
|
||||||
*args,
|
*args,
|
||||||
bubble_class = ThoughtBubble,
|
bubble_class=ThoughtBubble,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
def say(self, *content, **kwargs):
|
def say(self, *content, **kwargs):
|
||||||
self.pi_creature_says(self.get_primary_pi_creature(), *content, **kwargs)
|
self.pi_creature_says(
|
||||||
|
self.get_primary_pi_creature(), *content, **kwargs)
|
||||||
|
|
||||||
def think(self, *content, **kwargs):
|
def think(self, *content, **kwargs):
|
||||||
self.pi_creature_thinks(self.get_primary_pi_creature(), *content, **kwargs)
|
self.pi_creature_thinks(
|
||||||
|
self.get_primary_pi_creature(), *content, **kwargs)
|
||||||
|
|
||||||
def compile_play_args_to_animation_list(self, *args):
|
def compile_play_args_to_animation_list(self, *args):
|
||||||
"""
|
"""
|
||||||
@ -157,13 +162,13 @@ class PiCreatureScene(Scene):
|
|||||||
return animations
|
return animations
|
||||||
|
|
||||||
non_pi_creature_anims = filter(
|
non_pi_creature_anims = filter(
|
||||||
lambda anim : anim.mobject not in self.get_pi_creatures(),
|
lambda anim: anim.mobject not in self.get_pi_creatures(),
|
||||||
animations
|
animations
|
||||||
)
|
)
|
||||||
if len(non_pi_creature_anims) == 0:
|
if len(non_pi_creature_anims) == 0:
|
||||||
return animations
|
return animations
|
||||||
first_anim = non_pi_creature_anims[0]
|
first_anim = non_pi_creature_anims[0]
|
||||||
#Look at ending state
|
# Look at ending state
|
||||||
first_anim.update(1)
|
first_anim.update(1)
|
||||||
point_of_interest = first_anim.mobject.get_center()
|
point_of_interest = first_anim.mobject.get_center()
|
||||||
first_anim.update(0)
|
first_anim.update(0)
|
||||||
@ -174,7 +179,7 @@ class PiCreatureScene(Scene):
|
|||||||
if pi_creature in first_anim.mobject.submobject_family():
|
if pi_creature in first_anim.mobject.submobject_family():
|
||||||
continue
|
continue
|
||||||
anims_with_pi_creature = filter(
|
anims_with_pi_creature = filter(
|
||||||
lambda anim : pi_creature in anim.mobject.submobject_family(),
|
lambda anim: pi_creature in anim.mobject.submobject_family(),
|
||||||
animations
|
animations
|
||||||
)
|
)
|
||||||
for anim in anims_with_pi_creature:
|
for anim in anims_with_pi_creature:
|
||||||
@ -193,7 +198,7 @@ class PiCreatureScene(Scene):
|
|||||||
def blink(self):
|
def blink(self):
|
||||||
self.play(Blink(random.choice(self.get_on_screen_pi_creatures())))
|
self.play(Blink(random.choice(self.get_on_screen_pi_creatures())))
|
||||||
|
|
||||||
def joint_blink(self, pi_creatures = None, shuffle = True, **kwargs):
|
def joint_blink(self, pi_creatures=None, shuffle=True, **kwargs):
|
||||||
if pi_creatures is None:
|
if pi_creatures is None:
|
||||||
pi_creatures = self.get_on_screen_pi_creatures()
|
pi_creatures = self.get_on_screen_pi_creatures()
|
||||||
creatures_list = list(pi_creatures)
|
creatures_list = list(pi_creatures)
|
||||||
@ -202,25 +207,25 @@ class PiCreatureScene(Scene):
|
|||||||
|
|
||||||
def get_rate_func(pi):
|
def get_rate_func(pi):
|
||||||
index = creatures_list.index(pi)
|
index = creatures_list.index(pi)
|
||||||
proportion = float(index)/len(creatures_list)
|
proportion = float(index) / len(creatures_list)
|
||||||
start_time = 0.8*proportion
|
start_time = 0.8 * proportion
|
||||||
return squish_rate_func(
|
return squish_rate_func(
|
||||||
there_and_back,
|
there_and_back,
|
||||||
start_time, start_time + 0.2
|
start_time, start_time + 0.2
|
||||||
)
|
)
|
||||||
|
|
||||||
self.play(*[
|
self.play(*[
|
||||||
Blink(pi, rate_func = get_rate_func(pi), **kwargs)
|
Blink(pi, rate_func=get_rate_func(pi), **kwargs)
|
||||||
for pi in creatures_list
|
for pi in creatures_list
|
||||||
])
|
])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def wait(self, time = 1, blink = True):
|
def wait(self, time=1, blink=True):
|
||||||
while time >= 1:
|
while time >= 1:
|
||||||
time_to_blink = self.total_wait_time%self.seconds_to_blink == 0
|
time_to_blink = self.total_wait_time % self.seconds_to_blink == 0
|
||||||
if blink and self.any_pi_creatures_on_screen() and time_to_blink:
|
if blink and self.any_pi_creatures_on_screen() and time_to_blink:
|
||||||
self.blink()
|
self.blink()
|
||||||
self.num_plays -= 1 #This shouldn't count as an animation
|
self.num_plays -= 1 # This shouldn't count as an animation
|
||||||
else:
|
else:
|
||||||
self.non_blink_wait()
|
self.non_blink_wait()
|
||||||
time -= 1
|
time -= 1
|
||||||
@ -229,14 +234,14 @@ class PiCreatureScene(Scene):
|
|||||||
self.non_blink_wait(time)
|
self.non_blink_wait(time)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def non_blink_wait(self, time = 1):
|
def non_blink_wait(self, time=1):
|
||||||
Scene.wait(self, time)
|
Scene.wait(self, time)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def change_mode(self, mode):
|
def change_mode(self, mode):
|
||||||
self.play(self.get_primary_pi_creature().change_mode, mode)
|
self.play(self.get_primary_pi_creature().change_mode, mode)
|
||||||
|
|
||||||
def look_at(self, thing_to_look_at, pi_creatures = None):
|
def look_at(self, thing_to_look_at, pi_creatures=None):
|
||||||
if pi_creatures is None:
|
if pi_creatures is None:
|
||||||
pi_creatures = self.get_pi_creatures()
|
pi_creatures = self.get_pi_creatures()
|
||||||
self.play(*it.chain(*[
|
self.play(*it.chain(*[
|
||||||
@ -244,30 +249,33 @@ class PiCreatureScene(Scene):
|
|||||||
for pi in pi_creatures
|
for pi in pi_creatures
|
||||||
]))
|
]))
|
||||||
|
|
||||||
|
|
||||||
class TeacherStudentsScene(PiCreatureScene):
|
class TeacherStudentsScene(PiCreatureScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"student_colors" : [BLUE_D, BLUE_E, BLUE_C],
|
"student_colors": [BLUE_D, BLUE_E, BLUE_C],
|
||||||
"student_scale_factor" : 0.8,
|
"student_scale_factor": 0.8,
|
||||||
"seconds_to_blink" : 2,
|
"seconds_to_blink": 2,
|
||||||
"screen_height" : 3,
|
"screen_height": 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
PiCreatureScene.setup(self)
|
PiCreatureScene.setup(self)
|
||||||
self.screen = ScreenRectangle(height = self.screen_height)
|
self.screen = ScreenRectangle(height=self.screen_height)
|
||||||
self.screen.to_corner(UP+LEFT)
|
self.screen.to_corner(UP + LEFT)
|
||||||
self.hold_up_spot = self.teacher.get_corner(UP+LEFT) + MED_LARGE_BUFF*UP
|
self.hold_up_spot = self.teacher.get_corner(
|
||||||
|
UP + LEFT) + MED_LARGE_BUFF * UP
|
||||||
|
|
||||||
def create_pi_creatures(self):
|
def create_pi_creatures(self):
|
||||||
self.teacher = Mortimer()
|
self.teacher = Mortimer()
|
||||||
self.teacher.to_corner(DOWN + RIGHT)
|
self.teacher.to_corner(DOWN + RIGHT)
|
||||||
self.teacher.look(DOWN+LEFT)
|
self.teacher.look(DOWN + LEFT)
|
||||||
self.students = VGroup(*[
|
self.students = VGroup(*[
|
||||||
Randolph(color = c)
|
Randolph(color=c)
|
||||||
for c in self.student_colors
|
for c in self.student_colors
|
||||||
])
|
])
|
||||||
self.students.arrange_submobjects(RIGHT)
|
self.students.arrange_submobjects(RIGHT)
|
||||||
self.students.scale(self.student_scale_factor)
|
self.students.scale(self.student_scale_factor)
|
||||||
self.students.to_corner(DOWN+LEFT)
|
self.students.to_corner(DOWN + LEFT)
|
||||||
self.teacher.look_at(self.students[-1].eyes)
|
self.teacher.look_at(self.students[-1].eyes)
|
||||||
for student in self.students:
|
for student in self.students:
|
||||||
student.look_at(self.teacher.eyes)
|
student.look_at(self.teacher.eyes)
|
||||||
@ -307,7 +315,7 @@ class TeacherStudentsScene(PiCreatureScene):
|
|||||||
return self.pi_creature_thinks(student, *content, **kwargs)
|
return self.pi_creature_thinks(student, *content, **kwargs)
|
||||||
|
|
||||||
def change_all_student_modes(self, mode, **kwargs):
|
def change_all_student_modes(self, mode, **kwargs):
|
||||||
self.change_student_modes(*[mode]*len(self.students), **kwargs)
|
self.change_student_modes(*[mode] * len(self.students), **kwargs)
|
||||||
|
|
||||||
def change_student_modes(self, *modes, **kwargs):
|
def change_student_modes(self, *modes, **kwargs):
|
||||||
added_anims = kwargs.pop("added_anims", [])
|
added_anims = kwargs.pop("added_anims", [])
|
||||||
@ -327,11 +335,11 @@ class TeacherStudentsScene(PiCreatureScene):
|
|||||||
submobject_mode = kwargs.get("submobject_mode", "lagged_start")
|
submobject_mode = kwargs.get("submobject_mode", "lagged_start")
|
||||||
return Transform(
|
return Transform(
|
||||||
start, target,
|
start, target,
|
||||||
submobject_mode = submobject_mode,
|
submobject_mode=submobject_mode,
|
||||||
run_time = 2
|
run_time=2
|
||||||
)
|
)
|
||||||
|
|
||||||
def zoom_in_on_thought_bubble(self, bubble = None, radius = FRAME_Y_RADIUS+FRAME_X_RADIUS):
|
def zoom_in_on_thought_bubble(self, bubble=None, radius=FRAME_Y_RADIUS + FRAME_X_RADIUS):
|
||||||
if bubble is None:
|
if bubble is None:
|
||||||
for pi in self.get_pi_creatures():
|
for pi in self.get_pi_creatures():
|
||||||
if hasattr(pi, "bubble") and isinstance(pi.bubble, ThoughtBubble):
|
if hasattr(pi, "bubble") and isinstance(pi.bubble, ThoughtBubble):
|
||||||
@ -340,15 +348,16 @@ class TeacherStudentsScene(PiCreatureScene):
|
|||||||
if bubble is None:
|
if bubble is None:
|
||||||
raise Exception("No pi creatures have a thought bubble")
|
raise Exception("No pi creatures have a thought bubble")
|
||||||
vect = -bubble.get_bubble_center()
|
vect = -bubble.get_bubble_center()
|
||||||
|
|
||||||
def func(point):
|
def func(point):
|
||||||
centered = point+vect
|
centered = point + vect
|
||||||
return radius*centered/np.linalg.norm(centered)
|
return radius * centered / np.linalg.norm(centered)
|
||||||
self.play(*[
|
self.play(*[
|
||||||
ApplyPointwiseFunction(func, mob)
|
ApplyPointwiseFunction(func, mob)
|
||||||
for mob in self.get_mobjects()
|
for mob in self.get_mobjects()
|
||||||
])
|
])
|
||||||
|
|
||||||
def teacher_holds_up(self, mobject, target_mode = "raise_right_hand", **kwargs):
|
def teacher_holds_up(self, mobject, target_mode="raise_right_hand", **kwargs):
|
||||||
mobject.move_to(self.hold_up_spot, DOWN)
|
mobject.move_to(self.hold_up_spot, DOWN)
|
||||||
mobject.shift_onto_screen()
|
mobject.shift_onto_screen()
|
||||||
mobject_copy = mobject.copy()
|
mobject_copy = mobject.copy()
|
||||||
@ -358,5 +367,3 @@ class TeacherStudentsScene(PiCreatureScene):
|
|||||||
ReplacementTransform(mobject_copy, mobject),
|
ReplacementTransform(mobject_copy, mobject),
|
||||||
self.teacher.change, target_mode,
|
self.teacher.change, target_mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,12 +12,13 @@ from constants import *
|
|||||||
|
|
||||||
VECTOR_LABEL_SCALE_FACTOR = 0.8
|
VECTOR_LABEL_SCALE_FACTOR = 0.8
|
||||||
|
|
||||||
|
|
||||||
def matrix_to_tex_string(matrix):
|
def matrix_to_tex_string(matrix):
|
||||||
matrix = np.array(matrix).astype("string")
|
matrix = np.array(matrix).astype("string")
|
||||||
if matrix.ndim == 1:
|
if matrix.ndim == 1:
|
||||||
matrix = matrix.reshape((matrix.size, 1))
|
matrix = matrix.reshape((matrix.size, 1))
|
||||||
n_rows, n_cols = matrix.shape
|
n_rows, n_cols = matrix.shape
|
||||||
prefix = "\\left[ \\begin{array}{%s}"%("c"*n_cols)
|
prefix = "\\left[ \\begin{array}{%s}" % ("c" * n_cols)
|
||||||
suffix = "\\end{array} \\right]"
|
suffix = "\\end{array} \\right]"
|
||||||
rows = [
|
rows = [
|
||||||
" & ".join(row)
|
" & ".join(row)
|
||||||
@ -25,36 +26,40 @@ def matrix_to_tex_string(matrix):
|
|||||||
]
|
]
|
||||||
return prefix + " \\\\ ".join(rows) + suffix
|
return prefix + " \\\\ ".join(rows) + suffix
|
||||||
|
|
||||||
|
|
||||||
def matrix_to_mobject(matrix):
|
def matrix_to_mobject(matrix):
|
||||||
return TexMobject(matrix_to_tex_string(matrix))
|
return TexMobject(matrix_to_tex_string(matrix))
|
||||||
|
|
||||||
def vector_coordinate_label(vector_mob, integer_labels = True,
|
|
||||||
n_dim = 2, color = WHITE):
|
def vector_coordinate_label(vector_mob, integer_labels=True,
|
||||||
|
n_dim=2, color=WHITE):
|
||||||
vect = np.array(vector_mob.get_end())
|
vect = np.array(vector_mob.get_end())
|
||||||
if integer_labels:
|
if integer_labels:
|
||||||
vect = np.round(vect).astype(int)
|
vect = np.round(vect).astype(int)
|
||||||
vect = vect[:n_dim]
|
vect = vect[:n_dim]
|
||||||
vect = vect.reshape((n_dim, 1))
|
vect = vect.reshape((n_dim, 1))
|
||||||
label = Matrix(vect, add_background_rectangles = True)
|
label = Matrix(vect, add_background_rectangles=True)
|
||||||
label.scale(VECTOR_LABEL_SCALE_FACTOR)
|
label.scale(VECTOR_LABEL_SCALE_FACTOR)
|
||||||
|
|
||||||
shift_dir = np.array(vector_mob.get_end())
|
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
|
shift_dir -= label.get_left() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER * LEFT
|
||||||
else: #Pointing left
|
else: # Pointing left
|
||||||
shift_dir -= label.get_right() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER*RIGHT
|
shift_dir -= label.get_right() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER * RIGHT
|
||||||
label.shift(shift_dir)
|
label.shift(shift_dir)
|
||||||
label.set_color(color)
|
label.set_color(color)
|
||||||
label.rect = BackgroundRectangle(label)
|
label.rect = BackgroundRectangle(label)
|
||||||
label.add_to_back(label.rect)
|
label.add_to_back(label.rect)
|
||||||
return label
|
return label
|
||||||
|
|
||||||
|
|
||||||
class Matrix(VMobject):
|
class Matrix(VMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"v_buff" : 0.5,
|
"v_buff": 0.5,
|
||||||
"h_buff" : 1,
|
"h_buff": 1,
|
||||||
"add_background_rectangles" : False
|
"add_background_rectangles": False
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, matrix, **kwargs):
|
def __init__(self, matrix, **kwargs):
|
||||||
"""
|
"""
|
||||||
Matrix can either either include numbres, tex_strings,
|
Matrix can either either include numbres, tex_strings,
|
||||||
@ -89,9 +94,9 @@ class Matrix(VMobject):
|
|||||||
if i == 0 and j == 0:
|
if i == 0 and j == 0:
|
||||||
continue
|
continue
|
||||||
elif i == 0:
|
elif i == 0:
|
||||||
mob.next_to(matrix[i][j-1], RIGHT, self.h_buff)
|
mob.next_to(matrix[i][j - 1], RIGHT, self.h_buff)
|
||||||
else:
|
else:
|
||||||
mob.next_to(matrix[i-1][j], DOWN, self.v_buff)
|
mob.next_to(matrix[i - 1][j], DOWN, self.v_buff)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_brackets(self):
|
def add_brackets(self):
|
||||||
@ -107,7 +112,7 @@ class Matrix(VMobject):
|
|||||||
|
|
||||||
def set_color_columns(self, *colors):
|
def set_color_columns(self, *colors):
|
||||||
for i, color in enumerate(colors):
|
for i, color in enumerate(colors):
|
||||||
VGroup(*self.mob_matrix[:,i]).set_color(color)
|
VGroup(*self.mob_matrix[:, i]).set_color(color)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_background_to_entries(self):
|
def add_background_to_entries(self):
|
||||||
@ -123,15 +128,3 @@ class Matrix(VMobject):
|
|||||||
|
|
||||||
def get_brackets(self):
|
def get_brackets(self):
|
||||||
return self.brackets
|
return self.brackets
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
argparse==1.4.0
|
||||||
colour==0.1.2
|
colour==0.1.2
|
||||||
numpy==1.11.0
|
numpy==1.11.0
|
||||||
Pillow==3.4.2
|
Pillow==3.4.2
|
||||||
|
@ -36,25 +36,27 @@ X_COLOR = GREEN_C
|
|||||||
Y_COLOR = RED_C
|
Y_COLOR = RED_C
|
||||||
Z_COLOR = BLUE_D
|
Z_COLOR = BLUE_D
|
||||||
|
|
||||||
|
|
||||||
class VectorScene(Scene):
|
class VectorScene(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"basis_vector_stroke_width" : 6
|
"basis_vector_stroke_width": 6
|
||||||
}
|
}
|
||||||
def add_plane(self, animate = False, **kwargs):
|
|
||||||
|
def add_plane(self, animate=False, **kwargs):
|
||||||
plane = NumberPlane(**kwargs)
|
plane = NumberPlane(**kwargs)
|
||||||
if animate:
|
if animate:
|
||||||
self.play(ShowCreation(plane, submobject_mode = "lagged_start"))
|
self.play(ShowCreation(plane, submobject_mode="lagged_start"))
|
||||||
self.add(plane)
|
self.add(plane)
|
||||||
return plane
|
return plane
|
||||||
|
|
||||||
def add_axes(self, animate = False, color = WHITE, **kwargs):
|
def add_axes(self, animate=False, color=WHITE, **kwargs):
|
||||||
axes = Axes(color = color, tick_frequency = 1)
|
axes = Axes(color=color, tick_frequency=1)
|
||||||
if animate:
|
if animate:
|
||||||
self.play(ShowCreation(axes, submobject_mode = "one_at_a_time"))
|
self.play(ShowCreation(axes, submobject_mode="one_at_a_time"))
|
||||||
self.add(axes)
|
self.add(axes)
|
||||||
return axes
|
return axes
|
||||||
|
|
||||||
def lock_in_faded_grid(self, dimness = 0.7, axes_dimness = 0.5):
|
def lock_in_faded_grid(self, dimness=0.7, axes_dimness=0.5):
|
||||||
plane = self.add_plane()
|
plane = self.add_plane()
|
||||||
axes = plane.get_axes()
|
axes = plane.get_axes()
|
||||||
plane.fade(dimness)
|
plane.fade(dimness)
|
||||||
@ -63,9 +65,9 @@ class VectorScene(Scene):
|
|||||||
self.add(axes)
|
self.add(axes)
|
||||||
self.freeze_background()
|
self.freeze_background()
|
||||||
|
|
||||||
def add_vector(self, vector, color = YELLOW, animate = True, **kwargs):
|
def add_vector(self, vector, color=YELLOW, animate=True, **kwargs):
|
||||||
if not isinstance(vector, Arrow):
|
if not isinstance(vector, Arrow):
|
||||||
vector = Vector(vector, color = color, **kwargs)
|
vector = Vector(vector, color=color, **kwargs)
|
||||||
if animate:
|
if animate:
|
||||||
self.play(ShowCreation(vector))
|
self.play(ShowCreation(vector))
|
||||||
self.add(vector)
|
self.add(vector)
|
||||||
@ -76,40 +78,41 @@ class VectorScene(Scene):
|
|||||||
self.play(Write(coords))
|
self.play(Write(coords))
|
||||||
return coords
|
return coords
|
||||||
|
|
||||||
def get_basis_vectors(self):
|
def get_basis_vectors(self, i_hat_color=X_COLOR, j_hat_color=Y_COLOR):
|
||||||
return [
|
return VGroup(*[
|
||||||
Vector(
|
Vector(
|
||||||
vect, color = color,
|
vect,
|
||||||
stroke_width = self.basis_vector_stroke_width
|
color=color,
|
||||||
|
stroke_width=self.basis_vector_stroke_width
|
||||||
)
|
)
|
||||||
for vect, color in [
|
for vect, color in [
|
||||||
([1, 0], X_COLOR),
|
([1, 0], i_hat_color),
|
||||||
([0, 1], Y_COLOR)
|
([0, 1], j_hat_color)
|
||||||
]
|
|
||||||
]
|
]
|
||||||
|
])
|
||||||
|
|
||||||
def get_basis_vector_labels(self, **kwargs):
|
def get_basis_vector_labels(self, **kwargs):
|
||||||
i_hat, j_hat = self.get_basis_vectors()
|
i_hat, j_hat = self.get_basis_vectors()
|
||||||
return VGroup(*[
|
return VGroup(*[
|
||||||
self.get_vector_label(
|
self.get_vector_label(
|
||||||
vect, label, color = color,
|
vect, label, color=color,
|
||||||
label_scale_factor = 1,
|
label_scale_factor=1,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
for vect, label , color in [
|
for vect, label, color in [
|
||||||
(i_hat, "\\hat{\\imath}", X_COLOR),
|
(i_hat, "\\hat{\\imath}", X_COLOR),
|
||||||
(j_hat, "\\hat{\\jmath}", Y_COLOR),
|
(j_hat, "\\hat{\\jmath}", Y_COLOR),
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
|
|
||||||
def get_vector_label(self, vector, label,
|
def get_vector_label(self, vector, label,
|
||||||
direction = "left",
|
direction="left",
|
||||||
rotate = False,
|
rotate=False,
|
||||||
color = None,
|
color=None,
|
||||||
label_scale_factor = VECTOR_LABEL_SCALE_FACTOR):
|
label_scale_factor=VECTOR_LABEL_SCALE_FACTOR):
|
||||||
if not isinstance(label, TexMobject):
|
if not isinstance(label, TexMobject):
|
||||||
if len(label) == 1:
|
if len(label) == 1:
|
||||||
label = "\\vec{\\textbf{%s}}"%label
|
label = "\\vec{\\textbf{%s}}" % label
|
||||||
label = TexMobject(label)
|
label = TexMobject(label)
|
||||||
if color is None:
|
if color is None:
|
||||||
color = vector.get_color()
|
color = vector.get_color()
|
||||||
@ -119,53 +122,53 @@ class VectorScene(Scene):
|
|||||||
|
|
||||||
angle = vector.get_angle()
|
angle = vector.get_angle()
|
||||||
if not rotate:
|
if not rotate:
|
||||||
label.rotate(-angle, about_point = ORIGIN)
|
label.rotate(-angle, about_point=ORIGIN)
|
||||||
if direction is "left":
|
if direction is "left":
|
||||||
label.shift(-label.get_bottom() + 0.1*UP)
|
label.shift(-label.get_bottom() + 0.1 * UP)
|
||||||
else:
|
else:
|
||||||
label.shift(-label.get_top() + 0.1*DOWN)
|
label.shift(-label.get_top() + 0.1 * DOWN)
|
||||||
label.rotate(angle, about_point = ORIGIN)
|
label.rotate(angle, about_point=ORIGIN)
|
||||||
label.shift((vector.get_end() - vector.get_start())/2)
|
label.shift((vector.get_end() - vector.get_start()) / 2)
|
||||||
return label
|
return label
|
||||||
|
|
||||||
def label_vector(self, vector, label, animate = True, **kwargs):
|
def label_vector(self, vector, label, animate=True, **kwargs):
|
||||||
label = self.get_vector_label(vector, label, **kwargs)
|
label = self.get_vector_label(vector, label, **kwargs)
|
||||||
if animate:
|
if animate:
|
||||||
self.play(Write(label, run_time = 1))
|
self.play(Write(label, run_time=1))
|
||||||
self.add(label)
|
self.add(label)
|
||||||
return label
|
return label
|
||||||
|
|
||||||
def position_x_coordinate(self, x_coord, x_line, vector):
|
def position_x_coordinate(self, x_coord, x_line, vector):
|
||||||
x_coord.next_to(x_line, -np.sign(vector[1])*UP)
|
x_coord.next_to(x_line, -np.sign(vector[1]) * UP)
|
||||||
x_coord.set_color(X_COLOR)
|
x_coord.set_color(X_COLOR)
|
||||||
return x_coord
|
return x_coord
|
||||||
|
|
||||||
def position_y_coordinate(self, y_coord, y_line, vector):
|
def position_y_coordinate(self, y_coord, y_line, vector):
|
||||||
y_coord.next_to(y_line, np.sign(vector[0])*RIGHT)
|
y_coord.next_to(y_line, np.sign(vector[0]) * RIGHT)
|
||||||
y_coord.set_color(Y_COLOR)
|
y_coord.set_color(Y_COLOR)
|
||||||
return y_coord
|
return y_coord
|
||||||
|
|
||||||
def coords_to_vector(self, vector, coords_start = 2*RIGHT+2*UP, clean_up = True):
|
def coords_to_vector(self, vector, coords_start=2 * RIGHT + 2 * UP, clean_up=True):
|
||||||
starting_mobjects = list(self.mobjects)
|
starting_mobjects = list(self.mobjects)
|
||||||
array = Matrix(vector)
|
array = Matrix(vector)
|
||||||
array.shift(coords_start)
|
array.shift(coords_start)
|
||||||
arrow = Vector(vector)
|
arrow = Vector(vector)
|
||||||
x_line = Line(ORIGIN, vector[0]*RIGHT)
|
x_line = Line(ORIGIN, vector[0] * RIGHT)
|
||||||
y_line = Line(x_line.get_end(), arrow.get_end())
|
y_line = Line(x_line.get_end(), arrow.get_end())
|
||||||
x_line.set_color(X_COLOR)
|
x_line.set_color(X_COLOR)
|
||||||
y_line.set_color(Y_COLOR)
|
y_line.set_color(Y_COLOR)
|
||||||
x_coord, y_coord = array.get_mob_matrix().flatten()
|
x_coord, y_coord = array.get_mob_matrix().flatten()
|
||||||
|
|
||||||
self.play(Write(array, run_time = 1))
|
self.play(Write(array, run_time=1))
|
||||||
self.wait()
|
self.wait()
|
||||||
self.play(ApplyFunction(
|
self.play(ApplyFunction(
|
||||||
lambda x : self.position_x_coordinate(x, x_line, vector),
|
lambda x: self.position_x_coordinate(x, x_line, vector),
|
||||||
x_coord
|
x_coord
|
||||||
))
|
))
|
||||||
self.play(ShowCreation(x_line))
|
self.play(ShowCreation(x_line))
|
||||||
self.play(
|
self.play(
|
||||||
ApplyFunction(
|
ApplyFunction(
|
||||||
lambda y : self.position_y_coordinate(y, y_line, vector),
|
lambda y: self.position_y_coordinate(y, y_line, vector),
|
||||||
y_coord
|
y_coord
|
||||||
),
|
),
|
||||||
FadeOut(array.get_brackets())
|
FadeOut(array.get_brackets())
|
||||||
@ -178,7 +181,7 @@ class VectorScene(Scene):
|
|||||||
self.clear()
|
self.clear()
|
||||||
self.add(*starting_mobjects)
|
self.add(*starting_mobjects)
|
||||||
|
|
||||||
def vector_to_coords(self, vector, integer_labels = True, clean_up = True):
|
def vector_to_coords(self, vector, integer_labels=True, clean_up=True):
|
||||||
starting_mobjects = list(self.mobjects)
|
starting_mobjects = list(self.mobjects)
|
||||||
show_creation = False
|
show_creation = False
|
||||||
if isinstance(vector, Arrow):
|
if isinstance(vector, Arrow):
|
||||||
@ -187,8 +190,8 @@ class VectorScene(Scene):
|
|||||||
else:
|
else:
|
||||||
arrow = Vector(vector)
|
arrow = Vector(vector)
|
||||||
show_creation = True
|
show_creation = True
|
||||||
array = vector_coordinate_label(arrow, integer_labels = integer_labels)
|
array = vector_coordinate_label(arrow, integer_labels=integer_labels)
|
||||||
x_line = Line(ORIGIN, vector[0]*RIGHT)
|
x_line = Line(ORIGIN, vector[0] * RIGHT)
|
||||||
y_line = Line(x_line.get_end(), arrow.get_end())
|
y_line = Line(x_line.get_end(), arrow.get_end())
|
||||||
x_line.set_color(X_COLOR)
|
x_line.set_color(X_COLOR)
|
||||||
y_line.set_color(Y_COLOR)
|
y_line.set_color(Y_COLOR)
|
||||||
@ -206,18 +209,18 @@ class VectorScene(Scene):
|
|||||||
self.play(
|
self.play(
|
||||||
ShowCreation(x_line),
|
ShowCreation(x_line),
|
||||||
Write(x_coord_start),
|
Write(x_coord_start),
|
||||||
run_time = 1
|
run_time=1
|
||||||
)
|
)
|
||||||
self.play(
|
self.play(
|
||||||
ShowCreation(y_line),
|
ShowCreation(y_line),
|
||||||
Write(y_coord_start),
|
Write(y_coord_start),
|
||||||
run_time = 1
|
run_time=1
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
self.play(
|
self.play(
|
||||||
Transform(x_coord_start, x_coord, submobject_mode = "all_at_once"),
|
Transform(x_coord_start, x_coord, submobject_mode="all_at_once"),
|
||||||
Transform(y_coord_start, y_coord, submobject_mode = "all_at_once"),
|
Transform(y_coord_start, y_coord, submobject_mode="all_at_once"),
|
||||||
Write(brackets, run_time = 1),
|
Write(brackets, run_time=1),
|
||||||
)
|
)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
@ -236,49 +239,52 @@ class VectorScene(Scene):
|
|||||||
x_max = int(FRAME_X_RADIUS + abs(vector[0]))
|
x_max = int(FRAME_X_RADIUS + abs(vector[0]))
|
||||||
y_max = int(FRAME_Y_RADIUS + abs(vector[1]))
|
y_max = int(FRAME_Y_RADIUS + abs(vector[1]))
|
||||||
dots = VMobject(*[
|
dots = VMobject(*[
|
||||||
Dot(x*RIGHT + y*UP)
|
Dot(x * RIGHT + y * UP)
|
||||||
for x in range(-x_max, x_max)
|
for x in range(-x_max, x_max)
|
||||||
for y in range(-y_max, y_max)
|
for y in range(-y_max, y_max)
|
||||||
])
|
])
|
||||||
dots.set_fill(BLACK, opacity = 0)
|
dots.set_fill(BLACK, opacity=0)
|
||||||
dots_halfway = dots.copy().shift(vector/2).set_fill(WHITE, 1)
|
dots_halfway = dots.copy().shift(vector / 2).set_fill(WHITE, 1)
|
||||||
dots_end = dots.copy().shift(vector)
|
dots_end = dots.copy().shift(vector)
|
||||||
|
|
||||||
self.play(Transform(
|
self.play(Transform(
|
||||||
dots, dots_halfway, rate_func = rush_into
|
dots, dots_halfway, rate_func=rush_into
|
||||||
))
|
))
|
||||||
self.play(Transform(
|
self.play(Transform(
|
||||||
dots, dots_end, rate_func = rush_from
|
dots, dots_end, rate_func=rush_from
|
||||||
))
|
))
|
||||||
self.remove(dots)
|
self.remove(dots)
|
||||||
|
|
||||||
|
|
||||||
class LinearTransformationScene(VectorScene):
|
class LinearTransformationScene(VectorScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"include_background_plane" : True,
|
"include_background_plane": True,
|
||||||
"include_foreground_plane" : True,
|
"include_foreground_plane": True,
|
||||||
"foreground_plane_kwargs" : {
|
"foreground_plane_kwargs": {
|
||||||
"x_radius" : FRAME_WIDTH,
|
"x_radius": FRAME_WIDTH,
|
||||||
"y_radius" : FRAME_HEIGHT,
|
"y_radius": FRAME_HEIGHT,
|
||||||
"secondary_line_ratio" : 0
|
"secondary_line_ratio": 0
|
||||||
},
|
},
|
||||||
"background_plane_kwargs" : {
|
"background_plane_kwargs": {
|
||||||
"color" : GREY,
|
"color": GREY,
|
||||||
"secondary_color" : DARK_GREY,
|
"secondary_color": DARK_GREY,
|
||||||
"axes_color" : GREY,
|
"axes_color": GREY,
|
||||||
"stroke_width" : 2,
|
"stroke_width": 2,
|
||||||
},
|
},
|
||||||
"show_coordinates" : False,
|
"show_coordinates": False,
|
||||||
"show_basis_vectors" : True,
|
"show_basis_vectors": True,
|
||||||
"i_hat_color" : X_COLOR,
|
"basis_vector_stroke_width": 6,
|
||||||
"j_hat_color" : Y_COLOR,
|
"i_hat_color": X_COLOR,
|
||||||
"leave_ghost_vectors" : False,
|
"j_hat_color": Y_COLOR,
|
||||||
"t_matrix" : [[3, 0], [1, 2]],
|
"leave_ghost_vectors": False,
|
||||||
|
"t_matrix": [[3, 0], [1, 2]],
|
||||||
}
|
}
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
if hasattr(self, "has_already_setup"):
|
if hasattr(self, "has_already_setup"):
|
||||||
return
|
return
|
||||||
self.has_already_setup = True
|
self.has_already_setup = True
|
||||||
##^This is to not break all the old Scenes
|
# ^This is to not break all the old Scenes
|
||||||
self.background_mobjects = []
|
self.background_mobjects = []
|
||||||
self.foreground_mobjects = []
|
self.foreground_mobjects = []
|
||||||
self.transformable_mobjects = []
|
self.transformable_mobjects = []
|
||||||
@ -299,15 +305,12 @@ class LinearTransformationScene(VectorScene):
|
|||||||
self.plane = NumberPlane(**self.foreground_plane_kwargs)
|
self.plane = NumberPlane(**self.foreground_plane_kwargs)
|
||||||
self.add_transformable_mobject(self.plane)
|
self.add_transformable_mobject(self.plane)
|
||||||
if self.show_basis_vectors:
|
if self.show_basis_vectors:
|
||||||
self.i_hat, self.j_hat = [
|
self.basis_vectors = self.get_basis_vectors(
|
||||||
self.add_vector(
|
i_hat_color=self.i_hat_color,
|
||||||
coords, color, animate = False, stroke_width = 6
|
j_hat_color=self.j_hat_color,
|
||||||
)
|
)
|
||||||
for coords, color in [
|
self.moving_vectors += list(self.basis_vectors)
|
||||||
((1, 0), self.i_hat_color),
|
self.i_hat, self.j_hat = self.basis_vectors
|
||||||
((0, 1), self.j_hat_color),
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
def add_special_mobjects(self, mob_list, *mobs_to_add):
|
def add_special_mobjects(self, mob_list, *mobs_to_add):
|
||||||
for mobject in mobs_to_add:
|
for mobject in mobs_to_add:
|
||||||
@ -324,13 +327,13 @@ class LinearTransformationScene(VectorScene):
|
|||||||
def add_transformable_mobject(self, *mobjects):
|
def add_transformable_mobject(self, *mobjects):
|
||||||
self.add_special_mobjects(self.transformable_mobjects, *mobjects)
|
self.add_special_mobjects(self.transformable_mobjects, *mobjects)
|
||||||
|
|
||||||
def add_moving_mobject(self, mobject, target_mobject = None):
|
def add_moving_mobject(self, mobject, target_mobject=None):
|
||||||
mobject.target = target_mobject
|
mobject.target = target_mobject
|
||||||
self.add_special_mobjects(self.moving_mobjects, mobject)
|
self.add_special_mobjects(self.moving_mobjects, mobject)
|
||||||
|
|
||||||
def add_unit_square(self, color = YELLOW, opacity = 0.3, animate = False):
|
def add_unit_square(self, color=YELLOW, opacity=0.3, animate=False):
|
||||||
square = Square(color = color, side_length = 1)
|
square = Square(color=color, side_length=1)
|
||||||
square.shift(-square.get_corner(DOWN+LEFT))
|
square.shift(-square.get_corner(DOWN + LEFT))
|
||||||
if animate:
|
if animate:
|
||||||
added_anims = map(Animation, self.moving_vectors)
|
added_anims = map(Animation, self.moving_vectors)
|
||||||
self.play(ShowCreation(square), *added_anims)
|
self.play(ShowCreation(square), *added_anims)
|
||||||
@ -342,9 +345,9 @@ class LinearTransformationScene(VectorScene):
|
|||||||
self.square = square
|
self.square = square
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_vector(self, vector, color = YELLOW, **kwargs):
|
def add_vector(self, vector, color=YELLOW, **kwargs):
|
||||||
vector = VectorScene.add_vector(
|
vector = VectorScene.add_vector(
|
||||||
self, vector, color = color, **kwargs
|
self, vector, color=color, **kwargs
|
||||||
)
|
)
|
||||||
self.moving_vectors.append(vector)
|
self.moving_vectors.append(vector)
|
||||||
return vector
|
return vector
|
||||||
@ -354,12 +357,12 @@ class LinearTransformationScene(VectorScene):
|
|||||||
self.add_foreground_mobject(coords)
|
self.add_foreground_mobject(coords)
|
||||||
return coords
|
return coords
|
||||||
|
|
||||||
def add_transformable_label(self, vector, label, new_label = None, **kwargs):
|
def add_transformable_label(self, vector, label, new_label=None, **kwargs):
|
||||||
label_mob = self.label_vector(vector, label, **kwargs)
|
label_mob = self.label_vector(vector, label, **kwargs)
|
||||||
if new_label:
|
if new_label:
|
||||||
label_mob.target_text = new_label
|
label_mob.target_text = new_label
|
||||||
else:
|
else:
|
||||||
label_mob.target_text = "L(%s)"%label_mob.get_tex_string()
|
label_mob.target_text = "L(%s)" % label_mob.get_tex_string()
|
||||||
label_mob.vector = vector
|
label_mob.vector = vector
|
||||||
label_mob.kwargs = kwargs
|
label_mob.kwargs = kwargs
|
||||||
if "animate" in label_mob.kwargs:
|
if "animate" in label_mob.kwargs:
|
||||||
@ -367,7 +370,7 @@ class LinearTransformationScene(VectorScene):
|
|||||||
self.transformable_labels.append(label_mob)
|
self.transformable_labels.append(label_mob)
|
||||||
return label_mob
|
return label_mob
|
||||||
|
|
||||||
def add_title(self, title, scale_factor = 1.5, animate = False):
|
def add_title(self, title, scale_factor=1.5, animate=False):
|
||||||
if not isinstance(title, Mobject):
|
if not isinstance(title, Mobject):
|
||||||
title = TextMobject(title).scale(scale_factor)
|
title = TextMobject(title).scale(scale_factor)
|
||||||
title.to_edge(UP)
|
title.to_edge(UP)
|
||||||
@ -378,7 +381,10 @@ class LinearTransformationScene(VectorScene):
|
|||||||
self.title = title
|
self.title = title
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_matrix_transformation(self, transposed_matrix):
|
def get_matrix_transformation(self, matrix):
|
||||||
|
return self.get_transposed_matrix_transformation(np.array(matrix).T)
|
||||||
|
|
||||||
|
def get_transposed_matrix_transformation(self, transposed_matrix):
|
||||||
transposed_matrix = np.array(transposed_matrix)
|
transposed_matrix = np.array(transposed_matrix)
|
||||||
if transposed_matrix.shape == (2, 2):
|
if transposed_matrix.shape == (2, 2):
|
||||||
new_matrix = np.identity(3)
|
new_matrix = np.identity(3)
|
||||||
@ -393,7 +399,7 @@ class LinearTransformationScene(VectorScene):
|
|||||||
target = VMobject(*[mob.target for mob in pieces])
|
target = VMobject(*[mob.target for mob in pieces])
|
||||||
if self.leave_ghost_vectors:
|
if self.leave_ghost_vectors:
|
||||||
self.add(start.copy().fade(0.7))
|
self.add(start.copy().fade(0.7))
|
||||||
return Transform(start, target, submobject_mode = "all_at_once")
|
return Transform(start, target, submobject_mode="all_at_once")
|
||||||
|
|
||||||
def get_moving_mobject_movement(self, func):
|
def get_moving_mobject_movement(self, func):
|
||||||
for m in self.moving_mobjects:
|
for m in self.moving_mobjects:
|
||||||
@ -405,7 +411,7 @@ class LinearTransformationScene(VectorScene):
|
|||||||
|
|
||||||
def get_vector_movement(self, func):
|
def get_vector_movement(self, func):
|
||||||
for v in self.moving_vectors:
|
for v in self.moving_vectors:
|
||||||
v.target = Vector(func(v.get_end()), color = v.get_color())
|
v.target = Vector(func(v.get_end()), color=v.get_color())
|
||||||
norm = np.linalg.norm(v.target.get_end())
|
norm = np.linalg.norm(v.target.get_end())
|
||||||
if norm < 0.1:
|
if norm < 0.1:
|
||||||
v.target.get_tip().scale_in_place(norm)
|
v.target.get_tip().scale_in_place(norm)
|
||||||
@ -418,12 +424,15 @@ class LinearTransformationScene(VectorScene):
|
|||||||
)
|
)
|
||||||
return self.get_piece_movement(self.transformable_labels)
|
return self.get_piece_movement(self.transformable_labels)
|
||||||
|
|
||||||
|
def apply_matrix(self, matrix, **kwargs):
|
||||||
|
self.apply_transposed_matrix(np.array(matrix).T, **kwargs)
|
||||||
|
|
||||||
def apply_transposed_matrix(self, transposed_matrix, **kwargs):
|
def apply_transposed_matrix(self, transposed_matrix, **kwargs):
|
||||||
func = self.get_matrix_transformation(transposed_matrix)
|
func = self.get_transposed_matrix_transformation(transposed_matrix)
|
||||||
if "path_arc" not in kwargs:
|
if "path_arc" not in kwargs:
|
||||||
net_rotation = np.mean([
|
net_rotation = np.mean([
|
||||||
angle_of_vector(func(RIGHT)),
|
angle_of_vector(func(RIGHT)),
|
||||||
angle_of_vector(func(UP))-np.pi/2
|
angle_of_vector(func(UP)) - np.pi / 2
|
||||||
])
|
])
|
||||||
kwargs["path_arc"] = net_rotation
|
kwargs["path_arc"] = net_rotation
|
||||||
self.apply_function(func, **kwargs)
|
self.apply_function(func, **kwargs)
|
||||||
@ -436,7 +445,7 @@ class LinearTransformationScene(VectorScene):
|
|||||||
self.plane.prepare_for_nonlinear_transform()
|
self.plane.prepare_for_nonlinear_transform()
|
||||||
self.apply_function(function, **kwargs)
|
self.apply_function(function, **kwargs)
|
||||||
|
|
||||||
def apply_function(self, function, added_anims = [], **kwargs):
|
def apply_function(self, function, added_anims=[], **kwargs):
|
||||||
if "run_time" not in kwargs:
|
if "run_time" not in kwargs:
|
||||||
kwargs["run_time"] = 3
|
kwargs["run_time"] = 3
|
||||||
anims = [
|
anims = [
|
||||||
@ -451,14 +460,3 @@ class LinearTransformationScene(VectorScene):
|
|||||||
for f_mob in self.foreground_mobjects
|
for f_mob in self.foreground_mobjects
|
||||||
] + added_anims
|
] + added_anims
|
||||||
self.play(*anims, **kwargs)
|
self.play(*anims, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user