def align_points(self, mobject): Mobject.align_points(self, mobject) is_subpath = self.is_subpath or mobject.is_subpath self.is_subpath = mobject.is_subpath = is_subpath mark_closed = self.mark_paths_closed and mobject.mark_paths_closed self.mark_paths_closed = mobject.mark_paths_closed = mark_closed return self
def test_align_on_border(mocker): mock_dir = np.random.rand(3) mock_point_to_align = np.random.rand(3) mock_buff = np.random.rand(3) mock_offset = np.random.rand(3) mocker.patch.object(mobject.mobject.Mobject, 'get_critical_point', return_value=mock_point_to_align) mocker.patch.object(mobject.mobject.Mobject, 'shift') m = Mobject() m.points = np.random.rand(10, 3) m.align_on_border(mock_dir, buff=mock_buff, initial_offset=mock_offset) mock_target_point = \ np.sign(mock_dir) * (const.FRAME_X_RADIUS, const.FRAME_Y_RADIUS, 0) mock_shift_val = mock_target_point - mock_point_to_align - mock_buff * np.array( mock_dir) mock_shift_val = mock_shift_val * abs(np.sign(mock_dir)) m.get_critical_point.assert_called() args, kwargs = m.get_critical_point.call_args assert np.allclose(args[0], mock_dir) assert kwargs == {} m.shift.assert_called() args, kwargs = m.shift.call_args assert np.allclose(args[0], mock_shift_val + mock_offset) assert kwargs == {}
def align_points(self, mobject): Mobject.align_points(self, mobject) is_subpath = self.is_subpath or mobject.is_subpath self.is_subpath = mobject.is_subpath = is_subpath mark_closed = self.mark_paths_closed and mobject.mark_paths_closed self.mark_paths_closed = mobject.mark_paths_closed = mark_closed return self
def apply_function(self, function): factor = self.pre_function_handle_to_anchor_scale_factor self.scale_handle_to_anchor_distances(factor) Mobject.apply_function(self, function) self.scale_handle_to_anchor_distances(1. / factor) if self.make_smooth_after_applying_functions: self.make_smooth() return self
def apply_function(self, function): factor = self.pre_function_handle_to_anchor_scale_factor self.scale_handle_to_anchor_distances(factor) Mobject.apply_function(self, function) self.scale_handle_to_anchor_distances(1. / factor) if self.make_smooth_after_applying_functions: self.make_smooth() return self
def test_reverse_points(): points = np.random.rand(10, 3) m = Mobject() m.points = points.copy() m.reverse_points() expected = points.copy() assert (np.allclose(m.points, np.flip(expected, axis=0)))
def align_points(self, vmobject): Mobject.align_points(self, vmobject) self.align_rgbas(vmobject) is_subpath = self.is_subpath or vmobject.is_subpath self.is_subpath = vmobject.is_subpath = is_subpath mark_closed = self.mark_paths_closed and vmobject.mark_paths_closed self.mark_paths_closed = vmobject.mark_paths_closed = mark_closed return self
def __init__(self, AnimationClass, mobjects, **kwargs): full_kwargs = AnimationClass.CONFIG full_kwargs.update(kwargs) full_kwargs["mobject"] = Mobject( *[mob.get_point_mobject() for mob in mobjects]) self.centers_container = AnimationClass(**full_kwargs) full_kwargs.pop("mobject") Animation.__init__(self, Mobject(*mobjects), **full_kwargs) self.name = str(self) + AnimationClass.__name__
def test_surround(mocker): mocker.patch.object(mobject.mobject.Mobject, 'replace') mocker.patch.object(mobject.mobject.Mobject, 'scale_in_place') m1 = Mobject() m2 = Mobject() m1.surround(m2) m1.replace.assert_called_once_with(m2, 0, False) m1.scale_in_place.assert_called_once_with(1.2)
def test_pose_at_angle(mocker): mocker.patch.object(mobject.mobject.Mobject, 'rotate', autospec=True), m = Mobject() m.pose_at_angle() m.rotate.assert_called_once() args, kwargs = m.rotate.call_args assert args[0] == m assert args[1] == const.TAU / 14 assert np.allclose(args[2], const.RIGHT + const.UP)
def test_get_image(mocker): mock_get_image = mocker.patch.object(camera.camera.Camera, "get_image") mock_capture_mobject = mocker.patch.object( camera.camera.Camera, "capture_mobject", ) m = Mobject() m.get_image() mock_capture_mobject.assert_called_once_with(m) mock_get_image.assert_called_once_with()
def __init__(self, condition=(lambda x, y: True), **kwargs): """ Condition must be a function which takes in two real arrays (representing x and y values of space respectively) and return a boolean array. This can essentially look like a function from R^2 to {True, False}, but & and | must be used in place of "and" and "or" """ Mobject.__init__(self, **kwargs) self.condition = condition
def __init__(self, condition=(lambda x, y: True), **kwargs): """ Condition must be a function which takes in two real arrays (representing x and y values of space respectively) and return a boolean array. This can essentially look like a function from R^2 to {True, False}, but & and | must be used in place of "and" and "or" """ Mobject.__init__(self, **kwargs) self.condition = condition
def test_align_to(): m1_points = np.random.rand(1, 3) m1 = Mobject() m1.points = m1_points m2_points = np.random.rand(1, 3) m2 = Mobject() m2.points = m2_points m1.align_to(m2) assert m1.get_critical_point(const.UP)[1] == m2.get_critical_point( const.UP)[1]
def test_rotate_about_origin(mocker): mocker.patch.object(mobject.mobject.Mobject, "rotate") m = Mobject() angle = 3 * const.PI / 4 m.rotate_about_origin(angle) m.rotate.assert_called_once_with( angle, const.OUT, about_point=const.ORIGIN, )
def test_stretch_about_point(mocker): mocker.patch.object(mobject.mobject.Mobject, 'stretch') point = np.random.rand(1, 3) m = Mobject() m.stretch_about_point(3, 1, point) m.stretch.assert_called_once() args, kwargs = m.stretch.call_args assert args[0] == 3 assert args[1] == 1 assert np.allclose(kwargs["about_point"], point)
def test_center(mocker): MOCK_CENTER = 5 mocker.patch.object(mobject.mobject.Mobject, 'shift') mocker.patch.object( mobject.mobject.Mobject, 'get_center', return_value=MOCK_CENTER, ) m = Mobject() m.center() m.shift.assert_called_once_with(-MOCK_CENTER)
def test_save_image(mocker, monkeypatch): m = Mobject() mock_animations_dir = "test_dir" mock_path = os.path.join(mock_animations_dir, f"{str(m)}.png") mocker.patch.object(mobject.mobject.Mobject, "get_image") monkeypatch.setattr(mobject.mobject, "ANIMATIONS_DIR", mock_animations_dir) mocker.spy(os.path, "join") m.save_image() os.path.join.assert_called_once_with(mock_animations_dir, f"{str(m)}.png") expected_get_image_calls = call().save(mock_path).call_list() assert m.get_image.mock_calls == expected_get_image_calls
def __init__(self, filename_or_array, **kwargs): digest_config(self, kwargs) if isinstance(filename_or_array, str): path = get_full_raster_image_path(filename_or_array) image = Image.open(path).convert(self.image_mode) self.pixel_array = np.array(image) else: self.pixel_array = np.array(filename_or_array) self.change_to_rgba_array() if self.invert: self.pixel_array[:, :, :3] = 255 - self.pixel_array[:, :, :3] Mobject.__init__(self, **kwargs)
def test_flip(mocker): mocker.spy(mobject.mobject.Mobject, "rotate") m = Mobject() m.points = np.array([ [1, 1, 0], [-1, -1, 0], [2, 2, 0], [-2, -2, 0], ]) m.flip() m.rotate.assert_called_once_with(m, const.TAU / 2, const.UP) expected = np.array([[-1, 1, 0], [1, -1, 0], [-2, 2, 0], [2, -2, 0]]) assert (np.allclose(m.points, expected))
def test_digest_mobject_attrs(): m = Mobject() a = Mobject() m.attr = a m.digest_mobject_attrs() assert m.submobjects == [a] m.attr = m with pytest.raises(Exception): m.digest_mobject_attrs()
def test_init(): m = Mobject() # test default instance variables default_config = Mobject.CONFIG assert m.color == Color(default_config["color"]) assert m.name == m.__class__.__name__ assert m.dim == default_config["dim"] assert m.target == default_config["target"] assert m.submobjects == [] # All submobjects must be of type Mobject with pytest.raises(Exception): m = Mobject(5)
def test_wag(): points = np.random.rand(10, 3) m = Mobject() m.points = points.copy() m.wag() expected = points.copy() alphas = np.dot(expected, np.transpose(const.DOWN)) alphas -= min(alphas) alphas /= max(alphas) # alphas = alphas**wag_factor expected += np.dot(alphas.reshape((len(alphas), 1)), np.array(const.RIGHT).reshape((1, m.dim))) assert (np.allclose(m.points, expected))
def test_scale(mocker): mocker.patch.object( mobject.mobject.Mobject, "apply_points_function_about_point", autospec=True, ) m = Mobject() m.scale(3) m.apply_points_function_about_point.assert_called_once() args, kwargs = m.apply_points_function_about_point.call_args assert args[0] is m assert callable(args[1]) assert (inspect.getsource( args[1]).strip() == "lambda points: scale_factor * points, **kwargs") assert kwargs == {}
def __init__(self, **kwargs): digest_config(self, kwargs, locals()) if self.file_name is None: raise Exception("Must invoke Bubble subclass") try: SVGMobject.__init__(self, **kwargs) except IOError as err: self.file_name = os.path.join(FILE_DIR, self.file_name) SVGMobject.__init__(self, **kwargs) self.center() self.stretch_to_fit_height(self.height) self.stretch_to_fit_width(self.width) if self.direction[0] > 0: Mobject.flip(self) self.direction_was_specified = ("direction" in kwargs) self.content = Mobject()
def test_apply_complex_function(mocker): mocker.patch.object( mobject.mobject.Mobject, 'apply_function', autospec=True, ) mock_func = mocker.Mock() m = Mobject() m.apply_complex_function(mock_func) m.apply_function.assert_called_once() args, kwargs = m.apply_function.call_args assert (len(args) == 2) assert (args[0] is m) assert (inspect.getsource(args[1]).strip( ) == "lambda x_y_z: complex_to_R3(function(complex(x_y_z[0], x_y_z[1]))),") assert (kwargs == {})
def test_apply_function(mocker): mocker.patch.object( mobject.mobject.Mobject, "apply_points_function_about_point", autospec=True, ) mock_func = mocker.Mock() m = Mobject() m.apply_function(mock_func) m.apply_points_function_about_point.assert_called_once() args, kwargs = m.apply_points_function_about_point.call_args assert args[0] is m assert callable(args[1]) assert (inspect.getsource(args[1]).strip() == "lambda points: np.apply_along_axis(function, 1, points),") assert kwargs == {"about_point": const.ORIGIN}
def __init__(self, **kwargs): digest_config(self, kwargs, locals()) if self.file_name is None: raise Exception("Must invoke Bubble subclass") try: SVGMobject.__init__(self, **kwargs) except IOError as err: self.file_name = os.path.join(FILE_DIR, self.file_name) SVGMobject.__init__(self, **kwargs) self.center() self.stretch_to_fit_height(self.height) self.stretch_to_fit_width(self.width) if self.direction[0] > 0: Mobject.flip(self) self.direction_was_specified = ("direction" in kwargs) self.content = Mobject()
def test_to_edge(mocker): mocker.patch.object(mobject.mobject.Mobject, 'align_on_border') mock_edge = np.random.rand(1, 3) mock_buff = np.random.rand(1, 3) mock_offset = np.random.rand(1, 3) m = Mobject() m.to_edge(mock_edge, buff=mock_buff, initial_offset=mock_offset) m.align_on_border.assert_called_once() args, kwargs = m.align_on_border.call_args assert np.allclose(args[0], mock_edge) assert np.allclose(args[1], mock_buff) assert np.allclose(args[2], mock_offset) assert kwargs == {}
def generate_points(self): phi = (1 + np.sqrt(5)) / 2 x = np.array([1, 0, 0]) y = np.array([0, 1, 0]) z = np.array([0, 0, 1]) v1, v2 = (phi, 1/phi, 0), (phi, -1/phi, 0) vertex_pairs = [ (v1, v2), (x+y+z, v1), (x+y-z, v1), (x-y+z, v2), (x-y-z, v2), ] five_lines_points = Mobject(*[ Line(pair[0], pair[1], density = 1.0/self.epsilon) for pair in vertex_pairs ]).points #Rotate those 5 edges into all 30. for i in range(3): perm = [j%3 for j in range(i, i+3)] for b in [-1, 1]: matrix = b*np.array([x[perm], y[perm], z[perm]]) self.add_points(np.dot(five_lines_points, matrix)) self.pose_at_angle() self.set_color(GREEN)
def test_apply_function_to_position(mocker): mock_get_center_return = np.random.randint(1000) mocker.patch.object( mobject.mobject.Mobject, 'get_center', autospec=True, return_value=mock_get_center_return, ) mock_func_return = np.random.randint(1000) mock_func = mocker.Mock(return_value=mock_func_return) mocker.patch.object(mobject.mobject.Mobject, 'move_to', autospec=True) m = Mobject() m.apply_function_to_position(mock_func) m.get_center.assert_called_once_with(m) mock_func.assert_called_once_with(mock_get_center_return) m.move_to.assert_called_once_with(m, mock_func_return)
def __init__(self, *args, **kwargs): # components are responsible for creating their own "unique enough" # keys self.key = self.make_key(*args) self.assert_primitive(self.key) self.labels = OrderedDict() # attributes are stored in the mobject, not the component. we call this # here so components can be added and removed like regular mobjects Mobject.__init__(self) delattr(self, "color") delattr(self, "name") delattr(self, "dim") delattr(self, "target") self.update_attrs(update_without_overwrite(kwargs, self.CONFIG), animate=False)
def test_shift(): submob = Mobject() m = Mobject(submob) mob_points = np.random.rand(10, 3) submob_points = np.random.rand(5, 3) m.points = mob_points submob.points = submob_points m.shift(2 * const.RIGHT - 1 * const.UP) assert m.points == approx(mob_points + np.array([2, -1, 0])) assert submob.points == approx(submob_points + np.array([2, -1, 0]))
def test_stretch(mocker): mocker.spy(mobject.mobject.Mobject, "apply_points_function_about_point") m = Mobject() m.points = np.array([ [0, 1, 0], [0, 0, 0], [0, -1, 0], ]) m.stretch(3, 1) m.apply_points_function_about_point.assert_called_once() args, kwargs = m.apply_points_function_about_point.call_args assert args[0] is m assert callable(args[1]) assert (inspect.getsource(args[1]).strip() == "def func(points):\n" " points[:, dim] *= factor\n" " return points") assert kwargs == {} assert (np.allclose(m.points, [[0, 3, 0], [0, 0, 0], [0, -3, 0]]))
def __init__(self, **kwargs): digest_config(self, kwargs) self.epsilon = 1.0 / self.density Mobject.__init__(self, **kwargs)
def get_array_attrs(self): return Mobject.get_array_attrs(self) + ["rgbas"]
def match_colors(self, mobject): Mobject.align_data(self, mobject) self.rgbas = np.array(mobject.rgbas) return self
class Bubble(SVGMobject): CONFIG = { "direction": LEFT, "center_point": ORIGIN, "content_scale_factor": 0.75, "height": 5, "width": 8, "bubble_center_adjustment_factor": 1. / 8, "file_name": None, "propagate_style_to_family": True, "fill_color": BLACK, "fill_opacity": 0.8, "stroke_color": WHITE, "stroke_width": 3, } def __init__(self, **kwargs): digest_config(self, kwargs, locals()) if self.file_name is None: raise Exception("Must invoke Bubble subclass") try: SVGMobject.__init__(self, **kwargs) except IOError as err: self.file_name = os.path.join(FILE_DIR, self.file_name) SVGMobject.__init__(self, **kwargs) self.center() self.stretch_to_fit_height(self.height) self.stretch_to_fit_width(self.width) if self.direction[0] > 0: Mobject.flip(self) self.direction_was_specified = ("direction" in kwargs) self.content = Mobject() def get_tip(self): # TODO, find a better way return self.get_corner(DOWN + self.direction) - 0.6 * self.direction def get_bubble_center(self): factor = self.bubble_center_adjustment_factor return self.get_center() + factor * self.get_height() * UP def move_tip_to(self, point): VGroup(self, self.content).shift(point - self.get_tip()) return self def flip(self): Mobject.flip(self) self.direction = -np.array(self.direction) return self def pin_to(self, mobject): mob_center = mobject.get_center() want_to_flip = np.sign(mob_center[0]) != np.sign(self.direction[0]) can_flip = not self.direction_was_specified if want_to_flip and can_flip: self.flip() boundary_point = mobject.get_critical_point(UP - self.direction) vector_from_center = 1.0 * (boundary_point - mob_center) self.move_tip_to(mob_center + vector_from_center) return self def position_mobject_inside(self, mobject): scaled_width = self.content_scale_factor * self.get_width() if mobject.get_width() > scaled_width: mobject.scale_to_fit_width(scaled_width) mobject.shift( self.get_bubble_center() - mobject.get_center() ) return mobject def add_content(self, mobject): self.position_mobject_inside(mobject) self.content = mobject return self.content def write(self, *text): self.add_content(TextMobject(*text)) return self def resize_to_content(self): target_width = self.content.get_width() target_width += max(MED_LARGE_BUFF, 2) target_height = self.content.get_height() target_height += 2.5 * LARGE_BUFF tip_point = self.get_tip() self.stretch_to_fit_width(target_width) self.stretch_to_fit_height(target_height) self.move_tip_to(tip_point) self.position_mobject_inside(self.content) def clear(self): self.add_content(VMobject()) return self
def flip(self): Mobject.flip(self) self.direction = -np.array(self.direction) return self