mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Mobjects now contain submobjects, giving a heirarchy. Thus CompoundMobject is replaced simply with Mobject, and display etc. needed updating
This commit is contained in:
parent
8663bda619
commit
38b07266b9
18 changed files with 491 additions and 457 deletions
10
displayer.py
10
displayer.py
|
@ -37,7 +37,7 @@ def paint_region(region, image_array = None, color = None):
|
||||||
def paint_mobject(mobject, image_array = None):
|
def paint_mobject(mobject, image_array = None):
|
||||||
return paint_mobjects([mobject], image_array)
|
return paint_mobjects([mobject], image_array)
|
||||||
|
|
||||||
def paint_mobjects(mobjects, image_array = None):
|
def paint_mobjects(mobjects, image_array = None, include_sub_mobjects = True):
|
||||||
pixels = get_pixels(image_array)
|
pixels = get_pixels(image_array)
|
||||||
height = pixels.shape[0]
|
height = pixels.shape[0]
|
||||||
width = pixels.shape[1]
|
width = pixels.shape[1]
|
||||||
|
@ -45,6 +45,13 @@ def paint_mobjects(mobjects, image_array = None):
|
||||||
space_width = SPACE_HEIGHT * width / height
|
space_width = SPACE_HEIGHT * width / height
|
||||||
pixels = pixels.reshape((pixels.size/3, 3)).astype('uint8')
|
pixels = pixels.reshape((pixels.size/3, 3)).astype('uint8')
|
||||||
|
|
||||||
|
if include_sub_mobjects:
|
||||||
|
all_families = [
|
||||||
|
mob.get_full_submobject_family()
|
||||||
|
for mob in mobjects
|
||||||
|
]
|
||||||
|
mobjects = reduce(op.add, all_families, [])
|
||||||
|
|
||||||
for mobject in mobjects:
|
for mobject in mobjects:
|
||||||
if mobject.get_num_points() == 0:
|
if mobject.get_num_points() == 0:
|
||||||
continue
|
continue
|
||||||
|
@ -73,7 +80,6 @@ def paint_mobjects(mobjects, image_array = None):
|
||||||
flattener = np.array([[1], [width]], dtype = 'int')
|
flattener = np.array([[1], [width]], dtype = 'int')
|
||||||
indices = np.dot(points, flattener)[:,0]
|
indices = np.dot(points, flattener)[:,0]
|
||||||
pixels[indices] = rgbs.astype('uint8')
|
pixels[indices] = rgbs.astype('uint8')
|
||||||
|
|
||||||
return pixels.reshape((height, width, 3))
|
return pixels.reshape((height, width, 3))
|
||||||
|
|
||||||
def add_thickness(pixel_indices_and_rgbs, thickness, width, height):
|
def add_thickness(pixel_indices_and_rgbs, thickness, width, height):
|
||||||
|
|
12
helpers.py
12
helpers.py
|
@ -11,8 +11,18 @@ import re
|
||||||
|
|
||||||
from constants import *
|
from constants import *
|
||||||
|
|
||||||
|
def remove_list_redundancies(l):
|
||||||
|
"""
|
||||||
|
Used instead of lsit(set(l)) to maintain order
|
||||||
|
"""
|
||||||
|
return sorted(list(set(l)), lambda a, b : l.index(a) - l.index(b))
|
||||||
|
|
||||||
def list_update(l1, l2):
|
def list_update(l1, l2):
|
||||||
return filter(lambda e : e not in l2, l1) + l2
|
"""
|
||||||
|
Used instead of list(set(l1).update(l2)) to maintain order,
|
||||||
|
making sure duplicates are removed from l1, not l2.
|
||||||
|
"""
|
||||||
|
return filter(lambda e : e not in l2, l1) + list(l2)
|
||||||
|
|
||||||
def all_elements_are_instances(iterable, Class):
|
def all_elements_are_instances(iterable, Class):
|
||||||
return all(map(lambda e : isinstance(e, Class), iterable))
|
return all(map(lambda e : isinstance(e, Class), iterable))
|
||||||
|
|
|
@ -23,24 +23,79 @@ class Mobject(object):
|
||||||
"name" : None,
|
"name" : None,
|
||||||
}
|
}
|
||||||
DIM = 3
|
DIM = 3
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, *sub_mobjects, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
|
self.sub_mobjects = list(sub_mobjects)
|
||||||
self.color = Color(self.color)
|
self.color = Color(self.color)
|
||||||
if self.name is None:
|
if self.name is None:
|
||||||
self.name = self.__class__.__name__
|
self.name = self.__class__.__name__
|
||||||
self.has_normals = hasattr(self, 'unit_normal')
|
self.has_normals = hasattr(self, 'unit_normal')
|
||||||
self.init_points()
|
self.init_points()
|
||||||
self.generate_points()
|
self.generate_points()
|
||||||
|
if self.has_normals:
|
||||||
|
self.unit_normals = np.apply_along_axis(
|
||||||
|
self.unit_normal,
|
||||||
|
1,
|
||||||
|
self.points,
|
||||||
|
)
|
||||||
|
|
||||||
def init_points(self):
|
def init_points(self):
|
||||||
self.points = np.zeros((0, 3))
|
for attr in self.get_array_attrs():
|
||||||
self.rgbs = np.zeros((0, 3))
|
setattr(self, attr, np.zeros((0, 3)))
|
||||||
if self.has_normals:
|
|
||||||
self.unit_normals = np.zeros((0, 3))
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def add_points(self, points, rgbs = None, color = None):
|
||||||
|
"""
|
||||||
|
points must be a Nx3 numpy array, as must rgbs if it is not None
|
||||||
|
"""
|
||||||
|
if not isinstance(points, np.ndarray):
|
||||||
|
points = np.array(points)
|
||||||
|
num_new_points = points.shape[0]
|
||||||
|
self.points = np.append(self.points, points, axis = 0)
|
||||||
|
if rgbs is None:
|
||||||
|
color = Color(color) if color else self.color
|
||||||
|
rgbs = np.array([color.get_rgb()] * num_new_points)
|
||||||
|
elif rgbs.shape != points.shape:
|
||||||
|
raise Exception("points and rgbs must have same shape")
|
||||||
|
self.rgbs = np.append(self.rgbs, rgbs, axis = 0)
|
||||||
|
if self.has_normals:
|
||||||
|
self.unit_normals = np.append(
|
||||||
|
self.unit_normals,
|
||||||
|
np.apply_along_axis(self.unit_normal, 1, points),
|
||||||
|
axis = 0
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def add(self, *mobjects):
|
||||||
|
self.sub_mobjects = list_update(self.sub_mobjects, mobjects)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def get_array_attrs(self):
|
||||||
|
result = ["points", "rgbs"]
|
||||||
|
if self.has_normals:
|
||||||
|
result.append("unit_normals")
|
||||||
|
return result
|
||||||
|
|
||||||
|
def digest_mobject_attrs(self):
|
||||||
|
"""
|
||||||
|
Ensures all attributes which are mobjects are included
|
||||||
|
in the sub_mobjects list.
|
||||||
|
"""
|
||||||
|
mobject_attrs = filter(
|
||||||
|
lambda x : isinstance(x, Mobject),
|
||||||
|
self.__dict__.values()
|
||||||
|
)
|
||||||
|
self.sub_mobjects = list_update(self.sub_mobjects, mobject_attrs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def apply_over_attr_arrays(self, func):
|
||||||
|
for attr in self.get_array_attrs(self):
|
||||||
|
setattr(self, attr, func(getattr(self, attr)))
|
||||||
|
return self
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
Image.fromarray(disp.paint_mobject(self)).show()
|
Image.fromarray(disp.paint_mobject(self)).show()
|
||||||
|
|
||||||
|
@ -49,42 +104,98 @@ class Mobject(object):
|
||||||
os.path.join(MOVIE_DIR, (name or str(self)) + ".png")
|
os.path.join(MOVIE_DIR, (name or str(self)) + ".png")
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_points(self, points, rgbs = None, color = None):
|
|
||||||
"""
|
#### Fundamental operations ######
|
||||||
points must be a Nx3 numpy array, as must rgbs if it is not None
|
|
||||||
"""
|
def shift(self, *vectors):
|
||||||
points = np.array(points)
|
total_vector = reduce(op.add, vectors)
|
||||||
num_new_points = points.shape[0]
|
for mob in self.get_full_submobject_family():
|
||||||
self.points = np.append(self.points, points)
|
mob.points += total_vector
|
||||||
self.points = self.points.reshape((self.points.size / 3, 3))
|
|
||||||
if rgbs is None:
|
|
||||||
color = Color(color) if color else self.color
|
|
||||||
rgbs = np.array([color.get_rgb()] * num_new_points)
|
|
||||||
else:
|
|
||||||
if rgbs.shape != points.shape:
|
|
||||||
raise Exception("points and rgbs must have same shape")
|
|
||||||
self.rgbs = np.append(self.rgbs, rgbs)
|
|
||||||
self.rgbs = self.rgbs.reshape((self.rgbs.size / 3, 3))
|
|
||||||
if self.has_normals:
|
|
||||||
self.unit_normals = np.append(
|
|
||||||
self.unit_normals,
|
|
||||||
np.array([self.unit_normal(point) for point in points])
|
|
||||||
).reshape(self.points.shape)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add(self, *mobjects):
|
def scale(self, scale_factor):
|
||||||
for mobject in mobjects:
|
for mob in self.get_full_submobject_family():
|
||||||
self.add_points(mobject.points, mobject.rgbs)
|
mob.points *= scale_factor
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def rotate(self, angle, axis = OUT):
|
||||||
|
t_rotation_matrix = np.transpose(rotation_matrix(angle, axis))
|
||||||
|
for mob in self.get_full_submobject_family():
|
||||||
|
mob.points = np.dot(mob.points, t_rotation_matrix)
|
||||||
|
if mob.has_normals:
|
||||||
|
mob.unit_normals = np.dot(mob.unit_normals, t_rotation_matrix)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def stretch(self, factor, dim):
|
||||||
|
for mob in self.get_full_submobject_family():
|
||||||
|
mob.points[:,dim] *= factor
|
||||||
|
return self
|
||||||
|
|
||||||
|
def apply_function(self, function):
|
||||||
|
for mob in self.get_full_submobject_family():
|
||||||
|
mob.points = np.apply_along_axis(function, 1, mob.points)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def wag(self, direction = RIGHT, axis = DOWN, wag_factor = 1.0):
|
||||||
|
for mob in self.get_full_submobject_family():
|
||||||
|
alphas = np.dot(mob.points, np.transpose(axis))
|
||||||
|
alphas -= min(alphas)
|
||||||
|
alphas /= max(alphas)
|
||||||
|
alphas = alphas**wag_factor
|
||||||
|
mob.points += np.dot(
|
||||||
|
alphas.reshape((len(alphas), 1)),
|
||||||
|
np.array(direction).reshape((1, mob.DIM))
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def highlight(self, color = "yellow", condition = None):
|
||||||
|
"""
|
||||||
|
Condition is function which takes in one arguments, (x, y, z).
|
||||||
|
"""
|
||||||
|
rgb = Color(color).get_rgb()
|
||||||
|
for mob in self.get_full_submobject_family():
|
||||||
|
if condition:
|
||||||
|
to_change = np.apply_along_axis(condition, 1, mob.points)
|
||||||
|
mob.rgbs[to_change, :] = rgb
|
||||||
|
else:
|
||||||
|
mob.rgbs[:,:] = rgb
|
||||||
|
return self
|
||||||
|
|
||||||
|
def filter_out(self, condition):
|
||||||
|
for mob in self.get_full_submobject_family():
|
||||||
|
to_eliminate = ~np.apply_along_axis(condition, 1, mob.points)
|
||||||
|
mob.points = mob.points[to_eliminate]
|
||||||
|
mob.rgbs = mob.rgbs[to_eliminate]
|
||||||
|
return self
|
||||||
|
|
||||||
|
def sort_points(self, function = lambda p : p[0]):
|
||||||
|
"""
|
||||||
|
function is any map from R^3 to R
|
||||||
|
"""
|
||||||
|
for mob in self.get_full_submobject_family():
|
||||||
|
indices = range(len(mob.points))
|
||||||
|
indices.sort(
|
||||||
|
lambda *pair : cmp(*map(function, mob.points[pair, :]))
|
||||||
|
)
|
||||||
|
mob.points = mob.points[indices]
|
||||||
|
mob.rgbs = mob.rgbs[indices]
|
||||||
|
return self
|
||||||
|
|
||||||
def repeat(self, count):
|
def repeat(self, count):
|
||||||
#Can make transition animations nicer
|
"""
|
||||||
points, rgbs = deepcopy(self.points), deepcopy(self.rgbs)
|
This can make transition animations nicer
|
||||||
for x in range(count - 1):
|
"""
|
||||||
self.add_points(points, rgbs)
|
def repeat_array(array):
|
||||||
|
return reduce(
|
||||||
|
lambda a1, a2 : np.append(a1, a2, axis = 0),
|
||||||
|
[array]*count
|
||||||
|
)
|
||||||
|
for mob in self.get_full_submobject_family():
|
||||||
|
mob.apply_over_attr_arrays(repeat_array)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
#### In place operations ######
|
||||||
|
|
||||||
def do_in_place(self, method, *args, **kwargs):
|
def do_in_place(self, method, *args, **kwargs):
|
||||||
center = self.get_center()
|
center = self.get_center()
|
||||||
self.shift(-center)
|
self.shift(-center)
|
||||||
|
@ -92,96 +203,50 @@ class Mobject(object):
|
||||||
self.shift(center)
|
self.shift(center)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate(self, angle, axis = OUT):
|
|
||||||
t_rotation_matrix = np.transpose(rotation_matrix(angle, axis))
|
|
||||||
self.points = np.dot(self.points, t_rotation_matrix)
|
|
||||||
if self.has_normals:
|
|
||||||
self.unit_normals = np.dot(self.unit_normals, t_rotation_matrix)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def rotate_in_place(self, angle, axis = OUT):
|
def rotate_in_place(self, angle, axis = OUT):
|
||||||
self.do_in_place(self.rotate, angle, axis)
|
self.do_in_place(self.rotate, angle, axis)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def shift(self, vector):
|
|
||||||
self.points += vector
|
|
||||||
return self
|
|
||||||
|
|
||||||
def wag(self, wag_direction = RIGHT, wag_axis = DOWN,
|
|
||||||
wag_factor = 1.0):
|
|
||||||
alphas = np.dot(self.points, np.transpose(wag_axis))
|
|
||||||
alphas -= min(alphas)
|
|
||||||
alphas /= max(alphas)
|
|
||||||
alphas = alphas**wag_factor
|
|
||||||
self.points += np.dot(
|
|
||||||
alphas.reshape((len(alphas), 1)),
|
|
||||||
np.array(wag_direction).reshape((1, self.DIM))
|
|
||||||
)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def center(self):
|
|
||||||
self.shift(-self.get_center())
|
|
||||||
return self
|
|
||||||
|
|
||||||
#Wrapper functions for better naming
|
|
||||||
def to_corner(self, corner = LEFT+DOWN, buff = DEFAULT_MOBJECT_TO_EDGE_BUFFER):
|
|
||||||
return self.align_on_border(corner, buff)
|
|
||||||
|
|
||||||
def to_edge(self, edge = LEFT, buff = DEFAULT_MOBJECT_TO_EDGE_BUFFER):
|
|
||||||
return self.align_on_border(edge, buff)
|
|
||||||
|
|
||||||
def align_on_border(self, direction, buff = DEFAULT_MOBJECT_TO_EDGE_BUFFER):
|
|
||||||
"""
|
|
||||||
Direction just needs to be a vector pointing towards side or
|
|
||||||
corner in the 2d plane.
|
|
||||||
"""
|
|
||||||
shift_val = np.zeros(3)
|
|
||||||
space_dim = (SPACE_WIDTH, SPACE_HEIGHT)
|
|
||||||
for i in [0, 1]:
|
|
||||||
if direction[i] == 0:
|
|
||||||
continue
|
|
||||||
elif direction[i] > 0:
|
|
||||||
shift_val[i] = space_dim[i]-buff-max(self.points[:,i])
|
|
||||||
else:
|
|
||||||
shift_val[i] = -space_dim[i]+buff-min(self.points[:,i])
|
|
||||||
self.shift(shift_val)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def next_to(self, mobject,
|
|
||||||
direction = RIGHT,
|
|
||||||
buff = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
||||||
aligned_edge = None):
|
|
||||||
direction = direction / np.linalg.norm(direction)
|
|
||||||
if aligned_edge is not None:
|
|
||||||
anchor_point = self.get_corner(aligned_edge-direction)
|
|
||||||
target_point = mobject.get_corner(aligned_edge+direction)
|
|
||||||
elif list(direction) in map(list, [LEFT, RIGHT, UP, DOWN]):
|
|
||||||
anchor_point = self.get_edge_center(-direction)
|
|
||||||
target_point = mobject.get_edge_center(direction)
|
|
||||||
else:
|
|
||||||
anchor_point = self.get_boundary_point(-direction)
|
|
||||||
target_point = mobject.get_boundary_point(direction)
|
|
||||||
self.shift(target_point - anchor_point + buff*direction)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def scale(self, scale_factor):
|
|
||||||
self.points *= scale_factor
|
|
||||||
return self
|
|
||||||
|
|
||||||
def scale_in_place(self, scale_factor):
|
def scale_in_place(self, scale_factor):
|
||||||
self.do_in_place(self.scale, scale_factor)
|
self.do_in_place(self.scale, scale_factor)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def stretch(self, factor, dim):
|
def pose_at_angle(self):
|
||||||
self.points[:,dim] *= factor
|
self.rotate_in_place(np.pi / 7, RIGHT+UP)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def center(self):
|
||||||
|
self.shift(-self.get_center())
|
||||||
|
return self
|
||||||
|
|
||||||
|
def align_on_border(self, direction, buff = DEFAULT_MOBJECT_TO_EDGE_BUFFER):
|
||||||
|
"""
|
||||||
|
Direction just needs to be a vector pointing towards side or
|
||||||
|
corner in the 2d plane.
|
||||||
|
"""
|
||||||
|
target_point = np.sign(direction) * (SPACE_WIDTH, SPACE_HEIGHT, 0)
|
||||||
|
anchor_point = self.get_critical_point(direction)
|
||||||
|
self.shift(target - anchor_point - buff * np.array(direction))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def to_corner(self, corner = LEFT+DOWN, buff = DEFAULT_MOBJECT_TO_EDGE_BUFFER):
|
||||||
|
return self.align_on_border(corner, buff)
|
||||||
|
|
||||||
|
def to_edge(self, edge = LEFT, buff = DEFAULT_MOBJECT_TO_EDGE_BUFFER):
|
||||||
|
return self.align_on_border(edge, buff)
|
||||||
|
|
||||||
|
def next_to(self, mobject,
|
||||||
|
direction = RIGHT,
|
||||||
|
buff = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
||||||
|
aligned_edge = ORIGIN):
|
||||||
|
anchor_point = self.get_critical_point(aligned_edge-direction)
|
||||||
|
target_point = mobject.get_critical_point(aligned_edge+direction)
|
||||||
|
self.shift(target_point - anchor_point + buff*direction)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def stretch_to_fit(self, length, dim):
|
def stretch_to_fit(self, length, dim):
|
||||||
center = self.get_center()
|
old_length = self.length_over_dim(dim)
|
||||||
old_length = max(self.points[:,dim]) - min(self.points[:,dim])
|
self.do_in_place(self.stretch, length/old_length, dim)
|
||||||
self.center()
|
|
||||||
self.stretch(length/old_length, dim)
|
|
||||||
self.shift(center)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def stretch_to_fit_width(self, width):
|
def stretch_to_fit_width(self, width):
|
||||||
|
@ -196,11 +261,6 @@ class Mobject(object):
|
||||||
def scale_to_fit_height(self, height):
|
def scale_to_fit_height(self, height):
|
||||||
return self.scale(height/self.get_height())
|
return self.scale(height/self.get_height())
|
||||||
|
|
||||||
def pose_at_angle(self):
|
|
||||||
self.rotate(np.pi / 7)
|
|
||||||
self.rotate(np.pi / 7, [1, 0, 0])
|
|
||||||
return self
|
|
||||||
|
|
||||||
def replace(self, mobject, stretch = False):
|
def replace(self, mobject, stretch = False):
|
||||||
if mobject.get_num_points() == 0:
|
if mobject.get_num_points() == 0:
|
||||||
raise Warning("Attempting to replace mobject with no points")
|
raise Warning("Attempting to replace mobject with no points")
|
||||||
|
@ -213,27 +273,11 @@ class Mobject(object):
|
||||||
self.center().shift(mobject.get_center())
|
self.center().shift(mobject.get_center())
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def apply_function(self, function):
|
|
||||||
self.points = np.apply_along_axis(function, 1, self.points)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def apply_complex_function(self, function):
|
def apply_complex_function(self, function):
|
||||||
return self.apply_function(
|
return self.apply_function(
|
||||||
lambda (x, y, z) : complex_to_R3(function(complex(x, y)))
|
lambda (x, y, z) : complex_to_R3(function(complex(x, y)))
|
||||||
)
|
)
|
||||||
|
|
||||||
def highlight(self, color = "yellow", condition = None):
|
|
||||||
"""
|
|
||||||
Condition is function which takes in one arguments, (x, y, z).
|
|
||||||
"""
|
|
||||||
rgb = Color(color).get_rgb()
|
|
||||||
if condition:
|
|
||||||
to_change = np.apply_along_axis(condition, 1, self.points)
|
|
||||||
self.rgbs[to_change, :] = rgb
|
|
||||||
else:
|
|
||||||
self.rgbs[:,:] = rgb
|
|
||||||
return self
|
|
||||||
|
|
||||||
def set_color(self, color):
|
def set_color(self, color):
|
||||||
self.highlight(color)
|
self.highlight(color)
|
||||||
self.color = Color(color)
|
self.color = Color(color)
|
||||||
|
@ -245,59 +289,92 @@ class Mobject(object):
|
||||||
|
|
||||||
def fade_to(self, color, alpha):
|
def fade_to(self, color, alpha):
|
||||||
self.rgbs = interpolate(self.rgbs, Color(color).rgb, alpha)
|
self.rgbs = interpolate(self.rgbs, Color(color).rgb, alpha)
|
||||||
|
for mob in self.sub_mobjects:
|
||||||
|
mob.fade_to(color, alpha)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def fade(self, brightness = 0.5):
|
def fade(self, brightness = 0.5):
|
||||||
self.rgbs *= brightness
|
self.fade_to(BLACK, brightness)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def filter_out(self, condition):
|
def reduce_across_dimension(self, points_func, reduce_func, dim):
|
||||||
to_eliminate = ~np.apply_along_axis(condition, 1, self.points)
|
try:
|
||||||
self.points = self.points[to_eliminate]
|
values = [points_func(self.points[:, dim])]
|
||||||
self.rgbs = self.rgbs[to_eliminate]
|
except:
|
||||||
return self
|
values = []
|
||||||
|
values += [
|
||||||
|
mob.reduce_across_dimension(points_func, reduce_func, dim)
|
||||||
|
for mob in self.sub_mobjects
|
||||||
|
]
|
||||||
|
try:
|
||||||
|
return reduce_func(values)
|
||||||
|
except:
|
||||||
|
return 0
|
||||||
|
|
||||||
def sort_points(self, function = lambda p : p[0]):
|
def get_merged_array(self, array_attr):
|
||||||
"""
|
return reduce(
|
||||||
function is any map from R^3 to R
|
lambda a1, a2 : np.append(a1, a2, axis = 0),
|
||||||
"""
|
[getattr(self, array_attr)] + [
|
||||||
indices = range(self.get_num_points())
|
mob.get_merged_array(array_attr)
|
||||||
indices.sort(
|
for mob in self.sub_mobjects
|
||||||
lambda *pair : cmp(*map(function, self.points[pair, :]))
|
]
|
||||||
)
|
)
|
||||||
self.points = self.points[indices]
|
|
||||||
self.rgbs = self.rgbs[indices]
|
def get_all_points(self):
|
||||||
|
return self.get_merged_array("points")
|
||||||
|
|
||||||
|
def ingest_sub_mobjects(self):
|
||||||
|
for attr in self.get_array_attrs():
|
||||||
|
setattr(self, attr, get_merged_array(attr))
|
||||||
|
self.sub_mobjects = []
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def split(self):
|
||||||
|
result = [self] if len(self.points) > 0 else []
|
||||||
|
return result + self.sub_mobjects
|
||||||
|
|
||||||
|
def get_full_submobject_family(self):
|
||||||
|
sub_families = map(Mobject.get_full_submobject_family, self.sub_mobjects)
|
||||||
|
all_mobjects = [self] + reduce(op.add, sub_families, [])
|
||||||
|
return remove_list_redundancies(all_mobjects)
|
||||||
|
|
||||||
### Getters ###
|
### Getters ###
|
||||||
|
|
||||||
def get_num_points(self):
|
def get_num_points(self, including_submobjects = False):
|
||||||
return len(self.points)
|
return self.reduce_across_dimension(len, sum, 0)
|
||||||
|
|
||||||
def get_center(self):
|
def get_critical_point(self, direction):
|
||||||
if self.get_num_points() == 0:
|
result = np.zeros(self.DIM)
|
||||||
return ORIGIN
|
for dim in [0, 1]:
|
||||||
return (np.max(self.points, 0) + np.min(self.points, 0))/2.0
|
if direction[dim] <= 0:
|
||||||
|
min_point = self.reduce_across_dimension(np.min, np.min, dim)
|
||||||
|
if direction[dim] >= 0:
|
||||||
|
max_point = self.reduce_across_dimension(np.max, np.max, dim)
|
||||||
|
|
||||||
def get_center_of_mass(self):
|
if direction[dim] == 0:
|
||||||
return np.apply_along_axis(np.mean, 0, self.points)
|
result[dim] = (max_point+min_point)/2
|
||||||
|
elif direction[dim] < 0:
|
||||||
def get_boundary_point(self, direction):
|
result[dim] = min_point
|
||||||
return self.points[np.argmax(np.dot(self.points, direction))]
|
else:
|
||||||
|
result[dim] = max_point
|
||||||
def get_edge_center(self, direction):
|
|
||||||
dim = np.argmax(map(abs, direction))
|
|
||||||
max_or_min_func = np.max if direction[dim] > 0 else np.min
|
|
||||||
result = self.get_center()
|
|
||||||
result[dim] = max_or_min_func(self.points[:,dim])
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
# Pseudonyms for more general get_critical_point method
|
||||||
|
def get_edge_center(self, direction):
|
||||||
|
return self.get_critical_point(direction)
|
||||||
|
|
||||||
def get_corner(self, direction):
|
def get_corner(self, direction):
|
||||||
return sum([
|
return self.get_critical_point(direction)
|
||||||
self.get_edge_center(RIGHT*direction[0]),
|
|
||||||
self.get_edge_center(UP*direction[1]),
|
def get_center(self):
|
||||||
-self.get_center()
|
return self.get_critical_point(np.zeros(self.DIM))
|
||||||
])
|
|
||||||
|
def get_center_of_mass(self):
|
||||||
|
return np.apply_along_axis(np.mean, 0, self.get_all_points())
|
||||||
|
|
||||||
|
def get_boundary_point(self, direction):
|
||||||
|
all_points = self.get_all_points()
|
||||||
|
return all_points[np.argmax(np.dot(all_points, direction))]
|
||||||
|
|
||||||
def get_top(self):
|
def get_top(self):
|
||||||
return self.get_edge_center(UP)
|
return self.get_edge_center(UP)
|
||||||
|
@ -311,11 +388,18 @@ class Mobject(object):
|
||||||
def get_left(self):
|
def get_left(self):
|
||||||
return self.get_edge_center(LEFT)
|
return self.get_edge_center(LEFT)
|
||||||
|
|
||||||
|
def length_over_dim(self, dim):
|
||||||
|
return (
|
||||||
|
self.reduce_across_dimension(np.max, np.max, dim) -
|
||||||
|
self.reduce_across_dimension(np.min, np.min, dim)
|
||||||
|
)
|
||||||
|
|
||||||
def get_width(self):
|
def get_width(self):
|
||||||
return np.max(self.points[:, 0]) - np.min(self.points[:, 0])
|
return self.length_over_dim(0)
|
||||||
|
|
||||||
def get_height(self):
|
def get_height(self):
|
||||||
return np.max(self.points[:, 1]) - np.min(self.points[:, 1])
|
return self.length_over_dim(1)
|
||||||
|
|
||||||
|
|
||||||
def get_color(self):
|
def get_color(self):
|
||||||
color = Color()
|
color = Color()
|
||||||
|
@ -346,7 +430,7 @@ class Mobject(object):
|
||||||
and mobject2.
|
and mobject2.
|
||||||
"""
|
"""
|
||||||
Mobject.align_data(mobject1, mobject2)
|
Mobject.align_data(mobject1, mobject2)
|
||||||
for attr in ['points', 'rgbs']:
|
for attr in self.get_array_attrs():
|
||||||
setattr(target_mobject, attr, interpolate(
|
setattr(target_mobject, attr, interpolate(
|
||||||
getattr(mobject1, attr),
|
getattr(mobject1, attr),
|
||||||
getattr(mobject2, attr),
|
getattr(mobject2, attr),
|
||||||
|
@ -380,29 +464,6 @@ class Mobject2D(Mobject):
|
||||||
self.epsilon = 1.0 / self.density
|
self.epsilon = 1.0 / self.density
|
||||||
Mobject.__init__(self, **kwargs)
|
Mobject.__init__(self, **kwargs)
|
||||||
|
|
||||||
class CompoundMobject(Mobject):
|
|
||||||
def __init__(self, *mobjects):
|
|
||||||
Mobject.__init__(self)
|
|
||||||
self.original_mobs_num_points = []
|
|
||||||
for mobject in mobjects:
|
|
||||||
self.original_mobs_num_points.append(mobject.points.shape[0])
|
|
||||||
self.add_points(mobject.points, mobject.rgbs)
|
|
||||||
self.point_thickness = max([
|
|
||||||
m.point_thickness
|
|
||||||
for m in mobjects
|
|
||||||
])
|
|
||||||
|
|
||||||
def split(self):
|
|
||||||
result = []
|
|
||||||
curr = 0
|
|
||||||
for num_points in self.original_mobs_num_points:
|
|
||||||
result.append(Mobject().add_points(
|
|
||||||
self.points[curr:curr+num_points, :],
|
|
||||||
self.rgbs[curr:curr+num_points, :]
|
|
||||||
))
|
|
||||||
curr += num_points
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
class Point(Mobject):
|
class Point(Mobject):
|
||||||
DEFAULT_CONFIG = {
|
DEFAULT_CONFIG = {
|
||||||
|
@ -415,47 +476,6 @@ class Point(Mobject):
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
self.add_points([self.location])
|
self.add_points([self.location])
|
||||||
|
|
||||||
# class CompoundMobject(Mobject):
|
|
||||||
# """
|
|
||||||
# Treats a collection of mobjects as if they were one.
|
|
||||||
|
|
||||||
# A weird form of inhertance is at play here...
|
|
||||||
# """
|
|
||||||
# def __init__(self, *mobjects):
|
|
||||||
# Mobject.__init__(self)
|
|
||||||
# self.mobjects = mobjects
|
|
||||||
# name_to_method = dict(
|
|
||||||
# inspect.getmembers(Mobject, predicate = inspect.ismethod)
|
|
||||||
# )
|
|
||||||
# names = name_to_method.keys()
|
|
||||||
# #Most reductions take the form of mapping a given method across
|
|
||||||
# #all constituent mobjects, then just returning self.
|
|
||||||
# name_to_reduce = dict([
|
|
||||||
# (name, lambda list : self)
|
|
||||||
# for name in names
|
|
||||||
# ])
|
|
||||||
# name_to_reduce.update(self.get_special_reduce_functions())
|
|
||||||
# def make_pseudo_method(name):
|
|
||||||
# return lambda *args, **kwargs : name_to_reduce[name]([
|
|
||||||
# name_to_method[name](mob, *args, **kwargs)
|
|
||||||
# for mob in self.mobjects
|
|
||||||
# ])
|
|
||||||
# for name in names:
|
|
||||||
# setattr(self, name, make_pseudo_method(name))
|
|
||||||
|
|
||||||
# def show(self):
|
|
||||||
|
|
||||||
|
|
||||||
# def get_special_reduce_functions(self):
|
|
||||||
# return {}
|
|
||||||
|
|
||||||
# def handle_method(self, method_name, *args, **kwargs):
|
|
||||||
# pass
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,7 @@ class ShowFrameNum(OverHand):
|
||||||
OverHand.construct(self)
|
OverHand.construct(self)
|
||||||
for frame, count in zip(self.frames, it.count()):
|
for frame, count in zip(self.frames, it.count()):
|
||||||
print count, "of", len(self.frames)
|
print count, "of", len(self.frames)
|
||||||
mob = CompoundMobject(*[
|
mob = Mobject(*[
|
||||||
TexMobject(char).shift(0.3*x*RIGHT)
|
TexMobject(char).shift(0.3*x*RIGHT)
|
||||||
for char, x, in zip(str(count), it.count())
|
for char, x, in zip(str(count), it.count())
|
||||||
])
|
])
|
||||||
|
@ -212,12 +212,12 @@ class CountTo1023(Scene):
|
||||||
rh_map = get_hand_map("right")
|
rh_map = get_hand_map("right")
|
||||||
lh_map = get_hand_map("left")
|
lh_map = get_hand_map("left")
|
||||||
def get_num(count):
|
def get_num(count):
|
||||||
return CompoundMobject(*[
|
return Mobject(*[
|
||||||
TexMobject(char).shift(0.35*x*RIGHT)
|
TexMobject(char).shift(0.35*x*RIGHT)
|
||||||
for char, x, in zip(str(count), it.count())
|
for char, x, in zip(str(count), it.count())
|
||||||
]).center().to_edge(UP)
|
]).center().to_edge(UP)
|
||||||
self.frames = [
|
self.frames = [
|
||||||
disp.paint_mobject(CompoundMobject(
|
disp.paint_mobject(Mobject(
|
||||||
rh_map[count%32], lh_map[count//32], get_num(count)
|
rh_map[count%32], lh_map[count//32], get_num(count)
|
||||||
))
|
))
|
||||||
for count in range(2**10)
|
for count in range(2**10)
|
||||||
|
@ -360,7 +360,7 @@ class ShowIncrementRule(Scene):
|
||||||
(2.25, 3.5, 0),
|
(2.25, 3.5, 0),
|
||||||
(1.5, 0.75, 0),
|
(1.5, 0.75, 0),
|
||||||
]
|
]
|
||||||
return CompoundMobject(*[
|
return Mobject(*[
|
||||||
deepcopy(arrow).shift(tip)
|
deepcopy(arrow).shift(tip)
|
||||||
for tip in tips
|
for tip in tips
|
||||||
])
|
])
|
||||||
|
@ -379,7 +379,7 @@ class MindFindsShortcuts(Scene):
|
||||||
hand = Hand(7).scale(0.5).center().shift(DOWN+2*LEFT)
|
hand = Hand(7).scale(0.5).center().shift(DOWN+2*LEFT)
|
||||||
sum421 = TexMobject("4+2+1").shift(DOWN+2*RIGHT)
|
sum421 = TexMobject("4+2+1").shift(DOWN+2*RIGHT)
|
||||||
seven = TexMobject("7").shift(DOWN+6*RIGHT)
|
seven = TexMobject("7").shift(DOWN+6*RIGHT)
|
||||||
compound = CompoundMobject(
|
compound = Mobject(
|
||||||
Arrow(hand, sum421),
|
Arrow(hand, sum421),
|
||||||
sum421,
|
sum421,
|
||||||
Arrow(sum421, seven)
|
Arrow(sum421, seven)
|
||||||
|
@ -438,7 +438,7 @@ class CountingExampleSentence(ShowCounting):
|
||||||
ShowCounting.construct(self)
|
ShowCounting.construct(self)
|
||||||
|
|
||||||
def get_counting_mob(self, num):
|
def get_counting_mob(self, num):
|
||||||
return CompoundMobject(*self.words[:num])
|
return Mobject(*self.words[:num])
|
||||||
|
|
||||||
class FinishCountingExampleSentence(Scene):
|
class FinishCountingExampleSentence(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
@ -449,7 +449,7 @@ class FinishCountingExampleSentence(Scene):
|
||||||
two = TexMobject("2").shift([3, 3.65, 0])
|
two = TexMobject("2").shift([3, 3.65, 0])
|
||||||
eightteen = TexMobject("18").shift([1.5, 2.5, 0])
|
eightteen = TexMobject("18").shift([1.5, 2.5, 0])
|
||||||
eightteen.sort_points()
|
eightteen.sort_points()
|
||||||
comp = CompoundMobject(sixteen, two)
|
comp = Mobject(sixteen, two)
|
||||||
self.add(hand, comp, words)
|
self.add(hand, comp, words)
|
||||||
self.dither()
|
self.dither()
|
||||||
self.play(Transform(comp, eightteen))
|
self.play(Transform(comp, eightteen))
|
||||||
|
|
|
@ -50,7 +50,7 @@ class PreferOtherProofDialogue(Scene):
|
||||||
self.dither(2)
|
self.dither(2)
|
||||||
self.play(Transform(
|
self.play(Transform(
|
||||||
Dot(student_bubble.tip).highlight("black"),
|
Dot(student_bubble.tip).highlight("black"),
|
||||||
CompoundMobject(student_bubble, student_bubble.text)
|
Mobject(student_bubble, student_bubble.text)
|
||||||
))
|
))
|
||||||
self.dither(2)
|
self.dither(2)
|
||||||
self.remove(teacher_bubble.text)
|
self.remove(teacher_bubble.text)
|
||||||
|
@ -81,7 +81,7 @@ class IllustrateDuality(GraphScene):
|
||||||
for edge_pair in zip(self.edges, self.dual_edges)
|
for edge_pair in zip(self.edges, self.dual_edges)
|
||||||
] + [
|
] + [
|
||||||
Transform(
|
Transform(
|
||||||
CompoundMobject(*[
|
Mobject(*[
|
||||||
self.vertices[index]
|
self.vertices[index]
|
||||||
for index in cycle
|
for index in cycle
|
||||||
]),
|
]),
|
||||||
|
@ -143,7 +143,7 @@ class IntroduceGraph(GraphScene):
|
||||||
self.add(not_okay)
|
self.add(not_okay)
|
||||||
self.remove(*edges_to_remove)
|
self.remove(*edges_to_remove)
|
||||||
self.play(ShowCreation(
|
self.play(ShowCreation(
|
||||||
CompoundMobject(*edges_to_remove),
|
Mobject(*edges_to_remove),
|
||||||
alpha_func = lambda t : 1 - t,
|
alpha_func = lambda t : 1 - t,
|
||||||
run_time = 1.0
|
run_time = 1.0
|
||||||
))
|
))
|
||||||
|
@ -182,10 +182,10 @@ class PlanarGraphDefinition(Scene):
|
||||||
"Not \\\\", "``", "Planar", "''",
|
"Not \\\\", "``", "Planar", "''",
|
||||||
# "no matter how \\\\ hard you try"
|
# "no matter how \\\\ hard you try"
|
||||||
]).split()
|
]).split()
|
||||||
shift_val = CompoundMobject(Not, planar).to_corner().get_center()
|
shift_val = Mobject(Not, planar).to_corner().get_center()
|
||||||
Not.highlight("red").shift(shift_val)
|
Not.highlight("red").shift(shift_val)
|
||||||
graphs = [
|
graphs = [
|
||||||
CompoundMobject(*GraphScene(g).mobjects)
|
Mobject(*GraphScene(g).mobjects)
|
||||||
for g in [
|
for g in [
|
||||||
CubeGraph(),
|
CubeGraph(),
|
||||||
CompleteGraph(5),
|
CompleteGraph(5),
|
||||||
|
@ -227,7 +227,7 @@ class TerminologyFromPolyhedra(GraphScene):
|
||||||
point / 2 + OUT if abs(point[0]) == 2 else point + IN
|
point / 2 + OUT if abs(point[0]) == 2 else point + IN
|
||||||
for point in self.points
|
for point in self.points
|
||||||
]
|
]
|
||||||
cube = CompoundMobject(*[
|
cube = Mobject(*[
|
||||||
Line(vertices[edge[0]], vertices[edge[1]])
|
Line(vertices[edge[0]], vertices[edge[1]])
|
||||||
for edge in self.graph.edges
|
for edge in self.graph.edges
|
||||||
])
|
])
|
||||||
|
@ -258,7 +258,7 @@ class TerminologyFromPolyhedra(GraphScene):
|
||||||
self.remove(dots_to_vertices, *self.vertices)
|
self.remove(dots_to_vertices, *self.vertices)
|
||||||
self.add(lines_to_edges)
|
self.add(lines_to_edges)
|
||||||
self.play(ApplyMethod(
|
self.play(ApplyMethod(
|
||||||
CompoundMobject(*self.edges).highlight, "yellow"
|
Mobject(*self.edges).highlight, "yellow"
|
||||||
))
|
))
|
||||||
self.dither(2)
|
self.dither(2)
|
||||||
self.clear()
|
self.clear()
|
||||||
|
@ -312,7 +312,7 @@ class ThreePiecesOfTerminology(GraphScene):
|
||||||
|
|
||||||
self.clear()
|
self.clear()
|
||||||
self.play(ApplyMethod(
|
self.play(ApplyMethod(
|
||||||
CompoundMobject(*terms).center
|
Mobject(*terms).center
|
||||||
))
|
))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
@ -361,14 +361,14 @@ class PathExamples(GraphScene):
|
||||||
mob.to_edge(UP)
|
mob.to_edge(UP)
|
||||||
kwargs = {"run_time" : 1.0}
|
kwargs = {"run_time" : 1.0}
|
||||||
for path, non_path in zip(paths, non_paths):
|
for path, non_path in zip(paths, non_paths):
|
||||||
path_lines = CompoundMobject(*[
|
path_lines = Mobject(*[
|
||||||
Line(
|
Line(
|
||||||
self.points[path[i]],
|
self.points[path[i]],
|
||||||
self.points[path[i+1]]
|
self.points[path[i+1]]
|
||||||
).highlight("yellow")
|
).highlight("yellow")
|
||||||
for i in range(len(path) - 1)
|
for i in range(len(path) - 1)
|
||||||
])
|
])
|
||||||
non_path_lines = CompoundMobject(*[
|
non_path_lines = Mobject(*[
|
||||||
Line(
|
Line(
|
||||||
self.points[pp[0]],
|
self.points[pp[0]],
|
||||||
self.points[pp[1]],
|
self.points[pp[1]],
|
||||||
|
@ -430,7 +430,7 @@ class DefineSpanningTree(GraphScene):
|
||||||
randy.scale(RANDOLPH_SCALE_VAL).move_to(self.points[0])
|
randy.scale(RANDOLPH_SCALE_VAL).move_to(self.points[0])
|
||||||
dollar_signs = TextMobject("\\$\\$")
|
dollar_signs = TextMobject("\\$\\$")
|
||||||
dollar_signs.scale(EDGE_ANNOTATION_SCALE_VAL)
|
dollar_signs.scale(EDGE_ANNOTATION_SCALE_VAL)
|
||||||
dollar_signs = CompoundMobject(*[
|
dollar_signs = Mobject(*[
|
||||||
deepcopy(dollar_signs).shift(edge.get_center())
|
deepcopy(dollar_signs).shift(edge.get_center())
|
||||||
for edge in self.edges
|
for edge in self.edges
|
||||||
])
|
])
|
||||||
|
@ -494,8 +494,8 @@ class NamingTree(GraphScene):
|
||||||
|
|
||||||
self.add(*branches)
|
self.add(*branches)
|
||||||
self.play(
|
self.play(
|
||||||
FadeOut(CompoundMobject(*self.edges + self.vertices)),
|
FadeOut(Mobject(*self.edges + self.vertices)),
|
||||||
Animation(CompoundMobject(*branches)),
|
Animation(Mobject(*branches)),
|
||||||
)
|
)
|
||||||
self.clear()
|
self.clear()
|
||||||
self.add(tree, *branches)
|
self.add(tree, *branches)
|
||||||
|
@ -599,7 +599,7 @@ class FacebookGraphAsAbstractSet(Scene):
|
||||||
accounts.shift(3*LEFT).to_edge(UP)
|
accounts.shift(3*LEFT).to_edge(UP)
|
||||||
friendships = TextMobject("\\textbf{Friendships}")
|
friendships = TextMobject("\\textbf{Friendships}")
|
||||||
friendships.shift(3*RIGHT).to_edge(UP)
|
friendships.shift(3*RIGHT).to_edge(UP)
|
||||||
lines = CompoundMobject(
|
lines = Mobject(
|
||||||
Line(UP*SPACE_HEIGHT, DOWN*SPACE_HEIGHT),
|
Line(UP*SPACE_HEIGHT, DOWN*SPACE_HEIGHT),
|
||||||
Line(LEFT*SPACE_WIDTH + 3*UP, RIGHT*SPACE_WIDTH + 3*UP)
|
Line(LEFT*SPACE_WIDTH + 3*UP, RIGHT*SPACE_WIDTH + 3*UP)
|
||||||
).highlight("white")
|
).highlight("white")
|
||||||
|
@ -622,7 +622,7 @@ class ExamplesOfGraphs(GraphScene):
|
||||||
)
|
)
|
||||||
GraphScene.construct(self)
|
GraphScene.construct(self)
|
||||||
self.generate_regions()
|
self.generate_regions()
|
||||||
objects, notions = CompoundMobject(*TextMobject(
|
objects, notions = Mobject(*TextMobject(
|
||||||
["Objects \\quad\\quad ", "Thing that connects objects"]
|
["Objects \\quad\\quad ", "Thing that connects objects"]
|
||||||
)).to_corner().shift(0.5*RIGHT).split()
|
)).to_corner().shift(0.5*RIGHT).split()
|
||||||
horizontal_line = Line(
|
horizontal_line = Line(
|
||||||
|
@ -687,8 +687,8 @@ class ExamplesOfGraphs(GraphScene):
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
comp_words = CompoundMobject(*words)
|
comp_words = Mobject(*words)
|
||||||
comp_lines = CompoundMobject(*lines)
|
comp_lines = Mobject(*lines)
|
||||||
self.add(words1)
|
self.add(words1)
|
||||||
self.play(ShowCreation(comp_words, run_time = 1.0))
|
self.play(ShowCreation(comp_words, run_time = 1.0))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
@ -852,7 +852,7 @@ class ListOfCorrespondances(Scene):
|
||||||
left.shift((min(arrow_xs) - SPACE_WIDTH, 0, 0))
|
left.shift((min(arrow_xs) - SPACE_WIDTH, 0, 0))
|
||||||
right.to_edge(LEFT)
|
right.to_edge(LEFT)
|
||||||
right.shift((max(arrow_xs) + SPACE_WIDTH, 0, 0))
|
right.shift((max(arrow_xs) + SPACE_WIDTH, 0, 0))
|
||||||
lines.append(CompoundMobject(left, right, this_arrow))
|
lines.append(Mobject(left, right, this_arrow))
|
||||||
last = None
|
last = None
|
||||||
for line in lines:
|
for line in lines:
|
||||||
self.add(line.highlight("yellow"))
|
self.add(line.highlight("yellow"))
|
||||||
|
@ -892,7 +892,7 @@ class CyclesCorrespondWithConnectedComponents(GraphScene):
|
||||||
self.highlight_region(region)
|
self.highlight_region(region)
|
||||||
self.dither(2)
|
self.dither(2)
|
||||||
self.reset_background()
|
self.reset_background()
|
||||||
lines = CompoundMobject(*[
|
lines = Mobject(*[
|
||||||
Line(self.dual_points[last], self.dual_points[next])
|
Line(self.dual_points[last], self.dual_points[next])
|
||||||
for last, next in zip(dual_cycle, dual_cycle[1:])
|
for last, next in zip(dual_cycle, dual_cycle[1:])
|
||||||
]).highlight("red")
|
]).highlight("red")
|
||||||
|
@ -1015,7 +1015,7 @@ class RandolphMortimerSpanningTreeGame(GraphScene):
|
||||||
cycle_index = region_ordering[-1]
|
cycle_index = region_ordering[-1]
|
||||||
cycle = self.graph.region_cycles[cycle_index]
|
cycle = self.graph.region_cycles[cycle_index]
|
||||||
self.highlight_region(self.regions[cycle_index], "black")
|
self.highlight_region(self.regions[cycle_index], "black")
|
||||||
self.play(ShowCreation(CompoundMobject(*[
|
self.play(ShowCreation(Mobject(*[
|
||||||
Line(self.points[last], self.points[next]).highlight("green")
|
Line(self.points[last], self.points[next]).highlight("green")
|
||||||
for last, next in zip(cycle, list(cycle)[1:] + [cycle[0]])
|
for last, next in zip(cycle, list(cycle)[1:] + [cycle[0]])
|
||||||
])))
|
])))
|
||||||
|
@ -1116,7 +1116,7 @@ class DualSpanningTree(GraphScene):
|
||||||
""").to_edge(UP)
|
""").to_edge(UP)
|
||||||
|
|
||||||
self.add(self.spanning_tree, randy, morty)
|
self.add(self.spanning_tree, randy, morty)
|
||||||
self.play(ShowCreation(CompoundMobject(
|
self.play(ShowCreation(Mobject(
|
||||||
*np.array(self.edges)[dual_edges]
|
*np.array(self.edges)[dual_edges]
|
||||||
).highlight("red")))
|
).highlight("red")))
|
||||||
self.add(words)
|
self.add(words)
|
||||||
|
@ -1147,7 +1147,7 @@ class TreeCountFormula(Scene):
|
||||||
self.remove(*all_dots)
|
self.remove(*all_dots)
|
||||||
self.play(
|
self.play(
|
||||||
FadeOut(text),
|
FadeOut(text),
|
||||||
FadeIn(CompoundMobject(*gs.edges + gs.vertices)),
|
FadeIn(Mobject(*gs.edges + gs.vertices)),
|
||||||
*[
|
*[
|
||||||
Transform(*pair)
|
Transform(*pair)
|
||||||
for pair in zip(branches,gs.spanning_tree.split())
|
for pair in zip(branches,gs.spanning_tree.split())
|
||||||
|
@ -1162,7 +1162,7 @@ class FinalSum(Scene):
|
||||||
"(\\text{Number of Mortimer's Edges}) + 1 &= F \\\\ \n",
|
"(\\text{Number of Mortimer's Edges}) + 1 &= F \\\\ \n",
|
||||||
" \\Downarrow \\\\", "E","+","2","&=","V","+","F",
|
" \\Downarrow \\\\", "E","+","2","&=","V","+","F",
|
||||||
], size = "\\large").split()
|
], size = "\\large").split()
|
||||||
for line in lines[:2] + [CompoundMobject(*lines[2:])]:
|
for line in lines[:2] + [Mobject(*lines[2:])]:
|
||||||
self.add(line)
|
self.add(line)
|
||||||
self.dither()
|
self.dither()
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
|
@ -96,7 +96,7 @@ def zero_to_one_interval():
|
||||||
interval.elongate_tick_at(INTERVAL_RADIUS, 4)
|
interval.elongate_tick_at(INTERVAL_RADIUS, 4)
|
||||||
zero = TexMobject("0").shift(INTERVAL_RADIUS*LEFT+DOWN)
|
zero = TexMobject("0").shift(INTERVAL_RADIUS*LEFT+DOWN)
|
||||||
one = TexMobject("1").shift(INTERVAL_RADIUS*RIGHT+DOWN)
|
one = TexMobject("1").shift(INTERVAL_RADIUS*RIGHT+DOWN)
|
||||||
return CompoundMobject(interval, zero, one)
|
return Mobject(interval, zero, one)
|
||||||
|
|
||||||
def draw_you(with_bubble = False):
|
def draw_you(with_bubble = False):
|
||||||
result = PiCreature()
|
result = PiCreature()
|
||||||
|
@ -175,7 +175,7 @@ class IntroduceDivergentSum(Scene):
|
||||||
self.add(brace, sum_value)
|
self.add(brace, sum_value)
|
||||||
self.dither(0.75)
|
self.dither(0.75)
|
||||||
self.remove(sum_value)
|
self.remove(sum_value)
|
||||||
ellipses = CompoundMobject(
|
ellipses = Mobject(
|
||||||
*[equation[NUM_WRITTEN_TERMS + i] for i in range(3)]
|
*[equation[NUM_WRITTEN_TERMS + i] for i in range(3)]
|
||||||
)
|
)
|
||||||
end_brace = deepcopy(brace).stretch_to_fit_width(
|
end_brace = deepcopy(brace).stretch_to_fit_width(
|
||||||
|
@ -264,7 +264,7 @@ class OutlineOfVideo(Scene):
|
||||||
]
|
]
|
||||||
last_one_split = texts[-1].split()
|
last_one_split = texts[-1].split()
|
||||||
last_one_split[1].highlight("skyblue")
|
last_one_split[1].highlight("skyblue")
|
||||||
texts[-1] = CompoundMobject(*last_one_split)
|
texts[-1] = Mobject(*last_one_split)
|
||||||
texts[0].shift(overbrace.get_top()+texts[0].get_height()*UP)
|
texts[0].shift(overbrace.get_top()+texts[0].get_height()*UP)
|
||||||
texts[1].shift(sum([
|
texts[1].shift(sum([
|
||||||
arrow.get_boundary_point(DOWN+RIGHT),
|
arrow.get_boundary_point(DOWN+RIGHT),
|
||||||
|
@ -335,7 +335,7 @@ class OutlineOfVideo(Scene):
|
||||||
# self.add(sum_mob)
|
# self.add(sum_mob)
|
||||||
# self.play(FadeIn(discover))
|
# self.play(FadeIn(discover))
|
||||||
# self.dither()
|
# self.dither()
|
||||||
# self.play(FadeIn(CompoundMobject(*define_parts)))
|
# self.play(FadeIn(Mobject(*define_parts)))
|
||||||
# self.dither()
|
# self.dither()
|
||||||
|
|
||||||
class YouAsMathematician(Scene):
|
class YouAsMathematician(Scene):
|
||||||
|
@ -376,7 +376,7 @@ class YouAsMathematician(Scene):
|
||||||
self.remove(bubble, *equation_parts)
|
self.remove(bubble, *equation_parts)
|
||||||
self.disapproving_friend()
|
self.disapproving_friend()
|
||||||
self.add(bubble, equation)
|
self.add(bubble, equation)
|
||||||
self.play(Transform(equation, CompoundMobject(*dot_pair)))
|
self.play(Transform(equation, Mobject(*dot_pair)))
|
||||||
self.remove(equation)
|
self.remove(equation)
|
||||||
self.add(*dot_pair)
|
self.add(*dot_pair)
|
||||||
two_arrows = [
|
two_arrows = [
|
||||||
|
@ -386,7 +386,7 @@ class YouAsMathematician(Scene):
|
||||||
self.play(*[ShowCreation(a) for a in two_arrows])
|
self.play(*[ShowCreation(a) for a in two_arrows])
|
||||||
self.play(BlinkPiCreature(you))
|
self.play(BlinkPiCreature(you))
|
||||||
self.remove(*dot_pair+two_arrows)
|
self.remove(*dot_pair+two_arrows)
|
||||||
everything = CompoundMobject(*self.mobjects)
|
everything = Mobject(*self.mobjects)
|
||||||
self.clear()
|
self.clear()
|
||||||
self.play(
|
self.play(
|
||||||
ApplyPointwiseFunction(
|
ApplyPointwiseFunction(
|
||||||
|
@ -559,7 +559,7 @@ class OrganizePartialSums(Scene):
|
||||||
|
|
||||||
self.play(ShowCreation(dots))
|
self.play(ShowCreation(dots))
|
||||||
self.dither()
|
self.dither()
|
||||||
self.play(FadeIn(CompoundMobject(down_arrow, infinite_sum)))
|
self.play(FadeIn(Mobject(down_arrow, infinite_sum)))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
class SeeNumbersApproachOne(Scene):
|
class SeeNumbersApproachOne(Scene):
|
||||||
|
@ -569,7 +569,7 @@ class SeeNumbersApproachOne(Scene):
|
||||||
arrow.shift(DOWN).highlight("yellow")
|
arrow.shift(DOWN).highlight("yellow")
|
||||||
num_dots = 6
|
num_dots = 6
|
||||||
colors = Color("green").range_to("yellow", num_dots)
|
colors = Color("green").range_to("yellow", num_dots)
|
||||||
dots = CompoundMobject(*[
|
dots = Mobject(*[
|
||||||
Dot(
|
Dot(
|
||||||
density = 2*DEFAULT_POINT_DENSITY_1D
|
density = 2*DEFAULT_POINT_DENSITY_1D
|
||||||
).scale(1+1.0/2.0**x).shift(
|
).scale(1+1.0/2.0**x).shift(
|
||||||
|
@ -682,7 +682,7 @@ class ListOfPartialSums(Scene):
|
||||||
self.play(ShowCreation(dots))
|
self.play(ShowCreation(dots))
|
||||||
self.dither()
|
self.dither()
|
||||||
self.play(
|
self.play(
|
||||||
FadeIn(CompoundMobject(*equals)),
|
FadeIn(Mobject(*equals)),
|
||||||
*[
|
*[
|
||||||
Transform(deepcopy(number), finite_sum)
|
Transform(deepcopy(number), finite_sum)
|
||||||
for number, finite_sum in zip(numbers, sums)
|
for number, finite_sum in zip(numbers, sums)
|
||||||
|
@ -712,7 +712,7 @@ class ShowDecreasingDistance(Scene):
|
||||||
lines = [vert_line0, vert_line1, horiz_line]
|
lines = [vert_line0, vert_line1, horiz_line]
|
||||||
for line in lines:
|
for line in lines:
|
||||||
line.highlight("green")
|
line.highlight("green")
|
||||||
dots = CompoundMobject(*[
|
dots = Mobject(*[
|
||||||
Dot().scale(1.0/(n+1)).shift((1+partial_sum(n))*RIGHT)
|
Dot().scale(1.0/(n+1)).shift((1+partial_sum(n))*RIGHT)
|
||||||
for n in range(10)
|
for n in range(10)
|
||||||
])
|
])
|
||||||
|
@ -734,7 +734,7 @@ class ShowDecreasingDistance(Scene):
|
||||||
class CircleZoomInOnOne(Scene):
|
class CircleZoomInOnOne(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
number_line = NumberLine(interval_size = 1).add_numbers()
|
number_line = NumberLine(interval_size = 1).add_numbers()
|
||||||
dots = CompoundMobject(*[
|
dots = Mobject(*[
|
||||||
Dot().scale(1.0/(n+1)).shift((1+partial_sum(n))*RIGHT)
|
Dot().scale(1.0/(n+1)).shift((1+partial_sum(n))*RIGHT)
|
||||||
for n in range(10)
|
for n in range(10)
|
||||||
])
|
])
|
||||||
|
@ -849,7 +849,7 @@ class DefineInfiniteSum(Scene):
|
||||||
"\\sum_{n = 0}^\\infty a_n = X"
|
"\\sum_{n = 0}^\\infty a_n = X"
|
||||||
]).split()
|
]).split()
|
||||||
define.highlight("skyblue")
|
define.highlight("skyblue")
|
||||||
expression = CompoundMobject(define, infinite_sum)
|
expression = Mobject(define, infinite_sum)
|
||||||
|
|
||||||
self.add(expression)
|
self.add(expression)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
@ -1041,7 +1041,7 @@ class ChopIntervalInProportions(Scene):
|
||||||
FadeIn(rt[0]),
|
FadeIn(rt[0]),
|
||||||
Transform(
|
Transform(
|
||||||
brace_to_replace.repeat(2),
|
brace_to_replace.repeat(2),
|
||||||
CompoundMobject(*braces)
|
Mobject(*braces)
|
||||||
),
|
),
|
||||||
FadeIn(left_paren),
|
FadeIn(left_paren),
|
||||||
FadeIn(right_paren),
|
FadeIn(right_paren),
|
||||||
|
@ -1052,7 +1052,7 @@ class ChopIntervalInProportions(Scene):
|
||||||
self.play(
|
self.play(
|
||||||
Transform(
|
Transform(
|
||||||
term_to_replace,
|
term_to_replace,
|
||||||
CompoundMobject(lt[0], rt[1])
|
Mobject(lt[0], rt[1])
|
||||||
),
|
),
|
||||||
FadeOut(left_paren),
|
FadeOut(left_paren),
|
||||||
FadeOut(right_paren)
|
FadeOut(right_paren)
|
||||||
|
@ -1064,26 +1064,26 @@ class ChopIntervalInProportions(Scene):
|
||||||
FadeIn(rt[0]),
|
FadeIn(rt[0]),
|
||||||
Transform(
|
Transform(
|
||||||
brace_to_replace.repeat(2),
|
brace_to_replace.repeat(2),
|
||||||
CompoundMobject(*braces)
|
Mobject(*braces)
|
||||||
),
|
),
|
||||||
Transform(
|
Transform(
|
||||||
term_to_replace,
|
term_to_replace,
|
||||||
CompoundMobject(lt[0], rt[1])
|
Mobject(lt[0], rt[1])
|
||||||
),
|
),
|
||||||
*additional_anims
|
*additional_anims
|
||||||
)
|
)
|
||||||
self.remove(*lt+rt)
|
self.remove(*lt+rt)
|
||||||
lt, rt = CompoundMobject(*lt), CompoundMobject(*rt)
|
lt, rt = Mobject(*lt), Mobject(*rt)
|
||||||
self.add(lt, rt)
|
self.add(lt, rt)
|
||||||
else:
|
else:
|
||||||
self.play(
|
self.play(
|
||||||
Transform(
|
Transform(
|
||||||
brace_to_replace.repeat(2),
|
brace_to_replace.repeat(2),
|
||||||
CompoundMobject(*braces)
|
Mobject(*braces)
|
||||||
),
|
),
|
||||||
Transform(
|
Transform(
|
||||||
term_to_replace,
|
term_to_replace,
|
||||||
CompoundMobject(lt, rt)
|
Mobject(lt, rt)
|
||||||
),
|
),
|
||||||
*additional_anims
|
*additional_anims
|
||||||
)
|
)
|
||||||
|
@ -1379,10 +1379,10 @@ class SumPowersOfTwoAnimation(Scene):
|
||||||
new_bottom_num = TexMobject(str(2**(n+1)))
|
new_bottom_num = TexMobject(str(2**(n+1)))
|
||||||
bottom_num.shift(bottombrace.get_center()+0.5*DOWN)
|
bottom_num.shift(bottombrace.get_center()+0.5*DOWN)
|
||||||
|
|
||||||
top_sum = CompoundMobject(*full_top_sum[:n]).center()
|
top_sum = Mobject(*full_top_sum[:n]).center()
|
||||||
top_sum_end = deepcopy(full_top_sum[n]).center()
|
top_sum_end = deepcopy(full_top_sum[n]).center()
|
||||||
top_sum.shift(topbrace.get_center()+0.5*UP)
|
top_sum.shift(topbrace.get_center()+0.5*UP)
|
||||||
new_top_sum = CompoundMobject(*full_top_sum[:(n+1)]).center()
|
new_top_sum = Mobject(*full_top_sum[:(n+1)]).center()
|
||||||
self.add(top_sum, bottom_num)
|
self.add(top_sum, bottom_num)
|
||||||
|
|
||||||
if n == iterations:
|
if n == iterations:
|
||||||
|
@ -1390,7 +1390,7 @@ class SumPowersOfTwoAnimation(Scene):
|
||||||
new_dot = deepcopy(dot).shift(circle.get_center())
|
new_dot = deepcopy(dot).shift(circle.get_center())
|
||||||
shift_val = (2**n)*(dot_width+dot_buff)
|
shift_val = (2**n)*(dot_width+dot_buff)
|
||||||
right += shift_val
|
right += shift_val
|
||||||
new_dots = CompoundMobject(new_dot, curr_dots)
|
new_dots = Mobject(new_dot, curr_dots)
|
||||||
new_dots.highlight(colors.next()).shift(shift_val)
|
new_dots.highlight(colors.next()).shift(shift_val)
|
||||||
alt_bottombrace = deepcopy(bottombrace).shift(shift_val)
|
alt_bottombrace = deepcopy(bottombrace).shift(shift_val)
|
||||||
alt_bottom_num = deepcopy(bottom_num).shift(shift_val)
|
alt_bottom_num = deepcopy(bottom_num).shift(shift_val)
|
||||||
|
@ -1408,7 +1408,7 @@ class SumPowersOfTwoAnimation(Scene):
|
||||||
if exp.get_width() > brace.get_width():
|
if exp.get_width() > brace.get_width():
|
||||||
exp.stretch_to_fit_width(brace.get_width())
|
exp.stretch_to_fit_width(brace.get_width())
|
||||||
new_top_sum = new_top_sum.split()
|
new_top_sum = new_top_sum.split()
|
||||||
new_top_sum_start = CompoundMobject(*new_top_sum[:-1])
|
new_top_sum_start = Mobject(*new_top_sum[:-1])
|
||||||
new_top_sum_end = new_top_sum[-1]
|
new_top_sum_end = new_top_sum[-1]
|
||||||
|
|
||||||
self.dither()
|
self.dither()
|
||||||
|
@ -1438,7 +1438,7 @@ class SumPowersOfTwoAnimation(Scene):
|
||||||
top_sum_end, new_top_sum_end,
|
top_sum_end, new_top_sum_end,
|
||||||
alt_topbrace, alt_bottombrace
|
alt_topbrace, alt_bottombrace
|
||||||
)
|
)
|
||||||
curr_dots = CompoundMobject(curr_dots, new_dots)
|
curr_dots = Mobject(curr_dots, new_dots)
|
||||||
|
|
||||||
|
|
||||||
class PretendTheyDoApproachNegativeOne(RearrangeEquation):
|
class PretendTheyDoApproachNegativeOne(RearrangeEquation):
|
||||||
|
@ -1730,7 +1730,7 @@ class RoomsAndSubrooms(Scene):
|
||||||
]
|
]
|
||||||
|
|
||||||
for group in rectangle_groups:
|
for group in rectangle_groups:
|
||||||
mob = CompoundMobject(*group)
|
mob = Mobject(*group)
|
||||||
mob.sort_points(np.linalg.norm)
|
mob.sort_points(np.linalg.norm)
|
||||||
self.play(ShowCreation(mob))
|
self.play(ShowCreation(mob))
|
||||||
|
|
||||||
|
@ -1945,7 +1945,7 @@ class DeduceWhereNegativeOneFalls(Scene):
|
||||||
colors = list(get_room_colors())
|
colors = list(get_room_colors())
|
||||||
num_labels = len(colors)
|
num_labels = len(colors)
|
||||||
texts = [
|
texts = [
|
||||||
CompoundMobject(parts[0], parts[1].highlight(color))
|
Mobject(parts[0], parts[1].highlight(color))
|
||||||
for count, color in zip(it.count(), colors)
|
for count, color in zip(it.count(), colors)
|
||||||
for parts in [TextMobject([
|
for parts in [TextMobject([
|
||||||
"Represented (heuristically) \\\\ by being in the same \\\\",
|
"Represented (heuristically) \\\\ by being in the same \\\\",
|
||||||
|
@ -2025,7 +2025,7 @@ class PAdicMetric(Scene):
|
||||||
self.play(DelayByOrder(Transform(curr, prime)))
|
self.play(DelayByOrder(Transform(curr, prime)))
|
||||||
self.dither()
|
self.dither()
|
||||||
if count == 2:
|
if count == 2:
|
||||||
self.spill(CompoundMobject(curr, text), arrow, new_numbers)
|
self.spill(Mobject(curr, text), arrow, new_numbers)
|
||||||
self.remove(curr)
|
self.remove(curr)
|
||||||
curr = prime
|
curr = prime
|
||||||
self.play(DelayByOrder(Transform(curr, p_str)))
|
self.play(DelayByOrder(Transform(curr, p_str)))
|
||||||
|
@ -2052,7 +2052,7 @@ class FuzzyDiscoveryToNewMath(Scene):
|
||||||
fuzzy.to_edge(UP).shift(SPACE_WIDTH*LEFT/2)
|
fuzzy.to_edge(UP).shift(SPACE_WIDTH*LEFT/2)
|
||||||
new_math = TextMobject("New Math")
|
new_math = TextMobject("New Math")
|
||||||
new_math.to_edge(UP).shift(SPACE_WIDTH*RIGHT/2)
|
new_math.to_edge(UP).shift(SPACE_WIDTH*RIGHT/2)
|
||||||
lines = CompoundMobject(
|
lines = Mobject(
|
||||||
Line(DOWN*SPACE_HEIGHT, UP*SPACE_HEIGHT),
|
Line(DOWN*SPACE_HEIGHT, UP*SPACE_HEIGHT),
|
||||||
Line(3*UP+LEFT*SPACE_WIDTH, 3*UP+RIGHT*SPACE_WIDTH)
|
Line(3*UP+LEFT*SPACE_WIDTH, 3*UP+RIGHT*SPACE_WIDTH)
|
||||||
)
|
)
|
||||||
|
@ -2071,7 +2071,7 @@ class FuzzyDiscoveryToNewMath(Scene):
|
||||||
line.highlight("blue")
|
line.highlight("blue")
|
||||||
char_mob = TexMobject(char).scale(0.25)
|
char_mob = TexMobject(char).scale(0.25)
|
||||||
line.add(char_mob.shift(line.get_center()))
|
line.add(char_mob.shift(line.get_center()))
|
||||||
triangle = CompoundMobject(*triangle_lines)
|
triangle = Mobject(*triangle_lines)
|
||||||
triangle.center().shift(1.5*fuzzy_discoveries[0].get_right())
|
triangle.center().shift(1.5*fuzzy_discoveries[0].get_right())
|
||||||
how_length = TextMobject("But how is length defined?").scale(0.5)
|
how_length = TextMobject("But how is length defined?").scale(0.5)
|
||||||
how_length.shift(0.75*DOWN)
|
how_length.shift(0.75*DOWN)
|
||||||
|
|
|
@ -48,7 +48,7 @@ def count_sections(*radians):
|
||||||
else:
|
else:
|
||||||
sc.animate(ShowCreation(dots[x]))
|
sc.animate(ShowCreation(dots[x]))
|
||||||
sc.add(dots[x])
|
sc.add(dots[x])
|
||||||
new_lines = CompoundMobject(*[
|
new_lines = Mobject(*[
|
||||||
Line(points[x], points[y]) for y in xrange(x)
|
Line(points[x], points[y]) for y in xrange(x)
|
||||||
])
|
])
|
||||||
sc.animate(Transform(deepcopy(dots[x]), new_lines, run_time = 2.0))
|
sc.animate(Transform(deepcopy(dots[x]), new_lines, run_time = 2.0))
|
||||||
|
@ -86,7 +86,7 @@ def summarize_pattern(*radians):
|
||||||
dots = [Dot(point) for point in points]
|
dots = [Dot(point) for point in points]
|
||||||
last_num = None
|
last_num = None
|
||||||
for x in xrange(len(points)):
|
for x in xrange(len(points)):
|
||||||
new_lines = CompoundMobject(*[
|
new_lines = Mobject(*[
|
||||||
Line(points[x], points[y]) for y in xrange(x)
|
Line(points[x], points[y]) for y in xrange(x)
|
||||||
])
|
])
|
||||||
num = TexMobject(str(moser_function(x + 1))).center()
|
num = TexMobject(str(moser_function(x + 1))).center()
|
||||||
|
@ -116,7 +116,7 @@ def connect_points(*radians):
|
||||||
all_lines = []
|
all_lines = []
|
||||||
for x in xrange(len(points)):
|
for x in xrange(len(points)):
|
||||||
lines = [Line(points[x], points[y]) for y in range(len(points))]
|
lines = [Line(points[x], points[y]) for y in range(len(points))]
|
||||||
lines = CompoundMobject(*lines)
|
lines = Mobject(*lines)
|
||||||
anims.append(Transform(deepcopy(dots[x]), lines, run_time = 3.0))
|
anims.append(Transform(deepcopy(dots[x]), lines, run_time = 3.0))
|
||||||
all_lines.append(lines)
|
all_lines.append(lines)
|
||||||
sc.animate(*anims)
|
sc.animate(*anims)
|
||||||
|
@ -127,13 +127,13 @@ def connect_points(*radians):
|
||||||
def interesting_problems():
|
def interesting_problems():
|
||||||
sc = Scene()
|
sc = Scene()
|
||||||
locales = [(6, 2, 0), (6, -2, 0), (-5, -2, 0)]
|
locales = [(6, 2, 0), (6, -2, 0), (-5, -2, 0)]
|
||||||
fermat = CompoundMobject(*TexMobjects(["x^n","+","y^n","=","z^n"]))
|
fermat = Mobject(*TexMobjects(["x^n","+","y^n","=","z^n"]))
|
||||||
fermat.scale(0.5).shift((-2.5, 0.7, 0))
|
fermat.scale(0.5).shift((-2.5, 0.7, 0))
|
||||||
face = SimpleFace()
|
face = SimpleFace()
|
||||||
tb = ThoughtBubble().shift((-1.5, 1, 0))
|
tb = ThoughtBubble().shift((-1.5, 1, 0))
|
||||||
sb = SpeechBubble().shift((-2.4, 1.3, 0))
|
sb = SpeechBubble().shift((-2.4, 1.3, 0))
|
||||||
fermat_copies, face_copies, tb_copies, sb_copies = (
|
fermat_copies, face_copies, tb_copies, sb_copies = (
|
||||||
CompoundMobject(*[
|
Mobject(*[
|
||||||
deepcopy(mob).scale(0.5).shift(locale)
|
deepcopy(mob).scale(0.5).shift(locale)
|
||||||
for locale in locales
|
for locale in locales
|
||||||
])
|
])
|
||||||
|
@ -162,11 +162,11 @@ def interesting_problems():
|
||||||
def response_invitation():
|
def response_invitation():
|
||||||
sc = Scene()
|
sc = Scene()
|
||||||
video_icon = VideoIcon()
|
video_icon = VideoIcon()
|
||||||
mini_videos = CompoundMobject(*[
|
mini_videos = Mobject(*[
|
||||||
deepcopy(video_icon).scale(0.5).shift((3, y, 0))
|
deepcopy(video_icon).scale(0.5).shift((3, y, 0))
|
||||||
for y in [-2, 0, 2]
|
for y in [-2, 0, 2]
|
||||||
])
|
])
|
||||||
comments = CompoundMobject(*[
|
comments = Mobject(*[
|
||||||
Line((-1.2, y, 0), (1.2, y, 0), color = 'white')
|
Line((-1.2, y, 0), (1.2, y, 0), color = 'white')
|
||||||
for y in [-1.5, -1.75, -2]
|
for y in [-1.5, -1.75, -2]
|
||||||
])
|
])
|
||||||
|
@ -191,7 +191,7 @@ def different_points(radians1, radians2):
|
||||||
for radians in (radians1, radians2)
|
for radians in (radians1, radians2)
|
||||||
)
|
)
|
||||||
dots1, dots2 = (
|
dots1, dots2 = (
|
||||||
CompoundMobject(*[Dot(point) for point in points])
|
Mobject(*[Dot(point) for point in points])
|
||||||
for points in (points1, points2)
|
for points in (points1, points2)
|
||||||
)
|
)
|
||||||
lines1, lines2 = (
|
lines1, lines2 = (
|
||||||
|
@ -219,14 +219,14 @@ def next_few_videos(*radians):
|
||||||
(RADIUS * np.cos(angle), RADIUS * np.sin(angle), 0)
|
(RADIUS * np.cos(angle), RADIUS * np.sin(angle), 0)
|
||||||
for angle in radians
|
for angle in radians
|
||||||
]
|
]
|
||||||
dots = CompoundMobject(*[
|
dots = Mobject(*[
|
||||||
Dot(point) for point in points
|
Dot(point) for point in points
|
||||||
])
|
])
|
||||||
lines = CompoundMobject(*[
|
lines = Mobject(*[
|
||||||
Line(point1, point2)
|
Line(point1, point2)
|
||||||
for point1, point2 in it.combinations(points, 2)
|
for point1, point2 in it.combinations(points, 2)
|
||||||
])
|
])
|
||||||
thumbnail = CompoundMobject(circle, dots, lines)
|
thumbnail = Mobject(circle, dots, lines)
|
||||||
frame = VideoIcon().highlight(
|
frame = VideoIcon().highlight(
|
||||||
"black",
|
"black",
|
||||||
lambda point : np.linalg.norm(point) < 0.5
|
lambda point : np.linalg.norm(point) < 0.5
|
||||||
|
|
|
@ -176,7 +176,7 @@ class HardProblemsSimplerQuestions(Scene):
|
||||||
fermat = dict([
|
fermat = dict([
|
||||||
(
|
(
|
||||||
sym,
|
sym,
|
||||||
CompoundMobject(*TexMobjects(
|
Mobject(*TexMobjects(
|
||||||
["x","^"+sym,"+","y","^"+sym,"=","z","^"+sym]
|
["x","^"+sym,"+","y","^"+sym,"=","z","^"+sym]
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
@ -234,7 +234,7 @@ class HardProblemsSimplerQuestions(Scene):
|
||||||
self.add(fermat["n"], fermat2, fermat3)
|
self.add(fermat["n"], fermat2, fermat3)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
circle_grid = CompoundMobject(
|
circle_grid = Mobject(
|
||||||
Circle(),
|
Circle(),
|
||||||
Grid(radius = 2),
|
Grid(radius = 2),
|
||||||
TexMobject(r"\mathds{R}^2").shift((2, -2, 0))
|
TexMobject(r"\mathds{R}^2").shift((2, -2, 0))
|
||||||
|
@ -244,12 +244,12 @@ class HardProblemsSimplerQuestions(Scene):
|
||||||
for mob in circle_grid, start_line, end_line:
|
for mob in circle_grid, start_line, end_line:
|
||||||
mob.scale(0.5).shift(right_center + (0, 2, 0))
|
mob.scale(0.5).shift(right_center + (0, 2, 0))
|
||||||
|
|
||||||
other_grid = CompoundMobject(
|
other_grid = Mobject(
|
||||||
Grid(radius = 2),
|
Grid(radius = 2),
|
||||||
TexMobject(r"\mathds{C}").shift((2, -2, 0))
|
TexMobject(r"\mathds{C}").shift((2, -2, 0))
|
||||||
)
|
)
|
||||||
omega = np.array((0.5, 0.5*np.sqrt(3), 0))
|
omega = np.array((0.5, 0.5*np.sqrt(3), 0))
|
||||||
dots = CompoundMobject(*[
|
dots = Mobject(*[
|
||||||
Dot(t*np.array((1, 0, 0)) + s * omega)
|
Dot(t*np.array((1, 0, 0)) + s * omega)
|
||||||
for t, s in it.product(range(-2, 3), range(-2, 3))
|
for t, s in it.product(range(-2, 3), range(-2, 3))
|
||||||
])
|
])
|
||||||
|
@ -264,7 +264,7 @@ class HardProblemsSimplerQuestions(Scene):
|
||||||
ShowCreation(dots)
|
ShowCreation(dots)
|
||||||
)
|
)
|
||||||
self.dither()
|
self.dither()
|
||||||
all_mobjects = CompoundMobject(*self.mobjects)
|
all_mobjects = Mobject(*self.mobjects)
|
||||||
self.remove(*self.mobjects)
|
self.remove(*self.mobjects)
|
||||||
self.play(
|
self.play(
|
||||||
Transform(
|
Transform(
|
||||||
|
@ -273,7 +273,7 @@ class HardProblemsSimplerQuestions(Scene):
|
||||||
),
|
),
|
||||||
Transform(
|
Transform(
|
||||||
Point((-SPACE_WIDTH, 0, 0)),
|
Point((-SPACE_WIDTH, 0, 0)),
|
||||||
CompoundMobject(*CircleScene(RADIANS).mobjects)
|
Mobject(*CircleScene(RADIANS).mobjects)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -436,7 +436,7 @@ class GeneralPositionRule(Scene):
|
||||||
])
|
])
|
||||||
if first_time:
|
if first_time:
|
||||||
self.play(Transform(
|
self.play(Transform(
|
||||||
CompoundMobject(*intersecting_lines),
|
Mobject(*intersecting_lines),
|
||||||
words_mob
|
words_mob
|
||||||
))
|
))
|
||||||
first_time = False
|
first_time = False
|
||||||
|
@ -542,7 +542,7 @@ class IllustrateNChooseK(Scene):
|
||||||
count_mob = TexMobject(str(count+1))
|
count_mob = TexMobject(str(count+1))
|
||||||
count_mob.center().shift(count_center)
|
count_mob.center().shift(count_center)
|
||||||
self.add(count_mob)
|
self.add(count_mob)
|
||||||
tuple_copy = CompoundMobject(*[nrange_mobs[index-1] for index in tup])
|
tuple_copy = Mobject(*[nrange_mobs[index-1] for index in tup])
|
||||||
tuple_copy.highlight()
|
tuple_copy.highlight()
|
||||||
self.add(tuple_copy)
|
self.add(tuple_copy)
|
||||||
self.add(tuple_mobs[count])
|
self.add(tuple_mobs[count])
|
||||||
|
@ -550,7 +550,7 @@ class IllustrateNChooseK(Scene):
|
||||||
self.remove(count_mob)
|
self.remove(count_mob)
|
||||||
self.remove(tuple_copy)
|
self.remove(tuple_copy)
|
||||||
self.add(count_mob)
|
self.add(count_mob)
|
||||||
self.play(FadeIn(CompoundMobject(form1, form2, pronunciation)))
|
self.play(FadeIn(Mobject(form1, form2, pronunciation)))
|
||||||
|
|
||||||
class IntersectionPointCorrespondances(CircleScene):
|
class IntersectionPointCorrespondances(CircleScene):
|
||||||
args_list = [
|
args_list = [
|
||||||
|
@ -661,7 +661,7 @@ class QuadrupletsToIntersections(CircleScene):
|
||||||
dot_quad = [deepcopy(self.dots[i]) for i in quad]
|
dot_quad = [deepcopy(self.dots[i]) for i in quad]
|
||||||
for dot in dot_quad:
|
for dot in dot_quad:
|
||||||
dot.scale_in_place(2)
|
dot.scale_in_place(2)
|
||||||
dot_quad = CompoundMobject(*dot_quad)
|
dot_quad = Mobject(*dot_quad)
|
||||||
dot_quad.highlight()
|
dot_quad.highlight()
|
||||||
self.add(dot_quad)
|
self.add(dot_quad)
|
||||||
self.dither(frame_time / 3)
|
self.dither(frame_time / 3)
|
||||||
|
@ -674,7 +674,7 @@ class QuadrupletsToIntersections(CircleScene):
|
||||||
class GraphsAndEulersFormulaJoke(Scene):
|
class GraphsAndEulersFormulaJoke(Scene):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
Scene.__init__(self, *args, **kwargs)
|
Scene.__init__(self, *args, **kwargs)
|
||||||
axes = CompoundMobject(
|
axes = Mobject(
|
||||||
NumberLine(),
|
NumberLine(),
|
||||||
NumberLine().rotate(np.pi / 2)
|
NumberLine().rotate(np.pi / 2)
|
||||||
)
|
)
|
||||||
|
@ -693,7 +693,7 @@ class GraphsAndEulersFormulaJoke(Scene):
|
||||||
self.remove(*self.mobjects)
|
self.remove(*self.mobjects)
|
||||||
self.add(eulers)
|
self.add(eulers)
|
||||||
self.play(CounterclockwiseTransform(
|
self.play(CounterclockwiseTransform(
|
||||||
CompoundMobject(axes, graph),
|
Mobject(axes, graph),
|
||||||
Point((-SPACE_WIDTH, SPACE_HEIGHT, 0))
|
Point((-SPACE_WIDTH, SPACE_HEIGHT, 0))
|
||||||
))
|
))
|
||||||
self.play(CounterclockwiseTransform(
|
self.play(CounterclockwiseTransform(
|
||||||
|
@ -709,7 +709,7 @@ class DefiningGraph(GraphScene):
|
||||||
edges_word = TextMobject("``Edges\"").shift(word_center)
|
edges_word = TextMobject("``Edges\"").shift(word_center)
|
||||||
dots, lines = self.vertices, self.edges
|
dots, lines = self.vertices, self.edges
|
||||||
self.remove(*dots + lines)
|
self.remove(*dots + lines)
|
||||||
all_dots = CompoundMobject(*dots)
|
all_dots = Mobject(*dots)
|
||||||
self.play(ShowCreation(all_dots))
|
self.play(ShowCreation(all_dots))
|
||||||
self.remove(all_dots)
|
self.remove(all_dots)
|
||||||
self.add(*dots)
|
self.add(*dots)
|
||||||
|
@ -786,7 +786,7 @@ class EulersFormula(GraphScene):
|
||||||
])
|
])
|
||||||
for mob in form.values():
|
for mob in form.values():
|
||||||
mob.shift((0, SPACE_HEIGHT-0.7, 0))
|
mob.shift((0, SPACE_HEIGHT-0.7, 0))
|
||||||
formula = CompoundMobject(*[form[k] for k in form.keys() if k != "=2"])
|
formula = Mobject(*[form[k] for k in form.keys() if k != "=2"])
|
||||||
new_form = dict([
|
new_form = dict([
|
||||||
(key, deepcopy(mob).shift((0, -0.7, 0)))
|
(key, deepcopy(mob).shift((0, -0.7, 0)))
|
||||||
for key, mob in zip(form.keys(), form.values())
|
for key, mob in zip(form.keys(), form.values())
|
||||||
|
@ -797,7 +797,7 @@ class EulersFormula(GraphScene):
|
||||||
for d in self.dots
|
for d in self.dots
|
||||||
]
|
]
|
||||||
colored_edges = [
|
colored_edges = [
|
||||||
CompoundMobject(
|
Mobject(
|
||||||
Line(midpoint, start),
|
Line(midpoint, start),
|
||||||
Line(midpoint, end),
|
Line(midpoint, end),
|
||||||
).highlight("red")
|
).highlight("red")
|
||||||
|
@ -843,7 +843,7 @@ class CannotDirectlyApplyEulerToMoser(CircleScene):
|
||||||
d.highlight("yellow").scale_in_place(2)
|
d.highlight("yellow").scale_in_place(2)
|
||||||
for d in deepcopy(self.dots)
|
for d in deepcopy(self.dots)
|
||||||
]
|
]
|
||||||
yellow_lines = CompoundMobject(*[
|
yellow_lines = Mobject(*[
|
||||||
l.highlight("yellow") for l in deepcopy(self.lines)
|
l.highlight("yellow") for l in deepcopy(self.lines)
|
||||||
])
|
])
|
||||||
self.play(*[
|
self.play(*[
|
||||||
|
@ -896,7 +896,7 @@ class ShowMoserGraphLines(CircleScene):
|
||||||
(self.lines, n_choose_2)
|
(self.lines, n_choose_2)
|
||||||
]:
|
]:
|
||||||
self.add(symbol)
|
self.add(symbol)
|
||||||
compound = CompoundMobject(*mobs)
|
compound = Mobject(*mobs)
|
||||||
if mobs in (self.dots, self.intersection_dots):
|
if mobs in (self.dots, self.intersection_dots):
|
||||||
self.remove(*mobs)
|
self.remove(*mobs)
|
||||||
self.play(CounterclockwiseTransform(
|
self.play(CounterclockwiseTransform(
|
||||||
|
@ -916,7 +916,7 @@ class ShowMoserGraphLines(CircleScene):
|
||||||
Transform(line, small_line, run_time = 3.0)
|
Transform(line, small_line, run_time = 3.0)
|
||||||
for line, small_line in zip(self.lines, small_lines)
|
for line, small_line in zip(self.lines, small_lines)
|
||||||
])
|
])
|
||||||
yellow_lines = CompoundMobject(*[
|
yellow_lines = Mobject(*[
|
||||||
line.highlight("yellow") for line in small_lines
|
line.highlight("yellow") for line in small_lines
|
||||||
])
|
])
|
||||||
self.add(plus_2_n_choose_4)
|
self.add(plus_2_n_choose_4)
|
||||||
|
@ -929,7 +929,7 @@ class ShowMoserGraphLines(CircleScene):
|
||||||
for p, sp in zip(self.circle_pieces, self.smaller_circle_pieces)
|
for p, sp in zip(self.circle_pieces, self.smaller_circle_pieces)
|
||||||
])
|
])
|
||||||
self.add(plus_n)
|
self.add(plus_n)
|
||||||
self.play(ShowCreation(CompoundMobject(*[
|
self.play(ShowCreation(Mobject(*[
|
||||||
mob.highlight("yellow") for mob in self.circle_pieces
|
mob.highlight("yellow") for mob in self.circle_pieces
|
||||||
])))
|
])))
|
||||||
|
|
||||||
|
@ -1111,7 +1111,7 @@ class ApplyEulerToMoser(CircleScene):
|
||||||
self.add(*all_mobs)
|
self.add(*all_mobs)
|
||||||
self.remove(*[d[1] for d in [V, minus, E, plus, F, equals, two]])
|
self.remove(*[d[1] for d in [V, minus, E, plus, F, equals, two]])
|
||||||
self.play(
|
self.play(
|
||||||
Transform(V[2].repeat(2), CompoundMobject(n[3], minus1[3], nc4[3])),
|
Transform(V[2].repeat(2), Mobject(n[3], minus1[3], nc4[3])),
|
||||||
*[
|
*[
|
||||||
Transform(d[2], d[3])
|
Transform(d[2], d[3])
|
||||||
for d in [F, equals, E, minus, plus, two]
|
for d in [F, equals, E, minus, plus, two]
|
||||||
|
@ -1120,7 +1120,7 @@ class ApplyEulerToMoser(CircleScene):
|
||||||
self.dither()
|
self.dither()
|
||||||
self.remove(*self.mobjects)
|
self.remove(*self.mobjects)
|
||||||
self.play(
|
self.play(
|
||||||
Transform(E[3], CompoundMobject(
|
Transform(E[3], Mobject(
|
||||||
nc2[4], plus1[4], two1[4], nc41[4], plus2[4], n1[4]
|
nc2[4], plus1[4], two1[4], nc41[4], plus2[4], n1[4]
|
||||||
)),
|
)),
|
||||||
*[
|
*[
|
||||||
|
@ -1142,7 +1142,7 @@ class ApplyEulerToMoser(CircleScene):
|
||||||
self.remove(*self.mobjects)
|
self.remove(*self.mobjects)
|
||||||
self.play(
|
self.play(
|
||||||
Transform(
|
Transform(
|
||||||
CompoundMobject(plus2[4], n1[4], minus[4], n[4]),
|
Mobject(plus2[4], n1[4], minus[4], n[4]),
|
||||||
Point((SPACE_WIDTH, SPACE_HEIGHT, 0))
|
Point((SPACE_WIDTH, SPACE_HEIGHT, 0))
|
||||||
),
|
),
|
||||||
*[
|
*[
|
||||||
|
@ -1202,7 +1202,7 @@ class FormulaRelatesToPowersOfTwo(Scene):
|
||||||
scale_factor = 1
|
scale_factor = 1
|
||||||
for mob in everything:
|
for mob in everything:
|
||||||
mob.scale(scale_factor)
|
mob.scale(scale_factor)
|
||||||
CompoundMobject(*everything).show()
|
Mobject(*everything).show()
|
||||||
forms = everything[0::3]
|
forms = everything[0::3]
|
||||||
sums = everything[1::3]
|
sums = everything[1::3]
|
||||||
results = everything[2::3]
|
results = everything[2::3]
|
||||||
|
@ -1238,7 +1238,7 @@ class DrawPascalsTriangle(PascalsTriangleScene):
|
||||||
for n in range(1, nrows):
|
for n in range(1, nrows):
|
||||||
starts = [deepcopy(self.coords_to_mobs[n-1][0])]
|
starts = [deepcopy(self.coords_to_mobs[n-1][0])]
|
||||||
starts += [
|
starts += [
|
||||||
CompoundMobject(
|
Mobject(
|
||||||
self.coords_to_mobs[n-1][k-1],
|
self.coords_to_mobs[n-1][k-1],
|
||||||
self.coords_to_mobs[n-1][k]
|
self.coords_to_mobs[n-1][k]
|
||||||
)
|
)
|
||||||
|
@ -1384,11 +1384,11 @@ class PascalsTriangleSumRows(PascalsTriangleScene):
|
||||||
powers_of_two.append(pof2)
|
powers_of_two.append(pof2)
|
||||||
equalses.append(new_equals)
|
equalses.append(new_equals)
|
||||||
powers_of_two_symbols.append(symbol)
|
powers_of_two_symbols.append(symbol)
|
||||||
self.play(FadeIn(CompoundMobject(*pluses)))
|
self.play(FadeIn(Mobject(*pluses)))
|
||||||
run_time = 0.5
|
run_time = 0.5
|
||||||
to_remove = []
|
to_remove = []
|
||||||
for n in range(self.nrows):
|
for n in range(self.nrows):
|
||||||
start = CompoundMobject(*[self.coords_to_mobs[n][k] for k in range(n+1)])
|
start = Mobject(*[self.coords_to_mobs[n][k] for k in range(n+1)])
|
||||||
to_remove.append(start)
|
to_remove.append(start)
|
||||||
self.play(
|
self.play(
|
||||||
Transform(start, powers_of_two[n]),
|
Transform(start, powers_of_two[n]),
|
||||||
|
@ -1481,14 +1481,14 @@ class MoserSolutionInPascal(PascalsTriangleScene):
|
||||||
self.add(self.coords_to_mobs[n][k])
|
self.add(self.coords_to_mobs[n][k])
|
||||||
self.play(Transform(
|
self.play(Transform(
|
||||||
terms[k],
|
terms[k],
|
||||||
CompoundMobject(*above_terms).highlight(term_color)
|
Mobject(*above_terms).highlight(term_color)
|
||||||
))
|
))
|
||||||
self.remove(*above_terms)
|
self.remove(*above_terms)
|
||||||
self.dither()
|
self.dither()
|
||||||
terms_sum = TexMobject(str(moser_function(n)))
|
terms_sum = TexMobject(str(moser_function(n)))
|
||||||
terms_sum.shift((SPACE_WIDTH-1, terms[0].get_center()[1], 0))
|
terms_sum.shift((SPACE_WIDTH-1, terms[0].get_center()[1], 0))
|
||||||
terms_sum.highlight(term_color)
|
terms_sum.highlight(term_color)
|
||||||
self.play(Transform(CompoundMobject(*terms), terms_sum))
|
self.play(Transform(Mobject(*terms), terms_sum))
|
||||||
|
|
||||||
class RotatingPolyhedra(Scene):
|
class RotatingPolyhedra(Scene):
|
||||||
args_list = [
|
args_list = [
|
||||||
|
@ -1530,12 +1530,12 @@ class ExplainNChoose2Formula(Scene):
|
||||||
r_paren, a_mob, comma, b_mob, l_paren = TexMobjects(
|
r_paren, a_mob, comma, b_mob, l_paren = TexMobjects(
|
||||||
("( %d , %d )"%(a, b)).split(" ")
|
("( %d , %d )"%(a, b)).split(" ")
|
||||||
)
|
)
|
||||||
parens = CompoundMobject(r_paren, comma, l_paren)
|
parens = Mobject(r_paren, comma, l_paren)
|
||||||
nums = [TexMobject(str(k)) for k in range(1, n+1)]
|
nums = [TexMobject(str(k)) for k in range(1, n+1)]
|
||||||
height = 1.5*nums[0].get_height()
|
height = 1.5*nums[0].get_height()
|
||||||
for x in range(n):
|
for x in range(n):
|
||||||
nums[x].shift((0, x*height, 0))
|
nums[x].shift((0, x*height, 0))
|
||||||
nums_compound = CompoundMobject(*nums)
|
nums_compound = Mobject(*nums)
|
||||||
nums_compound.shift(a_mob.get_center() - nums[0].get_center())
|
nums_compound.shift(a_mob.get_center() - nums[0].get_center())
|
||||||
n_mob, n_minus_1, over_2 = TexMobject([
|
n_mob, n_minus_1, over_2 = TexMobject([
|
||||||
str(n), "(%d-1)"%n, r"\over{2}"
|
str(n), "(%d-1)"%n, r"\over{2}"
|
||||||
|
@ -1550,7 +1550,7 @@ class ExplainNChoose2Formula(Scene):
|
||||||
self.remove(nums_compound)
|
self.remove(nums_compound)
|
||||||
nums = nums_compound.split()
|
nums = nums_compound.split()
|
||||||
a_mob = nums.pop(a-1)
|
a_mob = nums.pop(a-1)
|
||||||
nums_compound = CompoundMobject(*nums)
|
nums_compound = Mobject(*nums)
|
||||||
self.add(a_mob, nums_compound)
|
self.add(a_mob, nums_compound)
|
||||||
self.dither()
|
self.dither()
|
||||||
right_shift = b_mob.get_center() - a_mob.get_center()
|
right_shift = b_mob.get_center() - a_mob.get_center()
|
||||||
|
@ -1602,17 +1602,17 @@ class ExplainNChoose4Formula(Scene):
|
||||||
("( %d , %d , %d , %d )"%quad).split(" ")
|
("( %d , %d , %d , %d )"%quad).split(" ")
|
||||||
)
|
)
|
||||||
quad_mobs = tuple_mobs[1::2]
|
quad_mobs = tuple_mobs[1::2]
|
||||||
parens = CompoundMobject(*tuple_mobs[0::2])
|
parens = Mobject(*tuple_mobs[0::2])
|
||||||
form_mobs = TexMobject([
|
form_mobs = TexMobject([
|
||||||
str(n), "(%d-1)"%n, "(%d-2)"%n,"(%d-3)"%n,
|
str(n), "(%d-1)"%n, "(%d-2)"%n,"(%d-3)"%n,
|
||||||
r"\over {4 \cdot 3 \cdot 2 \cdot 1}"
|
r"\over {4 \cdot 3 \cdot 2 \cdot 1}"
|
||||||
]).split()
|
]).split()
|
||||||
form_mobs = CompoundMobject(*form_mobs).scale(0.7).shift((4, 3, 0)).split()
|
form_mobs = Mobject(*form_mobs).scale(0.7).shift((4, 3, 0)).split()
|
||||||
nums = [TexMobject(str(k)) for k in range(1, n+1)]
|
nums = [TexMobject(str(k)) for k in range(1, n+1)]
|
||||||
height = 1.5*nums[0].get_height()
|
height = 1.5*nums[0].get_height()
|
||||||
for x in range(n):
|
for x in range(n):
|
||||||
nums[x].shift((0, x*height, 0))
|
nums[x].shift((0, x*height, 0))
|
||||||
nums_compound = CompoundMobject(*nums)
|
nums_compound = Mobject(*nums)
|
||||||
nums_compound.shift(quad_mobs[0].get_center() - nums[0].get_center())
|
nums_compound.shift(quad_mobs[0].get_center() - nums[0].get_center())
|
||||||
curr_num = 1
|
curr_num = 1
|
||||||
self.add(parens)
|
self.add(parens)
|
||||||
|
@ -1625,7 +1625,7 @@ class ExplainNChoose4Formula(Scene):
|
||||||
nums = nums_compound.split()
|
nums = nums_compound.split()
|
||||||
chosen = nums[quad[i]-1]
|
chosen = nums[quad[i]-1]
|
||||||
nums[quad[i]-1] = Point(chosen.get_center()).highlight("black")
|
nums[quad[i]-1] = Point(chosen.get_center()).highlight("black")
|
||||||
nums_compound = CompoundMobject(*nums)
|
nums_compound = Mobject(*nums)
|
||||||
self.add(chosen)
|
self.add(chosen)
|
||||||
if i < 3:
|
if i < 3:
|
||||||
right_shift = quad_mobs[i+1].get_center() - chosen.get_center()
|
right_shift = quad_mobs[i+1].get_center() - chosen.get_center()
|
||||||
|
@ -1657,10 +1657,10 @@ class ExplainNChoose4Formula(Scene):
|
||||||
)
|
)
|
||||||
for i in range(4)
|
for i in range(4)
|
||||||
]
|
]
|
||||||
compound_quad = CompoundMobject(*quad_mobs)
|
compound_quad = Mobject(*quad_mobs)
|
||||||
self.play(CounterclockwiseTransform(
|
self.play(CounterclockwiseTransform(
|
||||||
compound_quad,
|
compound_quad,
|
||||||
CompoundMobject(*new_quad_mobs)
|
Mobject(*new_quad_mobs)
|
||||||
))
|
))
|
||||||
self.remove(compound_quad)
|
self.remove(compound_quad)
|
||||||
quad_mobs = new_quad_mobs
|
quad_mobs = new_quad_mobs
|
||||||
|
|
|
@ -81,12 +81,12 @@ class RightParen(Mobject):
|
||||||
return Mobject.get_center(self) + 0.04*RIGHT
|
return Mobject.get_center(self) + 0.04*RIGHT
|
||||||
|
|
||||||
|
|
||||||
class OpenInterval(CompoundMobject):
|
class OpenInterval(Mobject):
|
||||||
def __init__(self, center_point = ORIGIN, width = 2, **kwargs):
|
def __init__(self, center_point = ORIGIN, width = 2, **kwargs):
|
||||||
digest_config(self, kwargs, locals())
|
digest_config(self, kwargs, locals())
|
||||||
left = LeftParen().shift(LEFT*width/2)
|
left = LeftParen().shift(LEFT*width/2)
|
||||||
right = RightParen().shift(RIGHT*width/2)
|
right = RightParen().shift(RIGHT*width/2)
|
||||||
CompoundMobject.__init__(self, left, right, **kwargs)
|
Mobject.__init__(self, left, right, **kwargs)
|
||||||
# scale_factor = width / 2.0
|
# scale_factor = width / 2.0
|
||||||
# self.stretch(scale_factor, 0)
|
# self.stretch(scale_factor, 0)
|
||||||
# self.stretch(0.5+0.5*scale_factor, 1)
|
# self.stretch(0.5+0.5*scale_factor, 1)
|
||||||
|
@ -199,7 +199,7 @@ class IntervalScene(NumberLineScene):
|
||||||
tick = Line(point+tick_rad*DOWN, point+tick_rad*UP)
|
tick = Line(point+tick_rad*DOWN, point+tick_rad*UP)
|
||||||
tick.highlight("yellow")
|
tick.highlight("yellow")
|
||||||
all_ticks.append(tick)
|
all_ticks.append(tick)
|
||||||
all_ticks = CompoundMobject(*all_ticks)
|
all_ticks = Mobject(*all_ticks)
|
||||||
if run_time > 0:
|
if run_time > 0:
|
||||||
self.play(ShowCreation(all_ticks))
|
self.play(ShowCreation(all_ticks))
|
||||||
else:
|
else:
|
||||||
|
@ -294,7 +294,7 @@ class MeasureTheoryToHarmony(IntervalScene):
|
||||||
IntervalScene.construct(self)
|
IntervalScene.construct(self)
|
||||||
self.cover_fractions()
|
self.cover_fractions()
|
||||||
self.dither()
|
self.dither()
|
||||||
all_mobs = CompoundMobject(*self.mobjects)
|
all_mobs = Mobject(*self.mobjects)
|
||||||
all_mobs.sort_points()
|
all_mobs.sort_points()
|
||||||
self.clear()
|
self.clear()
|
||||||
radius = self.interval.radius
|
radius = self.interval.radius
|
||||||
|
@ -516,7 +516,7 @@ class DecomposeTwoFrequencies(Scene):
|
||||||
sine1 = LongSine().shift(2*UP).highlight("yellow")
|
sine1 = LongSine().shift(2*UP).highlight("yellow")
|
||||||
sine2 = LongSine().shift(DOWN).highlight("lightgreen")
|
sine2 = LongSine().shift(DOWN).highlight("lightgreen")
|
||||||
sine1.stretch(2.0/3, 0)
|
sine1.stretch(2.0/3, 0)
|
||||||
comp = CompoundMobject(sine1, sine2)
|
comp = Mobject(sine1, sine2)
|
||||||
|
|
||||||
self.add(line)
|
self.add(line)
|
||||||
self.play(ApplyMethod(
|
self.play(ApplyMethod(
|
||||||
|
@ -562,12 +562,12 @@ class PatternInFrequencies(Scene):
|
||||||
setup_width = 2*SPACE_WIDTH
|
setup_width = 2*SPACE_WIDTH
|
||||||
num_top_lines = int(setup_width)
|
num_top_lines = int(setup_width)
|
||||||
num_bot_lines = int(setup_width*num1/num2)
|
num_bot_lines = int(setup_width*num1/num2)
|
||||||
top_lines = CompoundMobject(*[
|
top_lines = Mobject(*[
|
||||||
deepcopy(line_template).shift(k*(float(num1)/num2)*RIGHT)
|
deepcopy(line_template).shift(k*(float(num1)/num2)*RIGHT)
|
||||||
for k in range(num_top_lines)
|
for k in range(num_top_lines)
|
||||||
])
|
])
|
||||||
line_template.shift(4*DOWN)
|
line_template.shift(4*DOWN)
|
||||||
bottom_lines = CompoundMobject(*[
|
bottom_lines = Mobject(*[
|
||||||
deepcopy(line_template).shift(k*RIGHT)
|
deepcopy(line_template).shift(k*RIGHT)
|
||||||
for k in range(num_bot_lines)
|
for k in range(num_bot_lines)
|
||||||
])
|
])
|
||||||
|
@ -601,7 +601,7 @@ class CompareFractionComplexity(Scene):
|
||||||
for num, den in [(4, 3), (1093,826)]:
|
for num, den in [(4, 3), (1093,826)]:
|
||||||
top = TexMobject("%d \\over"%num)
|
top = TexMobject("%d \\over"%num)
|
||||||
bottom = TexMobject(str(den)).next_to(top, DOWN, buff = 0.3)
|
bottom = TexMobject(str(den)).next_to(top, DOWN, buff = 0.3)
|
||||||
fractions.append(CompoundMobject(top, bottom))
|
fractions.append(Mobject(top, bottom))
|
||||||
frac0 = fractions[0].shift(3*LEFT).split()
|
frac0 = fractions[0].shift(3*LEFT).split()
|
||||||
frac1 = fractions[1].shift(3*RIGHT).split()
|
frac1 = fractions[1].shift(3*RIGHT).split()
|
||||||
arrow1 = Arrow(UP, ORIGIN).next_to(frac0[0], UP)
|
arrow1 = Arrow(UP, ORIGIN).next_to(frac0[0], UP)
|
||||||
|
@ -642,7 +642,7 @@ class IrrationalGang(Scene):
|
||||||
sqrt13.highlight("green")
|
sqrt13.highlight("green")
|
||||||
zeta3 = TexMobject("\\zeta(3)").shift(2*RIGHT)
|
zeta3 = TexMobject("\\zeta(3)").shift(2*RIGHT)
|
||||||
zeta3.highlight("grey")
|
zeta3.highlight("grey")
|
||||||
eyes = CompoundMobject(*randy.eyes)
|
eyes = Mobject(*randy.eyes)
|
||||||
eyes.scale(0.5)
|
eyes.scale(0.5)
|
||||||
sqrt13.add(eyes.next_to(sqrt13, UP, buff = 0).shift(0.25*RIGHT))
|
sqrt13.add(eyes.next_to(sqrt13, UP, buff = 0).shift(0.25*RIGHT))
|
||||||
eyes.scale(0.5)
|
eyes.scale(0.5)
|
||||||
|
@ -682,7 +682,7 @@ class PianoTuning(Scene):
|
||||||
jump = piano.half_note_jump
|
jump = piano.half_note_jump
|
||||||
semicircle = Circle().filter_out(lambda p : p[1] < 0)
|
semicircle = Circle().filter_out(lambda p : p[1] < 0)
|
||||||
semicircle.scale(jump/semicircle.get_width())
|
semicircle.scale(jump/semicircle.get_width())
|
||||||
semicircles = CompoundMobject(*[
|
semicircles = Mobject(*[
|
||||||
deepcopy(semicircle).shift(jump*k*RIGHT)
|
deepcopy(semicircle).shift(jump*k*RIGHT)
|
||||||
for k in range(23)
|
for k in range(23)
|
||||||
])
|
])
|
||||||
|
@ -802,14 +802,14 @@ class PowersOfTwelfthRoot(Scene):
|
||||||
])
|
])
|
||||||
error_string = error_string.split()
|
error_string = error_string.split()
|
||||||
error_string[1].highlight()
|
error_string[1].highlight()
|
||||||
error_string = CompoundMobject(*error_string)
|
error_string = Mobject(*error_string)
|
||||||
error_string.scale(approx_form.get_height()/error_string.get_height())
|
error_string.scale(approx_form.get_height()/error_string.get_height())
|
||||||
error_string.next_to(frac_mob)
|
error_string.next_to(frac_mob)
|
||||||
|
|
||||||
mob_list.append(CompoundMobject(*[
|
mob_list.append(Mobject(*[
|
||||||
term, approx_copy, approx_form, words, frac_mob, error_string
|
term, approx_copy, approx_form, words, frac_mob, error_string
|
||||||
]))
|
]))
|
||||||
self.play(ShimmerIn(CompoundMobject(*mob_list), run_time = 3.0))
|
self.play(ShimmerIn(Mobject(*mob_list), run_time = 3.0))
|
||||||
|
|
||||||
class InterestingQuestion(Scene):
|
class InterestingQuestion(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
@ -898,7 +898,7 @@ class ChallengeTwo(Scene):
|
||||||
class CoveringSetsWithOpenIntervals(IntervalScene):
|
class CoveringSetsWithOpenIntervals(IntervalScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
IntervalScene.construct(self)
|
IntervalScene.construct(self)
|
||||||
dots = CompoundMobject(*[
|
dots = Mobject(*[
|
||||||
Dot().shift(self.number_line.number_to_point(num)+UP)
|
Dot().shift(self.number_line.number_to_point(num)+UP)
|
||||||
for num in set([0.2, 0.25, 0.45, 0.6, 0.65])
|
for num in set([0.2, 0.25, 0.45, 0.6, 0.65])
|
||||||
])
|
])
|
||||||
|
@ -1168,7 +1168,7 @@ class StepsToSolution(IntervalScene):
|
||||||
tick_copy = deepcopy(tick).center().shift(1.6*UP)
|
tick_copy = deepcopy(tick).center().shift(1.6*UP)
|
||||||
tick_copy.shift((-SPACE_WIDTH+self.spacing*count)*RIGHT)
|
tick_copy.shift((-SPACE_WIDTH+self.spacing*count)*RIGHT)
|
||||||
new_ticks.append(tick_copy)
|
new_ticks.append(tick_copy)
|
||||||
new_ticks = CompoundMobject(*new_ticks)
|
new_ticks = Mobject(*new_ticks)
|
||||||
anims.append(DelayByOrder(Transform(ticks, new_ticks)))
|
anims.append(DelayByOrder(Transform(ticks, new_ticks)))
|
||||||
self.dither()
|
self.dither()
|
||||||
self.play(*anims)
|
self.play(*anims)
|
||||||
|
@ -1219,7 +1219,7 @@ class StepsToSolution(IntervalScene):
|
||||||
frac_bottom.scale(scale_val)
|
frac_bottom.scale(scale_val)
|
||||||
one = TexMobject("1").scale(scale_val)
|
one = TexMobject("1").scale(scale_val)
|
||||||
one.next_to(frac_bottom, UP, buff = 0.1)
|
one.next_to(frac_bottom, UP, buff = 0.1)
|
||||||
compound = CompoundMobject(frac_bottom, one)
|
compound = Mobject(frac_bottom, one)
|
||||||
if plus:
|
if plus:
|
||||||
compound.next_to(plus)
|
compound.next_to(plus)
|
||||||
else:
|
else:
|
||||||
|
@ -1313,9 +1313,9 @@ class TroubleDrawingSmallInterval(IntervalScene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
IntervalScene.construct(self)
|
IntervalScene.construct(self)
|
||||||
interval, line = self.add_open_interval(0.5, 0.5)
|
interval, line = self.add_open_interval(0.5, 0.5)
|
||||||
big = CompoundMobject(interval, line)
|
big = Mobject(interval, line)
|
||||||
small_int, small_line = self.add_open_interval(0.5, 0.01)
|
small_int, small_line = self.add_open_interval(0.5, 0.01)
|
||||||
small = CompoundMobject(small_int, line.scale_in_place(0.01/0.5))
|
small = Mobject(small_int, line.scale_in_place(0.01/0.5))
|
||||||
shrunk = deepcopy(big).scale_in_place(0.01/0.5)
|
shrunk = deepcopy(big).scale_in_place(0.01/0.5)
|
||||||
self.clear()
|
self.clear()
|
||||||
IntervalScene.construct(self)
|
IntervalScene.construct(self)
|
||||||
|
@ -1354,7 +1354,7 @@ class ZoomInOnSqrt2Over2(IntervalScene):
|
||||||
epsilon, equals, num = map(TexMobject, ["\\epsilon", "=", "0.3"])
|
epsilon, equals, num = map(TexMobject, ["\\epsilon", "=", "0.3"])
|
||||||
equals.next_to(epsilon)
|
equals.next_to(epsilon)
|
||||||
num.next_to(equals)
|
num.next_to(equals)
|
||||||
self.add(CompoundMobject(epsilon, equals, num).center().shift(2*UP))
|
self.add(Mobject(epsilon, equals, num).center().shift(2*UP))
|
||||||
intervals, lines = self.cover_fractions()
|
intervals, lines = self.cover_fractions()
|
||||||
self.remove(*lines)
|
self.remove(*lines)
|
||||||
irr = TexMobject("\\frac{\\sqrt{2}}{2}")
|
irr = TexMobject("\\frac{\\sqrt{2}}{2}")
|
||||||
|
@ -1464,7 +1464,7 @@ class ShiftSetupByOne(IntervalScene):
|
||||||
"real numbers \\emph{very very very} close to them",
|
"real numbers \\emph{very very very} close to them",
|
||||||
size = "\\small"
|
size = "\\small"
|
||||||
)
|
)
|
||||||
compound = CompoundMobject(answer1, answer2.next_to(answer1))
|
compound = Mobject(answer1, answer2.next_to(answer1))
|
||||||
compound.next_to(words, DOWN)
|
compound.next_to(words, DOWN)
|
||||||
answer1, answer2 = compound.split()
|
answer1, answer2 = compound.split()
|
||||||
|
|
||||||
|
@ -1485,7 +1485,7 @@ class ShiftSetupByOne(IntervalScene):
|
||||||
words[3].highlight()
|
words[3].highlight()
|
||||||
self.add(*words)
|
self.add(*words)
|
||||||
self.play(ShowCreation(
|
self.play(ShowCreation(
|
||||||
CompoundMobject(*intervals),
|
Mobject(*intervals),
|
||||||
run_time = 5.0
|
run_time = 5.0
|
||||||
))
|
))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
@ -1502,12 +1502,12 @@ class FinalEquivalence(IntervalScene):
|
||||||
for interval, frac in zip(intervals, rationals()):
|
for interval, frac in zip(intervals, rationals()):
|
||||||
interval.scale_in_place(2.0/frac.denominator)
|
interval.scale_in_place(2.0/frac.denominator)
|
||||||
self.remove(*intervals+lines)
|
self.remove(*intervals+lines)
|
||||||
intervals = CompoundMobject(*intervals)
|
intervals = Mobject(*intervals)
|
||||||
arrow = TexMobject("\\Leftrightarrow")
|
arrow = TexMobject("\\Leftrightarrow")
|
||||||
top_words = TextMobject("Harmonious numbers are rare,")
|
top_words = TextMobject("Harmonious numbers are rare,")
|
||||||
bot_words = TextMobject("even for the savant")
|
bot_words = TextMobject("even for the savant")
|
||||||
bot_words.highlight().next_to(top_words, DOWN)
|
bot_words.highlight().next_to(top_words, DOWN)
|
||||||
words = CompoundMobject(top_words, bot_words)
|
words = Mobject(top_words, bot_words)
|
||||||
words.next_to(arrow)
|
words.next_to(arrow)
|
||||||
|
|
||||||
self.play(
|
self.play(
|
||||||
|
@ -1517,7 +1517,7 @@ class FinalEquivalence(IntervalScene):
|
||||||
intervals
|
intervals
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
everything = CompoundMobject(*self.mobjects)
|
everything = Mobject(*self.mobjects)
|
||||||
self.clear()
|
self.clear()
|
||||||
self.play(Transform(
|
self.play(Transform(
|
||||||
everything,
|
everything,
|
||||||
|
|
|
@ -211,7 +211,7 @@ class ShowFrameNum(SceneFromVideo):
|
||||||
SceneFromVideo.construct(self, path)
|
SceneFromVideo.construct(self, path)
|
||||||
for frame, count in zip(self.frames, it.count()):
|
for frame, count in zip(self.frames, it.count()):
|
||||||
print count, "of", len(self.frames)
|
print count, "of", len(self.frames)
|
||||||
mob = CompoundMobject(*[
|
mob = Mobject(*[
|
||||||
TexMobject(char).shift(0.3*x*RIGHT)
|
TexMobject(char).shift(0.3*x*RIGHT)
|
||||||
for char, x, in zip(str(count), it.count())
|
for char, x, in zip(str(count), it.count())
|
||||||
])
|
])
|
||||||
|
|
|
@ -441,7 +441,7 @@ class LabelLargeSquare(DrawCSquareWithAllTraingles):
|
||||||
args_list = []
|
args_list = []
|
||||||
def construct(self):
|
def construct(self):
|
||||||
DrawCSquareWithAllTraingles.construct(self)
|
DrawCSquareWithAllTraingles.construct(self)
|
||||||
everything = CompoundMobject(*self.mobjects)
|
everything = Mobject(*self.mobjects)
|
||||||
u_brace = Underbrace(2*(DOWN+LEFT), 2*(DOWN+RIGHT))
|
u_brace = Underbrace(2*(DOWN+LEFT), 2*(DOWN+RIGHT))
|
||||||
u_brace.shift(0.2*DOWN)
|
u_brace.shift(0.2*DOWN)
|
||||||
side_brace = deepcopy(u_brace).rotate(np.pi/2)
|
side_brace = deepcopy(u_brace).rotate(np.pi/2)
|
||||||
|
|
|
@ -80,11 +80,9 @@ class Scene(object):
|
||||||
"""
|
"""
|
||||||
So a scene can just add all mobjects it's defined up to that point
|
So a scene can just add all mobjects it's defined up to that point
|
||||||
"""
|
"""
|
||||||
caller_locals = inspect.currentframe().f_back.f_locals
|
name_to_mob = get_caller_locals(lambda x : isinstance(x, Mobject))
|
||||||
self.add(*filter(
|
self.add(*name_to_mob.values())
|
||||||
lambda m : isinstance(m, Mobject),
|
return self
|
||||||
caller_locals.values()
|
|
||||||
))
|
|
||||||
|
|
||||||
def remove(self, *mobjects):
|
def remove(self, *mobjects):
|
||||||
if not all_elements_are_instances(mobjects, Mobject):
|
if not all_elements_are_instances(mobjects, Mobject):
|
||||||
|
@ -161,8 +159,17 @@ class Scene(object):
|
||||||
for animation in animations:
|
for animation in animations:
|
||||||
animation.set_run_time(run_time)
|
animation.set_run_time(run_time)
|
||||||
moving_mobjects = [anim.mobject for anim in animations]
|
moving_mobjects = [anim.mobject for anim in animations]
|
||||||
self.remove(*moving_mobjects)
|
|
||||||
background = self.get_frame()
|
bundle = Mobject(*self.mobjects)
|
||||||
|
static_mobjects = filter(
|
||||||
|
lambda m : m not in moving_mobjects,
|
||||||
|
bundle.get_full_submobject_family()
|
||||||
|
)
|
||||||
|
background = disp.paint_mobjects(
|
||||||
|
static_mobjects,
|
||||||
|
self.background,
|
||||||
|
include_sub_mobjects = False
|
||||||
|
)
|
||||||
|
|
||||||
print "Generating " + ", ".join(map(str, animations))
|
print "Generating " + ", ".join(map(str, animations))
|
||||||
progress_bar = progressbar.ProgressBar(maxval=run_time)
|
progress_bar = progressbar.ProgressBar(maxval=run_time)
|
||||||
|
@ -176,7 +183,7 @@ class Scene(object):
|
||||||
self.frames.append(new_frame)
|
self.frames.append(new_frame)
|
||||||
for animation in animations:
|
for animation in animations:
|
||||||
animation.clean_up()
|
animation.clean_up()
|
||||||
self.add(*moving_mobjects)
|
self.repaint_mojects()
|
||||||
progress_bar.finish()
|
progress_bar.finish()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ class TkSceneRoot(Tkinter.Tk):
|
||||||
raise Exception(str(scene) + " has no frames!")
|
raise Exception(str(scene) + " has no frames!")
|
||||||
Tkinter.Tk.__init__(self)
|
Tkinter.Tk.__init__(self)
|
||||||
|
|
||||||
height, width = scene.shape
|
kwargs = {"height" : scene.height, "width" : scene.width}
|
||||||
kwargs = {"height" : height, "width" : width}
|
|
||||||
self.frame = Tkinter.Frame(self, **kwargs)
|
self.frame = Tkinter.Frame(self, **kwargs)
|
||||||
self.frame.pack()
|
self.frame.pack()
|
||||||
self.canvas = Tkinter.Canvas(self.frame, **kwargs)
|
self.canvas = Tkinter.Canvas(self.frame, **kwargs)
|
||||||
|
|
|
@ -24,9 +24,9 @@ class RearrangeEquation(Scene):
|
||||||
start_terms, end_terms, size
|
start_terms, end_terms, size
|
||||||
)
|
)
|
||||||
if start_transform:
|
if start_transform:
|
||||||
start_mobs = start_transform(CompoundMobject(*start_mobs)).split()
|
start_mobs = start_transform(Mobject(*start_mobs)).split()
|
||||||
if end_transform:
|
if end_transform:
|
||||||
end_mobs = end_transform(CompoundMobject(*end_mobs)).split()
|
end_mobs = end_transform(Mobject(*end_mobs)).split()
|
||||||
unmatched_start_indices = set(range(len(start_mobs)))
|
unmatched_start_indices = set(range(len(start_mobs)))
|
||||||
unmatched_end_indices = set(range(len(end_mobs)))
|
unmatched_end_indices = set(range(len(end_mobs)))
|
||||||
unmatched_start_indices.difference_update(
|
unmatched_start_indices.difference_update(
|
||||||
|
@ -50,7 +50,7 @@ class RearrangeEquation(Scene):
|
||||||
|
|
||||||
self.add(*start_mobs)
|
self.add(*start_mobs)
|
||||||
if leave_start_terms:
|
if leave_start_terms:
|
||||||
self.add(CompoundMobject(*start_mobs))
|
self.add(Mobject(*start_mobs))
|
||||||
self.dither()
|
self.dither()
|
||||||
self.play(*[
|
self.play(*[
|
||||||
Transform(*pair, **transform_kwargs)
|
Transform(*pair, **transform_kwargs)
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
from mobject import Mobject, CompoundMobject
|
from mobject import Mobject, Mobject, ImageMobject, TexMobject
|
||||||
from image_mobject import ImageMobject
|
|
||||||
|
|
||||||
PI_CREATURE_DIR = os.path.join(IMAGE_DIR, "PiCreature")
|
PI_CREATURE_DIR = os.path.join(IMAGE_DIR, "PiCreature")
|
||||||
PI_CREATURE_PART_NAME_TO_DIR = lambda name : os.path.join(PI_CREATURE_DIR, "pi_creature_"+name) + ".png"
|
|
||||||
PI_CREATURE_SCALE_VAL = 0.5
|
PI_CREATURE_SCALE_VAL = 0.5
|
||||||
PI_CREATURE_MOUTH_TO_EYES_DISTANCE = 0.25
|
PI_CREATURE_MOUTH_TO_EYES_DISTANCE = 0.25
|
||||||
|
|
||||||
class PiCreature(CompoundMobject):
|
def part_name_to_directory(name):
|
||||||
DEFAULT_COLOR = BLUE
|
return os.path.join(PI_CREATURE_DIR, "pi_creature_"+name) + ".png"
|
||||||
|
|
||||||
|
class PiCreature(Mobject):
|
||||||
|
DEFAULT_CONFIG = {
|
||||||
|
"color" : BLUE_E
|
||||||
|
}
|
||||||
PART_NAMES = [
|
PART_NAMES = [
|
||||||
'arm',
|
'arm',
|
||||||
'body',
|
'body',
|
||||||
|
@ -23,42 +29,30 @@ class PiCreature(CompoundMobject):
|
||||||
MOUTH_NAMES = ["smile", "frown", "straight_mouth"]
|
MOUTH_NAMES = ["smile", "frown", "straight_mouth"]
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
color = self.DEFAULT_COLOR if "color" not in kwargs else kwargs.pop("color")
|
Mobject.__init__(self, **kwargs)
|
||||||
for part_name in self.PART_NAMES:
|
for part_name in self.PART_NAMES:
|
||||||
mob = ImageMobject(
|
mob = ImageMobject(
|
||||||
PI_CREATURE_PART_NAME_TO_DIR(part_name)
|
part_name_to_directory(part_name),
|
||||||
|
should_center = False
|
||||||
)
|
)
|
||||||
if part_name not in self.WHITE_PART_NAMES:
|
if part_name not in self.WHITE_PART_NAMES:
|
||||||
mob.highlight(color)
|
mob.highlight(self.color)
|
||||||
mob.scale(PI_CREATURE_SCALE_VAL)
|
|
||||||
setattr(self, part_name, mob)
|
setattr(self, part_name, mob)
|
||||||
self.eyes = [self.left_eye, self.right_eye]
|
self.eyes = Mobject(self.left_eye, self.right_eye)
|
||||||
self.legs = [self.left_leg, self.right_leg]
|
self.legs = Mobject(self.left_leg, self.right_leg)
|
||||||
mouth_center = self.get_mouth_center()
|
mouth_center = self.get_mouth_center()
|
||||||
self.mouth.center()
|
self.mouth.center()
|
||||||
self.smile = deepcopy(self.mouth)
|
self.smile = self.mouth
|
||||||
self.frown = deepcopy(self.mouth).rotate(np.pi, RIGHT)
|
self.frown = deepcopy(self.mouth).rotate(np.pi, RIGHT)
|
||||||
self.straight_mouth = TexMobject("-").scale(0.5)
|
self.straight_mouth = TexMobject("-").scale(0.5)
|
||||||
for mouth_name in ["mouth"] + self.MOUTH_NAMES:
|
for mouth in self.smile, self.frown, self.straight_mouth:
|
||||||
mouth = getattr(self, mouth_name)
|
|
||||||
mouth.sort_points(lambda p : p[0])
|
mouth.sort_points(lambda p : p[0])
|
||||||
|
mouth.highlight(self.color) ##to blend into background
|
||||||
mouth.shift(mouth_center)
|
mouth.shift(mouth_center)
|
||||||
#Ordering matters here, so hidden mouths are behind body
|
self.digest_mobject_attrs()
|
||||||
self.part_names = self.MOUTH_NAMES + self.PART_NAMES
|
self.give_smile()
|
||||||
self.white_parts = self.MOUTH_NAMES + self.WHITE_PART_NAMES
|
self.add(self.mouth)
|
||||||
CompoundMobject.__init__(
|
self.scale(PI_CREATURE_SCALE_VAL)
|
||||||
self,
|
|
||||||
*self.get_parts(),
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
def sync_parts(self):
|
|
||||||
CompoundMobject.__init__(self, *self.get_parts())
|
|
||||||
return self
|
|
||||||
|
|
||||||
# def TODO_what_should_I_do_with_this(self):
|
|
||||||
# for part_name, mob in zip(self.part_names, self.split()):
|
|
||||||
# setattr(self, part_name, mob)
|
|
||||||
|
|
||||||
|
|
||||||
def get_parts(self):
|
def get_parts(self):
|
||||||
|
@ -68,26 +62,30 @@ class PiCreature(CompoundMobject):
|
||||||
return [getattr(self, pn) for pn in self.white_parts]
|
return [getattr(self, pn) for pn in self.white_parts]
|
||||||
|
|
||||||
def get_mouth_center(self):
|
def get_mouth_center(self):
|
||||||
left_center = self.left_eye.get_center()
|
result = self.body.get_center()
|
||||||
right_center = self.right_eye.get_center()
|
result[0] = self.eyes.get_center()[0]
|
||||||
l_to_r = right_center-left_center
|
return result
|
||||||
eyes_to_mouth = rotate_vector(l_to_r, -np.pi/2, OUT)
|
# left_center = self.left_eye.get_center()
|
||||||
eyes_to_mouth /= np.linalg.norm(eyes_to_mouth)
|
# right_center = self.right_eye.get_center()
|
||||||
return left_center/2 + right_center/2 + \
|
# l_to_r = right_center-left_center
|
||||||
PI_CREATURE_MOUTH_TO_EYES_DISTANCE*eyes_to_mouth
|
# eyes_to_mouth = rotate_vector(l_to_r, -np.pi/2, OUT)
|
||||||
|
# eyes_to_mouth /= np.linalg.norm(eyes_to_mouth)
|
||||||
|
# return left_center/2 + right_center/2 + \
|
||||||
|
# PI_CREATURE_MOUTH_TO_EYES_DISTANCE*eyes_to_mouth
|
||||||
|
|
||||||
def highlight(self, color, condition = None):
|
def highlight(self, color, condition = None):
|
||||||
for part in set(self.get_parts()).difference(self.get_white_parts()):
|
for part in set(self.get_parts()).difference(self.get_white_parts()):
|
||||||
part.highlight(color, condition)
|
part.highlight(color, condition)
|
||||||
return self.sync_parts()
|
return self
|
||||||
|
|
||||||
def move_to(self, destination):
|
def move_to(self, destination):
|
||||||
self.shift(destination-self.get_bottom())
|
self.shift(destination-self.get_bottom())
|
||||||
return self.sync_parts()
|
return self
|
||||||
|
|
||||||
def change_mouth_to(self, mouth_name):
|
def change_mouth_to(self, mouth_name):
|
||||||
self.mouth = getattr(self, mouth_name)
|
self.mouth.points = getattr(self, mouth_name).points
|
||||||
return self.sync_parts()
|
self.mouth.highlight(WHITE)
|
||||||
|
return self
|
||||||
|
|
||||||
def give_smile(self):
|
def give_smile(self):
|
||||||
return self.change_mouth_to("smile")
|
return self.change_mouth_to("smile")
|
||||||
|
@ -99,29 +97,24 @@ class PiCreature(CompoundMobject):
|
||||||
return self.change_mouth_to("straight_mouth")
|
return self.change_mouth_to("straight_mouth")
|
||||||
|
|
||||||
def get_eye_center(self):
|
def get_eye_center(self):
|
||||||
return center_of_mass([
|
return self.eyes.get_center()
|
||||||
self.left_eye.get_center(),
|
|
||||||
self.right_eye.get_center()
|
|
||||||
]) + 0.04*RIGHT + 0.02*UP
|
|
||||||
|
|
||||||
def make_mean(self):
|
def make_mean(self):
|
||||||
eye_x, eye_y = self.get_eye_center()[:2]
|
eye_x, eye_y = self.get_eye_center()[:2]
|
||||||
def should_delete((x, y, z)):
|
def should_delete((x, y, z)):
|
||||||
return y - eye_y > 0.3*abs(x - eye_x)
|
return y - eye_y > 0.3*abs(x - eye_x)
|
||||||
for eye in self.left_eye, self.right_eye:
|
self.eyes.highlight("black", should_delete)
|
||||||
eye.highlight("black", should_delete)
|
|
||||||
self.give_straight_face()
|
self.give_straight_face()
|
||||||
return self.sync_parts()
|
return self
|
||||||
|
|
||||||
def make_sad(self):
|
def make_sad(self):
|
||||||
eye_x, eye_y = self.get_eye_center()[:2]
|
eye_x, eye_y = self.get_eye_center()[:2]
|
||||||
eye_y += 0.15
|
eye_y += 0.15
|
||||||
def should_delete((x, y, z)):
|
def should_delete((x, y, z)):
|
||||||
return y - eye_y > -0.3*abs(x - eye_x)
|
return y - eye_y > -0.3*abs(x - eye_x)
|
||||||
for eye in self.left_eye, self.right_eye:
|
self.eyey.highlight("black", should_delete)
|
||||||
eye.highlight("black", should_delete)
|
|
||||||
self.give_frown()
|
self.give_frown()
|
||||||
return self.sync_parts()
|
return self
|
||||||
|
|
||||||
def get_step_intermediate(self, pi_creature):
|
def get_step_intermediate(self, pi_creature):
|
||||||
vect = pi_creature.get_center() - self.get_center()
|
vect = pi_creature.get_center() - self.get_center()
|
||||||
|
@ -136,23 +129,22 @@ class PiCreature(CompoundMobject):
|
||||||
else:
|
else:
|
||||||
result.right_leg.wag(vect/2.0, DOWN)
|
result.right_leg.wag(vect/2.0, DOWN)
|
||||||
result.left_leg.wag(-vect/2.0, DOWN)
|
result.left_leg.wag(-vect/2.0, DOWN)
|
||||||
return result.sync_parts()
|
return result
|
||||||
|
|
||||||
def blink(self):
|
def blink(self):
|
||||||
for eye in self.left_eye, self.right_eye:
|
bottom = self.eyes.get_bottom()
|
||||||
bottom = eye.get_bottom()
|
self.eyes.apply_function(
|
||||||
eye.apply_function(
|
lambda (x, y, z) : (x, bottom[1], z)
|
||||||
lambda (x, y, z) : (x, bottom[1], z)
|
)
|
||||||
)
|
return self
|
||||||
return self.sync_parts()
|
|
||||||
|
|
||||||
def shift_eyes(self):
|
def shift_eyes(self):
|
||||||
for eye in self.left_eye, self.right_eye:
|
for eye in self.left_eye, self.right_eye:
|
||||||
eye.rotate_in_place(np.pi, UP)
|
eye.rotate_in_place(np.pi, UP)
|
||||||
return self.sync_parts()
|
return self
|
||||||
|
|
||||||
def to_symbol(self):
|
def to_symbol(self):
|
||||||
CompoundMobject.__init__(
|
Mobject.__init__(
|
||||||
self,
|
self,
|
||||||
*list(set(self.get_parts()).difference(self.get_white_parts()))
|
*list(set(self.get_parts()).difference(self.get_white_parts()))
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,7 +2,7 @@ from helpers import *
|
||||||
|
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
from mobject import Mobject, Mobject1D, CompoundMobject
|
from mobject import Mobject, Mobject1D, Mobject
|
||||||
|
|
||||||
|
|
||||||
class FunctionGraph(Mobject1D):
|
class FunctionGraph(Mobject1D):
|
||||||
|
@ -58,11 +58,11 @@ class ParametricFunction(Mobject):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
class Axes(CompoundMobject):
|
class Axes(Mobject):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
x_axis = NumberLine(**kwargs)
|
x_axis = NumberLine(**kwargs)
|
||||||
y_axis = NumberLine(**kwargs).rotate(np.pi/2, OUT)
|
y_axis = NumberLine(**kwargs).rotate(np.pi/2, OUT)
|
||||||
CompoundMobject.__init__(self, x_axis, y_axis)
|
Mobject.__init__(self, x_axis, y_axis)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,7 @@ class GraphScene(Scene):
|
||||||
|
|
||||||
def draw_vertices(self, **kwargs):
|
def draw_vertices(self, **kwargs):
|
||||||
self.clear()
|
self.clear()
|
||||||
self.play(ShowCreation(CompoundMobject(*self.vertices), **kwargs))
|
self.play(ShowCreation(Mobject(*self.vertices), **kwargs))
|
||||||
|
|
||||||
def draw_edges(self):
|
def draw_edges(self):
|
||||||
self.play(*[
|
self.play(*[
|
||||||
|
@ -227,8 +227,8 @@ class GraphScene(Scene):
|
||||||
|
|
||||||
def accent_vertices(self, **kwargs):
|
def accent_vertices(self, **kwargs):
|
||||||
self.remove(*self.vertices)
|
self.remove(*self.vertices)
|
||||||
start = CompoundMobject(*self.vertices)
|
start = Mobject(*self.vertices)
|
||||||
end = CompoundMobject(*[
|
end = Mobject(*[
|
||||||
Dot(point, radius = 3*Dot.DEFAULT_RADIUS, color = "lightgreen")
|
Dot(point, radius = 3*Dot.DEFAULT_RADIUS, color = "lightgreen")
|
||||||
for point in self.points
|
for point in self.points
|
||||||
])
|
])
|
||||||
|
@ -275,7 +275,7 @@ class GraphScene(Scene):
|
||||||
time_per_edge = run_time / len(cycle)
|
time_per_edge = run_time / len(cycle)
|
||||||
next_in_cycle = it.cycle(cycle)
|
next_in_cycle = it.cycle(cycle)
|
||||||
next_in_cycle.next()#jump one ahead
|
next_in_cycle.next()#jump one ahead
|
||||||
self.traced_cycle = CompoundMobject(*[
|
self.traced_cycle = Mobject(*[
|
||||||
Line(self.points[i], self.points[j]).highlight(color)
|
Line(self.points[i], self.points[j]).highlight(color)
|
||||||
for i, j in zip(cycle, next_in_cycle)
|
for i, j in zip(cycle, next_in_cycle)
|
||||||
])
|
])
|
||||||
|
@ -299,7 +299,7 @@ class GraphScene(Scene):
|
||||||
self.spanning_tree_index_pairs.append(pair)
|
self.spanning_tree_index_pairs.append(pair)
|
||||||
spanned_vertices.add(pair[1])
|
spanned_vertices.add(pair[1])
|
||||||
to_check.add(pair[1])
|
to_check.add(pair[1])
|
||||||
self.spanning_tree = CompoundMobject(*[
|
self.spanning_tree = Mobject(*[
|
||||||
Line(
|
Line(
|
||||||
self.points[pair[0]],
|
self.points[pair[0]],
|
||||||
self.points[pair[1]]
|
self.points[pair[1]]
|
||||||
|
@ -361,7 +361,7 @@ class GraphScene(Scene):
|
||||||
])
|
])
|
||||||
for index in indices
|
for index in indices
|
||||||
]
|
]
|
||||||
self.treeified_spanning_tree = CompoundMobject(*[
|
self.treeified_spanning_tree = Mobject(*[
|
||||||
Line(new_points[i], new_points[j]).highlight(color)
|
Line(new_points[i], new_points[j]).highlight(color)
|
||||||
for i, j in self.spanning_tree_index_pairs
|
for i, j in self.spanning_tree_index_pairs
|
||||||
])
|
])
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import itertools as it
|
import itertools as it
|
||||||
|
|
||||||
from mobject import Mobject, Mobject1D, Mobject2D, CompoundMobject
|
from mobject import Mobject, Mobject1D, Mobject2D, Mobject
|
||||||
from geometry import Line
|
from geometry import Line
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class Dodecahedron(Mobject1D):
|
||||||
(x-y+z, v2),
|
(x-y+z, v2),
|
||||||
(x-y-z, v2),
|
(x-y-z, v2),
|
||||||
]
|
]
|
||||||
five_lines_points = CompoundMobject(*[
|
five_lines_points = Mobject(*[
|
||||||
Line(pair[0], pair[1], density = 1.0/self.epsilon)
|
Line(pair[0], pair[1], density = 1.0/self.epsilon)
|
||||||
for pair in vertex_pairs
|
for pair in vertex_pairs
|
||||||
]).points
|
]).points
|
||||||
|
|
Loading…
Add table
Reference in a new issue