Manim v0.15.1 版本详解:TransformMatchingTex 分组支持、渲染流程修复与 LaTeX/Jupyter 关键 Bug 修复
【免费下载链接】manimA community-maintained Python framework for creating mathematical animations.项目地址: https://gitcode.com/GitHub_Trending/man/manim
Manim(Mathematical Animation)是一个社区维护的、用于创建数学动画的 Python 框架。v0.15.1 是发布于 2022 年 3 月 8 日的一个 bugfix 版本,共合并了 9 个 Pull Request,核心内容包括:为TransformMatchingTex增加 Group 支持、修复引入式动画(introducer animations)的渲染流程问题、修复None颜色类型、修复含%字符的 TeX 字符串渲染,以及修复 Jupyter Notebook 中config.media_embed为False时图片无法显示的问题。读完本文,你将理解这些修复背后的源码机制,并掌握在 v0.15.1 及后续版本中正确使用相关 API 的实战方法。
版本概况与贡献者
v0.15.1 于 2022 年 3 月 8 日发布,是一个典型的补丁版本(bugfix release),共合并了 9 个 Pull Request。本次发布共有 9 人参与贡献,其中带+标记的是首次为项目提交补丁的贡献者,包括 Benjamin Hackl、Nicolai Weitkemper、Yuchen、ad_chaos;补丁评审由 Alex Lembcke、Darylgolden、Naveen M K、Raghav Goel、icedcoffeeee 等社区成员完成。
从变更类型分布看,本次发布的重心非常明确:4 项 Bug 修复(Fixed bugs)占据了绝对主体,另含 1 项增强(Enhancements)、2 项文档相关改动和 2 项代码质量改进。这与官方 changelog 中:pr:引用一一对应,详见 0.15.1-changelog.rst。
核心增强:TransformMatchingTex 支持 Group(PR #2602)
本次版本最重要的功能增强是让TransformMatchingTex能够处理Group类型的 mobject。在此之前,TransformMatchingTex只能直接作用于单个 TeX mobject(如MathTex),无法将一组对象(例如几个独立的公式组合成的VGroup/Group)作为变换的起点或终点。
源码层面的实现
从当前仓库源码 transform_matching_parts.py 可以清晰看到这一能力的具体实现。TransformMatchingTex继承自TransformMatchingAbstractBase,该基类在__init__中会根据 mobject 的类型选择不同的容器:
OpenGLVMobject→OpenGLVGroupOpenGLMobject→OpenGLGroupVMobject→VGroup- 其他类型 →
Group
随后通过get_shape_map将 mobject 拆分为“子对象 → key”的映射,再对 key 集合求交集与差集,分别执行变换(Transform)、淡入淡出(FadeOut/FadeIn)或通过key_map强制配对。
关键改动位于get_mobject_parts静态方法(transform_matching_parts.py):当传入的 mobject 是Group、VGroup、OpenGLGroup或OpenGLVGroup时,会递归遍历所有submobjects并收集每一个叶子 TeX 子对象的submobjects(即单个MathTexPart);否则要求 mobject 具有tex_string属性。而get_mobject_key则直接返回MathTexPart.tex_string,即两个子对象只要 TeX 源字符串相同就会被匹配并互相变换。
实战用法:组与公式的互相变换
官方 docstring 中给出了一个典型示例:将三个独立的变量a、b、c组成的VGroup与一个完整公式进行变换。核心代码如下:
from manim import * class MatchingEquationParts(Scene): def construct(self): variables = VGroup(MathTex("a"), MathTex("b"), MathTex("c")).arrange_submobjects().shift(UP) eq1 = MathTex("{{x}}^2", "+", "{{y}}^2", "=", "{{z}}^2") eq2 = MathTex("{{a}}^2", "+", "{{b}}^2", "=", "{{c}}^2") eq3 = MathTex("{{a}}^2", "=", "{{c}}^2", "-", "{{b}}^2") self.add(eq1) self.wait(0.5) self.play(TransformMatchingTex(Group(eq1, variables), eq2)) self.wait(0.5) self.play(TransformMatchingTex(eq2, eq3)) self.wait(0.5)注意这里Group(eq1, variables)将公式与变量组再次打包成一个 Group,这正是 v0.15.1 新增能力发挥作用的场景。由于匹配基于tex_string,x、y、z会分别平滑地“变身”为a、b、c,而=、+、^2等相同部分保持不变,呈现出行云流水的公式变形效果。
匹配规则与不匹配部分的行为
TransformMatchingAbstractBase(transform_matching_parts.py)提供了三个关键参数来控制匹配行为:
transform_mismatches:默认为False。若为True,key 不匹配的子对象之间改用Transform直接变换(此时自动设置replace_mobject_with_target_in_scene=True)。fade_transform_mismatches:默认为False。若为True,不匹配部分使用FadeTransformPieces变换。key_map:可选字典,用于手动指定“源 key → 目标 key”的强制配对,即使两个子对象的 key 不同也会被变换。
当上述两个布尔参数均为False时,源对象中无匹配的部分朝目标对象中不匹配部分的方向淡出(FadeOut),目标对象中新增的无匹配部分则从对应方向淡入(FadeIn)。另一个值得注意的细节是clean_up_from_scene(transform_matching_parts.py)会把所有内部动画插值回 0,以保证源 mobject 在动画结束后保持不变。
同类动画TransformMatchingShapes(transform_matching_parts.py)则基于几何形状匹配:子对象经过“平移到原点、归一化高度为 1、坐标四舍五入到 3 位小数”后取点坐标哈希作为 key,常用于字母重排类动画。
渲染流程修复:引入式动画(PR #2594)
v0.15.1 修复了引入式动画(introducer animations)的渲染流程问题。所谓引入式动画,是指用于将 mobject“带入场内”的动画,例如Create、Write、DrawBorderThenFill、ShowIncreasingSubsets等。
从 creation.py 源码可以看出,Create、Uncreate、Write、Unwrite等动画类在构造时都会接收一个introducer布尔参数(如 creation.py 中super().__init__(mobject, lag_ratio=lag_ratio, introducer=introducer, **kwargs)),并在ShowPartial(creation.py)的体系内实现逐段展示。v0.15.1 修复的正是这些动画在某些组合/嵌套场景下(例如动画组中先执行引入式动画、后续动画依赖其输出)的渲染顺序与状态同步问题,确保动画的引入阶段与后续阶段衔接正确。这类问题通常表现为画面闪烁、mobject 提前/延后出现等,修复后动画组的整体渲染流程更加稳定。
颜色系统修复:非法颜色类型 None(PR #2584)
本次发布修复了传入None作为颜色类型时抛出的异常。在 manim 的颜色体系中,ParsableManimColor表示可解析的颜色类型,而None是一个特殊的合法取值——例如在 core.py 中可以看到默认None被解释为BLACK的说明,以及ManimColor.__init__中对value is None的特殊处理分支。
修复前,某些代码路径把None直接当作颜色值解析,导致类型断言或转换失败;修复后,None会在ManimColor内部被一致地映射为默认黑色,同时color_to_rgb、color_to_rgba、color_to_int_rgb、color_to_int_rgba等工具函数(core.py)在处理边界输入时也更加健壮。相关类型提示也在 PR #2578 中得到修正(见下文“代码质量改进”)。
TeX 渲染修复:包含 % 字符的字符串(PR #2587)
TeX 中%是注释字符,任何出现在%之后的文本都会被编译器忽略,因此当用户渲染包含%的字符串(例如“50% of the time”)时,LaTeX 编译会产生错误输出或直接失败。PR #2587 修复了这一问题,使得包含%的 TeX 字符串能够被正确渲染。
从 tex.py 的TexTemplate实现可以看到,manim 的 TeX 模板将表达式替换到placeholder_text位置(tex.py),并通过body属性拼装完整的 document(tex.py)。修复后,写入 TeX 文件的表达式会对%等特殊字符进行转义处理,避免其被 LaTeX 误判为注释符。该修复覆盖Tex、MathTex、TexTemplate相关的全部渲染路径,涉及 tex.py 与 tex_file_writing.py 两个模块。如果你需要在文本中展示百分比,修复后可以直接书写50\%或由 manim 自动处理。
Jupyter 修复:media_embed=False 时图片无法显示(PR #2593)
manim 的 IPython 魔术命令(%%manim)允许在 Notebook 中直接渲染并展示动画。其行为由config.media_embed控制:为True时视频以 Base64 内嵌方式写入 Notebook;为False时则以外部文件引用方式展示。v0.15.1 修复了当media_embed=False时图片无法显示的问题。
配置项说明
media_embed定义在 default.cfg 的[jupyter]配置段中,默认值为False,同时还有media_width(默认60%%,注意配置文件中需写为%%以转义百分号)用于控制嵌入媒体的显示宽度。在 Python 代码中可通过config.media_embed = True或config.media_embed = False动态设置(对应 utils.py 中的属性 setter,内部调用_set_boolean保证类型安全)。
底层展示逻辑
在 ipython_magic.py 中可以看到修复涉及的展示逻辑:
embed = config["media_embed"] if not embed: # videos need to be embedded when running in google colab. # do this automatically in case config.media_embed has not been # set explicitly. embed = "google.colab" in str(get_ipython()) if file_type.startswith("image"): result = Image(filename=output_file) else: result = Video( tmpfile, html_attributes=f'controls autoplay loop style="max-width: {config["media_width"]};"', embed=embed, )修复要点有两个:其一,当media_embed未被显式设置时,若运行环境是 Google Colab,则自动降级为内嵌模式(因为 Colab 无法直接引用本地媒体文件);其二,修复了图片(Image分支)在非内嵌模式下因文件名/路径处理不当而无法显示的问题。这一逻辑同样适用于视频,保证了 Notebook 与 Colab 两种环境下的稳定输出。
文档与代码质量改进
本次发布还包含两项文档相关改动与一项类型修复:
- PR #2570:重构了 coordinate_systems.py 模块的 docstring,使其与 autosummary 生成的 API 文档(见 reference_index)保持一致。
- PR #2603:减少了文档构建期间的警告数量,提升 conf.py 驱动的 Sphinx 构建体验。
- PR #2578:修正了 text_mobject.py 中
Text.color属性的错误类型提示,与 PR #2584 的颜色系统修复形成配套,确保类型标注与实际行为一致。
升级与验证建议
对于正在使用 v0.15.0 及更早版本的用户,升级到 v0.15.1 的收益主要是稳定性的提升:
- 公式变形场景:如果你在场景中频繁使用
TransformMatchingTex,并且起点/终点是多个公式组合成的Group或VGroup,升级后可直接传入组合对象,无需手动拆解。 - 含百分号的文本:涉及
Tex/MathTex渲染百分比、取模等含%内容时,升级后不再需要手工转义。 - Jupyter/Colab 工作流:使用
%%manim魔术命令的用户应确认config.media_embed的设置符合预期,非 Colab 环境下建议保持默认False以获得更小的 Notebook 体积。 - 颜色边界输入:若代码中存在
color=None的边界情况,升级后会被稳定解释为黑色。
本仓库当前的 完整 changelog 记录了从 v0.1.0 到 v0.21.0 的全部版本变更,v0.15.1 之后的版本在此基础上持续演进;相关源码与测试用例(如 tests/module/animation/test_transform.py)可作为进一步研究TransformMatchingTex等动画行为的参考。
【免费下载链接】manimA community-maintained Python framework for creating mathematical animations.项目地址: https://gitcode.com/GitHub_Trending/man/manim
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考