Manim 的 Text、Tex、MathTex 有什么区别,该用哪个?中文和公式混排怎么写

2026 年 10 月 20 日 · 极坐标⋅XYZ

Manim 的 Text、Tex、MathTex 有什么区别,该用哪个?中文和公式混排怎么写

写字用 Text,写公式用 MathTex,英文句子里夹公式用 Tex,中文句子里夹公式用 0.21 新增的 Typst。Text 用电脑里的字体直接画字,不认 LaTeX 语法,中文直接写;Tex 和 MathTex 都交给 LaTeX 排版,区别只在默认模式:Tex 默认是正文,公式要用 $...$ 包起来,MathTex 整串都是公式。这两个写中文都要换 ctex 模板,不然 LaTeX 直接报错。Typst 和 MathTypst 是同一套分工换成 Typst 排版,中文直接写,也不用装 LaTeX。

Manim 是 Grant Sanderson 给 3Blue1Brown 做视频写的 Python 动画库,现在大家装的多是社区版 Manim Community。字和公式是数学动画里用得最多的东西,也是新手最容易卡住的地方:同一句话有五六个类能写,报错信息又常常是 LaTeX 的。这篇的结论和数字,我们在 0.21.0 和 2026 年 10 月 8 日发布的 0.22.0 上各跑了一遍,两边一样。不熟悉 Manim 可以先看这篇介绍;想从头系统学,极坐标⋅XYZ 上 2026 年按新版本录的 Manim 中文教程里,文字和公式单独是一课。

标了「在工作区中打开」的代码,点一下就能在极坐标⋅XYZ 的工作区里跑,三段我们都在线上工作区跑过。工作区装的是 Manim 0.21.0,电脑上不用装 Python,也不用装 LaTeX。

先看一眼:同一个 1/2,三种写法

from manim import *


class OneHalfThreeWays(Scene):
    def construct(self):
        a = Text("1/2")               # 普通文字:三个字符排成一行
        b = MathTex(r"\frac{1}{2}")   # LaTeX 排出来的上下分数
        c = MathTypst("1/2")          # Typst 排出来的上下分数
        row = VGroup(a, b, c).scale(2.5).arrange(RIGHT, buff=2.5)

        names = VGroup(*[Text(n, font_size=30, color=GRAY) for n in ("Text", "MathTex", "MathTypst")])
        for name, m in zip(names, row):
            name.move_to([m.get_x(), row.get_bottom()[1] - 0.5, 0], aligned_edge=UP)

        self.play(LaggedStart(*[Write(m) for m in row], lag_ratio=0.5))
        self.play(FadeIn(names))
        self.wait()

Text("1/2") 就是「1」「/」「2」三个字符排一行,和你在记事本里打出来的一样。另外两个是真分数,分子分母上下叠,中间一条分数线。MathTex 要写 LaTeX 的 \frac{1}{2},MathTypst 直接写 1/2,Typst 自己会把它排成分数。

在工作区第一次用 Typst,浏览器要先下载一个十几 MB 的 Typst 编译器,之后走缓存。

怎么选

类 谁来排版 默认是 写中文 本机要装 适合写
Text 系统字体 普通文字 直接写 不用额外装 标题、说明、标签、中文
Tex LaTeX 正文,公式要 $...$ 要 ctex 模板 LaTeX 英文句子里夹公式
MathTex LaTeX 公式 放进 \text{},也要 ctex LaTeX 单独的公式、要拆开上色或变形的公式
Typst Typst 正文,公式要 $...$ 直接写 pip install "manim[typst]" 中文句子里夹公式
MathTypst Typst 公式 一般不在公式里放中文 同上 单独的公式,按名字分组上色

Typst 和 MathTypst 是 0.21.0 才有的,老教程里看不到。新写的代码要不要换成 Typst,我们的看法是:已经装好 LaTeX、公式都是英文的,继续用 MathTex 没问题,网上的例子也多;要写中文、或者不想装 LaTeX,Typst 省事很多。

同一句「直角三角形中 a²+b²=c²」在 Manim 里的四种写法:Text 直接写中文、不用 LaTeX,上标是 Unicode 字符;Tex 和 MathTex 写中文要 ctex 模板、要装 LaTeX;Typst 直接写中文、不用 LaTeX,公式由排版引擎排出

Text:写字用它,别在里面写公式

Text 拿系统里的字体把字一个个画成矢量图形,中文英文都行,跟 Word 里打字差不多。它不认任何排版语法,Text("$x^2$") 画出来就是 $、x、^、2、$ 五个字符。想要个上标,可以直接打 Unicode 的「²」,比如上面图里第一行的 a²+b²=c²,但那是字体里现成的上标字符,大小位置都是死的,写复杂一点的公式还是得交给排版引擎。

它快。我们在本机测,进程里第一个 Text 要加载字体,用了 400 毫秒左右,之后每个只要几毫秒;MathTex 每个新公式都要调一次 LaTeX,第一次 0.4~0.7 秒,同样的公式第二次走缓存只要 1 毫秒。一个场景里几十个标签,用 Text 能省不少时间。

常用的几个参数:font_size 改字号(默认 48),font="..." 换成本机装的别的字体,\n 换行、line_spacing 调行距,t2c={"勾股": YELLOW} 把某几个字单独上色,t2w、t2s 同理改粗细和斜体。要在一段话里混好几种样式,还有个 MarkupText,用类似 HTML 的标签写,比如 <span fgcolor="yellow">c²</span>。

Tex 和 MathTex:差一对美元符号

两个都是把字符串塞进一份 LaTeX 文档,编译成 SVG 再读回来。区别在套的环境:

  • Tex("...") 套的是 center 环境,里面默认是普通正文,要写公式得自己加 $...$;
  • MathTex("...") 套的是 align* 环境,整串一进去就是数学模式,不用写美元符号。

所以 Tex(r"The area is $\pi r^2$") 和 MathTex(r"\pi r^2") 里的公式长得一样。纯公式就用 MathTex,省得到处写 $;一句英文里夹个公式,用 Tex。

这里有个容易忽略的差别:Tex 里的 $...$ 是「行内公式」,LaTeX 会把分数、求和这些压扁,好塞进一行字里。我们量了 Tex(r"$\frac{1}{2}$"),高 0.60 个单位,MathTex(r"\frac{1}{2}") 高 1.01,差了快一半。想在 Tex 里要正常大小的分数,写成 $\displaystyle\frac{1}{2}$,量出来也是 1.01。

数学模式还会吃掉空格:MathTex("a b") 和 MathTex("ab") 量出来宽度一模一样,都是 0.45。要空格得写 a\ b 或 a\quad b。另外因为是 align*,MathTex 里可以用 & 和 \\ 写多行对齐的公式,这个在教程「多行公式对齐」那一节里专门讲。

MathTex 可以传好几个字符串,每个字符串变成一个子对象。MathTex("a^2", "+", "b^2", "=", "c^2") 有 5 个子对象,eq[4] 就是 c^2,后面上色和做动画都靠这个。

中文怎么写

在默认设置下,Tex("面积") 和 MathTex(r"\text{面积}") 都会报错,日志里是这么一行:

LaTeX Error: Unicode character 面 (U+9762)

Manim 默认的 LaTeX 模板用 latex 编译,不认中文。有三个办法。

第一个,换 ctex 模板,用 xelatex 编译:

Tex(r"直角三角形中 $a^2+b^2=c^2$", tex_template=TexTemplateLibrary.ctex)
MathTex(r"\text{面积 } S = \pi r^2", tex_template=TexTemplateLibrary.ctex)

前提是本机的 TeX 发行版里有 xelatex 和 ctex 宏包,TeX Live 完整安装就带,MiKTeX 一般会在第一次用到时提示下载。xelatex 比 latex 慢,我们测一个带中文的 Tex 第一次编译要 1 秒多。整个文件都要中文的话,可以在文件顶层写 config.tex_template = TexTemplateLibrary.ctex,不用每个都传。

第二个,中文和公式分开写:中文用 Text,公式用 MathTex,再用 next_to 或 VGroup(...).arrange(RIGHT) 拼在一起。不用装 ctex,缺点是基线要自己对,字号也要调:同样 font_size=48,Text("x") 高 0.30 个单位,MathTex("x") 只有 0.23,拼在一起公式会显得小一号。

第三个,用 Typst。Typst 默认就能排中文,公式写在 $...$ 里,不用装 LaTeX:

from manim import *


class ChineseWithFormula(Scene):
    def construct(self):
        title = Text("勾股定理", font_size=56).to_edge(UP)
        # 中文夹公式:Typst 里用 $...$ 包住公式,中文直接写
        line = Typst("直角三角形里,两条直角边的平方和等于斜边的平方:$a^2 + b^2 = c^2$", font_size=40)
        line.next_to(title, DOWN, buff=0.6)
        # 单独的大公式:{{ … : 名字 }} 分组,之后按名字取出来上色
        eq = MathTypst("{{ a^2 + b^2 : lhs }} = {{ c^2 : rhs }}", font_size=96).shift(DOWN * 0.8)

        self.play(Write(title))
        self.play(FadeIn(line, shift=UP * 0.2))
        self.play(Write(eq))
        self.play(eq.select("lhs").animate.set_color(BLUE), eq.select("rhs").animate.set_color(YELLOW))
        self.wait()

Typst 的公式语法和 LaTeX 不一样,分数直接写 /,求和写 sum_(k=1)^n,{{ ... : 名字 }} 圈起来的部分可以用 .select("名字") 取出来。细节我们在这篇 Typst 用法里写过,这里不重复。

在工作区里写中文,用 Text 或者 Typst。工作区的 LaTeX 公式是浏览器里的 MathJax 排的,MathTex 写英文公式没问题,Tex 的正文模式和 \text{} 里的中文目前排不出来,ctex 模板在浏览器里也用不上。

给公式的一部分上色

讲题的时候经常要把某一项标出来。MathTex 上色有个前提:你要的那一项,得是单独的一段。

from manim import *


class ColorOnePart(Scene):
    def construct(self):
        # 拆成五段,每段是一个子对象:eq[0] 是 a^2,eq[4] 是 c^2
        eq = MathTex("a^2", "+", "b^2", "=", "c^2", font_size=96)
        self.play(Write(eq))
        self.play(eq.animate.set_color_by_tex("c^2", YELLOW))
        self.play(Indicate(eq[4]))
        self.wait()

拆段有三种写法,效果一样:像上面这样传多个字符串;在一个字符串里用 {{c^2}} 圈出来;或者传 substrings_to_isolate=["c^2"]。也可以一步到位写 tex_to_color_map={"c^2": YELLOW}。

我们把五种写法挨个试了,有两种不生效,而且不报错:

MathTex 给 c² 单独上黄色的五种写法:拆成多个参数、{{c^2}} 不带空格、substrings_to_isolate 三种生效;{{ c^2 }} 带空格和整串不拆两种不生效,因为 set_color_by_tex 按整段字符串精确匹配

原因在 set_color_by_tex 的匹配方式。0.21.0 和 0.22.0 里它拿你给的字符串和每一段做精确比较,一个字符都不能差。{{ c^2 }} 圈出来的那一段是带空格的「 c^2 」,和 "c^2" 对不上;整串不拆时只有一段「a^2 + b^2 = c^2」,更对不上。同理,set_color_by_tex("x", ...) 不会把 x^2、2x 里的 x 都染上,只认正好是「x」的那一段。

不想拆段,也能按字形下标直接取:本机用 LaTeX 渲的时候,MathTex("a^2 + b^2 = c^2") 的 eq[0] 是 8 个字形(a、2、+、b、2、=、c、2),eq[0][6:8] 就是 c 和它的上标。下标不好数的时候,临时加一行 self.add(index_labels(eq[0])),每个字形旁边会标出它的编号。

Text 上色用 t2c,MathTypst 用 {{ ... : 名字 }} 加 .select("名字"),上面两段代码里都有。

常见写错的地方

在 Text 里写 LaTeX

Text(r"$\frac{1}{2}$")

画出来就是这一串字符原样,带美元符号和反斜杠。公式交给 MathTex 或 MathTypst。

字符串前面忘了 r

MathTex("\frac{1}{2}")   # 少了 r

Python 会把 \f 当成换页符,LaTeX 收到的是一个看不见的字符加上 rac{1}{2},报 Missing $ inserted。我们照这样写,报的就是这个。更麻烦的是不报错的:MathTex("\theta") 里的 \t 被当成制表符,画出来是斜体的「heta」,我们量了宽 0.97 个单位,一个 θ 才 0.2 左右。\n(\nabla)、\b(\beta)也会被 Python 先转义掉,所以 LaTeX 字符串一律写成 r"..."。

Tex 写中文没换模板

报 LaTeX Error: Unicode character 面 (U+9762) 这一类,就是中文进了默认模板。换 TexTemplateLibrary.ctex,或者改用 Text、Typst,见上面「中文怎么写」。

{{ }} 里带了空格,上色没反应

MathTex("{{ a^2 }} + {{ b^2 }} = {{ c^2 }}") 拆出来的段是「 a^2 」「 c^2 」,前后各带一个空格,set_color_by_tex("c^2", ...) 匹配不上,也不报错。去掉空格写成 {{c^2}},或者改用多参数的写法。

Tex 里的分数、求和变小了

单个 $...$ 是行内公式,分数会被压到一行字的高度。要么改用 MathTex,要么在公式前面加 \displaystyle。

常见追问(FAQ)

Q:电脑上没装 LaTeX,还能写公式吗? A:能。Text 本来就不需要 LaTeX;0.21.0 之后 pip install "manim[typst]" 装上 Typst 支持,Typst 和 MathTypst 就能写公式,Typst 编译器跟着 Python 包一起装,不用单独装 TeX 发行版。不想在本机装任何东西,用极坐标⋅XYZ 的工作区,浏览器打开就有 Text、MathTex 和 Typst。

Q:三个类的字号是一样的吗? A:font_size 默认都是 48,但字形大小不完全一样。我们量了单个字母 x:Text 高 0.30 个单位,MathTex 高 0.23,MathTypst 也在 0.23 左右。混排时 Text 那边可以调小一点,或者统一用一种。

Q:多行公式怎么让等号对齐? A:MathTex 里用 & 标对齐点、\\ 换行,比如 MathTex(r"x &= 1 + 1 \\ &= 2")。教程《文本与公式》的「多行公式对齐」一节有完整例子。

Q:一个公式变成另一个公式的动画用什么? A:TransformMatchingTex,它按拆好的段去配对,所以前面「拆段」那一步同样重要。教程最后一节「公式变换 TransformMatchingTex」专门讲。

Q:0.22.0 在这些地方有变化吗? A:我们没测出差别。文中的尺寸、报错、上色结果在 0.21.0 和 0.22.0 上逐项对过,完全一样。工作区目前装的是 0.21.0。


这些内容在教程《文本与公式》里分成五节:「Text 与字体」「Tex 与 MathTex」「公式分组与上色」「多行公式对齐」「公式变换 TransformMatchingTex」,每节有视频,旁边的代码可以边看边改。想直接动手,打开工作区,把上面的代码贴进去点运行。

来源:极坐标⋅XYZ · jizuobiao.xyz · 更新于 2026-10-20 · 基于 Manim Community 0.21.0,0.22.0 复核