跳转至

变换

影片代码
import manimgx as m


class TransformsHero(m.Scene):
    def construct(self) -> None:
        square = m.Square(color=m.BLUE, fill_opacity=0.5).shift(3 * m.LEFT)
        circle = m.Circle(color=m.PINK, fill_opacity=0.5).shift(3 * m.LEFT)
        star = m.Star(color=m.YELLOW, fill_opacity=0.5).shift(3 * m.RIGHT)
        self.play(m.Create(square))
        self.play(m.ReplacementTransform(square, circle))
        self.play(m.TransformFromCopy(circle, star, path_arc=m.PI / 2))
        self.play(m.Swap(circle, star))
        self.wait()

变换将一个 mobject 变为另一个:其点行进到另一个的点,其样式融入另一个的样式。 ReplacementTransform 随后将另一个 mobject 放在其 位置,以便你继续使用新的 mobject;Transform 保留第一个 mobject, 此时它已变为另一个的形状。要将一个公式逐部分变为另一个,匹配它们各部分: TransformMatchingTex。

每个点沿直线行进,除非你给定一条弧线:path_arc=m.PI 让每个点绕半圈行进。路径函数可 选择任何其他方式。

Transform

代码
import manimgx as m


class TransformExample(m.Scene):
    def construct(self) -> None:
        square = m.Square(side_length=3, color=m.BLUE, fill_opacity=0.5)
        circle = m.Circle(radius=1.5, color=m.YELLOW, fill_opacity=0.5)
        square.shift(3 * m.LEFT)
        circle.shift(3 * m.RIGHT)
        self.add(square)
        self.play(m.Transform(square, circle, path_arc=m.PI / 2, run_time=2))

将一个 mobject 变换为另一个的形状和样式。

该 mobject 留在场景中,结束时外观与 target_mobject 一致,后者不会被添加 (使用 ReplacementTransform 时,目标会取代 mobject 的位置)。它们的各部分被一一对应匹配(部分较少的一侧会增加一些, 每一对的点也是如此),因此 mobject 最终可能拥有比原来更多的部分。每个点 从起点到终点沿直线行进,或通过 path_arc 沿弧行进。

在同一 mobject 上同时开始的变换会进行合成:square.animate.shift(RIGHT) 与 Rotate(square) 一起播放会移动并旋转正方形。较晚开始的变换会从其他变换 将该 mobject 带到的位置接管它。带有更新器且不在场景中的目标会在动画播放 期间移动(动画会运行其更新器),mobject 会跟随它。

m.Transform(mobject, target_mobject=None, path_func=None, path_arc=0, path_arc_axis=OUT, path_arc_centers=None, replace_mobject_with_target_in_scene=False, *, keys=None, **kwargs)
mobject

要变换的 mobject。

target_mobject

它要变成的 mobject;当省略 keys 时,None 会创建一个空 目标。仅传入 keys 时 target_mobject 保持为 None。

path_func

每个点从起点到终点的行进方式:以起点、终点和进度为参数的函数 (参见 paths);它替代 path_arc 和 path_arc_centers。 None:直线路径。

path_arc

每个点在行进过程中转过的角度,以弧度为单位:0 为直线路径, 正角度表示逆时针旋转。

path_arc_axis

path_arc 的弧所绕的轴。

path_arc_centers

mobject 在行进过程中绕其转过 path_arc 的点,或为每个 点各指定一个;None:每个点绕自身弧的中心旋转。

replace_mobject_with_target_in_scene

动画结束时独立的目标是否取代 mobject 的位置。没有此类目标的预设保留其通常的移除或恢复行为。

keys

依次经过的两个或更多状态:None 表示动画开始时的 mobject,为其函数, 或为一个 mobject,在动画开始时复制。未提供时,状态为 mobject 和 target_mobject。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 动画关键字。

源码

manimgx\animation\transform.py

def __init__(
    self,
    mobject: M | None,
    target_mobject: Mobject | None = None,
    path_func: PathFunc | None = None,
    path_arc: float = 0,
    path_arc_axis: Vector3DLike = OUT,
    path_arc_centers: Point3DLike | Point3DLike_Array | None = None,
    replace_mobject_with_target_in_scene: bool = False,
    *,
    keys: Sequence[Key] | None = None,
    **kwargs: Unpack[AnimationOptions],
) -> None:
    self.path_arc_axis, self.path_arc_centers = path_arc_axis, path_arc_centers
    self.path_arc = path_arc
    if path_func is not None:
        self._path_func = path_func
    elif path_arc_centers is not None:
        self._path_func = path_along_circles(
            path_arc, path_arc_centers, path_arc_axis
        )
    self.replace_mobject_with_target_in_scene = replace_mobject_with_target_in_scene
    self.target_mobject = target_mobject
    if keys is None:
        if self.target_mobject is None:
            self.target_mobject = Mobject()
        keys = (None, self.target_mobject)
    self.keys: Sequence[Key] = keys
    self.shared: set[int] = set()  # its leaves other tweens drive too (`compose`)
    super().__init__(mobject, **kwargs)

path_arc

每个点在行进过程中转过的角度,以弧度为单位。

设置它会使路径成为绕 path_arc_axis 的该角度的弧。

transform.path_arc
源码

manimgx\animation\transform.py

def path_arc(self) -> float:
    """每个点在行进过程中转过的角度,以弧度为单位。

    设置它会使路径成为绕 `path_arc_axis` 的该角度的弧。
    """
    return self._path_arc

path_func

每个点从起点到终点的行进方式。

以起点、终点和进度为参数的函数;设置为 None 会保留当前的路径函数。

transform.path_func
源码

manimgx\animation\transform.py

def path_func(self) -> PathFunc:
    """每个点从起点到终点的行进方式。

    以起点、终点和进度为参数的函数;设置为 None 会保留当前的路径函数。
    """
    return self._path_func

ReplacementTransform

代码
import manimgx as m


class ReplacementTransformExample(m.Scene):
    def construct(self) -> None:
        numbers = m.VGroup(*(m.MathTex(n, font_size=144) for n in "123"))
        numbers.arrange(buff=3)
        self.add(numbers[0])
        self.play(m.ReplacementTransform(numbers[0], numbers[1]))
        self.play(m.ReplacementTransform(numbers[1], numbers[2]))

将一个 mobject 变换为另一个,后者随后取代其在场景中的位置。

其播放方式与 Transform 相同;动画结束时, target_mobject 位于场景中 mobject 原先所在的位置,而 mobject 不再在场景中: 可继续对目标进行动画。

m.ReplacementTransform(mobject, target_mobject, **kwargs)
mobject

要变换的 mobject;它将离开场景。

target_mobject

它所变成的 mobject,取代其位置。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\motion.py

def __init__(
    self,
    mobject: Mobject,
    target_mobject: Mobject,
    **kwargs: Unpack[TransformOptions],
) -> None:
    kwargs.setdefault("replace_mobject_with_target_in_scene", True)
    super().__init__(mobject, target_mobject, **kwargs)

TransformFromCopy

代码
import manimgx as m


class TransformFromCopyExample(m.Scene):
    def construct(self) -> None:
        square = m.Square(side_length=2.5, color=m.BLUE, fill_opacity=0.5)
        circle = m.Circle(radius=1.25, color=m.YELLOW, fill_opacity=0.5)
        square.shift(3 * m.LEFT)
        circle.shift(3 * m.RIGHT)
        self.add(square)
        self.play(m.TransformFromCopy(square, circle, run_time=2))

将一个 mobject 的副本变换为另一个,而该 mobject 留在原处。

target_mobject 加入场景,起始为该 mobject 的副本并变为自身; 该 mobject 保持原状。

m.TransformFromCopy(mobject, target_mobject, **kwargs)
mobject

制作副本所用的 mobject。

target_mobject

副本所变成的 mobject;它加入场景。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\motion.py

def __init__(
    self,
    mobject: Mobject,
    target_mobject: Mobject,
    **kwargs: Unpack[TransformOptions],
) -> None:
    super().__init__(target_mobject, mobject, **kwargs)

ClockwiseTransform

代码
import manimgx as m


class ClockwiseTransformExample(m.Scene):
    def construct(self) -> None:
        dot = m.Dot(2.5 * m.LEFT, radius=0.3, color=m.YELLOW)
        square = m.Square(side_length=1.5, color=m.BLUE, fill_opacity=0.5)
        square.shift(2.5 * m.RIGHT)
        self.add(dot)
        self.play(m.ClockwiseTransform(dot, square, run_time=2))

沿顺时针半圆将一个 mobject 变换为另一个。

每个点从其起点到终点沿顺时针半圆移动:即一个 path_arc 为 −π 的 Transform,除非另行指定。

m.ClockwiseTransform(mobject, target_mobject, **kwargs)
mobject

要变换的 mobject。

target_mobject

它所取得的形状与样式的 mobject。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\motion.py

def __init__(
    self,
    mobject: Mobject,
    target_mobject: Mobject,
    **kwargs: Unpack[TransformOptions],
) -> None:
    kwargs.setdefault("path_arc", -PI)
    super().__init__(mobject, target_mobject, **kwargs)

CounterclockwiseTransform

代码
import manimgx as m


class CounterclockwiseTransformExample(m.Scene):
    def construct(self) -> None:
        square = m.Square(side_length=1.5, color=m.BLUE, fill_opacity=0.5)
        circle = m.Circle(radius=0.75, color=m.YELLOW, fill_opacity=0.5)
        square.shift(2.5 * m.RIGHT)
        circle.shift(2.5 * m.LEFT)
        self.add(square)
        self.play(m.CounterclockwiseTransform(square, circle, run_time=2))

沿逆时针半圆将一个 mobject 变换为另一个。

每个点从其起点到终点沿逆时针半圆移动:即一个 path_arc 为 π 的 Transform,除非另行指定。

m.CounterclockwiseTransform(mobject, target_mobject, **kwargs)
mobject

要变换的 mobject。

target_mobject

它所取得的形状与样式的 mobject。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\motion.py

def __init__(
    self,
    mobject: Mobject,
    target_mobject: Mobject,
    **kwargs: Unpack[TransformOptions],
) -> None:
    kwargs.setdefault("path_arc", PI)
    super().__init__(mobject, target_mobject, **kwargs)

FadeTransform

代码
import manimgx as m


class FadeTransformExample(m.Scene):
    def construct(self) -> None:
        rectangle = m.Rectangle(
            width=4, height=1.5, color=m.BLUE, fill_opacity=0.5
        ).shift(3 * m.LEFT)
        circle = m.Circle(radius=1.5, color=m.YELLOW, fill_opacity=0.5)
        circle.shift(3 * m.RIGHT)
        self.add(rectangle)
        self.play(m.FadeTransform(rectangle, circle, run_time=2))

将一个 mobject 交叉淡入为另一个,各自移向对方的位置与大小。

该 mobject 在移动并拉伸到 target_mobject 的过程中淡出, 而目标从该 mobject 的位置与大小淡入。动画结束时,目标位于场景中, 而该 mobject 不在场景中(它恢复为动画创建时的状态)。

m.FadeTransform(mobject, target_mobject, stretch=True, dim_to_match=1, **kwargs)
mobject

要淡出的 mobject。

target_mobject

要淡入的 mobject;它加入场景。

stretch

是否各自被拉伸到对方的宽度和高度;若否,则均匀缩放以匹配 维度 dim_to_match。

dim_to_match

不拉伸时匹配的维度:0 为宽度,1 为高度。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\motion.py

def __init__(
    self,
    mobject: Mobject,
    target_mobject: Mobject,
    stretch: bool = True,
    dim_to_match: int = 1,
    **kwargs: Unpack[TransformOptions],
) -> None:
    self.to_add_on_completion, self.stretch, self.dim_to_match = (
        target_mobject,
        stretch,
        dim_to_match,
    )
    self._start = mobject.copy()  # what the mobject is put back to when it is done
    super().__init__(
        Group(mobject, target_mobject.copy()),
        keys=(self._fading_in, self._faded_out),
        **kwargs,
    )

FadeTransformPieces

代码
import manimgx as m


class FadeTransformPiecesExample(m.Scene):
    def construct(self) -> None:
        source = m.VGroup(m.Square(), m.Circle().shift(m.LEFT + m.UP))
        target = m.VGroup(m.Circle(), m.Triangle().shift(m.RIGHT + m.DOWN))
        source.set_color(m.BLUE).shift(3 * m.LEFT)
        target.set_color(m.YELLOW).shift(3 * m.RIGHT)
        self.add(source)
        self.play(m.FadeTransformPieces(source, target, run_time=2))

将一个 mobject 逐部分交叉淡入为另一个。

两者的各部分被配对,每个部分如 FadeTransform 对整体所做的那样交叉淡入到其匹配部分。

m.FadeTransformPieces(mobject, target_mobject, stretch=True, dim_to_match=1, **kwargs)
mobject

要淡出的 mobject。

target_mobject

要淡入的 mobject;它加入场景。

stretch

是否每个部分被拉伸到其匹配部分的宽度和高度;若否, 则均匀缩放以匹配维度 dim_to_match。

dim_to_match

不拉伸时匹配的维度:0 为宽度,1 为高度。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\motion.py

def __init__(
    self,
    mobject: Mobject,
    target_mobject: Mobject,
    stretch: bool = True,
    dim_to_match: int = 1,
    **kwargs: Unpack[TransformOptions],
) -> None:
    self.to_add_on_completion, self.stretch, self.dim_to_match = (
        target_mobject,
        stretch,
        dim_to_match,
    )
    self._start = mobject.copy()  # what the mobject is put back to when it is done
    super().__init__(
        Group(mobject, target_mobject.copy()),
        keys=(self._fading_in, self._faded_out),
        **kwargs,
    )

匹配各部分

TransformMatchingTex

代码
import manimgx as m


class TransformMatchingTexExample(m.Scene):
    def construct(self) -> None:
        before = m.MathTex("a^2", "+", "b^2", "=", "c^2", font_size=120)
        after = m.MathTex("a^2", "=", "c^2", "-", "b^2", font_size=120)
        self.add(before)
        self.play(
            m.TransformMatchingTex(before, after, path_arc=m.PI / 2), run_time=2
        )
        self.wait(0.5)

通过匹配各部分将一个公式变换为另一个:每个部分移动到以相同方式书写的部分,其余部分淡入淡出。

MathTex 的各部分是构成它的字符串:所给定的参数以及 {{…}} 在其中 分隔出的内容,并进一步在其 substrings_to_isolate 处和其 tex_to_color_map 的字符串处 切分(组的各部分是其成员的各部分)。当两部分的字符串相同时它们匹配,因此应将每个需要移动 的项作为独立参数给出。动画结束时,target_mobject 出现在场景中 mobject 的位置。

m.TransformMatchingTex(mobject, target_mobject, transform_mismatches=False, fade_transform_mismatches=False, key_map=None, **kwargs)
mobject

要变换的公式:一个 MathTex,或一组 MathTex。

target_mobject

它将变成的公式。

transform_mismatches

未匹配的部分是否变换为目标的未匹配部分,而非淡入淡出。

fade_transform_mismatches

它们是否交叉淡入到目标的未匹配部分 (参见 FadeTransformPieces),而非淡入淡出。

key_map

尽管不同但仍要匹配的字符串对:以第一种方式书写的 mobject 部分交叉淡入到 以第二种方式书写的目标部分。这些匹配优先于相等的键。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\matching.py

def __init__[Key: Hashable](
    self,
    mobject: Mobject,
    target_mobject: Mobject,
    transform_mismatches: bool = False,
    fade_transform_mismatches: bool = False,
    key_map: Mapping[Key, Hashable] | None = None,
    **kwargs: Unpack[TransformOptions],
):
    source_map = self.get_shape_map(mobject)
    target_map = self.get_shape_map(target_mobject)
    key_mapped_source, key_mapped_target = Group(), Group()
    for key1, key2 in (key_map or {}).items():
        if key1 in source_map and key2 in target_map:
            key_mapped_source.add(source_map.pop(key1))
            key_mapped_target.add(target_map.pop(key2))
    matched = [key for key in source_map if key in target_map]
    anims: list[AnimationGroup | Transform] = [
        Transform(
            Group(*(source_map[k] for k in matched)),
            Group(*(target_map[k] for k in matched)),
            **kwargs,
        )
    ]
    if len(key_mapped_source) > 0:
        anims.append(
            FadeTransformPieces(key_mapped_source, key_mapped_target, **kwargs)
        )
    fade_source = Group(
        *(part for key, part in source_map.items() if key not in target_map)
    )
    fade_target = Group(
        *(part for key, part in target_map.items() if key not in source_map)
    )
    fade_target_copy = fade_target.copy()
    if transform_mismatches:
        kwargs.setdefault("replace_mobject_with_target_in_scene", True)
        anims.append(Transform(fade_source, fade_target, **kwargs))
    elif fade_transform_mismatches:
        anims.append(FadeTransformPieces(fade_source, fade_target, **kwargs))
    else:
        anims.append(FadeOut(fade_source, target_position=fade_target, **kwargs))
        anims.append(
            FadeIn(fade_target_copy, target_position=fade_target, **kwargs)
        )
    super().__init__(*anims)
    self.to_remove = [mobject, fade_target_copy]
    self.to_add = target_mobject

TransformMatchingShapes

代码
import manimgx as m


class TransformMatchingShapesExample(m.Scene):
    def construct(self) -> None:
        source = m.Text("the morse code", font_size=96)
        target = m.Text("here come dots", font_size=96, color=m.YELLOW)
        self.add(source)
        self.play(
            m.TransformMatchingShapes(source, target, path_arc=m.PI / 2),
            run_time=2,
        )
        self.wait(0.5)

通过匹配形状将一个 mobject 变换为另一个:每个部分移动到同形状的部分,其余部分淡入淡出。

各部分是带有点的成员(文本的字母);当两部分具有相同形状时它们匹配,无论其大小和位置如何 (它们的点经居中并缩放至高度为 1 后,在 3 位小数精度上一致)。因此文本逐字母地变为它的 字母重排。动画结束时,target_mobject 出现在场景中 mobject 的位置。

m.TransformMatchingShapes(mobject, target_mobject, transform_mismatches=False, fade_transform_mismatches=False, key_map=None, **kwargs)
mobject

要变换的 mobject。

target_mobject

它将变成的 mobject。

transform_mismatches

未匹配的部分是否变换为目标的未匹配部分,而非淡入淡出。

fade_transform_mismatches

它们是否交叉淡入到目标的未匹配部分 (参见 FadeTransformPieces),而非淡入淡出。

key_map

尽管不同但仍要匹配的键对:mobject 中具有第一个键的部分交叉淡入到 目标中具有第二个键的部分。这些匹配优先于相等的键。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\matching.py

def __init__[Key: Hashable](
    self,
    mobject: Mobject,
    target_mobject: Mobject,
    transform_mismatches: bool = False,
    fade_transform_mismatches: bool = False,
    key_map: Mapping[Key, Hashable] | None = None,
    **kwargs: Unpack[TransformOptions],
):
    source_map = self.get_shape_map(mobject)
    target_map = self.get_shape_map(target_mobject)
    key_mapped_source, key_mapped_target = Group(), Group()
    for key1, key2 in (key_map or {}).items():
        if key1 in source_map and key2 in target_map:
            key_mapped_source.add(source_map.pop(key1))
            key_mapped_target.add(target_map.pop(key2))
    matched = [key for key in source_map if key in target_map]
    anims: list[AnimationGroup | Transform] = [
        Transform(
            Group(*(source_map[k] for k in matched)),
            Group(*(target_map[k] for k in matched)),
            **kwargs,
        )
    ]
    if len(key_mapped_source) > 0:
        anims.append(
            FadeTransformPieces(key_mapped_source, key_mapped_target, **kwargs)
        )
    fade_source = Group(
        *(part for key, part in source_map.items() if key not in target_map)
    )
    fade_target = Group(
        *(part for key, part in target_map.items() if key not in source_map)
    )
    fade_target_copy = fade_target.copy()
    if transform_mismatches:
        kwargs.setdefault("replace_mobject_with_target_in_scene", True)
        anims.append(Transform(fade_source, fade_target, **kwargs))
    elif fade_transform_mismatches:
        anims.append(FadeTransformPieces(fade_source, fade_target, **kwargs))
    else:
        anims.append(FadeOut(fade_source, target_position=fade_target, **kwargs))
        anims.append(
            FadeIn(fade_target_copy, target_position=fade_target, **kwargs)
        )
    super().__init__(*anims)
    self.to_remove = [mobject, fade_target_copy]
    self.to_add = target_mobject

交换位置

Swap

代码
import manimgx as m


class SwapExample(m.Scene):
    def construct(self) -> None:
        square = m.Square(side_length=2, color=m.BLUE, fill_opacity=1)
        circle = m.Circle(color=m.RED, fill_opacity=1)
        square.shift(2 * m.LEFT)
        circle.shift(2 * m.RIGHT)
        self.add(square, circle)
        self.play(m.Swap(square, circle))

交换两个 mobject 的位置,各自沿弧线移动。

与 CyclicReplace 相同,后者对两个 mobject 将每个移到另一个的位置。

m.Swap(*mobjects, **kwargs)
*mobjects

这两个 mobject。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\motion.py

def __init__(self, *mobjects: Mobject, **kwargs: Unpack[TransformOptions]) -> None:
    self.group = (
        mobjects[0]
        if len(mobjects) == 1 and isinstance(mobjects[0], Group)
        else _gathered(*mobjects)
    )
    kwargs.setdefault("path_arc", 90 * DEGREES)
    super().__init__(self.group, keys=(None, self._cycled), **kwargs)

CyclicReplace

代码
import manimgx as m


class CyclicReplaceExample(m.Scene):
    def construct(self) -> None:
        shapes = m.VGroup(
            m.Square(color=m.BLUE),
            m.Circle(color=m.YELLOW),
            m.Triangle(color=m.GREEN),
            m.Star(color=m.RED),
        ).arrange(buff=1)
        self.add(shapes)
        self.play(m.CyclicReplace(*shapes))
        self.play(m.CyclicReplace(*shapes))

将每个 mobject 移动到下一个的位置,并将最后一个移到第一个的位置。

每个沿弧线移动,默认为 90°(path_arc)。单独给出的组被视为这些 mobject。

m.CyclicReplace(*mobjects, **kwargs)
*mobjects

这些 mobject,按循环顺序排列。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

还接受 变换关键字。

源码

manimgx\animation\motion.py

def __init__(self, *mobjects: Mobject, **kwargs: Unpack[TransformOptions]) -> None:
    self.group = (
        mobjects[0]
        if len(mobjects) == 1 and isinstance(mobjects[0], Group)
        else _gathered(*mobjects)
    )
    kwargs.setdefault("path_arc", 90 * DEGREES)
    super().__init__(self.group, keys=(None, self._cycled), **kwargs)

变换关键字

TransformOptions

变换所接受的选项,按关键字给出:动画选项及其路径。

path_func

每个点从起点到终点的行进方式:以起点、终点和进度为参数的函数 (参见 paths);它替代 path_arc 和 path_arc_centers (默认 None:直线路径)。

path_arc

每个点在行进过程中转过的角度,以弧度为单位:0 为直线路径, 正角度表示绕 path_arc_axis 逆时针旋转(默认 0)。

path_arc_axis

path_arc 的弧所绕的轴(默认 OUT:在屏幕平面内)。

path_arc_centers

mobject 在行进过程中绕其转过 path_arc 的点,或为每个点各指定一个 (默认 None:每个点绕自身弧的中心旋转)。

replace_mobject_with_target_in_scene

动画结束时目标是否取代 mobject 在场景中的位置,如同 ReplacementTransform(默认 False)。

run_time

动画播放时长,以秒为单位(默认 1)。

lag_ratio

mobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。

rate_func

动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为 smooth;参见 rate functions)。

reverse_rate_function

是否反向运行动画(默认 False)。

name

动画的名称。

remover

动画结束时 mobject 是否离开场景 (默认 False)。

suspend_mobject_updating

动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。

introducer

动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。

use_override

若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。

path_func

每个点从起点到终点的行进方式:以起点、终点和进度为参数的函数 (参见 paths);它替代 path_arc 和 path_arc_centers (默认 None:直线路径)。

path_arc

每个点在行进过程中转过的角度,以弧度为单位:0 为直线路径, 正角度表示绕 path_arc_axis 逆时针旋转(默认 0)。

path_arc_axis

path_arc 的弧所绕的轴(默认 OUT:在屏幕平面内)。

path_arc_centers

mobject 在行进过程中绕其转过 path_arc 的点,或为每个点各指定一个 (默认 None:每个点绕自身弧的中心旋转)。

replace_mobject_with_target_in_scene

动画结束时目标是否取代 mobject 在场景中的位置,如同 ReplacementTransform(默认 False)。

路径

路径函数说明每个点如何从起点行进到终点:将一个作为 path_func 传入。

straight_path

直线路径:每个点沿其起点到终点的直线行进,即变换默认移动点的方式。

m.straight_path()
源码

manimgx\drawing\geometry.py

def straight_path() -> Path:
    """直线路径:每个点沿其起点到终点的直线行进,即变换默认移动点的方式。
    """
    return Path()

path_along_arc

沿圆弧的路径:每个点沿圆弧从起点到终点,转过某个角度,即变换的 path_arc 使其移动的方式。

m.path_along_arc(arc_angle, axis=_PATH_AXIS)
arc_angle

每段弧转过的角度,以弧度为单位,绕 axis 逆时针方向; 绝对值小于 STRAIGHT_PATH_THRESHOLD 时为 直线路径。

axis

各弧所绕的轴。

源码

manimgx\drawing\geometry.py

def path_along_arc(arc_angle: float, axis: Vector3DLike = _PATH_AXIS) -> Path:
    """沿圆弧的路径:每个点沿圆弧从起点到终点,转过某个角度,即变换的
    `path_arc` 使其移动的方式。

    Args:
        arc_angle: 每段弧转过的角度,以弧度为单位,绕 `axis` 逆时针方向;
            绝对值小于
            [STRAIGHT_PATH_THRESHOLD][manimgx.STRAIGHT_PATH_THRESHOLD] 时为
            直线路径。
        axis: 各弧所绕的轴。
    """
    if abs(arc_angle) < STRAIGHT_PATH_THRESHOLD:
        return straight_path()
    return Path("arc", arc_angle, _unit(axis))

clockwise_path

沿半圆顺时针的路径:每个点在从起点到终点的途中转过 π。

m.clockwise_path()
源码

manimgx\drawing\geometry.py

def clockwise_path() -> Path:
    """沿半圆顺时针的路径:每个点在从起点到终点的途中转过 π。
    """
    return path_along_arc(-np.pi)

counterclockwise_path

沿半圆逆时针的路径:每个点在从起点到终点的途中转过 π。

m.counterclockwise_path()
源码

manimgx\drawing\geometry.py

def counterclockwise_path() -> Path:
    """沿半圆逆时针的路径:每个点在从起点到终点的途中转过 π。
    """
    return path_along_arc(np.pi)

spiral_path

螺旋路径:每个点从起点螺旋到终点,其相对起点的偏移在逆时针转过 angle (角度为正时)的过程中增长,直至与终点成一直线。

m.spiral_path(angle, axis=_PATH_AXIS)
angle

每个点转过的距离,以弧度为单位,绕 axis;绝对值小于 STRAIGHT_PATH_THRESHOLD 时为 直线路径。

axis

各点所绕的轴。

源码

manimgx\drawing\geometry.py

def spiral_path(angle: float, axis: Vector3DLike = _PATH_AXIS) -> Path:
    """螺旋路径:每个点从起点螺旋到终点,其相对起点的偏移在逆时针转过 `angle`
    (角度为正时)的过程中增长,直至与终点成一直线。

    Args:
        angle: 每个点转过的距离,以弧度为单位,绕 `axis`;绝对值小于
            [STRAIGHT_PATH_THRESHOLD][manimgx.STRAIGHT_PATH_THRESHOLD] 时为
            直线路径。
        axis: 各点所绕的轴。
    """
    if abs(angle) < STRAIGHT_PATH_THRESHOLD:
        return straight_path()
    return Path("spiral", angle, _unit(axis))

path_along_circles

绕各中心的路径:每个点在从起点移动到终点的同时绕其中心转过某个角度, 即变换的 path_arc_centers 使其移动的方式。

若只有一个中心,则形状作为整体绕其转动,返回一个 Path; 若每个点一个中心,则每个点绕各自的中心转动,返回一个 (start, end, alpha) 的普通函数。

m.path_along_circles(arc_angle, centers, axis=_PATH_AXIS)
arc_angle

角度,以弧度为单位,绕 axis 逆时针方向。

centers

一个中心,或每个点一个中心,以场景坐标表示。

axis

各点所绕的轴。

源码

manimgx\drawing\geometry.py

def path_along_circles(
    arc_angle: float,
    centers: Point3DLike | Point3DLike_Array,
    axis: Vector3DLike = _PATH_AXIS,
) -> PathFunc:
    """绕各中心的路径:每个点在从起点移动到终点的同时绕其中心转过某个角度,
    即变换的 `path_arc_centers` 使其移动的方式。

    若只有一个中心,则形状作为整体绕其转动,返回一个 [Path][manimgx.Path];
    若每个点一个中心,则每个点绕各自的中心转动,返回一个
    `(start, end, alpha)` 的普通函数。

    Args:
        arc_angle: 角度,以弧度为单位,绕 `axis` 逆时针方向。
        centers: 一个中心,或每个点一个中心,以场景坐标表示。
        axis: 各点所绕的轴。
    """
    unit_axis = _unit(axis)
    points: Floats = np.asarray(centers, dtype=np.float64)
    if points.ndim == 1:
        return Path(steps=((arc_angle, unit_axis, points),))

    def path(start: Point3D_Array, end: Point3D_Array, alpha: float) -> Point3D_Array:
        detransformed = (
            points + (end - points) @ rotation_matrix(-arc_angle, unit_axis).T
        )
        rot = rotation_matrix(alpha * arc_angle, unit_axis)
        return points + ((1 - alpha) * start + alpha * detransformed - points) @ rot.T

    return path

Path

在变换中一个形状的各点如何从其起点行进到其终点,以值的形式表示。

一条路径将每个点变到 Lₛ·start + Lₑ·end + k,其中 Lₛ、Lₑ 和 k 仅取决于 动画的进度 α:因此形状在移动时其点本身不被触碰。以 path(start, end, alpha) 形式调用,作用于点数组;下面的函数构造 ManimGX 所提供的各路径。

m.Path(kind='motion', angle=0.0, axis=(lambda: copy())(), steps=())
kind

路径的种类。"motion":形状被其 steps 的运动 G 携带,同时在 运动坐标系中沿直线变化, G(α)·((1 − α)·start + α·G(1)⁻¹·end);无步骤时为直线路径。 "arc":每个点沿圆弧从起点到终点,转过 angle(若其两端沿 axis 不同,则沿该轴匀速行进)。"spiral":每个点从起点螺旋 到终点,start + α·R((α − 1)·angle)·(end − start)。

angle

"arc" 或 "spiral" 路径转过的角度,以弧度为单位,绕 axis 逆时针方向。

axis

路径所绕的轴。

steps

"motion" 路径的各步骤,按顺序执行:每一步为一次移动(一个向量)、 沿曲线的一次移动,或绕支点的一次转动。

m.STRAIGHT_PATH_THRESHOLD

path_along_arc 和 spiral_path 所转过的最小角度,以弧度为单位:小于此值时即为 直线路径。