Merge branch 'master' into eop

This commit is contained in:
Ben Hambrecht 2018-04-30 15:48:45 +02:00
commit 24276ff1f5
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 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

View file

@ -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:

View file

@ -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)

View file

@ -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 = {

View file

@ -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,6 +136,11 @@ class VectorScene(Scene):
label.scale(label_scale_factor) label.scale(label_scale_factor)
label.add_background_rectangle() 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() angle = vector.get_angle()
if not rotate: if not rotate:
label.rotate(-angle, about_point=ORIGIN) label.rotate(-angle, about_point=ORIGIN)
@ -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: