Merge pull request #220 from 3b1b/eola2

Eola2
This commit is contained in:
Grant Sanderson
2018-04-28 11:31:08 -07:00
committed by GitHub
6 changed files with 2032 additions and 65 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,10 @@ from __future__ import absolute_import
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 TextMobject
from mobject.types.vectorized_mobject import VGroup
from mobject.types.vectorized_mobject import VMobject
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 = vect[:n_dim]
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)
shift_dir = np.array(vector_mob.get_end())
@ -55,9 +57,13 @@ def vector_coordinate_label(vector_mob, integer_labels=True,
class Matrix(VMobject):
CONFIG = {
"v_buff": 0.5,
"h_buff": 1,
"add_background_rectangles": False
"v_buff": 0.8,
"h_buff": 1.3,
"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):
@ -69,34 +75,34 @@ class Matrix(VMobject):
matrix = np.array(matrix)
if matrix.ndim == 1:
matrix = matrix.reshape((matrix.size, 1))
if not isinstance(matrix[0][0], Mobject):
matrix = matrix.astype("string")
matrix = self.string_matrix_to_mob_matrix(matrix)
self.organize_mob_matrix(matrix)
self.add(*matrix.flatten())
mob_matrix = self.matrix_to_mob_matrix(matrix)
self.organize_mob_matrix(mob_matrix)
self.elements = VGroup(*mob_matrix.flatten())
self.add(self.elements)
self.add_brackets()
self.center()
self.mob_matrix = matrix
if self.add_background_rectangles:
for mob in matrix.flatten():
self.mob_matrix = mob_matrix
if self.add_background_rectangles_to_entries:
for mob in self.elements:
mob.add_background_rectangle()
if self.include_background_rectangle:
self.add_background_rectangle()
def string_matrix_to_mob_matrix(self, matrix):
return np.array([
map(TexMobject, row)
for row in matrix
]).reshape(matrix.shape)
def matrix_to_mob_matrix(self, matrix):
return np.vectorize(
lambda e: self.element_to_mobject(
e, **self.element_to_mobject_config
)
)(matrix)
def organize_mob_matrix(self, matrix):
for i, row in enumerate(matrix):
for j, elem in enumerate(row):
mob = matrix[i][j]
if i == 0 and j == 0:
continue
elif i == 0:
mob.next_to(matrix[i][j - 1], RIGHT, self.h_buff)
else:
mob.next_to(matrix[i - 1][j], DOWN, self.v_buff)
mob.move_to(
i * self.v_buff * DOWN + j * self.h_buff * RIGHT,
self.element_alignment_corner
)
return self
def add_brackets(self):
@ -110,6 +116,10 @@ class Matrix(VMobject):
self.brackets = VGroup(l_bracket, r_bracket)
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):
for i, color in enumerate(colors):
VGroup(*self.mob_matrix[:, i]).set_color(color)
@ -128,3 +138,42 @@ class Matrix(VMobject):
def get_brackets(self):
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

View File

@ -887,7 +887,7 @@ class MatrixVectorMultiplication(LinearTransformationScene):
)
concrete_matrix = Matrix(
copy.deepcopy(abstract_matrix),
add_background_rectangles = True
add_background_rectangles_to_entries = True
)
concrete_matrix.to_edge(UP)
if self.abstract:

View File

@ -106,7 +106,7 @@ class FollowLinearCombination(LinearTransformationScene):
direction = "right", color = Y_COLOR
)
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.split()[0].set_color(YELLOW)
v_equals.next_to(vect_array, LEFT)

View File

@ -1,24 +1,6 @@
from big_ol_pile_of_manim_imports import *
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):
CONFIG = {

View File

@ -10,6 +10,7 @@ from animation.creation import Write
from animation.transform import ApplyFunction
from animation.transform import ApplyPointwiseFunction
from animation.creation import FadeOut
from animation.creation import GrowArrow
from animation.transform import Transform
from mobject.mobject import Mobject
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 Dot
from mobject.geometry import Line
from mobject.geometry import Square
from mobject.geometry import Rectangle
from mobject.geometry import Vector
from mobject.coordinate_systems import Axes
from mobject.coordinate_systems import NumberPlane
@ -37,6 +38,12 @@ Y_COLOR = RED_C
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):
CONFIG = {
"basis_vector_stroke_width": 6
@ -65,11 +72,19 @@ class VectorScene(Scene):
self.add(axes)
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):
if not isinstance(vector, Arrow):
vector = Vector(vector, color=color, **kwargs)
if animate:
self.play(ShowCreation(vector))
self.play(GrowArrow(vector))
self.add(vector)
return vector
@ -106,6 +121,7 @@ class VectorScene(Scene):
])
def get_vector_label(self, vector, label,
at_tip=False,
direction="left",
rotate=False,
color=None,
@ -120,6 +136,11 @@ class VectorScene(Scene):
label.scale(label_scale_factor)
label.add_background_rectangle()
if at_tip:
vect = vector.get_vector()
vect /= np.linalg.norm(vect)
label.next_to(vector.get_end(), vect, buff=SMALL_BUFF)
else:
angle = vector.get_angle()
if not rotate:
label.rotate(-angle, about_point=ORIGIN)
@ -281,10 +302,10 @@ class LinearTransformationScene(VectorScene):
}
def setup(self):
# The has_already_setup attr is to not break all the old Scenes
if hasattr(self, "has_already_setup"):
return
self.has_already_setup = True
# ^This is to not break all the old Scenes
self.background_mobjects = []
self.foreground_mobjects = []
self.transformable_mobjects = []
@ -311,6 +332,7 @@ class LinearTransformationScene(VectorScene):
)
self.moving_vectors += list(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):
for mobject in mobs_to_add:
@ -321,6 +343,7 @@ class LinearTransformationScene(VectorScene):
def add_background_mobject(self, *mobjects):
self.add_special_mobjects(self.background_mobjects, *mobjects)
# TODO, this conflicts with Scene.add_fore
def add_foreground_mobject(self, *mobjects):
self.add_special_mobjects(self.foreground_mobjects, *mobjects)
@ -331,15 +354,26 @@ class LinearTransformationScene(VectorScene):
mobject.target = target_mobject
self.add_special_mobjects(self.moving_mobjects, mobject)
def add_unit_square(self, color=YELLOW, opacity=0.3, animate=False):
square = Square(color=color, side_length=1)
square.shift(-square.get_corner(DOWN + LEFT))
def get_unit_square(self, color=YELLOW, opacity=0.3, stroke_width=3):
square = Rectangle(
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:
added_anims = map(Animation, self.moving_vectors)
self.play(ShowCreation(square), *added_anims)
self.play(square.set_fill, color, opacity, *added_anims)
else:
square.set_fill(color, opacity)
self.play(
DrawBorderThenFill(square),
Animation(Group(*self.moving_vectors))
)
self.add_transformable_mobject(square)
self.bring_to_front(*self.moving_vectors)
self.square = square
@ -357,12 +391,19 @@ class LinearTransformationScene(VectorScene):
self.add_foreground_mobject(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)
if new_label:
label_mob.target_text = new_label
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.kwargs = kwargs
if "animate" in label_mob.kwargs:
@ -427,6 +468,9 @@ class LinearTransformationScene(VectorScene):
def apply_matrix(self, matrix, **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):
func = self.get_transposed_matrix_transformation(transposed_matrix)
if "path_arc" not in kwargs: