mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Merge branch 'master' into eop
This commit is contained in:
commit
24276ff1f5
6 changed files with 2032 additions and 65 deletions
1892
active_projects/eola2/cramer.py
Normal file
1892
active_projects/eola2/cramer.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -2,8 +2,10 @@ from __future__ import absolute_import
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from mobject.mobject import Mobject
|
from mobject.numbers import DecimalNumber
|
||||||
|
from mobject.numbers import Integer
|
||||||
from mobject.svg.tex_mobject import TexMobject
|
from mobject.svg.tex_mobject import TexMobject
|
||||||
|
from mobject.svg.tex_mobject import TextMobject
|
||||||
from mobject.types.vectorized_mobject import VGroup
|
from mobject.types.vectorized_mobject import VGroup
|
||||||
from mobject.types.vectorized_mobject import VMobject
|
from mobject.types.vectorized_mobject import VMobject
|
||||||
from mobject.shape_matchers import BackgroundRectangle
|
from mobject.shape_matchers import BackgroundRectangle
|
||||||
|
@ -38,7 +40,7 @@ def vector_coordinate_label(vector_mob, integer_labels=True,
|
||||||
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_to_entries=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())
|
||||||
|
@ -55,9 +57,13 @@ def vector_coordinate_label(vector_mob, integer_labels=True,
|
||||||
|
|
||||||
class Matrix(VMobject):
|
class Matrix(VMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"v_buff": 0.5,
|
"v_buff": 0.8,
|
||||||
"h_buff": 1,
|
"h_buff": 1.3,
|
||||||
"add_background_rectangles": False
|
"add_background_rectangles_to_entries": False,
|
||||||
|
"include_background_rectangle": False,
|
||||||
|
"element_to_mobject": TexMobject,
|
||||||
|
"element_to_mobject_config": {},
|
||||||
|
"element_alignment_corner": DR,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, matrix, **kwargs):
|
def __init__(self, matrix, **kwargs):
|
||||||
|
@ -69,34 +75,34 @@ class Matrix(VMobject):
|
||||||
matrix = np.array(matrix)
|
matrix = np.array(matrix)
|
||||||
if matrix.ndim == 1:
|
if matrix.ndim == 1:
|
||||||
matrix = matrix.reshape((matrix.size, 1))
|
matrix = matrix.reshape((matrix.size, 1))
|
||||||
if not isinstance(matrix[0][0], Mobject):
|
mob_matrix = self.matrix_to_mob_matrix(matrix)
|
||||||
matrix = matrix.astype("string")
|
self.organize_mob_matrix(mob_matrix)
|
||||||
matrix = self.string_matrix_to_mob_matrix(matrix)
|
self.elements = VGroup(*mob_matrix.flatten())
|
||||||
self.organize_mob_matrix(matrix)
|
self.add(self.elements)
|
||||||
self.add(*matrix.flatten())
|
|
||||||
self.add_brackets()
|
self.add_brackets()
|
||||||
self.center()
|
self.center()
|
||||||
self.mob_matrix = matrix
|
self.mob_matrix = mob_matrix
|
||||||
if self.add_background_rectangles:
|
if self.add_background_rectangles_to_entries:
|
||||||
for mob in matrix.flatten():
|
for mob in self.elements:
|
||||||
mob.add_background_rectangle()
|
mob.add_background_rectangle()
|
||||||
|
if self.include_background_rectangle:
|
||||||
|
self.add_background_rectangle()
|
||||||
|
|
||||||
def string_matrix_to_mob_matrix(self, matrix):
|
def matrix_to_mob_matrix(self, matrix):
|
||||||
return np.array([
|
return np.vectorize(
|
||||||
map(TexMobject, row)
|
lambda e: self.element_to_mobject(
|
||||||
for row in matrix
|
e, **self.element_to_mobject_config
|
||||||
]).reshape(matrix.shape)
|
)
|
||||||
|
)(matrix)
|
||||||
|
|
||||||
def organize_mob_matrix(self, matrix):
|
def organize_mob_matrix(self, matrix):
|
||||||
for i, row in enumerate(matrix):
|
for i, row in enumerate(matrix):
|
||||||
for j, elem in enumerate(row):
|
for j, elem in enumerate(row):
|
||||||
mob = matrix[i][j]
|
mob = matrix[i][j]
|
||||||
if i == 0 and j == 0:
|
mob.move_to(
|
||||||
continue
|
i * self.v_buff * DOWN + j * self.h_buff * RIGHT,
|
||||||
elif i == 0:
|
self.element_alignment_corner
|
||||||
mob.next_to(matrix[i][j - 1], RIGHT, self.h_buff)
|
)
|
||||||
else:
|
|
||||||
mob.next_to(matrix[i - 1][j], DOWN, self.v_buff)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_brackets(self):
|
def add_brackets(self):
|
||||||
|
@ -110,6 +116,10 @@ class Matrix(VMobject):
|
||||||
self.brackets = VGroup(l_bracket, r_bracket)
|
self.brackets = VGroup(l_bracket, r_bracket)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def add_background_rectangle(self):
|
||||||
|
self.background_rectangle = BackgroundRectangle(self)
|
||||||
|
self.add_to_back(self.background_rectangle)
|
||||||
|
|
||||||
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)
|
||||||
|
@ -128,3 +138,42 @@ class Matrix(VMobject):
|
||||||
|
|
||||||
def get_brackets(self):
|
def get_brackets(self):
|
||||||
return self.brackets
|
return self.brackets
|
||||||
|
|
||||||
|
|
||||||
|
class DecimalMatrix(Matrix):
|
||||||
|
CONFIG = {
|
||||||
|
"element_to_mobject": DecimalNumber,
|
||||||
|
"element_to_mobject_config": {"num_decimal_points": 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IntegerMatrix(Matrix):
|
||||||
|
CONFIG = {
|
||||||
|
"element_to_mobject": Integer,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MobjectMatrix(Matrix):
|
||||||
|
CONFIG = {
|
||||||
|
"element_to_mobject": lambda m: m,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_det_text(matrix, determinant=None, background_rect=True, initial_scale_factor=2):
|
||||||
|
parens = TexMobject(["(", ")"])
|
||||||
|
parens.scale(initial_scale_factor)
|
||||||
|
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)
|
||||||
|
if background_rect:
|
||||||
|
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
|
||||||
|
|
|
@ -887,7 +887,7 @@ class MatrixVectorMultiplication(LinearTransformationScene):
|
||||||
)
|
)
|
||||||
concrete_matrix = Matrix(
|
concrete_matrix = Matrix(
|
||||||
copy.deepcopy(abstract_matrix),
|
copy.deepcopy(abstract_matrix),
|
||||||
add_background_rectangles = True
|
add_background_rectangles_to_entries = True
|
||||||
)
|
)
|
||||||
concrete_matrix.to_edge(UP)
|
concrete_matrix.to_edge(UP)
|
||||||
if self.abstract:
|
if self.abstract:
|
||||||
|
|
|
@ -106,7 +106,7 @@ class FollowLinearCombination(LinearTransformationScene):
|
||||||
direction = "right", color = Y_COLOR
|
direction = "right", color = Y_COLOR
|
||||||
)
|
)
|
||||||
vect = self.add_vector(vect_coords)
|
vect = self.add_vector(vect_coords)
|
||||||
vect_array = Matrix(["x", "y"], add_background_rectangles = True)
|
vect_array = Matrix(["x", "y"], add_background_rectangles_to_entries = True)
|
||||||
v_equals = TexMobject(["\\vec{\\textbf{v}}", "="])
|
v_equals = TexMobject(["\\vec{\\textbf{v}}", "="])
|
||||||
v_equals.split()[0].set_color(YELLOW)
|
v_equals.split()[0].set_color(YELLOW)
|
||||||
v_equals.next_to(vect_array, LEFT)
|
v_equals.next_to(vect_array, LEFT)
|
||||||
|
|
|
@ -1,24 +1,6 @@
|
||||||
from big_ol_pile_of_manim_imports import *
|
from big_ol_pile_of_manim_imports import *
|
||||||
from eola.chapter3 import MatrixVectorMultiplicationAbstract
|
from eola.chapter3 import MatrixVectorMultiplicationAbstract
|
||||||
|
|
||||||
def get_det_text(matrix, determinant = None, background_rect = True):
|
|
||||||
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)
|
|
||||||
if background_rect:
|
|
||||||
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):
|
class Blob(Circle):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
|
|
@ -10,6 +10,7 @@ from animation.creation import Write
|
||||||
from animation.transform import ApplyFunction
|
from animation.transform import ApplyFunction
|
||||||
from animation.transform import ApplyPointwiseFunction
|
from animation.transform import ApplyPointwiseFunction
|
||||||
from animation.creation import FadeOut
|
from animation.creation import FadeOut
|
||||||
|
from animation.creation import GrowArrow
|
||||||
from animation.transform import Transform
|
from animation.transform import Transform
|
||||||
from mobject.mobject import Mobject
|
from mobject.mobject import Mobject
|
||||||
from mobject.svg.tex_mobject import TexMobject
|
from mobject.svg.tex_mobject import TexMobject
|
||||||
|
@ -20,7 +21,7 @@ from scene.scene import Scene
|
||||||
from mobject.geometry import Arrow
|
from mobject.geometry import Arrow
|
||||||
from mobject.geometry import Dot
|
from mobject.geometry import Dot
|
||||||
from mobject.geometry import Line
|
from mobject.geometry import Line
|
||||||
from mobject.geometry import Square
|
from mobject.geometry import Rectangle
|
||||||
from mobject.geometry import Vector
|
from mobject.geometry import Vector
|
||||||
from mobject.coordinate_systems import Axes
|
from mobject.coordinate_systems import Axes
|
||||||
from mobject.coordinate_systems import NumberPlane
|
from mobject.coordinate_systems import NumberPlane
|
||||||
|
@ -37,6 +38,12 @@ Y_COLOR = RED_C
|
||||||
Z_COLOR = BLUE_D
|
Z_COLOR = BLUE_D
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Much of this scene type seems dependent on the coordinate system chosen.
|
||||||
|
# That is, being centered at the origin with grid units corresponding to the
|
||||||
|
# arbitrary space units. Change it!
|
||||||
|
#
|
||||||
|
# Also, methods I would have thought of as getters, like coords_to_vector, are
|
||||||
|
# actually doing a lot of animating.
|
||||||
class VectorScene(Scene):
|
class VectorScene(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"basis_vector_stroke_width": 6
|
"basis_vector_stroke_width": 6
|
||||||
|
@ -65,11 +72,19 @@ class VectorScene(Scene):
|
||||||
self.add(axes)
|
self.add(axes)
|
||||||
self.freeze_background()
|
self.freeze_background()
|
||||||
|
|
||||||
|
def get_vector(self, numerical_vector, **kwargs):
|
||||||
|
return Arrow(
|
||||||
|
self.plane.coords_to_point(0, 0),
|
||||||
|
self.plane.coords_to_point(*numerical_vector[:2]),
|
||||||
|
buff=0,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
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(GrowArrow(vector))
|
||||||
self.add(vector)
|
self.add(vector)
|
||||||
return vector
|
return vector
|
||||||
|
|
||||||
|
@ -106,6 +121,7 @@ class VectorScene(Scene):
|
||||||
])
|
])
|
||||||
|
|
||||||
def get_vector_label(self, vector, label,
|
def get_vector_label(self, vector, label,
|
||||||
|
at_tip=False,
|
||||||
direction="left",
|
direction="left",
|
||||||
rotate=False,
|
rotate=False,
|
||||||
color=None,
|
color=None,
|
||||||
|
@ -120,15 +136,20 @@ class VectorScene(Scene):
|
||||||
label.scale(label_scale_factor)
|
label.scale(label_scale_factor)
|
||||||
label.add_background_rectangle()
|
label.add_background_rectangle()
|
||||||
|
|
||||||
angle = vector.get_angle()
|
if at_tip:
|
||||||
if not rotate:
|
vect = vector.get_vector()
|
||||||
label.rotate(-angle, about_point=ORIGIN)
|
vect /= np.linalg.norm(vect)
|
||||||
if direction is "left":
|
label.next_to(vector.get_end(), vect, buff=SMALL_BUFF)
|
||||||
label.shift(-label.get_bottom() + 0.1 * UP)
|
|
||||||
else:
|
else:
|
||||||
label.shift(-label.get_top() + 0.1 * DOWN)
|
angle = vector.get_angle()
|
||||||
label.rotate(angle, about_point=ORIGIN)
|
if not rotate:
|
||||||
label.shift((vector.get_end() - vector.get_start()) / 2)
|
label.rotate(-angle, about_point=ORIGIN)
|
||||||
|
if direction is "left":
|
||||||
|
label.shift(-label.get_bottom() + 0.1 * UP)
|
||||||
|
else:
|
||||||
|
label.shift(-label.get_top() + 0.1 * DOWN)
|
||||||
|
label.rotate(angle, about_point=ORIGIN)
|
||||||
|
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):
|
||||||
|
@ -281,10 +302,10 @@ class LinearTransformationScene(VectorScene):
|
||||||
}
|
}
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
|
# The has_already_setup attr is to not break all the old Scenes
|
||||||
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
|
|
||||||
self.background_mobjects = []
|
self.background_mobjects = []
|
||||||
self.foreground_mobjects = []
|
self.foreground_mobjects = []
|
||||||
self.transformable_mobjects = []
|
self.transformable_mobjects = []
|
||||||
|
@ -311,6 +332,7 @@ class LinearTransformationScene(VectorScene):
|
||||||
)
|
)
|
||||||
self.moving_vectors += list(self.basis_vectors)
|
self.moving_vectors += list(self.basis_vectors)
|
||||||
self.i_hat, self.j_hat = self.basis_vectors
|
self.i_hat, self.j_hat = self.basis_vectors
|
||||||
|
self.add(self.basis_vectors)
|
||||||
|
|
||||||
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:
|
||||||
|
@ -321,6 +343,7 @@ class LinearTransformationScene(VectorScene):
|
||||||
def add_background_mobject(self, *mobjects):
|
def add_background_mobject(self, *mobjects):
|
||||||
self.add_special_mobjects(self.background_mobjects, *mobjects)
|
self.add_special_mobjects(self.background_mobjects, *mobjects)
|
||||||
|
|
||||||
|
# TODO, this conflicts with Scene.add_fore
|
||||||
def add_foreground_mobject(self, *mobjects):
|
def add_foreground_mobject(self, *mobjects):
|
||||||
self.add_special_mobjects(self.foreground_mobjects, *mobjects)
|
self.add_special_mobjects(self.foreground_mobjects, *mobjects)
|
||||||
|
|
||||||
|
@ -331,15 +354,26 @@ class LinearTransformationScene(VectorScene):
|
||||||
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 get_unit_square(self, color=YELLOW, opacity=0.3, stroke_width=3):
|
||||||
square = Square(color=color, side_length=1)
|
square = Rectangle(
|
||||||
square.shift(-square.get_corner(DOWN + LEFT))
|
color=color,
|
||||||
|
width=self.plane.get_x_unit_size(),
|
||||||
|
height=self.plane.get_y_unit_size(),
|
||||||
|
stroke_color=color,
|
||||||
|
stroke_width=stroke_width,
|
||||||
|
fill_color=color,
|
||||||
|
fill_opacity=opacity
|
||||||
|
)
|
||||||
|
square.move_to(self.plane.coords_to_point(0, 0), DL)
|
||||||
|
return square
|
||||||
|
|
||||||
|
def add_unit_square(self, animate=False, **kwargs):
|
||||||
|
square = self.get_unit_square(**kwargs)
|
||||||
if animate:
|
if animate:
|
||||||
added_anims = map(Animation, self.moving_vectors)
|
self.play(
|
||||||
self.play(ShowCreation(square), *added_anims)
|
DrawBorderThenFill(square),
|
||||||
self.play(square.set_fill, color, opacity, *added_anims)
|
Animation(Group(*self.moving_vectors))
|
||||||
else:
|
)
|
||||||
square.set_fill(color, opacity)
|
|
||||||
self.add_transformable_mobject(square)
|
self.add_transformable_mobject(square)
|
||||||
self.bring_to_front(*self.moving_vectors)
|
self.bring_to_front(*self.moving_vectors)
|
||||||
self.square = square
|
self.square = square
|
||||||
|
@ -357,12 +391,19 @@ 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,
|
||||||
|
transformation_name="L",
|
||||||
|
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 = "%s(%s)" % (
|
||||||
|
transformation_name,
|
||||||
|
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:
|
||||||
|
@ -427,6 +468,9 @@ class LinearTransformationScene(VectorScene):
|
||||||
def apply_matrix(self, matrix, **kwargs):
|
def apply_matrix(self, matrix, **kwargs):
|
||||||
self.apply_transposed_matrix(np.array(matrix).T, **kwargs)
|
self.apply_transposed_matrix(np.array(matrix).T, **kwargs)
|
||||||
|
|
||||||
|
def apply_inverse(self, matrix, **kwargs):
|
||||||
|
self.apply_matrix(np.linalg.inv(matrix), **kwargs)
|
||||||
|
|
||||||
def apply_transposed_matrix(self, transposed_matrix, **kwargs):
|
def apply_transposed_matrix(self, transposed_matrix, **kwargs):
|
||||||
func = self.get_transposed_matrix_transformation(transposed_matrix)
|
func = self.get_transposed_matrix_transformation(transposed_matrix)
|
||||||
if "path_arc" not in kwargs:
|
if "path_arc" not in kwargs:
|
||||||
|
|
Loading…
Add table
Reference in a new issue