Mobjects now contain submobjects, giving a heirarchy. Thus CompoundMobject is replaced simply with Mobject, and display etc. needed updating

This commit is contained in:
Grant Sanderson 2015-11-02 13:03:01 -08:00
parent 8663bda619
commit 38b07266b9
18 changed files with 491 additions and 457 deletions

View file

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

View file

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

View file

@ -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 ######
def shift(self, *vectors):
total_vector = reduce(op.add, vectors)
for mob in self.get_full_submobject_family():
mob.points += total_vector
return self
def scale(self, scale_factor):
for mob in self.get_full_submobject_family():
mob.points *= scale_factor
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):
""" """
points must be a Nx3 numpy array, as must rgbs if it is not None Condition is function which takes in one arguments, (x, y, z).
""" """
points = np.array(points) rgb = Color(color).get_rgb()
num_new_points = points.shape[0] for mob in self.get_full_submobject_family():
self.points = np.append(self.points, points) if condition:
self.points = self.points.reshape((self.points.size / 3, 3)) to_change = np.apply_along_axis(condition, 1, mob.points)
if rgbs is None: mob.rgbs[to_change, :] = rgb
color = Color(color) if color else self.color
rgbs = np.array([color.get_rgb()] * num_new_points)
else: else:
if rgbs.shape != points.shape: mob.rgbs[:,:] = rgb
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 filter_out(self, condition):
for mobject in mobjects: for mob in self.get_full_submobject_family():
self.add_points(mobject.points, mobject.rgbs) to_eliminate = ~np.apply_along_axis(condition, 1, mob.points)
mob.points = mob.points[to_eliminate]
mob.rgbs = mob.rgbs[to_eliminate]
return self 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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.sync_parts() return self
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()))
) )

View file

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

View file

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

View file

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