From 7ae64884f7632c94fa0e3fe69b76a4c1a7b50e3a Mon Sep 17 00:00:00 2001 From: GoThrones Date: Wed, 29 Apr 2026 00:35:51 +0530 Subject: [PATCH 1/9] Fix/Transform --- manim/animation/transform.py | 41 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index 9719ddf7c1..8972d425c6 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -29,12 +29,14 @@ import inspect import types from collections.abc import Callable, Iterable, Sequence -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Self import numpy as np from manim.data_structures import MethodWithArgs from manim.mobject.opengl.opengl_mobject import OpenGLGroup, OpenGLMobject +from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject +from manim.mobject.types.vectorized_mobject import VMobject from .. import config from ..animation.animation import Animation @@ -66,6 +68,8 @@ class Transform(Animation): path_func A function defining the path that the points of the ``mobject`` are being moved along until they match the points of the ``target_mobject``, see :mod:`.utils.paths`. + If path_func is None, it defaults to a straight line, + which is set up inside the path_arc setter. path_arc The arc angle (in radians) that the points of ``mobject`` will follow to reach the points of the target if using a circular path arc, see ``path_arc_centers``. @@ -133,8 +137,8 @@ def make_arc_path(start, end, arc_angle): def __init__( self, - mobject: Mobject | None, - target_mobject: Mobject | None = None, + mobject: VMobject | OpenGLVMobject | None, + target_mobject: VMobject | OpenGLVMobject | None = None, path_func: Callable | None = None, path_arc: float = 0, path_arc_axis: np.ndarray = OUT, @@ -142,26 +146,21 @@ def __init__( replace_mobject_with_target_in_scene: bool = False, **kwargs, ) -> None: - self.path_arc_axis: np.ndarray = path_arc_axis - self.path_arc_centers: Point3DLike | Point3DLike_Array | None = path_arc_centers - self.path_arc: float = path_arc - - # path_func is a property a few lines below so it doesn't need to be set in any case - if path_func is not None: - self.path_func: Callable = path_func - elif self.path_arc_centers is not None: + self.path_arc_axis = path_arc_axis + self.path_arc_centers = path_arc_centers + self.path_arc = path_arc + self.path_func = path_func + if self.path_arc_centers is not None: self.path_func = path_along_circles( path_arc, self.path_arc_centers, self.path_arc_axis, ) - self.replace_mobject_with_target_in_scene: bool = ( - replace_mobject_with_target_in_scene - ) - self.target_mobject: Mobject = ( - target_mobject if target_mobject is not None else Mobject() - ) + self.replace_mobject_with_target_in_scene = replace_mobject_with_target_in_scene + + self.target_mobject = target_mobject if target_mobject is not None else Mobject() + super().__init__(mobject, **kwargs) @property @@ -240,11 +239,11 @@ def get_all_families_zipped(self) -> Iterable[tuple]: # more precise typing? def interpolate_submobject( self, - submobject: Mobject, - starting_submobject: Mobject, - target_copy: Mobject, + submobject: VMobject | OpenGLVMobject, + starting_submobject: VMobject | OpenGLVMobject, + target_copy: VMobject | OpenGLVMobject, alpha: float, - ) -> Transform: + ) -> Self: submobject.interpolate(starting_submobject, target_copy, alpha, self.path_func) return self From d351ebab62c782200604b6b4cf1cf6c15e1a80a1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 19:12:23 +0000 Subject: [PATCH 2/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- manim/animation/transform.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index 8972d425c6..60a59dd282 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -68,7 +68,7 @@ class Transform(Animation): path_func A function defining the path that the points of the ``mobject`` are being moved along until they match the points of the ``target_mobject``, see :mod:`.utils.paths`. - If path_func is None, it defaults to a straight line, + If path_func is None, it defaults to a straight line, which is set up inside the path_arc setter. path_arc The arc angle (in radians) that the points of ``mobject`` will follow to reach @@ -158,8 +158,10 @@ def __init__( ) self.replace_mobject_with_target_in_scene = replace_mobject_with_target_in_scene - - self.target_mobject = target_mobject if target_mobject is not None else Mobject() + + self.target_mobject = ( + target_mobject if target_mobject is not None else Mobject() + ) super().__init__(mobject, **kwargs) From 2a535512035282201a39b31f1dcb3d64a11decbe Mon Sep 17 00:00:00 2001 From: GoThrones Date: Wed, 29 Apr 2026 00:55:57 +0530 Subject: [PATCH 3/9] reverted typehints of mobject and target_mobject to Mobject --- manim/animation/transform.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index 8972d425c6..29aea9e086 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -137,8 +137,8 @@ def make_arc_path(start, end, arc_angle): def __init__( self, - mobject: VMobject | OpenGLVMobject | None, - target_mobject: VMobject | OpenGLVMobject | None = None, + mobject: Mobject | None, + target_mobject: Mobject | None = None, path_func: Callable | None = None, path_arc: float = 0, path_arc_axis: np.ndarray = OUT, From 65cfc36eeeed58ce63b1d1ae1f2b29a4814634ad Mon Sep 17 00:00:00 2001 From: GoThrones Date: Wed, 29 Apr 2026 14:09:30 +0530 Subject: [PATCH 4/9] restored the if clause of path_func --- manim/animation/transform.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index 44e7e240b3..df56dec92d 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -149,8 +149,9 @@ def __init__( self.path_arc_axis = path_arc_axis self.path_arc_centers = path_arc_centers self.path_arc = path_arc - self.path_func = path_func - if self.path_arc_centers is not None: + if path_func is not None: + self.path_func: Callable = path_func + elif self.path_arc_centers is not None: self.path_func = path_along_circles( path_arc, self.path_arc_centers, From 5ecbcbab2fa9b3aa7c6606706cfe8b2e9f3a7b81 Mon Sep 17 00:00:00 2001 From: GoThrones Date: Sat, 2 May 2026 10:16:46 +0530 Subject: [PATCH 5/9] some more minor alterations --- manim/animation/transform.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index df56dec92d..471e172ae1 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -150,7 +150,7 @@ def __init__( self.path_arc_centers = path_arc_centers self.path_arc = path_arc if path_func is not None: - self.path_func: Callable = path_func + self.path_func = path_func elif self.path_arc_centers is not None: self.path_func = path_along_circles( path_arc, @@ -463,7 +463,9 @@ class ApplyMethod(Transform): Parameters ---------- method - The method that will be applied in the animation. + The bound method of a Mobject that will be applied in the animation. + Pass the method itself, not its result. + For example, pass ``sq.shift`` not ``sq.shift(UP)``. args Any positional arguments to be passed when applying the method. kwargs @@ -484,6 +486,7 @@ def check_validity_of_input(self, method: Callable) -> None: raise ValueError( "Whoops, looks like you accidentally invoked " "the method you want to animate", + "Pass the method itself, e.g. ``sq.shift`` instead of ``sq.shift(UP)``." ) assert isinstance(method.__self__, (Mobject, OpenGLMobject)) @@ -683,7 +686,7 @@ def initialize_matrix(self, matrix: np.ndarray) -> np.ndarray: new_matrix[:2, :2] = matrix matrix = new_matrix elif matrix.shape != (3, 3): - raise ValueError("Matrix has bad dimensions") + raise ValueError("Only a 2D Matrix having shape either (2,2) or (3,3) is accepted.") return matrix @@ -691,16 +694,9 @@ class ApplyComplexFunction(ApplyMethod): def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None: self.function = function method = mobject.apply_complex_function + kwargs["path_arc"] = np.log(function(complex(1))).imag super().__init__(method, function, **kwargs) - def _init_path_func(self) -> None: - func1 = self.function(complex(1)) - self.path_arc = np.log(func1).imag - super()._init_path_func() - - -### - class CyclicReplace(Transform): """An animation moving mobjects cyclically. From cd88538c995351f9dc103131eb9116f38bb791b7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 2 May 2026 04:48:22 +0000 Subject: [PATCH 6/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- manim/animation/transform.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index 471e172ae1..3487f4eb94 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -486,7 +486,7 @@ def check_validity_of_input(self, method: Callable) -> None: raise ValueError( "Whoops, looks like you accidentally invoked " "the method you want to animate", - "Pass the method itself, e.g. ``sq.shift`` instead of ``sq.shift(UP)``." + "Pass the method itself, e.g. ``sq.shift`` instead of ``sq.shift(UP)``.", ) assert isinstance(method.__self__, (Mobject, OpenGLMobject)) @@ -686,7 +686,9 @@ def initialize_matrix(self, matrix: np.ndarray) -> np.ndarray: new_matrix[:2, :2] = matrix matrix = new_matrix elif matrix.shape != (3, 3): - raise ValueError("Only a 2D Matrix having shape either (2,2) or (3,3) is accepted.") + raise ValueError( + "Only a 2D Matrix having shape either (2,2) or (3,3) is accepted." + ) return matrix From 0aaada76079120f4bab8af83ec6df905af06eb59 Mon Sep 17 00:00:00 2001 From: GoThrones Date: Sat, 2 May 2026 19:16:17 +0530 Subject: [PATCH 7/9] ApplyComplexFunction refactored to match pixel test --- manim/animation/transform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index 471e172ae1..3a628da303 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -694,7 +694,7 @@ class ApplyComplexFunction(ApplyMethod): def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None: self.function = function method = mobject.apply_complex_function - kwargs["path_arc"] = np.log(function(complex(1))).imag + kwargs["path_arc"] = np.log(function(complex(1)) - function(complex(0))).imag super().__init__(method, function, **kwargs) From 1a9eb6af02edf7e5314656854d3402d5a8a87e9f Mon Sep 17 00:00:00 2001 From: GoThrones Date: Sat, 2 May 2026 21:20:12 +0530 Subject: [PATCH 8/9] refactored ApplyComplexFunction --- manim/animation/transform.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index 6e129b8e73..3eda6513a8 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -696,7 +696,13 @@ class ApplyComplexFunction(ApplyMethod): def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> None: self.function = function method = mobject.apply_complex_function - kwargs["path_arc"] = np.log(function(complex(1)) - function(complex(0))).imag + rotational_component = function(complex(1)) - function(complex(0)) + arc = ( + np.log(rotational_component).imag + if rotational_component != 0 + else 0 + ) + kwargs["path_arc"] = arc if np.isfinite(arc) else 0 super().__init__(method, function, **kwargs) From 62fbafc3e1eea3b65bd7be19bc447b4686c34cf0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 2 May 2026 15:50:36 +0000 Subject: [PATCH 9/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- manim/animation/transform.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/manim/animation/transform.py b/manim/animation/transform.py index 3eda6513a8..88e55505ba 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -697,11 +697,7 @@ def __init__(self, function: types.MethodType, mobject: Mobject, **kwargs) -> No self.function = function method = mobject.apply_complex_function rotational_component = function(complex(1)) - function(complex(0)) - arc = ( - np.log(rotational_component).imag - if rotational_component != 0 - else 0 - ) + arc = np.log(rotational_component).imag if rotational_component != 0 else 0 kwargs["path_arc"] = arc if np.isfinite(arc) else 0 super().__init__(method, function, **kwargs)