呈现文本和公式#

有两种不同的方法可以在视频中渲染Text文本

  1. Using Pango (text_mobject)

  2. Using LaTeX (tex_mobject)

如果您想呈现简单的文本,您应该使用 TextMarkupText ,或者其中的一个派生类,比如 Paragraph。 有关更多信息,请参阅 Text Without LaTeX

当您需要进行数学排版时,应使用 LaTeX。有关更多信息,请参阅 Text With LaTeX

没有 LaTeX 的文本#

向动画中添加文本的最简单方法是使用Text 类。 它使用 Pango 库来呈现文本。 使用 Pango,您还可以呈现像“你好 or こんにちは or 안녕하세요 or مرحبا بالعالم.”等非英文字母的文本。

这是一个简单的 Hello World 动画.

Example: HelloWorld

../_images/HelloWorld-1.png
from manim import *

class HelloWorld(Scene):
    def construct(self):
        text = Text("Hello world", font_size=144)
        self.add(text)

References: Text

您还可以使用 MarkupText, 它允许使用 PangoMarkup(有关详细信息,请参阅 MarkupText 的文档)来呈现文本。例如:

Example: SingleLineColor

../_images/SingleLineColor-1.png
from manim import *

class SingleLineColor(Scene):
    def construct(self):
        text = MarkupText(
            f'all in red <span fgcolor="{YELLOW}">except this</span>', color=RED
        )
        self.add(text)

References: MarkupText

处理 Text#

本节将解释 Text的属性以及如何在您的动画中使用它。

使用 Fonts#

您可以使用 font 属性设置不同的字体。

Note

使用的字体必须已安装在您的系统中,并且 Pango 应该知道它。您可以使用 manimpango.list_fonts()获取字体列表。

>>> import manimpango
>>> manimpango.list_fonts()
[...]

Example: FontsExample

../_images/FontsExample-1.png
from manim import *

class FontsExample(Scene):
    def construct(self):
        ft = Text("Noto Sans", font="Noto Sans")
        self.add(ft)

设置字体的斜体和加粗(Slant and Weight)#

斜体(Slant)是 Text 的样式,可以是 NORMAL(默认值), ITALICOBLIQUE。通常,对于许多字体,ITALICOBLIQUE 看起来相似,但是 ITALIC使用 Roman Style,而 OBLIQUE 使用 Italic Style

Weight 指定字体的加粗程度。您可以在 manimpango.Weight 中查看权重列表。

Example: SlantsExample

../_images/SlantsExample-1.png
from manim import *

class SlantsExample(Scene):
    def construct(self):
        a = Text("Italic", slant=ITALIC)
        self.add(a)

Example: DifferentWeight

../_images/DifferentWeight-1.png
from manim import *

class DifferentWeight(Scene):
    def construct(self):
        import manimpango

        g = VGroup()
        weight_list = dict(
            sorted(
                {
                    weight: manimpango.Weight(weight).value
                    for weight in manimpango.Weight
                }.items(),
                key=lambda x: x[1],
            )
        )
        for weight in weight_list:
            g += Text(weight.name, weight=weight.name, font="Open Sans")
        self.add(g.arrange(DOWN).scale(0.5))

使用 Colors#

您可以使用color属性设置文本的颜色:

Example: SimpleColor

../_images/SimpleColor-1.png
from manim import *

class SimpleColor(Scene):
    def construct(self):
        col = Text("RED COLOR", color=RED)
        self.add(col)

您可以使用像 t2c 这样的工具为特定字符着色。如果您的文本包含如迭代文本所述的Iterating Text连字,则可能会出现问题。

t2c 接受两种类型的字典,

  • 键可以包含类似 [2:-1][4:8]的索引, 这类似于 Python 中的slicing切片工作原理。值应该是来自 Color的 Text 的颜色。

  • 键包含应单独着色的单词或字符,而值应该是来自 Color的颜色:

Example: Textt2cExample

../_images/Textt2cExample-1.png
from manim import *

class Textt2cExample(Scene):
    def construct(self):
        t2cindices = Text('Hello', t2c={'[1:-1]': BLUE}).move_to(LEFT)
        t2cwords = Text('World',t2c={'rl':RED}).next_to(t2cindices, RIGHT)
        self.add(t2cindices, t2cwords)

如果您想避免使用颜色时出现问题(由于连字),请考虑使用 MarkupText

使用渐变(Gradients) #

您可以使用gradient属性添加渐变。值必须是任意长度的可迭代对象:

Example: GradientExample

../_images/GradientExample-1.png
from manim import *

class GradientExample(Scene):
    def construct(self):
        t = Text("Hello", gradient=(RED, BLUE, GREEN), font_size=96)
        self.add(t)

您还可以使用 t2g 为文本的特定字符创建渐变。它具有与the interface for colors颜色接口类似的语法:

Example: t2gExample

../_images/t2gExample-1.png
from manim import *

class t2gExample(Scene):
    def construct(self):
        t2gindices = Text(
            'Hello',
            t2g={
                '[1:-1]': (RED,GREEN),
            },
        ).move_to(LEFT)
        t2gwords = Text(
            'World',
            t2g={
                'World':(RED,BLUE),
            },
        ).next_to(t2gindices, RIGHT)
        self.add(t2gindices, t2gwords)

设置行距(Setting Line Spacing) #

您可以使用 line_spacing属性设置行距:

Example: LineSpacing

../_images/LineSpacing-1.png
from manim import *

class LineSpacing(Scene):
    def construct(self):
        a = Text("Hello\nWorld", line_spacing=1)
        b = Text("Hello\nWorld", line_spacing=4)
        self.add(Group(a,b).arrange(LEFT, buff=5))

禁用连字(Disabling Ligatures) #

通过禁用连字,您将获得字符和子对象之间的一对一映射。这解决了对文本进行着色的问题。

Warning

请注意,对于严重依赖连字的文本(如阿拉伯文本),使用此方法可能会产生意外的结果。

您可以通过将 disable_ligatures 传递给 Text 来禁用连字。例如:

Example: DisableLigature

../_images/DisableLigature-1.png
from manim import *

class DisableLigature(Scene):
    def construct(self):
        li = Text("fl ligature",font_size=96)
        nli = Text("fl ligature", disable_ligatures=True, font_size=96)
        self.add(Group(li, nli).arrange(DOWN, buff=.8))

迭代文本(Iterating Text#

Text 对象的行为类似于VGroups。 因此,您可以对文本进行切片和索引。

例如,您可以通过迭代文本的每个字母来将它们设置为不同的颜色。

Example: IterateColor

../_images/IterateColor-1.png
from manim import *

class IterateColor(Scene):
    def construct(self):
        text = Text("Colors", font_size=96)
        for letter in text:
            letter.set_color(random_bright_color())
        self.add(text)

Warning

请注意,这里Ligature连字可能会导致问题。 如果您需要一个字符到子对象的一对一映射,您应该将 disable_ligatures 参数传递给 Text。请参阅Disabling Ligatures禁用连字

使用 MarkupText#

MarkupText 与 Text 相似, 它们之间唯一的区别在于 MarkupText 接受并处理 PangoMarkup(类似于 HTML),而不仅仅呈现纯文本。

有关 PangoMarkup 的更多详细信息和更多参考,请参阅MarkupText的文档。

Example: MarkupTest

../_images/MarkupTest-1.png
from manim import *

class MarkupTest(Scene):
    def construct(self):
        text = MarkupText(
            f'<span underline="double" underline_color="green">double green underline</span> in red text<span fgcolor="{YELLOW}"> except this</span>',
            color=RED,
            font_size=34
        )
        self.add(text)

使用 LaTeX 的文本#

就像您可以使用 Text 向视频中添加文本一样,您可以使用 Tex 插入 LaTeX。

比如,

Example: HelloLaTeX

../_images/HelloLaTeX-1.png
from manim import *

class HelloLaTeX(Scene):
    def construct(self):
        tex = Tex(r"\LaTeX", font_size=144)
        self.add(tex)

注意

请注意,我们使用原始字符串(r'...')而不是常规字符串('...')。 这是因为 TeX 代码使用了许多特殊字符 - 例如 \ - 它们在常规 Python 字符串中具有特殊含义。另一种选择是使用 \\转义反斜杠:Tex('\\LaTeX')

使用MathTex#

默认情况下,传递给 MathTex 的所有内容都处于数学模式下。 更精确地说, MathTexalign* 环境中进行处理。 您可以使用 $ 符号将您的公式括在其中,在 Tex 中实现类似的效果:$ 符号: $\xrightarrow{x^6y^8}$

Example: MathTeXDemo

../_images/MathTeXDemo-1.png
from manim import *

class MathTeXDemo(Scene):
    def construct(self):
        rtarrow0 = MathTex(r"\xrightarrow{x^6y^8}", font_size=96)
        rtarrow1 = Tex(r"$\xrightarrow{x^6y^8}$", font_size=96)

        self.add(VGroup(rtarrow0, rtarrow1).arrange(DOWN))

LaTeX 命令和关键字参数#

我们可以在 AMS 数学包中使用任何标准 LaTeX 命令,例如 mathtt 数学文本类型或 looparrowright 箭头。

Example: AMSLaTeX

../_images/AMSLaTeX-1.png
from manim import *

class AMSLaTeX(Scene):
    def construct(self):
        tex = Tex(r'$\mathtt{H} \looparrowright$ \LaTeX', font_size=144)
        self.add(tex)

在 Manim 方面,Tex 类还接受属性来更改输出的外观。 这与 Text 类非常相似。 例如,color 关键字可以更改 TeX mobject 的颜色。

Example: LaTeXAttributes

../_images/LaTeXAttributes-1.png
from manim import *

class LaTeXAttributes(Scene):
    def construct(self):
        tex = Tex(r'Hello \LaTeX', color=BLUE, font_size=144)
        self.add(tex)

额外的 LaTeX 包#

有些命令需要将特殊的包加载到 TeX 模板中。 例如,要使用 mathscr字体,我们需要添加mathrsfs包。由于此包默认未加载到 Manim 的 TeX 模板中,因此我们需要手动添加它。

Example: AddPackageLatex

../_images/AddPackageLatex-1.png
from manim import *

class AddPackageLatex(Scene):
    def construct(self):
        myTemplate = TexTemplate()
        myTemplate.add_to_preamble(r"\usepackage{mathrsfs}")
        tex = Tex(
            r"$\mathscr{H} \rightarrow \mathbb{H}$}",
            tex_template=myTemplate,
            font_size=144,
        )
        self.add(tex)

子字符串和部分 #

TeX mobject 可以接受多个字符串作为参数。之后,您可以通过它们的索引(例如 tex[1])或选择 tex 代码的部分来引用各个部分。在这个例子中,我们使用 set_color_by_tex()来设置 \bigstar 的颜色:

Example: LaTeXSubstrings

../_images/LaTeXSubstrings-1.png
from manim import *

class LaTeXSubstrings(Scene):
    def construct(self):
        tex = Tex('Hello', r'$\bigstar$', r'\LaTeX', font_size=144)
        tex.set_color_by_tex('igsta', RED)
        self.add(tex)

请注意,set_color_by_tex()会着色包含 Tex 的整个子字符串, 而不仅仅是特定的符号或 Tex 表达式。请考虑以下示例:

Example: IncorrectLaTeXSubstringColoring

../_images/IncorrectLaTeXSubstringColoring-1.png
from manim import *

class IncorrectLaTeXSubstringColoring(Scene):
    def construct(self):
        equation = MathTex(
            r"e^x = x^0 + x^1 + \frac{1}{2} x^2 + \frac{1}{6} x^3 + \cdots + \frac{1}{n!} x^n + \cdots"
        )
        equation.set_color_by_tex("x", YELLOW)
        self.add(equation)

正如您所看到的,这将整个等式着成了黄色,而不是预期的结果。为了仅将 x 着色为黄色,我们需要执行以下操作:

Example: CorrectLaTeXSubstringColoring

../_images/CorrectLaTeXSubstringColoring-1.png
from manim import *

class CorrectLaTeXSubstringColoring(Scene):
    def construct(self):
        equation = MathTex(
            r"e^x = x^0 + x^1 + \frac{1}{2} x^2 + \frac{1}{6} x^3 + \cdots + \frac{1}{n!} x^n + \cdots",
            substrings_to_isolate="x"
        )
        equation.set_color_by_tex("x", YELLOW)
        self.add(equation)

通过将substrings_to_isolate设置为 x,我们自动将 MathTex分解为子字符串,并将 x 组件分离为单独的子字符串。只有在这种情况下, set_color_by_tex() 才能用于实现所需的结果。

请注意,Manim 还支持一种自定义语法,可以轻松将 TeX 字符串拆分为子字符串:只需用双括号括起要隔离的公式部分即可。 在字符串 MathTex(r"{{ a^2 }} + {{ b^2 }} = {{ c^2 }}"), 中,渲染的 mobject 将包含子字符串 a^2, +, b^2, =, 和 c^2。这使得使用 TransformMatchingTex 在类似文本片段之间进行转换变得更加容易。

使用 index_labels 处理复杂字符串#

有时您可能正在处理非常复杂的 MathTex,这使得难以处理其各个组件。这就是调试函数 index_labels() 非常有用的地方。

该方法显示 mobject 的子对象的索引,使您可以轻松找到要更改的 mobject 组件。

Example: IndexLabelsMathTex

../_images/IndexLabelsMathTex-1.png
from manim import *

class IndexLabelsMathTex(Scene):
    def construct(self):
        text = MathTex(r"\binom{2n}{n+2}", font_size=96)

        # index the first (and only) term of the MathTex mob
        self.add(index_labels(text[0]))

        text[0][1:3].set_color(YELLOW)
        text[0][3:6].set_color(RED)
        self.add(text)

LaTeX 数学字体 - 模板库#

在排版数学公式时更改 LaTeX 字体比普通文本更棘手。这需要更改用于编译 TeX 的模板。 Manim 提供了一系列 TexFontTemplates,供您使用。这些模板都可以在数学模式下使用:

Example: LaTeXMathFonts

../_images/LaTeXMathFonts-1.png
from manim import *

class LaTeXMathFonts(Scene):
    def construct(self):
        tex = Tex(
            r"$x^2 + y^2 = z^2$",
            tex_template=TexFontTemplates.french_cursive,
            font_size=144,
        )
        self.add(tex)

Manim 还有一个 TexTemplateLibrary, 其中包含 3Blue1Brown 使用的 TeX 模板。其中一个示例是用于排版中文的 ctex 模板。 为此,您的系统必须安装 ctex LaTeX 包。此外,如果您只需要排版文本,可能根本不需要 Tex,应该使用 Text

Example: LaTeXTemplateLibrary

../_images/LaTeXTemplateLibrary-1.png
from manim import *

class LaTeXTemplateLibrary(Scene):
    def construct(self):
        tex = Tex('Hello 你好 \\LaTeX', tex_template=TexTemplateLibrary.ctex, font_size=144)
        self.add(tex)

对齐公式(Aligning formulae)#

MathTex mobject 是在 LaTeX align*环境中排版的。这意味着在排版多行公式时,您可以使用 & 对齐字符:

Example: LaTeXAlignEnvironment

../_images/LaTeXAlignEnvironment-1.png
from manim import *

class LaTeXAlignEnvironment(Scene):
    def construct(self):
        tex = MathTex(r'f(x) &= 3 + 2 + 1\\ &= 5 + 1 \\ &= 6', font_size=96)
        self.add(tex)