From 38b07266b97108f646670576fa7ec6a79f4e131a Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Mon, 2 Nov 2015 13:03:01 -0800 Subject: [PATCH] Mobjects now contain submobjects, giving a heirarchy. Thus CompoundMobject is replaced simply with Mobject, and display etc. needed updating --- displayer.py | 10 +- helpers.py | 12 +- mobject/mobject.py | 494 +++++++++--------- old_projects/counting_in_binary.py | 14 +- old_projects/eulers_characteristic_formula.py | 46 +- old_projects/inventing_math.py | 58 +- old_projects/moser_intro.py | 22 +- old_projects/moser_main.py | 74 +-- old_projects/music_and_measure.py | 48 +- old_projects/playground_counting_in_binary.py | 2 +- old_projects/pythagorean_proof.py | 2 +- scene/scene.py | 23 +- scene/tk_scene.py | 3 +- topics/arithmetic.py | 6 +- topics/characters.py | 112 ++-- topics/functions.py | 6 +- topics/graph_theory.py | 12 +- topics/three_dimensions.py | 4 +- 18 files changed, 491 insertions(+), 457 deletions(-) diff --git a/displayer.py b/displayer.py index 1a62c398..c2879741 100644 --- a/displayer.py +++ b/displayer.py @@ -37,7 +37,7 @@ def paint_region(region, image_array = None, color = None): def paint_mobject(mobject, image_array = None): 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) height = pixels.shape[0] width = pixels.shape[1] @@ -45,6 +45,13 @@ def paint_mobjects(mobjects, image_array = None): space_width = SPACE_HEIGHT * width / height 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: if mobject.get_num_points() == 0: continue @@ -73,7 +80,6 @@ def paint_mobjects(mobjects, image_array = None): flattener = np.array([[1], [width]], dtype = 'int') indices = np.dot(points, flattener)[:,0] pixels[indices] = rgbs.astype('uint8') - return pixels.reshape((height, width, 3)) def add_thickness(pixel_indices_and_rgbs, thickness, width, height): diff --git a/helpers.py b/helpers.py index 813d2bc9..5f23a1b7 100644 --- a/helpers.py +++ b/helpers.py @@ -11,8 +11,18 @@ import re 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): - 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): return all(map(lambda e : isinstance(e, Class), iterable)) diff --git a/mobject/mobject.py b/mobject/mobject.py index 59656767..fd84190a 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -23,24 +23,79 @@ class Mobject(object): "name" : None, } DIM = 3 - def __init__(self, **kwargs): + def __init__(self, *sub_mobjects, **kwargs): digest_config(self, kwargs) + self.sub_mobjects = list(sub_mobjects) self.color = Color(self.color) if self.name is None: self.name = self.__class__.__name__ self.has_normals = hasattr(self, 'unit_normal') self.init_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): - self.points = np.zeros((0, 3)) - self.rgbs = np.zeros((0, 3)) - if self.has_normals: - self.unit_normals = np.zeros((0, 3)) + for attr in self.get_array_attrs(): + setattr(self, attr, np.zeros((0, 3))) def __str__(self): 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): Image.fromarray(disp.paint_mobject(self)).show() @@ -49,42 +104,98 @@ class Mobject(object): os.path.join(MOVIE_DIR, (name or str(self)) + ".png") ) - def add_points(self, points, rgbs = None, color = None): - """ - points must be a Nx3 numpy array, as must rgbs if it is not None - """ - points = np.array(points) - num_new_points = points.shape[0] - self.points = np.append(self.points, points) - 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) + + #### 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 add(self, *mobjects): - for mobject in mobjects: - self.add_points(mobject.points, mobject.rgbs) + 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): + """ + 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): - #Can make transition animations nicer - points, rgbs = deepcopy(self.points), deepcopy(self.rgbs) - for x in range(count - 1): - self.add_points(points, rgbs) + """ + This can make transition animations nicer + """ + 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 + #### In place operations ###### + def do_in_place(self, method, *args, **kwargs): center = self.get_center() self.shift(-center) @@ -92,96 +203,50 @@ class Mobject(object): self.shift(center) 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): self.do_in_place(self.rotate, angle, axis) 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): self.do_in_place(self.scale, scale_factor) return self - def stretch(self, factor, dim): - self.points[:,dim] *= factor + def pose_at_angle(self): + 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 def stretch_to_fit(self, length, dim): - center = self.get_center() - old_length = max(self.points[:,dim]) - min(self.points[:,dim]) - self.center() - self.stretch(length/old_length, dim) - self.shift(center) + old_length = self.length_over_dim(dim) + self.do_in_place(self.stretch, length/old_length, dim) return self def stretch_to_fit_width(self, width): @@ -196,11 +261,6 @@ class Mobject(object): def scale_to_fit_height(self, 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): if mobject.get_num_points() == 0: raise Warning("Attempting to replace mobject with no points") @@ -213,27 +273,11 @@ class Mobject(object): self.center().shift(mobject.get_center()) 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): return self.apply_function( 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): self.highlight(color) self.color = Color(color) @@ -245,59 +289,92 @@ class Mobject(object): def fade_to(self, color, alpha): self.rgbs = interpolate(self.rgbs, Color(color).rgb, alpha) + for mob in self.sub_mobjects: + mob.fade_to(color, alpha) return self def fade(self, brightness = 0.5): - self.rgbs *= brightness + self.fade_to(BLACK, brightness) return self - def filter_out(self, condition): - to_eliminate = ~np.apply_along_axis(condition, 1, self.points) - self.points = self.points[to_eliminate] - self.rgbs = self.rgbs[to_eliminate] - return self + def reduce_across_dimension(self, points_func, reduce_func, dim): + try: + values = [points_func(self.points[:, dim])] + except: + 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]): - """ - function is any map from R^3 to R - """ - indices = range(self.get_num_points()) - indices.sort( - lambda *pair : cmp(*map(function, self.points[pair, :])) + def get_merged_array(self, array_attr): + return reduce( + lambda a1, a2 : np.append(a1, a2, axis = 0), + [getattr(self, array_attr)] + [ + mob.get_merged_array(array_attr) + for mob in self.sub_mobjects + ] ) - 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 + 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 ### - def get_num_points(self): - return len(self.points) + def get_num_points(self, including_submobjects = False): + return self.reduce_across_dimension(len, sum, 0) - def get_center(self): - if self.get_num_points() == 0: - return ORIGIN - return (np.max(self.points, 0) + np.min(self.points, 0))/2.0 + def get_critical_point(self, direction): + result = np.zeros(self.DIM) + for dim in [0, 1]: + 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): - return np.apply_along_axis(np.mean, 0, self.points) - - def get_boundary_point(self, direction): - return self.points[np.argmax(np.dot(self.points, direction))] - - 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]) + if direction[dim] == 0: + result[dim] = (max_point+min_point)/2 + elif direction[dim] < 0: + result[dim] = min_point + else: + result[dim] = max_point 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): - return sum([ - self.get_edge_center(RIGHT*direction[0]), - self.get_edge_center(UP*direction[1]), - -self.get_center() - ]) + return self.get_critical_point(direction) + + def get_center(self): + 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): return self.get_edge_center(UP) @@ -311,11 +388,18 @@ class Mobject(object): def get_left(self): 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): - return np.max(self.points[:, 0]) - np.min(self.points[:, 0]) + return self.length_over_dim(0) 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): color = Color() @@ -346,7 +430,7 @@ class Mobject(object): and mobject2. """ Mobject.align_data(mobject1, mobject2) - for attr in ['points', 'rgbs']: + for attr in self.get_array_attrs(): setattr(target_mobject, attr, interpolate( getattr(mobject1, attr), getattr(mobject2, attr), @@ -380,29 +464,6 @@ class Mobject2D(Mobject): self.epsilon = 1.0 / self.density 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): DEFAULT_CONFIG = { @@ -415,47 +476,6 @@ class Point(Mobject): def generate_points(self): 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 - - - - - diff --git a/old_projects/counting_in_binary.py b/old_projects/counting_in_binary.py index 6fe2333f..3d77ccf5 100644 --- a/old_projects/counting_in_binary.py +++ b/old_projects/counting_in_binary.py @@ -198,7 +198,7 @@ class ShowFrameNum(OverHand): OverHand.construct(self) for frame, count in zip(self.frames, it.count()): print count, "of", len(self.frames) - mob = CompoundMobject(*[ + mob = Mobject(*[ TexMobject(char).shift(0.3*x*RIGHT) for char, x, in zip(str(count), it.count()) ]) @@ -212,12 +212,12 @@ class CountTo1023(Scene): rh_map = get_hand_map("right") lh_map = get_hand_map("left") def get_num(count): - return CompoundMobject(*[ + return Mobject(*[ TexMobject(char).shift(0.35*x*RIGHT) for char, x, in zip(str(count), it.count()) ]).center().to_edge(UP) self.frames = [ - disp.paint_mobject(CompoundMobject( + disp.paint_mobject(Mobject( rh_map[count%32], lh_map[count//32], get_num(count) )) for count in range(2**10) @@ -360,7 +360,7 @@ class ShowIncrementRule(Scene): (2.25, 3.5, 0), (1.5, 0.75, 0), ] - return CompoundMobject(*[ + return Mobject(*[ deepcopy(arrow).shift(tip) for tip in tips ]) @@ -379,7 +379,7 @@ class MindFindsShortcuts(Scene): hand = Hand(7).scale(0.5).center().shift(DOWN+2*LEFT) sum421 = TexMobject("4+2+1").shift(DOWN+2*RIGHT) seven = TexMobject("7").shift(DOWN+6*RIGHT) - compound = CompoundMobject( + compound = Mobject( Arrow(hand, sum421), sum421, Arrow(sum421, seven) @@ -438,7 +438,7 @@ class CountingExampleSentence(ShowCounting): ShowCounting.construct(self) def get_counting_mob(self, num): - return CompoundMobject(*self.words[:num]) + return Mobject(*self.words[:num]) class FinishCountingExampleSentence(Scene): def construct(self): @@ -449,7 +449,7 @@ class FinishCountingExampleSentence(Scene): two = TexMobject("2").shift([3, 3.65, 0]) eightteen = TexMobject("18").shift([1.5, 2.5, 0]) eightteen.sort_points() - comp = CompoundMobject(sixteen, two) + comp = Mobject(sixteen, two) self.add(hand, comp, words) self.dither() self.play(Transform(comp, eightteen)) diff --git a/old_projects/eulers_characteristic_formula.py b/old_projects/eulers_characteristic_formula.py index 30664590..8466ddd5 100644 --- a/old_projects/eulers_characteristic_formula.py +++ b/old_projects/eulers_characteristic_formula.py @@ -50,7 +50,7 @@ class PreferOtherProofDialogue(Scene): self.dither(2) self.play(Transform( Dot(student_bubble.tip).highlight("black"), - CompoundMobject(student_bubble, student_bubble.text) + Mobject(student_bubble, student_bubble.text) )) self.dither(2) self.remove(teacher_bubble.text) @@ -81,7 +81,7 @@ class IllustrateDuality(GraphScene): for edge_pair in zip(self.edges, self.dual_edges) ] + [ Transform( - CompoundMobject(*[ + Mobject(*[ self.vertices[index] for index in cycle ]), @@ -143,7 +143,7 @@ class IntroduceGraph(GraphScene): self.add(not_okay) self.remove(*edges_to_remove) self.play(ShowCreation( - CompoundMobject(*edges_to_remove), + Mobject(*edges_to_remove), alpha_func = lambda t : 1 - t, run_time = 1.0 )) @@ -182,10 +182,10 @@ class PlanarGraphDefinition(Scene): "Not \\\\", "``", "Planar", "''", # "no matter how \\\\ hard you try" ]).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) graphs = [ - CompoundMobject(*GraphScene(g).mobjects) + Mobject(*GraphScene(g).mobjects) for g in [ CubeGraph(), CompleteGraph(5), @@ -227,7 +227,7 @@ class TerminologyFromPolyhedra(GraphScene): point / 2 + OUT if abs(point[0]) == 2 else point + IN for point in self.points ] - cube = CompoundMobject(*[ + cube = Mobject(*[ Line(vertices[edge[0]], vertices[edge[1]]) for edge in self.graph.edges ]) @@ -258,7 +258,7 @@ class TerminologyFromPolyhedra(GraphScene): self.remove(dots_to_vertices, *self.vertices) self.add(lines_to_edges) self.play(ApplyMethod( - CompoundMobject(*self.edges).highlight, "yellow" + Mobject(*self.edges).highlight, "yellow" )) self.dither(2) self.clear() @@ -312,7 +312,7 @@ class ThreePiecesOfTerminology(GraphScene): self.clear() self.play(ApplyMethod( - CompoundMobject(*terms).center + Mobject(*terms).center )) self.dither() @@ -361,14 +361,14 @@ class PathExamples(GraphScene): mob.to_edge(UP) kwargs = {"run_time" : 1.0} for path, non_path in zip(paths, non_paths): - path_lines = CompoundMobject(*[ + path_lines = Mobject(*[ Line( self.points[path[i]], self.points[path[i+1]] ).highlight("yellow") for i in range(len(path) - 1) ]) - non_path_lines = CompoundMobject(*[ + non_path_lines = Mobject(*[ Line( self.points[pp[0]], self.points[pp[1]], @@ -430,7 +430,7 @@ class DefineSpanningTree(GraphScene): randy.scale(RANDOLPH_SCALE_VAL).move_to(self.points[0]) dollar_signs = TextMobject("\\$\\$") dollar_signs.scale(EDGE_ANNOTATION_SCALE_VAL) - dollar_signs = CompoundMobject(*[ + dollar_signs = Mobject(*[ deepcopy(dollar_signs).shift(edge.get_center()) for edge in self.edges ]) @@ -494,8 +494,8 @@ class NamingTree(GraphScene): self.add(*branches) self.play( - FadeOut(CompoundMobject(*self.edges + self.vertices)), - Animation(CompoundMobject(*branches)), + FadeOut(Mobject(*self.edges + self.vertices)), + Animation(Mobject(*branches)), ) self.clear() self.add(tree, *branches) @@ -599,7 +599,7 @@ class FacebookGraphAsAbstractSet(Scene): accounts.shift(3*LEFT).to_edge(UP) friendships = TextMobject("\\textbf{Friendships}") friendships.shift(3*RIGHT).to_edge(UP) - lines = CompoundMobject( + lines = Mobject( Line(UP*SPACE_HEIGHT, DOWN*SPACE_HEIGHT), Line(LEFT*SPACE_WIDTH + 3*UP, RIGHT*SPACE_WIDTH + 3*UP) ).highlight("white") @@ -622,7 +622,7 @@ class ExamplesOfGraphs(GraphScene): ) GraphScene.construct(self) self.generate_regions() - objects, notions = CompoundMobject(*TextMobject( + objects, notions = Mobject(*TextMobject( ["Objects \\quad\\quad ", "Thing that connects objects"] )).to_corner().shift(0.5*RIGHT).split() horizontal_line = Line( @@ -687,8 +687,8 @@ class ExamplesOfGraphs(GraphScene): ] ] - comp_words = CompoundMobject(*words) - comp_lines = CompoundMobject(*lines) + comp_words = Mobject(*words) + comp_lines = Mobject(*lines) self.add(words1) self.play(ShowCreation(comp_words, run_time = 1.0)) self.dither() @@ -852,7 +852,7 @@ class ListOfCorrespondances(Scene): left.shift((min(arrow_xs) - SPACE_WIDTH, 0, 0)) right.to_edge(LEFT) 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 for line in lines: self.add(line.highlight("yellow")) @@ -892,7 +892,7 @@ class CyclesCorrespondWithConnectedComponents(GraphScene): self.highlight_region(region) self.dither(2) self.reset_background() - lines = CompoundMobject(*[ + lines = Mobject(*[ Line(self.dual_points[last], self.dual_points[next]) for last, next in zip(dual_cycle, dual_cycle[1:]) ]).highlight("red") @@ -1015,7 +1015,7 @@ class RandolphMortimerSpanningTreeGame(GraphScene): cycle_index = region_ordering[-1] cycle = self.graph.region_cycles[cycle_index] 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") for last, next in zip(cycle, list(cycle)[1:] + [cycle[0]]) ]))) @@ -1116,7 +1116,7 @@ class DualSpanningTree(GraphScene): """).to_edge(UP) self.add(self.spanning_tree, randy, morty) - self.play(ShowCreation(CompoundMobject( + self.play(ShowCreation(Mobject( *np.array(self.edges)[dual_edges] ).highlight("red"))) self.add(words) @@ -1147,7 +1147,7 @@ class TreeCountFormula(Scene): self.remove(*all_dots) self.play( FadeOut(text), - FadeIn(CompoundMobject(*gs.edges + gs.vertices)), + FadeIn(Mobject(*gs.edges + gs.vertices)), *[ Transform(*pair) 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", " \\Downarrow \\\\", "E","+","2","&=","V","+","F", ], size = "\\large").split() - for line in lines[:2] + [CompoundMobject(*lines[2:])]: + for line in lines[:2] + [Mobject(*lines[2:])]: self.add(line) self.dither() self.dither() diff --git a/old_projects/inventing_math.py b/old_projects/inventing_math.py index 8d525e5b..877723ea 100644 --- a/old_projects/inventing_math.py +++ b/old_projects/inventing_math.py @@ -96,7 +96,7 @@ def zero_to_one_interval(): interval.elongate_tick_at(INTERVAL_RADIUS, 4) zero = TexMobject("0").shift(INTERVAL_RADIUS*LEFT+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): result = PiCreature() @@ -175,7 +175,7 @@ class IntroduceDivergentSum(Scene): self.add(brace, sum_value) self.dither(0.75) self.remove(sum_value) - ellipses = CompoundMobject( + ellipses = Mobject( *[equation[NUM_WRITTEN_TERMS + i] for i in range(3)] ) end_brace = deepcopy(brace).stretch_to_fit_width( @@ -264,7 +264,7 @@ class OutlineOfVideo(Scene): ] last_one_split = texts[-1].split() 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[1].shift(sum([ arrow.get_boundary_point(DOWN+RIGHT), @@ -335,7 +335,7 @@ class OutlineOfVideo(Scene): # self.add(sum_mob) # self.play(FadeIn(discover)) # self.dither() -# self.play(FadeIn(CompoundMobject(*define_parts))) +# self.play(FadeIn(Mobject(*define_parts))) # self.dither() class YouAsMathematician(Scene): @@ -376,7 +376,7 @@ class YouAsMathematician(Scene): self.remove(bubble, *equation_parts) self.disapproving_friend() self.add(bubble, equation) - self.play(Transform(equation, CompoundMobject(*dot_pair))) + self.play(Transform(equation, Mobject(*dot_pair))) self.remove(equation) self.add(*dot_pair) two_arrows = [ @@ -386,7 +386,7 @@ class YouAsMathematician(Scene): self.play(*[ShowCreation(a) for a in two_arrows]) self.play(BlinkPiCreature(you)) self.remove(*dot_pair+two_arrows) - everything = CompoundMobject(*self.mobjects) + everything = Mobject(*self.mobjects) self.clear() self.play( ApplyPointwiseFunction( @@ -559,7 +559,7 @@ class OrganizePartialSums(Scene): self.play(ShowCreation(dots)) self.dither() - self.play(FadeIn(CompoundMobject(down_arrow, infinite_sum))) + self.play(FadeIn(Mobject(down_arrow, infinite_sum))) self.dither() class SeeNumbersApproachOne(Scene): @@ -569,7 +569,7 @@ class SeeNumbersApproachOne(Scene): arrow.shift(DOWN).highlight("yellow") num_dots = 6 colors = Color("green").range_to("yellow", num_dots) - dots = CompoundMobject(*[ + dots = Mobject(*[ Dot( density = 2*DEFAULT_POINT_DENSITY_1D ).scale(1+1.0/2.0**x).shift( @@ -682,7 +682,7 @@ class ListOfPartialSums(Scene): self.play(ShowCreation(dots)) self.dither() self.play( - FadeIn(CompoundMobject(*equals)), + FadeIn(Mobject(*equals)), *[ Transform(deepcopy(number), finite_sum) for number, finite_sum in zip(numbers, sums) @@ -712,7 +712,7 @@ class ShowDecreasingDistance(Scene): lines = [vert_line0, vert_line1, horiz_line] for line in lines: line.highlight("green") - dots = CompoundMobject(*[ + dots = Mobject(*[ Dot().scale(1.0/(n+1)).shift((1+partial_sum(n))*RIGHT) for n in range(10) ]) @@ -734,7 +734,7 @@ class ShowDecreasingDistance(Scene): class CircleZoomInOnOne(Scene): def construct(self): number_line = NumberLine(interval_size = 1).add_numbers() - dots = CompoundMobject(*[ + dots = Mobject(*[ Dot().scale(1.0/(n+1)).shift((1+partial_sum(n))*RIGHT) for n in range(10) ]) @@ -849,7 +849,7 @@ class DefineInfiniteSum(Scene): "\\sum_{n = 0}^\\infty a_n = X" ]).split() define.highlight("skyblue") - expression = CompoundMobject(define, infinite_sum) + expression = Mobject(define, infinite_sum) self.add(expression) self.dither() @@ -1041,7 +1041,7 @@ class ChopIntervalInProportions(Scene): FadeIn(rt[0]), Transform( brace_to_replace.repeat(2), - CompoundMobject(*braces) + Mobject(*braces) ), FadeIn(left_paren), FadeIn(right_paren), @@ -1052,7 +1052,7 @@ class ChopIntervalInProportions(Scene): self.play( Transform( term_to_replace, - CompoundMobject(lt[0], rt[1]) + Mobject(lt[0], rt[1]) ), FadeOut(left_paren), FadeOut(right_paren) @@ -1064,26 +1064,26 @@ class ChopIntervalInProportions(Scene): FadeIn(rt[0]), Transform( brace_to_replace.repeat(2), - CompoundMobject(*braces) + Mobject(*braces) ), Transform( term_to_replace, - CompoundMobject(lt[0], rt[1]) + Mobject(lt[0], rt[1]) ), *additional_anims ) self.remove(*lt+rt) - lt, rt = CompoundMobject(*lt), CompoundMobject(*rt) + lt, rt = Mobject(*lt), Mobject(*rt) self.add(lt, rt) else: self.play( Transform( brace_to_replace.repeat(2), - CompoundMobject(*braces) + Mobject(*braces) ), Transform( term_to_replace, - CompoundMobject(lt, rt) + Mobject(lt, rt) ), *additional_anims ) @@ -1379,10 +1379,10 @@ class SumPowersOfTwoAnimation(Scene): new_bottom_num = TexMobject(str(2**(n+1))) 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.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) if n == iterations: @@ -1390,7 +1390,7 @@ class SumPowersOfTwoAnimation(Scene): new_dot = deepcopy(dot).shift(circle.get_center()) shift_val = (2**n)*(dot_width+dot_buff) 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) alt_bottombrace = deepcopy(bottombrace).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(): exp.stretch_to_fit_width(brace.get_width()) 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] self.dither() @@ -1438,7 +1438,7 @@ class SumPowersOfTwoAnimation(Scene): top_sum_end, new_top_sum_end, alt_topbrace, alt_bottombrace ) - curr_dots = CompoundMobject(curr_dots, new_dots) + curr_dots = Mobject(curr_dots, new_dots) class PretendTheyDoApproachNegativeOne(RearrangeEquation): @@ -1730,7 +1730,7 @@ class RoomsAndSubrooms(Scene): ] for group in rectangle_groups: - mob = CompoundMobject(*group) + mob = Mobject(*group) mob.sort_points(np.linalg.norm) self.play(ShowCreation(mob)) @@ -1945,7 +1945,7 @@ class DeduceWhereNegativeOneFalls(Scene): colors = list(get_room_colors()) num_labels = len(colors) texts = [ - CompoundMobject(parts[0], parts[1].highlight(color)) + Mobject(parts[0], parts[1].highlight(color)) for count, color in zip(it.count(), colors) for parts in [TextMobject([ "Represented (heuristically) \\\\ by being in the same \\\\", @@ -2025,7 +2025,7 @@ class PAdicMetric(Scene): self.play(DelayByOrder(Transform(curr, prime))) self.dither() if count == 2: - self.spill(CompoundMobject(curr, text), arrow, new_numbers) + self.spill(Mobject(curr, text), arrow, new_numbers) self.remove(curr) curr = prime self.play(DelayByOrder(Transform(curr, p_str))) @@ -2052,7 +2052,7 @@ class FuzzyDiscoveryToNewMath(Scene): fuzzy.to_edge(UP).shift(SPACE_WIDTH*LEFT/2) new_math = TextMobject("New Math") new_math.to_edge(UP).shift(SPACE_WIDTH*RIGHT/2) - lines = CompoundMobject( + lines = Mobject( Line(DOWN*SPACE_HEIGHT, UP*SPACE_HEIGHT), Line(3*UP+LEFT*SPACE_WIDTH, 3*UP+RIGHT*SPACE_WIDTH) ) @@ -2071,7 +2071,7 @@ class FuzzyDiscoveryToNewMath(Scene): line.highlight("blue") char_mob = TexMobject(char).scale(0.25) 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()) how_length = TextMobject("But how is length defined?").scale(0.5) how_length.shift(0.75*DOWN) diff --git a/old_projects/moser_intro.py b/old_projects/moser_intro.py index 9f957e35..58febd6f 100644 --- a/old_projects/moser_intro.py +++ b/old_projects/moser_intro.py @@ -48,7 +48,7 @@ def count_sections(*radians): else: sc.animate(ShowCreation(dots[x])) sc.add(dots[x]) - new_lines = CompoundMobject(*[ + new_lines = Mobject(*[ Line(points[x], points[y]) for y in xrange(x) ]) 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] last_num = None for x in xrange(len(points)): - new_lines = CompoundMobject(*[ + new_lines = Mobject(*[ Line(points[x], points[y]) for y in xrange(x) ]) num = TexMobject(str(moser_function(x + 1))).center() @@ -116,7 +116,7 @@ def connect_points(*radians): all_lines = [] for x in xrange(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)) all_lines.append(lines) sc.animate(*anims) @@ -127,13 +127,13 @@ def connect_points(*radians): def interesting_problems(): sc = Scene() 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)) face = SimpleFace() tb = ThoughtBubble().shift((-1.5, 1, 0)) sb = SpeechBubble().shift((-2.4, 1.3, 0)) fermat_copies, face_copies, tb_copies, sb_copies = ( - CompoundMobject(*[ + Mobject(*[ deepcopy(mob).scale(0.5).shift(locale) for locale in locales ]) @@ -162,11 +162,11 @@ def interesting_problems(): def response_invitation(): sc = Scene() video_icon = VideoIcon() - mini_videos = CompoundMobject(*[ + mini_videos = Mobject(*[ deepcopy(video_icon).scale(0.5).shift((3, y, 0)) for y in [-2, 0, 2] ]) - comments = CompoundMobject(*[ + comments = Mobject(*[ Line((-1.2, y, 0), (1.2, y, 0), color = 'white') for y in [-1.5, -1.75, -2] ]) @@ -191,7 +191,7 @@ def different_points(radians1, radians2): for radians in (radians1, radians2) ) dots1, dots2 = ( - CompoundMobject(*[Dot(point) for point in points]) + Mobject(*[Dot(point) for point in points]) for points in (points1, points2) ) lines1, lines2 = ( @@ -219,14 +219,14 @@ def next_few_videos(*radians): (RADIUS * np.cos(angle), RADIUS * np.sin(angle), 0) for angle in radians ] - dots = CompoundMobject(*[ + dots = Mobject(*[ Dot(point) for point in points ]) - lines = CompoundMobject(*[ + lines = Mobject(*[ Line(point1, point2) for point1, point2 in it.combinations(points, 2) ]) - thumbnail = CompoundMobject(circle, dots, lines) + thumbnail = Mobject(circle, dots, lines) frame = VideoIcon().highlight( "black", lambda point : np.linalg.norm(point) < 0.5 diff --git a/old_projects/moser_main.py b/old_projects/moser_main.py index 5c556502..40894352 100644 --- a/old_projects/moser_main.py +++ b/old_projects/moser_main.py @@ -176,7 +176,7 @@ class HardProblemsSimplerQuestions(Scene): fermat = dict([ ( sym, - CompoundMobject(*TexMobjects( + Mobject(*TexMobjects( ["x","^"+sym,"+","y","^"+sym,"=","z","^"+sym] )) ) @@ -234,7 +234,7 @@ class HardProblemsSimplerQuestions(Scene): self.add(fermat["n"], fermat2, fermat3) self.dither() - circle_grid = CompoundMobject( + circle_grid = Mobject( Circle(), Grid(radius = 2), 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: mob.scale(0.5).shift(right_center + (0, 2, 0)) - other_grid = CompoundMobject( + other_grid = Mobject( Grid(radius = 2), TexMobject(r"\mathds{C}").shift((2, -2, 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) for t, s in it.product(range(-2, 3), range(-2, 3)) ]) @@ -264,7 +264,7 @@ class HardProblemsSimplerQuestions(Scene): ShowCreation(dots) ) self.dither() - all_mobjects = CompoundMobject(*self.mobjects) + all_mobjects = Mobject(*self.mobjects) self.remove(*self.mobjects) self.play( Transform( @@ -273,7 +273,7 @@ class HardProblemsSimplerQuestions(Scene): ), Transform( Point((-SPACE_WIDTH, 0, 0)), - CompoundMobject(*CircleScene(RADIANS).mobjects) + Mobject(*CircleScene(RADIANS).mobjects) ) ) @@ -436,7 +436,7 @@ class GeneralPositionRule(Scene): ]) if first_time: self.play(Transform( - CompoundMobject(*intersecting_lines), + Mobject(*intersecting_lines), words_mob )) first_time = False @@ -542,7 +542,7 @@ class IllustrateNChooseK(Scene): count_mob = TexMobject(str(count+1)) count_mob.center().shift(count_center) 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() self.add(tuple_copy) self.add(tuple_mobs[count]) @@ -550,7 +550,7 @@ class IllustrateNChooseK(Scene): self.remove(count_mob) self.remove(tuple_copy) self.add(count_mob) - self.play(FadeIn(CompoundMobject(form1, form2, pronunciation))) + self.play(FadeIn(Mobject(form1, form2, pronunciation))) class IntersectionPointCorrespondances(CircleScene): args_list = [ @@ -661,7 +661,7 @@ class QuadrupletsToIntersections(CircleScene): dot_quad = [deepcopy(self.dots[i]) for i in quad] for dot in dot_quad: dot.scale_in_place(2) - dot_quad = CompoundMobject(*dot_quad) + dot_quad = Mobject(*dot_quad) dot_quad.highlight() self.add(dot_quad) self.dither(frame_time / 3) @@ -674,7 +674,7 @@ class QuadrupletsToIntersections(CircleScene): class GraphsAndEulersFormulaJoke(Scene): def __init__(self, *args, **kwargs): Scene.__init__(self, *args, **kwargs) - axes = CompoundMobject( + axes = Mobject( NumberLine(), NumberLine().rotate(np.pi / 2) ) @@ -693,7 +693,7 @@ class GraphsAndEulersFormulaJoke(Scene): self.remove(*self.mobjects) self.add(eulers) self.play(CounterclockwiseTransform( - CompoundMobject(axes, graph), + Mobject(axes, graph), Point((-SPACE_WIDTH, SPACE_HEIGHT, 0)) )) self.play(CounterclockwiseTransform( @@ -709,7 +709,7 @@ class DefiningGraph(GraphScene): edges_word = TextMobject("``Edges\"").shift(word_center) dots, lines = self.vertices, self.edges self.remove(*dots + lines) - all_dots = CompoundMobject(*dots) + all_dots = Mobject(*dots) self.play(ShowCreation(all_dots)) self.remove(all_dots) self.add(*dots) @@ -786,7 +786,7 @@ class EulersFormula(GraphScene): ]) for mob in form.values(): 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([ (key, deepcopy(mob).shift((0, -0.7, 0))) for key, mob in zip(form.keys(), form.values()) @@ -797,7 +797,7 @@ class EulersFormula(GraphScene): for d in self.dots ] colored_edges = [ - CompoundMobject( + Mobject( Line(midpoint, start), Line(midpoint, end), ).highlight("red") @@ -843,7 +843,7 @@ class CannotDirectlyApplyEulerToMoser(CircleScene): d.highlight("yellow").scale_in_place(2) for d in deepcopy(self.dots) ] - yellow_lines = CompoundMobject(*[ + yellow_lines = Mobject(*[ l.highlight("yellow") for l in deepcopy(self.lines) ]) self.play(*[ @@ -896,7 +896,7 @@ class ShowMoserGraphLines(CircleScene): (self.lines, n_choose_2) ]: self.add(symbol) - compound = CompoundMobject(*mobs) + compound = Mobject(*mobs) if mobs in (self.dots, self.intersection_dots): self.remove(*mobs) self.play(CounterclockwiseTransform( @@ -916,7 +916,7 @@ class ShowMoserGraphLines(CircleScene): Transform(line, small_line, run_time = 3.0) for line, small_line in zip(self.lines, small_lines) ]) - yellow_lines = CompoundMobject(*[ + yellow_lines = Mobject(*[ line.highlight("yellow") for line in small_lines ]) 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) ]) self.add(plus_n) - self.play(ShowCreation(CompoundMobject(*[ + self.play(ShowCreation(Mobject(*[ mob.highlight("yellow") for mob in self.circle_pieces ]))) @@ -1111,7 +1111,7 @@ class ApplyEulerToMoser(CircleScene): self.add(*all_mobs) self.remove(*[d[1] for d in [V, minus, E, plus, F, equals, two]]) 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]) for d in [F, equals, E, minus, plus, two] @@ -1120,7 +1120,7 @@ class ApplyEulerToMoser(CircleScene): self.dither() self.remove(*self.mobjects) self.play( - Transform(E[3], CompoundMobject( + Transform(E[3], Mobject( nc2[4], plus1[4], two1[4], nc41[4], plus2[4], n1[4] )), *[ @@ -1142,7 +1142,7 @@ class ApplyEulerToMoser(CircleScene): self.remove(*self.mobjects) self.play( 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)) ), *[ @@ -1202,7 +1202,7 @@ class FormulaRelatesToPowersOfTwo(Scene): scale_factor = 1 for mob in everything: mob.scale(scale_factor) - CompoundMobject(*everything).show() + Mobject(*everything).show() forms = everything[0::3] sums = everything[1::3] results = everything[2::3] @@ -1238,7 +1238,7 @@ class DrawPascalsTriangle(PascalsTriangleScene): for n in range(1, nrows): starts = [deepcopy(self.coords_to_mobs[n-1][0])] starts += [ - CompoundMobject( + Mobject( self.coords_to_mobs[n-1][k-1], self.coords_to_mobs[n-1][k] ) @@ -1384,11 +1384,11 @@ class PascalsTriangleSumRows(PascalsTriangleScene): powers_of_two.append(pof2) equalses.append(new_equals) powers_of_two_symbols.append(symbol) - self.play(FadeIn(CompoundMobject(*pluses))) + self.play(FadeIn(Mobject(*pluses))) run_time = 0.5 to_remove = [] 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) self.play( Transform(start, powers_of_two[n]), @@ -1481,14 +1481,14 @@ class MoserSolutionInPascal(PascalsTriangleScene): self.add(self.coords_to_mobs[n][k]) self.play(Transform( terms[k], - CompoundMobject(*above_terms).highlight(term_color) + Mobject(*above_terms).highlight(term_color) )) self.remove(*above_terms) self.dither() terms_sum = TexMobject(str(moser_function(n))) terms_sum.shift((SPACE_WIDTH-1, terms[0].get_center()[1], 0)) terms_sum.highlight(term_color) - self.play(Transform(CompoundMobject(*terms), terms_sum)) + self.play(Transform(Mobject(*terms), terms_sum)) class RotatingPolyhedra(Scene): args_list = [ @@ -1530,12 +1530,12 @@ class ExplainNChoose2Formula(Scene): r_paren, a_mob, comma, b_mob, l_paren = TexMobjects( ("( %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)] height = 1.5*nums[0].get_height() for x in range(n): 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()) n_mob, n_minus_1, over_2 = TexMobject([ str(n), "(%d-1)"%n, r"\over{2}" @@ -1550,7 +1550,7 @@ class ExplainNChoose2Formula(Scene): self.remove(nums_compound) nums = nums_compound.split() a_mob = nums.pop(a-1) - nums_compound = CompoundMobject(*nums) + nums_compound = Mobject(*nums) self.add(a_mob, nums_compound) self.dither() right_shift = b_mob.get_center() - a_mob.get_center() @@ -1602,17 +1602,17 @@ class ExplainNChoose4Formula(Scene): ("( %d , %d , %d , %d )"%quad).split(" ") ) quad_mobs = tuple_mobs[1::2] - parens = CompoundMobject(*tuple_mobs[0::2]) + parens = Mobject(*tuple_mobs[0::2]) form_mobs = TexMobject([ str(n), "(%d-1)"%n, "(%d-2)"%n,"(%d-3)"%n, r"\over {4 \cdot 3 \cdot 2 \cdot 1}" ]).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)] height = 1.5*nums[0].get_height() for x in range(n): 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()) curr_num = 1 self.add(parens) @@ -1625,7 +1625,7 @@ class ExplainNChoose4Formula(Scene): nums = nums_compound.split() chosen = nums[quad[i]-1] nums[quad[i]-1] = Point(chosen.get_center()).highlight("black") - nums_compound = CompoundMobject(*nums) + nums_compound = Mobject(*nums) self.add(chosen) if i < 3: right_shift = quad_mobs[i+1].get_center() - chosen.get_center() @@ -1657,10 +1657,10 @@ class ExplainNChoose4Formula(Scene): ) for i in range(4) ] - compound_quad = CompoundMobject(*quad_mobs) + compound_quad = Mobject(*quad_mobs) self.play(CounterclockwiseTransform( compound_quad, - CompoundMobject(*new_quad_mobs) + Mobject(*new_quad_mobs) )) self.remove(compound_quad) quad_mobs = new_quad_mobs diff --git a/old_projects/music_and_measure.py b/old_projects/music_and_measure.py index 6d96287c..98f06edf 100644 --- a/old_projects/music_and_measure.py +++ b/old_projects/music_and_measure.py @@ -81,12 +81,12 @@ class RightParen(Mobject): return Mobject.get_center(self) + 0.04*RIGHT -class OpenInterval(CompoundMobject): +class OpenInterval(Mobject): def __init__(self, center_point = ORIGIN, width = 2, **kwargs): digest_config(self, kwargs, locals()) left = LeftParen().shift(LEFT*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 # self.stretch(scale_factor, 0) # 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.highlight("yellow") all_ticks.append(tick) - all_ticks = CompoundMobject(*all_ticks) + all_ticks = Mobject(*all_ticks) if run_time > 0: self.play(ShowCreation(all_ticks)) else: @@ -294,7 +294,7 @@ class MeasureTheoryToHarmony(IntervalScene): IntervalScene.construct(self) self.cover_fractions() self.dither() - all_mobs = CompoundMobject(*self.mobjects) + all_mobs = Mobject(*self.mobjects) all_mobs.sort_points() self.clear() radius = self.interval.radius @@ -516,7 +516,7 @@ class DecomposeTwoFrequencies(Scene): sine1 = LongSine().shift(2*UP).highlight("yellow") sine2 = LongSine().shift(DOWN).highlight("lightgreen") sine1.stretch(2.0/3, 0) - comp = CompoundMobject(sine1, sine2) + comp = Mobject(sine1, sine2) self.add(line) self.play(ApplyMethod( @@ -562,12 +562,12 @@ class PatternInFrequencies(Scene): setup_width = 2*SPACE_WIDTH num_top_lines = int(setup_width) num_bot_lines = int(setup_width*num1/num2) - top_lines = CompoundMobject(*[ + top_lines = Mobject(*[ deepcopy(line_template).shift(k*(float(num1)/num2)*RIGHT) for k in range(num_top_lines) ]) line_template.shift(4*DOWN) - bottom_lines = CompoundMobject(*[ + bottom_lines = Mobject(*[ deepcopy(line_template).shift(k*RIGHT) for k in range(num_bot_lines) ]) @@ -601,7 +601,7 @@ class CompareFractionComplexity(Scene): for num, den in [(4, 3), (1093,826)]: top = TexMobject("%d \\over"%num) 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() frac1 = fractions[1].shift(3*RIGHT).split() arrow1 = Arrow(UP, ORIGIN).next_to(frac0[0], UP) @@ -642,7 +642,7 @@ class IrrationalGang(Scene): sqrt13.highlight("green") zeta3 = TexMobject("\\zeta(3)").shift(2*RIGHT) zeta3.highlight("grey") - eyes = CompoundMobject(*randy.eyes) + eyes = Mobject(*randy.eyes) eyes.scale(0.5) sqrt13.add(eyes.next_to(sqrt13, UP, buff = 0).shift(0.25*RIGHT)) eyes.scale(0.5) @@ -682,7 +682,7 @@ class PianoTuning(Scene): jump = piano.half_note_jump semicircle = Circle().filter_out(lambda p : p[1] < 0) semicircle.scale(jump/semicircle.get_width()) - semicircles = CompoundMobject(*[ + semicircles = Mobject(*[ deepcopy(semicircle).shift(jump*k*RIGHT) for k in range(23) ]) @@ -802,14 +802,14 @@ class PowersOfTwelfthRoot(Scene): ]) error_string = error_string.split() 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.next_to(frac_mob) - mob_list.append(CompoundMobject(*[ + mob_list.append(Mobject(*[ 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): def construct(self): @@ -898,7 +898,7 @@ class ChallengeTwo(Scene): class CoveringSetsWithOpenIntervals(IntervalScene): def construct(self): IntervalScene.construct(self) - dots = CompoundMobject(*[ + dots = Mobject(*[ Dot().shift(self.number_line.number_to_point(num)+UP) 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.shift((-SPACE_WIDTH+self.spacing*count)*RIGHT) new_ticks.append(tick_copy) - new_ticks = CompoundMobject(*new_ticks) + new_ticks = Mobject(*new_ticks) anims.append(DelayByOrder(Transform(ticks, new_ticks))) self.dither() self.play(*anims) @@ -1219,7 +1219,7 @@ class StepsToSolution(IntervalScene): frac_bottom.scale(scale_val) one = TexMobject("1").scale(scale_val) one.next_to(frac_bottom, UP, buff = 0.1) - compound = CompoundMobject(frac_bottom, one) + compound = Mobject(frac_bottom, one) if plus: compound.next_to(plus) else: @@ -1313,9 +1313,9 @@ class TroubleDrawingSmallInterval(IntervalScene): def construct(self): IntervalScene.construct(self) 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 = 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) self.clear() IntervalScene.construct(self) @@ -1354,7 +1354,7 @@ class ZoomInOnSqrt2Over2(IntervalScene): epsilon, equals, num = map(TexMobject, ["\\epsilon", "=", "0.3"]) equals.next_to(epsilon) 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() self.remove(*lines) irr = TexMobject("\\frac{\\sqrt{2}}{2}") @@ -1464,7 +1464,7 @@ class ShiftSetupByOne(IntervalScene): "real numbers \\emph{very very very} close to them", size = "\\small" ) - compound = CompoundMobject(answer1, answer2.next_to(answer1)) + compound = Mobject(answer1, answer2.next_to(answer1)) compound.next_to(words, DOWN) answer1, answer2 = compound.split() @@ -1485,7 +1485,7 @@ class ShiftSetupByOne(IntervalScene): words[3].highlight() self.add(*words) self.play(ShowCreation( - CompoundMobject(*intervals), + Mobject(*intervals), run_time = 5.0 )) self.dither() @@ -1502,12 +1502,12 @@ class FinalEquivalence(IntervalScene): for interval, frac in zip(intervals, rationals()): interval.scale_in_place(2.0/frac.denominator) self.remove(*intervals+lines) - intervals = CompoundMobject(*intervals) + intervals = Mobject(*intervals) arrow = TexMobject("\\Leftrightarrow") top_words = TextMobject("Harmonious numbers are rare,") bot_words = TextMobject("even for the savant") bot_words.highlight().next_to(top_words, DOWN) - words = CompoundMobject(top_words, bot_words) + words = Mobject(top_words, bot_words) words.next_to(arrow) self.play( @@ -1517,7 +1517,7 @@ class FinalEquivalence(IntervalScene): intervals ) ) - everything = CompoundMobject(*self.mobjects) + everything = Mobject(*self.mobjects) self.clear() self.play(Transform( everything, diff --git a/old_projects/playground_counting_in_binary.py b/old_projects/playground_counting_in_binary.py index 8bcdb522..5e036730 100644 --- a/old_projects/playground_counting_in_binary.py +++ b/old_projects/playground_counting_in_binary.py @@ -211,7 +211,7 @@ class ShowFrameNum(SceneFromVideo): SceneFromVideo.construct(self, path) for frame, count in zip(self.frames, it.count()): print count, "of", len(self.frames) - mob = CompoundMobject(*[ + mob = Mobject(*[ TexMobject(char).shift(0.3*x*RIGHT) for char, x, in zip(str(count), it.count()) ]) diff --git a/old_projects/pythagorean_proof.py b/old_projects/pythagorean_proof.py index d352278f..e042a4fe 100644 --- a/old_projects/pythagorean_proof.py +++ b/old_projects/pythagorean_proof.py @@ -441,7 +441,7 @@ class LabelLargeSquare(DrawCSquareWithAllTraingles): args_list = [] def construct(self): DrawCSquareWithAllTraingles.construct(self) - everything = CompoundMobject(*self.mobjects) + everything = Mobject(*self.mobjects) u_brace = Underbrace(2*(DOWN+LEFT), 2*(DOWN+RIGHT)) u_brace.shift(0.2*DOWN) side_brace = deepcopy(u_brace).rotate(np.pi/2) diff --git a/scene/scene.py b/scene/scene.py index e08ec83f..efcda548 100644 --- a/scene/scene.py +++ b/scene/scene.py @@ -80,11 +80,9 @@ class Scene(object): """ So a scene can just add all mobjects it's defined up to that point """ - caller_locals = inspect.currentframe().f_back.f_locals - self.add(*filter( - lambda m : isinstance(m, Mobject), - caller_locals.values() - )) + name_to_mob = get_caller_locals(lambda x : isinstance(x, Mobject)) + self.add(*name_to_mob.values()) + return self def remove(self, *mobjects): if not all_elements_are_instances(mobjects, Mobject): @@ -161,8 +159,17 @@ class Scene(object): for animation in animations: animation.set_run_time(run_time) 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)) progress_bar = progressbar.ProgressBar(maxval=run_time) @@ -176,7 +183,7 @@ class Scene(object): self.frames.append(new_frame) for animation in animations: animation.clean_up() - self.add(*moving_mobjects) + self.repaint_mojects() progress_bar.finish() return self diff --git a/scene/tk_scene.py b/scene/tk_scene.py index ab6f7ead..a3eab8f4 100644 --- a/scene/tk_scene.py +++ b/scene/tk_scene.py @@ -10,8 +10,7 @@ class TkSceneRoot(Tkinter.Tk): raise Exception(str(scene) + " has no frames!") Tkinter.Tk.__init__(self) - height, width = scene.shape - kwargs = {"height" : height, "width" : width} + kwargs = {"height" : scene.height, "width" : scene.width} self.frame = Tkinter.Frame(self, **kwargs) self.frame.pack() self.canvas = Tkinter.Canvas(self.frame, **kwargs) diff --git a/topics/arithmetic.py b/topics/arithmetic.py index e763a355..83574a2e 100644 --- a/topics/arithmetic.py +++ b/topics/arithmetic.py @@ -24,9 +24,9 @@ class RearrangeEquation(Scene): start_terms, end_terms, size ) if start_transform: - start_mobs = start_transform(CompoundMobject(*start_mobs)).split() + start_mobs = start_transform(Mobject(*start_mobs)).split() 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_end_indices = set(range(len(end_mobs))) unmatched_start_indices.difference_update( @@ -50,7 +50,7 @@ class RearrangeEquation(Scene): self.add(*start_mobs) if leave_start_terms: - self.add(CompoundMobject(*start_mobs)) + self.add(Mobject(*start_mobs)) self.dither() self.play(*[ Transform(*pair, **transform_kwargs) diff --git a/topics/characters.py b/topics/characters.py index f4ea277e..1e7bbdeb 100644 --- a/topics/characters.py +++ b/topics/characters.py @@ -1,15 +1,21 @@ +from copy import deepcopy + from helpers import * -from mobject import Mobject, CompoundMobject -from image_mobject import ImageMobject +from mobject import Mobject, Mobject, ImageMobject, TexMobject + 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_MOUTH_TO_EYES_DISTANCE = 0.25 -class PiCreature(CompoundMobject): - DEFAULT_COLOR = BLUE +def part_name_to_directory(name): + return os.path.join(PI_CREATURE_DIR, "pi_creature_"+name) + ".png" + +class PiCreature(Mobject): + DEFAULT_CONFIG = { + "color" : BLUE_E + } PART_NAMES = [ 'arm', 'body', @@ -23,42 +29,30 @@ class PiCreature(CompoundMobject): MOUTH_NAMES = ["smile", "frown", "straight_mouth"] 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: 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: - mob.highlight(color) - mob.scale(PI_CREATURE_SCALE_VAL) + mob.highlight(self.color) setattr(self, part_name, mob) - self.eyes = [self.left_eye, self.right_eye] - self.legs = [self.left_leg, self.right_leg] + self.eyes = Mobject(self.left_eye, self.right_eye) + self.legs = Mobject(self.left_leg, self.right_leg) mouth_center = self.get_mouth_center() self.mouth.center() - self.smile = deepcopy(self.mouth) + self.smile = self.mouth self.frown = deepcopy(self.mouth).rotate(np.pi, RIGHT) self.straight_mouth = TexMobject("-").scale(0.5) - for mouth_name in ["mouth"] + self.MOUTH_NAMES: - mouth = getattr(self, mouth_name) + for mouth in self.smile, self.frown, self.straight_mouth: mouth.sort_points(lambda p : p[0]) + mouth.highlight(self.color) ##to blend into background mouth.shift(mouth_center) - #Ordering matters here, so hidden mouths are behind body - self.part_names = self.MOUTH_NAMES + self.PART_NAMES - self.white_parts = self.MOUTH_NAMES + self.WHITE_PART_NAMES - CompoundMobject.__init__( - 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) + self.digest_mobject_attrs() + self.give_smile() + self.add(self.mouth) + self.scale(PI_CREATURE_SCALE_VAL) def get_parts(self): @@ -68,26 +62,30 @@ class PiCreature(CompoundMobject): return [getattr(self, pn) for pn in self.white_parts] def get_mouth_center(self): - left_center = self.left_eye.get_center() - right_center = self.right_eye.get_center() - l_to_r = right_center-left_center - 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 + result = self.body.get_center() + result[0] = self.eyes.get_center()[0] + return result + # left_center = self.left_eye.get_center() + # right_center = self.right_eye.get_center() + # l_to_r = right_center-left_center + # 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): for part in set(self.get_parts()).difference(self.get_white_parts()): part.highlight(color, condition) - return self.sync_parts() + return self def move_to(self, destination): self.shift(destination-self.get_bottom()) - return self.sync_parts() + return self def change_mouth_to(self, mouth_name): - self.mouth = getattr(self, mouth_name) - return self.sync_parts() + self.mouth.points = getattr(self, mouth_name).points + self.mouth.highlight(WHITE) + return self def give_smile(self): return self.change_mouth_to("smile") @@ -99,29 +97,24 @@ class PiCreature(CompoundMobject): return self.change_mouth_to("straight_mouth") def get_eye_center(self): - return center_of_mass([ - self.left_eye.get_center(), - self.right_eye.get_center() - ]) + 0.04*RIGHT + 0.02*UP + return self.eyes.get_center() def make_mean(self): eye_x, eye_y = self.get_eye_center()[:2] def should_delete((x, y, z)): return y - eye_y > 0.3*abs(x - eye_x) - for eye in self.left_eye, self.right_eye: - eye.highlight("black", should_delete) + self.eyes.highlight("black", should_delete) self.give_straight_face() - return self.sync_parts() + return self def make_sad(self): eye_x, eye_y = self.get_eye_center()[:2] eye_y += 0.15 def should_delete((x, y, z)): return y - eye_y > -0.3*abs(x - eye_x) - for eye in self.left_eye, self.right_eye: - eye.highlight("black", should_delete) + self.eyey.highlight("black", should_delete) self.give_frown() - return self.sync_parts() + return self def get_step_intermediate(self, pi_creature): vect = pi_creature.get_center() - self.get_center() @@ -136,23 +129,22 @@ class PiCreature(CompoundMobject): else: result.right_leg.wag(vect/2.0, DOWN) result.left_leg.wag(-vect/2.0, DOWN) - return result.sync_parts() + return result def blink(self): - for eye in self.left_eye, self.right_eye: - bottom = eye.get_bottom() - eye.apply_function( - lambda (x, y, z) : (x, bottom[1], z) - ) - return self.sync_parts() + bottom = self.eyes.get_bottom() + self.eyes.apply_function( + lambda (x, y, z) : (x, bottom[1], z) + ) + return self def shift_eyes(self): for eye in self.left_eye, self.right_eye: eye.rotate_in_place(np.pi, UP) - return self.sync_parts() + return self def to_symbol(self): - CompoundMobject.__init__( + Mobject.__init__( self, *list(set(self.get_parts()).difference(self.get_white_parts())) ) diff --git a/topics/functions.py b/topics/functions.py index 67298d42..3c1c8011 100644 --- a/topics/functions.py +++ b/topics/functions.py @@ -2,7 +2,7 @@ from helpers import * from helpers import * -from mobject import Mobject, Mobject1D, CompoundMobject +from mobject import Mobject, Mobject1D, Mobject class FunctionGraph(Mobject1D): @@ -58,11 +58,11 @@ class ParametricFunction(Mobject): ]) -class Axes(CompoundMobject): +class Axes(Mobject): def __init__(self, **kwargs): x_axis = NumberLine(**kwargs) y_axis = NumberLine(**kwargs).rotate(np.pi/2, OUT) - CompoundMobject.__init__(self, x_axis, y_axis) + Mobject.__init__(self, x_axis, y_axis) \ No newline at end of file diff --git a/topics/graph_theory.py b/topics/graph_theory.py index 9767cd30..f8aa8688 100644 --- a/topics/graph_theory.py +++ b/topics/graph_theory.py @@ -217,7 +217,7 @@ class GraphScene(Scene): def draw_vertices(self, **kwargs): self.clear() - self.play(ShowCreation(CompoundMobject(*self.vertices), **kwargs)) + self.play(ShowCreation(Mobject(*self.vertices), **kwargs)) def draw_edges(self): self.play(*[ @@ -227,8 +227,8 @@ class GraphScene(Scene): def accent_vertices(self, **kwargs): self.remove(*self.vertices) - start = CompoundMobject(*self.vertices) - end = CompoundMobject(*[ + start = Mobject(*self.vertices) + end = Mobject(*[ Dot(point, radius = 3*Dot.DEFAULT_RADIUS, color = "lightgreen") for point in self.points ]) @@ -275,7 +275,7 @@ class GraphScene(Scene): time_per_edge = run_time / len(cycle) next_in_cycle = it.cycle(cycle) next_in_cycle.next()#jump one ahead - self.traced_cycle = CompoundMobject(*[ + self.traced_cycle = Mobject(*[ Line(self.points[i], self.points[j]).highlight(color) for i, j in zip(cycle, next_in_cycle) ]) @@ -299,7 +299,7 @@ class GraphScene(Scene): self.spanning_tree_index_pairs.append(pair) spanned_vertices.add(pair[1]) to_check.add(pair[1]) - self.spanning_tree = CompoundMobject(*[ + self.spanning_tree = Mobject(*[ Line( self.points[pair[0]], self.points[pair[1]] @@ -361,7 +361,7 @@ class GraphScene(Scene): ]) for index in indices ] - self.treeified_spanning_tree = CompoundMobject(*[ + self.treeified_spanning_tree = Mobject(*[ Line(new_points[i], new_points[j]).highlight(color) for i, j in self.spanning_tree_index_pairs ]) diff --git a/topics/three_dimensions.py b/topics/three_dimensions.py index dc9dbc38..809da3cd 100644 --- a/topics/three_dimensions.py +++ b/topics/three_dimensions.py @@ -1,7 +1,7 @@ import numpy as np import itertools as it -from mobject import Mobject, Mobject1D, Mobject2D, CompoundMobject +from mobject import Mobject, Mobject1D, Mobject2D, Mobject from geometry import Line from helpers import * @@ -87,7 +87,7 @@ class Dodecahedron(Mobject1D): (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) for pair in vertex_pairs ]).points