ManimCE的安装与配置——让数学舞蹈
前言
简介
Manim是一个用于解释数学的开源动画制作引擎,由Manim社区进行维护。
Manim由斯坦福大学数学高材生/教授Grant Sanderson创建,其最经典的成果就是发布于Youtube的3Blue1Brown(简称:3b1b)频道的一系列视频,用于解说高等数学、线性代数、概率统计等内容。
Grant Sanderson已经将Manim动画引擎的源代码开源到github,但其本人不承诺对后续的代码进行维护、升级。
Github-3Blue1Brown
较为幸运的是,3b1b系列视频发布之后,在广大数学爱好者和数据分析师中有巨大的反响,不断有维护者对初代Manim进行升级,甚至给出了Manim的安装使用例程,便于更方便的应用Manim系列引擎进行数学讲解。
发展
最初由Grand Sanderson发布的Manim只能在命令行下运行,安装时依赖较多的Python包和第三方工具进行制作和渲染,很多初学者在不了解Python和Latex的情况下,几乎迈不出第一步。
Manin的开发者们后期一直致力于精确动画引擎的升级与优化,在这两年中,manim 的 Github 项目发生了很大的变化,并衍生出了三个主要版本,分别是 manimCairo、manimGL、manimCE。
manimCairo
manim 的早期版本,该版本自 2020 年 末已经停止了更新维护。
manimGL
该版本由 Grant Sanderson 主要负责维护。该版本已近趋于稳定,但还尚未完成。
manimCE
由 2020 年中旬的一个 manim 分支演化而来,该分支后来社区化,被称为是 manim Community Edition ,缩写为 manimCE。
这是 manim 当前的一个最为稳定的版本,相对于早期版本,其在语法结构上做了大量优化,并简化了安装步骤。由于参与者更多,所以其更新维护最为频繁,一些常见的 BUG 能在较短的时间内被解决,所以更加适合新手上手。
组成
Manim主要由以下这些部分组成
在其中,Python是连接Manim各个部件的核心;然后是Latex,是一种公式编辑语言,常用于书写学术论文;再然后是Cairo,是Python的一个包,用于绘制图形的程序;还有FFmpeg,是图像的渲染工具,如果你使用过Captura这个录像工具,就会看到FFmpeg这个渲染选项;最后是SoX,用于处理音频。
尽管Manim有这么多组成部分,但实际上并不需要用户去学会每一个部件的原理和使用,而是只要懂一些Python的基本语法,其他部件只要安装在你的电脑上就可,甚至像SoX这个音频处理软件,可以不使用。这样你就可以使用Manim系列引擎制作自己短视频了。
注意事项
本文主要讲解ManimCE的安装与调试过程,尽管ManimCE和Manim出自同一个引擎,但是ManimCE和Manim可能会有相互不兼容的语句或者组件存在,这意味着你必须完全按照ManimCE的一整套流程进行操作。
最终二者可以做出相同的动画。
本文进行所有组件的安装的时候,都不要有中文路径,否则会出现错误。
安装过程
安装Python
一般来说,一台电脑基本不会随时去更新Python到最新的版本,而ManimCE仅仅对Python3版本有较好的兼容性。当你电脑中安装有Python2的时候,也许你不会愿意去卸载重新安装Python3。
在这里,我推荐使用Anaconda的虚拟环境,相当于一个独立的小房间,里面的Python和Python包可以随意安装,并不会和电脑本身的Python版本冲突。
你可以直接搜索Anaconda3,双击进行安装。
我们要使用的是Anaconda Prompt这个工具,打开之后是黑色的命令行。
需要注意的是,这里安装好Anaconda之后,需要找到conda.exe这个文件,然后将其路径复制到环境变量中。
创建并激活虚拟环境
在Anaconda Prompt下输入如下命令(若有提示,请输入y):
conda create -n manimCE
执行完成之后,Anaconda会创建一个虚拟环境,然后运行如下命令,进入到该虚拟环境下,运行成功后你会看见前面有一个圆括号,里面是(manimCE)字样,这说明你成功的进入了manimCE虚拟环境。
conda activate manimCE
ManimCE仅支持Python3.7-3.9,我们在虚拟环境下运行:
conda install python=3.9
这样,虚拟环境下会安装3.9版本的Python。
然后输入:
python --version
查看python版本,如果出现python 3.9.7或者类似的,只要是Python3.9即说明虚拟环境下Python安装成功。
安装FFmPeg
在虚拟环境下,直接输入如下命令:
conda install ffmpeg
输入y完成安装,这里可能会比较慢,请耐心等待。
安装Manim
直接在虚拟环境下输入:
pip install manim
输入y等待安装完成。
安装MikTeX
实际上MikTex是latex的一个发行版本,由于原作者Grand即使用MikTeX,为了降低出错的概率,这里同样使用MikTeX。
进入如下网站下载并且安装MikTeX即可,安装时候默认安装即可,也可以更改安装路径,但是路径不要有中文。
MikTeX网址
完成引擎安装
当你成功完成如上步骤,并且没有报错的时候,你已经完成了ManimCE动画引擎的安装。这时候你可以退出Anaconda Prompt了。
测试
打开Anaconda Prompt,输入
conda info --envs
查看环境变量。
输入
activate manimCE
进入虚拟环境。成功运行且不报错即可。
总结
尽管你到这里已经成功安装好了ManimCE,但是使用ManimCE引擎进行动画的制作还是路途漫漫,ManimCE的作者(维护团队)也给出了ManimCE的官方例程,但是我并不满足于只运行例程,而是想自己随心所欲的应用ManimCE。我自己也在不断地对Manim引擎进行学习,希望读者也能在自己的使用过程中有进步。
附录——ManimCE例程
#!/usr/bin/env python
from manim import *
# To watch one of these scenes, run the following:
# python --quality m manim -p example_scenes.py SquareToCircle
#
# Use the flag --quality l for a faster rendering at a lower quality.
# Use -s to skip to the end and just save the final frame
# Use the -p to have preview of the animation (or image, if -s was
# used) pop up once done.
# Use -n <number> to skip ahead to the nth animation of a scene.
# Use -r <number> to specify a resolution (for example, -r 1920,1080
# for a 1920x1080 video)
class OpeningManim(Scene):
def construct(self):
title = Tex(r"This is some \LaTeX")
basel = MathTex(r"\sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}")
VGroup(title, basel).arrange(DOWN)
self.play(
Write(title),
FadeIn(basel, shift=DOWN),
)
self.wait()
transform_title = Tex("That was a transform")
transform_title.to_corner(UP + LEFT)
self.play(
Transform(title, transform_title),
LaggedStart(*(FadeOut(obj, shift=DOWN) for obj in basel)),
)
self.wait()
grid = NumberPlane()
grid_title = Tex("This is a grid", font_size=72)
grid_title.move_to(transform_title)
self.add(grid, grid_title) # Make sure title is on top of grid
self.play(
FadeOut(title),
FadeIn(grid_title, shift=UP),
Create(grid, run_time=3, lag_ratio=0.1),
)
self.wait()
grid_transform_title = Tex(
r"That was a non-linear function \\ applied to the grid",
)
grid_transform_title.move_to(grid_title, UL)
grid.prepare_for_nonlinear_transform()
self.play(
grid.animate.apply_function(
lambda p: p
+ np.array(
[
np.sin(p[1]),
np.sin(p[0]),
0,
],
),
),
run_time=3,
)
self.wait()
self.play(Transform(grid_title, grid_transform_title))
self.wait()
class SquareToCircle(Scene):
def construct(self):
circle = Circle()
square = Square()
square.flip(RIGHT)
square.rotate(-3 * TAU / 8)
circle.set_fill(PINK, opacity=0.5)
self.play(Create(square))
self.play(Transform(square, circle))
self.play(FadeOut(square))
class WarpSquare(Scene):
def construct(self):
square = Square()
self.play(
ApplyPointwiseFunction(
lambda point: complex_to_R3(np.exp(R3_to_complex(point))),
square,
),
)
self.wait()
class WriteStuff(Scene):
def construct(self):
example_text = Tex("This is a some text", tex_to_color_map={"text": YELLOW})
example_tex = MathTex(
"\\sum_{k=1}^\\infty {1 \\over k^2} = {\\pi^2 \\over 6}",
)
group = VGroup(example_text, example_tex)
group.arrange(DOWN)
group.width = config["frame_width"] - 2 * LARGE_BUFF
self.play(Write(example_text))
self.play(Write(example_tex))
self.wait()
class UpdatersExample(Scene):
def construct(self):
decimal = DecimalNumber(
0,
show_ellipsis=True,
num_decimal_places=3,
include_sign=True,
)
square = Square().to_edge(UP)
decimal.add_updater(lambda d: d.next_to(square, RIGHT))
decimal.add_updater(lambda d: d.set_value(square.get_center()[1]))
self.add(square, decimal)
self.play(
square.animate.to_edge(DOWN),
rate_func=there_and_back,
run_time=5,
)
self.wait()
class AnimateSyntax(Scene):
def construct(self):
triangle = Triangle(color=RED, fill_opacity=1)
self.play(DrawBorderThenFill(triangle))
self.play(triangle.animate.shift(LEFT))
self.play(triangle.animate.shift(RIGHT).scale(2))
self.play(triangle.animate.rotate(PI/3))
self.play(triangle.animate.set_color(GREEN))
class OpeningManim(Scene):
def construct(self):
title = Tex(r"This is some \LaTeX")
basel = MathTex(r"\sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}")
VGroup(title, basel).arrange(DOWN)
self.play(
Write(title),
FadeIn(basel, shift=UP),
)
self.wait()
transform_title = Tex("That was a transform")
transform_title.to_corner(UP + LEFT)
self.play(
Transform(title, transform_title),
LaggedStart(*[FadeOut(obj, shift=DOWN) for obj in basel]),
)
self.wait()
grid = NumberPlane(x_range=(-10, 10, 1), y_range=(-6.0, 6.0, 1))
grid_title = Tex("This is a grid")
grid_title.scale(1.5)
grid_title.move_to(transform_title)
self.add(grid, grid_title)
self.play(
FadeOut(title),
FadeIn(grid_title, shift=DOWN),
Create(grid, run_time=3, lag_ratio=0.1),
)
self.wait()
grid_transform_title = Tex(
r"That was a non-linear function \\ applied to the grid"
)
grid_transform_title.move_to(grid_title, UL)
grid.prepare_for_nonlinear_transform()
self.play(
grid.animate.apply_function(
lambda p: p + np.array([np.sin(p[1]), np.sin(p[0]), 0])
),
run_time=3,
)
self.wait()
self.play(Transform(grid_title, grid_transform_title))
self.wait()
class PlotExample(Scene):
def construct(self):
plot_axes = Axes(
x_range=[0, 1, 0.05],
y_range=[0, 1, 0.05],
x_length=9,
y_length=5.5,
axis_config={
"numbers_to_include": np.arange(0, 1 + 0.1, 0.1),
"font_size": 24,
},
tips=False,
)
y_label = plot_axes.get_y_axis_label("y", edge=LEFT, direction=LEFT, buff=0.4)
x_label = plot_axes.get_x_axis_label("x")
plot_labels = VGroup(x_label, y_label)
plots = VGroup()
for n in np.arange(1, 20 + 0.5, 0.5):
plots += plot_axes.plot(lambda x: x**n, color=WHITE)
plots += plot_axes.plot(
lambda x: x**(1 / n), color=WHITE, use_smoothing=False
)
extras = VGroup()
extras += plot_axes.get_horizontal_line(plot_axes.c2p(1, 1, 0), color=BLUE)
extras += plot_axes.get_vertical_line(plot_axes.c2p(1, 1, 0), color=BLUE)
extras += Dot(point=plot_axes.c2p(1, 1, 0), color=YELLOW)
title = Title(
r"Graphs of $y=x^{\frac{1}{n}}$ and $y=x^n (n=1, 1.5, 2, 2.5, 3, \dots, 20)$",
include_underline=False,
font_size=40,
)
self.play(Write(title))
self.play(Create(plot_axes), Create(plot_labels), Create(extras))
self.play(AnimationGroup(*[Create(plot) for plot in plots], lag_ratio=0.05))
# See many more examples at https://docs.manim.community/en/stable/examples.html
使用时候,将以下代码复制到Manim文件夹下,命名为:basic.py,并且在该路径进入Anaconda的,激活ManimCE的虚拟环境。在虚拟环境下运行:
#低帧率动画
mainm basic.py -pql
或者
#高帧率动画
mainm basic.py -pqh
也许我制作的这个教程效果并不理想,也许你遇到了其它问题,你可以随时向我的邮箱发送信息共同讨论:
xlxlqqq@163.com