#manim使用记录 ##安装
###创建虚拟环境
1
2
conda create -n [env_name] python=3.7
conda activate [env_name]
###安装必要环境
1
2
3
4
5
6
7
brew install cairo
brew install pkg-config
pip3 install sox
pip3 install ffmpeg
pip3 install latex
pip3 install pycairo
pip3 install -r requirements.txt
####pip3安装对照表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- python=3.7
- cairo
- ffmpeg
- colour==0.1.5
- numpy==1.15.0
- pillow==5.2.0
- scipy==1.1.0
- tqdm==4.24.0
- opencv==3.4.2
- pycairo==1.18.0
- pydub==0.23.0
- ffmpeg
- pip:
- pyreadline
###克隆 Manim 存储库
1
git clone https://github.com/3b1b/manim.git
##配置修改 ###存储位置修改
1
2
3
4
5
6
7
8
9
10
# manimlib/constants.py
# 替换 Dropbox(3Blue1Brown)/ 3Blue1Brown Team Folder 为需要保存的路径
# 以下为样例代码
if config["media_dir"]:
MEDIA_DIR = config["media_dir"]
else:
MEDIA_DIR = os.path.join(
os.path.expanduser('~'),
"Documents/mkVideo/manimOutput"
)
###编译配置修改
1
2
# 修改TEX_USE_CTEX 以支持中文
TEX_USE_CTEX = True
##一. 基本使用与样例 ###经典程序 HelloWorld
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env python
# coding=utf-8
# HelloWorld.py
from manimlib.imports import *
class HelloWorld(Scene):
def construct(self):
helloworld = TextMobject("HelloWorld!", color=RED)
rectangle = Rectangle(color=BLUE)
rectangle.surround(helloworld)
group1 = VGroup(helloworld, rectangle)
hellomanim = TextMobject("Hello Manim", color=BLUE)
hellomanim.scale(2.5)
self.play(Write(helloworld))
self.wait(1)
self.play(FadeIn(rectangle))
self.wait(1)
self.play(ApplyMethod(group1.scale, 2.5))
self.wait(1)
self.play(Transform(helloworld, hellomanim))
self.wait(1)
###结果展示
####提炼知识点
-
使用时应导入库文件
1
import manimlib.imports import *
- 文件名与类名应保持一致
- 必须继承自 Scene 或其子类
- manim 引擎会主动调用 construct 方法
新应用类 | 用途 | e.g. |
---|---|---|
TextMobject(TexMobject) | 显示普通文本 | TextMobject(“HelloWorld!”, color=RED) |
Rectangle(Polygon) | 矩形类 | Rectangle(color=BLUE) |
VGroup(VMobject) | 组合SVG和图形类 | VGroup(helloworld, rectangle) |
Write(DrawBorderThenFill) | 通常用来创建文本 | self.play(Write(helloworld)) |
Transform(Animation) | 转化为另一个图形 | self.play(Transform(helloworld, hellomanim)) |
FadeIn(Transform) | 显现 | self.play(FadeIn(rectangle)) |
ApplyMethod(Transform) | 修改图形的属性 | self.play(ApplyMethod(group1.scale, 2.5)) |
新应用方法 | 用途 | e.g. |
---|---|---|
surround(mobject) | 设置环绕 | rectangle.surround(helloworld) |
scale(scale_factor) | 设定大小比例 | hellomanim.scale(2.5) |
play(*args, **kwargs) | 播放 | self.play(Write(helloworld)) |
wait(duration=DEFAULT_WAIT_TIME, stop_condition=None) | 图像静止 | self.wait(1) |
###基础图形样例 baseShape.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ring = Annulus(inner_radius=.4, outer_radius=1, color=BLUE)
square = Square(color=ORANGE, fill_color=ORANGE, fill_opacity=0.5)
rect = Rectangle(height=3.2, width=1.2, color=PINK, fill_color=PINK, fill_opacity=0.5)
line01 = Line(np.array([0, 3.6, 0]), np.array([0, 2, 0]), color=BLUE)
line02 = Line(np.array([-1, 2, 0]), np.array([-1, -1, 0]), color=BLUE)
line03 = Line(np.array([1, 2, 0]), np.array([1, 0.5, 0]), color=BLUE)
ring.shift(UP * 2)
square.shift(LEFT + DOWN * 2)
rect.shift(RIGHT + DOWN * (3.2 / 2 - 0.5))
self.add(line01)
self.play(GrowFromCenter(ring))
self.wait(0.5)
self.play(FadeIn(line02), FadeIn(line03))
self.wait(0.5)
self.play(FadeInFromDown(square))
self.play(FadeInFromDown(rect))
self.wait()
###结果展示
####提炼知识点
- 整体程序有三个步骤:创建实例,定位初始位置,播放实例
- 定位方法使用: UP DOWN LEFT RIGHT
- 调用 play 函数的参数个数及调用顺序来控制播放实例
新应用类 | 用途 | e.g. |
---|---|---|
Annulus(Circle) | 环形类 | Annulus(inner_radius=.4, outer_radius=1, color=BLUE) |
Square(Rectangle) | 方形类 | Square(color=ORANGE, fill_color=ORANGE, fill_opacity=0.5) |
Line(TipableVMobject) | 线形类 | Line(np.array([0, 3.6, 0]), np.array([0, 2, 0]), color=BLUE) |
GrowFromCenter(GrowFromPoint) | 从中间出现 | self.play(GrowFromCenter(ring)) |
FadeInFromDown(FadeInFrom) | 从下面渐入 | self.play(FadeInFromDown(square)) |
新应用方法 | 用途 | e.g. |
---|---|---|
shift(*vectors) | 移动对象 | ring.shift(UP * 2) |
add(*mobjects) | 添加对象 | self.add(line01) |
###射击样例 shoot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
circle01 = Circle(color=BLUE)
circle02 = Circle(color=RED, fill_color=RED, fill_opacity=1)
circle02.scale(0.1)
line01 = Line(np.array([-1, 0, 0]), np.array([1, 0, 0]), color=RED)
line02 = Line(np.array([0, 1, 0]), np.array([0, -1, 0]), color=RED)
aim_scope = VGroup(circle01, circle02, line01, line02)
target_list = []
for i in range(3):
for j in range(5):
target_ij = Circle(color=YELLOW, fill_color=YELLOW, fill_opacity=0.4)
target_ij.scale(0.4)
target_ij.shift(np.array([-4 + j * 2, -2 + i * 2, 0]))
self.play(FadeIn(target_ij))
target_list.append(target_ij)
self.wait(1)
def shoot_ij(i, j):
target_ij = target_list[j + i * 5]
self.play(ApplyMethod(aim_scope.next_to, target_ij, 0))
self.play(ApplyMethod(target_ij.set_fill, GREY), ApplyMethod(target_ij.set_color, GREY))
self.wait(0.5)
ij = TextMobject("(%d, %d)" % (i, j), color=GREY)
ij.next_to(target_ij, DOWN)
self.play(Write(ij))
self.wait(1)
return 0
self.add(aim_scope)
self.play(ApplyMethod(aim_scope.shift, DOWN*3 + LEFT*6.1))
shoot_ij(0, 1)
shoot_ij(2, 0)
shoot_ij(1, 3)
shoot_ij(0, 0)
shoot_ij(2, 4)
###结果展示
####提炼知识点
- 定位使用 np.array 与 UP DOWN LEFT RIGHT 等价:
- np.array([-4, -2, 0] <=> LEFT * 4 + DOWN * 2
新应用类 | 用途 | e.g. |
---|---|---|
Circle(Arc) | 圆形类 | Circle(color=BLUE) |
新应用方法 | 用途 | e.g. |
---|---|---|
next_to(self, mobject_or_point, direction=RIGHT, buff=DEFAULT_MOBJECT_TO_MOBJECT_BUFFER, aligned_edge=ORIGIN, submobject_to_align=None, index_of_submobject_to_align=None, coor_mask=np.array([1, 1, 1])) | 设定相对位置 | ij.next_to(target_ij, DOWN) |
###小成品 loveDeathRobots.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 创建基础图形
circle01 = Circle(fill_color=RED, color=RED, fill_opacity=0.5)
circle02 = Circle(fill_color=RED, color=RED, fill_opacity=0.5)
square01 = Square(fill_color=RED, color=RED, fill_opacity=0.5)
love = VGroup(circle01, circle02, square01)
rect01 = Rectangle(height=0.8, width=4, fill_color=RED, color=RED, fill_opacity=0.5)
rect02 = Rectangle(height=0.8, width=4, fill_color=RED, color=RED, fill_opacity=0.5)
death = VGroup(rect01, rect02)
square02 = Square(fill_color=RED, color=RED, fill_opacity=0.5)
square02.scale(1.6)
circle03 = Circle(fill_color=BLACK, color=RED, fill_opacity=0.5)
circle04 = Circle(fill_color=BLACK, color=RED, fill_opacity=0.5)
circle03.scale(0.45)
circle04.scale(0.45)
robots = VGroup(square02, circle03, circle04)
line01 = Line(np.array([-6, -2.4, 0]), np.array([6, -2.4, 0]), color=RED)
line01.set_height(0.2)
text01 = TextMobject("LOVE\nDEATH\n\&\nROBOTS", color=RED)
text01.scale(1.8)
group_all = VGroup(love, death, robots, line01, text01)
1
2
3
4
5
6
7
8
9
10
# 初始化位置 默认中间位置
circle01.shift((UP + LEFT) * np.sqrt(2) / 2)
circle02.shift((UP + RIGHT) * np.sqrt(2) / 2)
square01.rotate(np.pi / 4)
rect01.rotate(np.pi / 4)
rect02.rotate(-np.pi / 4)
circle03.shift(np.array([-0.72, 0.6, 0]))
circle04.shift(np.array([0.72, 0.6, 0]))
robots.shift(RIGHT * 4)
text01.shift(DOWN * 2.5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 定义出现及播放顺序
self.play(ShowCreation(circle01), ShowCreation(circle02), ShowCreation(square01))
self.wait(1)
self.play(ApplyMethod(love.shift, LEFT * 4))
self.wait(1)
self.play(ShowCreation(rect01), ShowCreation(rect02))
self.wait(1)
self.play(ShowCreation(square02))
self.play(ShowCreation(circle03), ShowCreation(circle04))
self.wait(1)
self.play(ApplyMethod(love.set_opacity, 1), ApplyMethod(death.set_opacity, 1),
ApplyMethod(robots.set_opacity, 1))
self.wait(1)
self.play(ShowCreation(line01))
self.wait(1)
self.play(Transform(line01, text01))
self.wait(1)
self.play(ApplyMethod(group_all.shift, UP * 0.5))
self.wait(1)
###结果展示
####提炼知识点
- 定位使用 np.array 与 UP DOWN LEFT RIGHT 等价:
- np.array([-4, -2, 0] <=> LEFT * 4 + DOWN * 2
新应用类 | 用途 | e.g. |
---|---|---|
ShowCreation(ShowPartial) | 创建并显示 | self.play(ShowCreation(square02)) |
新应用方法 | 用途 | e.g. |
---|---|---|
rotate(self, angle, axis=OUT, **kwargs) | 旋转对象 | square01.rotate(np.pi / 4) |
###文字动画 quote.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
quote01 = TextMobject("写代码真是有趣呢~T\_T", color=RED)
quote01.to_edge(UP)
quote02 = TextMobject("苦逼的一个字母字母的敲\nT\_T\n", color=BLUE)
author = TextMobject("——\nDoni\nDaniel")
author.next_to(quote01.get_corner(DOWN + RIGHT), DOWN)
self.add(quote01)
self.add(author)
self.wait(2)
self.play(Transform(quote01, quote02),
ApplyMethod(author.move_to, quote02.get_corner(DOWN + RIGHT) + DOWN + 2 * LEFT))
self.play(ApplyMethod(author.scale, 1.6))
author.match_color(quote02)
self.play(FadeOut(quote01), FadeOut(author))
self.wait()
###结果展示
####提炼知识点 |新应用类|用途|e.g.| |—|—|—| |FadeOut(Transform)|淡出|self.play(FadeOut(quote01), FadeOut(author))|
新应用方法 | 用途 | e.g. |
---|---|---|
to_edge(self, edge=LEFT, buff=DEFAULT_MOBJECT_TO_EDGE_BUFFER) | 移动对象 | quote01.to_edge(UP) |
get_corner(self, direction) | 获取右下角 | author.next_to(quote01.get_corner(DOWN + RIGHT), DOWN) |
move_to(self, point_or_mobject, aligned_edge=ORIGIN, coor_mask=np.array([1, 1, 1])) | 移动到 | ApplyMethod(author.move_to, quote02.get_corner(DOWN + RIGHT) + DOWN + 2 * LEFT)) |
###文字动画2 textMove.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
square = Square(side_length=5, fill_color=BLUE, fill_opacity=0.5)
label=TextMobject("扭一下身子")
label.bg = BackgroundRectangle(label, fill_opacity=1)
label_group = VGroup(label.bg, label)
label_group.rotate(TAU / 8)
label2 = TextMobject("加个边框", color=BLACK)
label2.bg = SurroundingRectangle(label2, color=BLUE, fill_color=RED, fill_opacity=0.5)
label2_group = VGroup(label2, label2.bg)
label2_group.next_to(label_group, DOWN)
label3 = TextMobject("变成彩虹")
label3.scale(1.8)
label3.set_color_by_gradient(RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE)
label3.to_edge(DOWN)
self.add(square)
self.play(FadeIn(label_group))
self.play(FadeIn(label2_group))
self.play(FadeIn(label3))
self.wait()
###结果展示
####提炼知识点 |新应用类|用途|e.g.| |—|—|—| |SurroundingRectangle(Rectangle)|环绕矩形类|SurroundingRectangle(label2, color=BLUE, fill_color=RED, fill_opacity=0.5)| |BackgroundRectangle(SurroundingRectangle)|背景矩形类|label.bg = BackgroundRectangle(label, fill_opacity=1)|
新应用方法 | 用途 | e.g. |
---|---|---|
set_color_by_gradient(self, *colors) | 设定颜色梯度 | label3.set_color_by_gradient(RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE) |
##二、数学公式与图像基础 ###小练习 Latex.py
1
2
3
4
5
6
7
8
title = TextMobject("This is some \\LaTeX")
basel = TexMobject(
"\\sum_{n=1}^\\infty "
"\\frac{1}{n^2} = \\frac{\\pi^2}{6}"
)
VGroup(title, basel).arrange(DOWN)
self.play(Write(title), FadeInFrom(basel, UP))
self.wait()
####结果展示
####提炼知识点 |新应用类|用途|e.g.| |—|—|—| |TexMobject(SingleStringTexMobject)|Tex文本类|basel = TexMobject(“\sum_{n=1}^\infty “ “\frac{1}{n^2} = \frac{\pi^2}{6}”)| |FadeInFrom(Transform)|从某位置淡入|self.play(Write(title), FadeInFrom(basel, UP))|
####符号表参考网址:Art of Problem Solving
###立方和公式 cubicSum.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
equal = TextMobject("=", color=RED)
eq_left01 = TextMobject("$1^3+2^3+3^3+\\quad\\dots\\quad+n^3$", color=GREEN)
eq_right01 = TextMobject("$(1+2+3+\\quad\\dots\\quad+n)^2$", color=YELLOW)
eq_left02 = TextMobject("$\Sigma_{i=1}^{n} i^3$", color=GREEN)
eq_right02 = TextMobject("$(\Sigma_{i=1}^{n} i)^{2}$", color=YELLOW)
equation02 = VGroup(equal, eq_left02, eq_right02)
eq_left01.next_to(equal, LEFT)
eq_right01.next_to(equal, RIGHT)
eq_left02.next_to(equal, LEFT)
eq_right02.next_to(equal, RIGHT)
self.play(FadeIn(eq_left01), FadeIn(equal), FadeIn(eq_right01))
self.wait(1)
self.play(ReplacementTransform(eq_left01, eq_left02))
self.play(ReplacementTransform(eq_right01, eq_right02))
self.wait(1)
self.play(ApplyMethod(equation02.scale, 2.4))
self.wait(1)
####结果展示
####提炼知识点 |新应用类|用途|e.g.| |—|—|—| |ReplacementTransform(Transform)|更换变换(完全替换,不影响其他操作)|self.play(ReplacementTransform(eq_left01, eq_left02))|
###函数图像 funcGraph.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class funcGraph(GraphScene):
CONFIG = {
"x_min": -10,
"x_man": 10.3,
"y_min": -1.5,
"y_max": 1.5,
"graph_origin": ORIGIN,
"function_color": RED,
"axes_color": GREEN,
"x_labeled_nums": range(-10, 12, 2),
}
def construct(self):
self.setup_axes(animate=True)
func_graph1 = self.get_graph(self.func_to_graph1, self.function_color)
func_graph2 = self.get_graph(self.func_to_graph2)
vert_line = self.get_vertical_line_to_graph(TAU, func_graph1, color=YELLOW)
graph_lab = self.get_graph_label(func_graph1, label = "\\cos(x)")
graph_lab2 = self.get_graph_label(func_graph2, label = "\\sin(x)", x_val=-10, direction=UP/2)
two_pi = TexMobject("x = 2 \\pi")
label_coord = self.input_to_graph_point(TAU, func_graph1)
two_pi.next_to(label_coord, RIGHT+UP)
self.play(ShowCreation(func_graph1), ShowCreation(func_graph2))
self.play(ShowCreation(vert_line), ShowCreation(graph_lab),
ShowCreation(graph_lab2), ShowCreation(two_pi))
def func_to_graph1(self, x):
return np.cos(x)
def func_to_graph2(self, x):
return np.sin(x)
####结果展示
####提炼知识点
- 函数作图继承的父类是 GraphScene
- 新配置CONFIG变量,可以设定类的私有变量
新应用方法 | 用途 | e.g. |
---|---|---|
setup_axes(self, animate=False) | 设定坐标轴是否绘制 | self.setup_axes(animate=True) |
get_graph(func, color=None, x_min=None, x_max=None, **kwargs) | 绘制函数 | self.get_graph(self.func_to_graph1, self.function_color) |
get_vertical_line_to_graph(x, graph, line_class=Line, **line_kwargs) | 绘制纵向线 | self.get_vertical_line_to_graph(TAU, func_graph1, color=YELLOW) |
get_graph_label(graph, label=”f(x)”, x_val=None, direction=RIGHT, buff=MED_SMALL_BUFF, color=None) | 绘制图标签 | self.get_graph_label(func_graph1, label = “\cos(x)”) |
input_to_graph_point(x, graph) | 获取坐标 | self.input_to_graph_point(TAU, func_graph1) |
##manim类参考手册
基础类 | 函数 | 用途 |
---|---|---|
Container | Container(object) | Composite模式通用基类 |
Scene | Scene(Container) | 应用场景基类 |
play(*args, **kwargs) | 播放 | |
wait(duration=DEFAULT_WAIT_TIME, stop_condition=None) | 停止画面 | |
GraphScene | GraphScene(Scene) | 图绘制基类 |
setup_axes(animate=False) | 绘制坐标轴动画 |
Mobject类 | 函数 | 用途 |
---|---|---|
Mobject | Mobject(Container) | 应用对象基类 |
set_color(color) | 设定颜色 | |
set_width(width) | 设定宽度 | |
set_opacity(opacity) | 设定透明度 | |
set_color_by_gradient(self, *colors) | 设定颜色梯度 | |
surround(mobject) | 设定环绕 | |
scale(scale_factor) | 等比放大 | |
shift(*vectors) | 移动对象 | |
next_to(self, mobject_or_point, direction=RIGHT, buff=DEFAULT_MOBJECT_TO_MOBJECT_BUFFER, aligned_edge=ORIGIN, submobject_to_align=None, index_of_submobject_to_align=None, coor_mask=np.array([1, 1, 1])) | 设定相对位置 | |
rotate(self, angle, axis=OUT, **kwargs) | 旋转对象 | |
to_edge(self, edge=LEFT, buff=DEFAULT_MOBJECT_TO_EDGE_BUFFER) | 移动对象 | |
get_corner(self, direction) | 获取右下角 | |
move_to(self, point_or_mobject, aligned_edge=ORIGIN, coor_mask=np.array([1, 1, 1])) | 移动到 | |
Group | Group(Mobject) | Composite模式组合类 |
types类 | ||
VMobject | VMobject(Mobject) | 未重写构造函数 |
VGroup | VGroup(VMobject) | 组合SVG和图形类 |
SVG类 | ||
SVGMobject | SVGMobject(VMobject) | 接口类 |
SingleStringTexMobject | SingleStringTexMobject(SVGMobject) | 单行文本类 |
TexMobject | TexMobject(SingleStringTexMobject) | Tex文本类 |
TextMobject | TextMobject(TexMobject) | 显示普通文本 |
几何(geometry)类 | 函数 | 用途 |
---|---|---|
Polygon | Polygon(VMobject) | 多边形类 |
Rectangle | Rectangle(color=BLUE) | 矩形类 |
SurroundingRectangle | SurroundingRectangle(Rectangle) | 环绕矩形类 |
BackgroundRectangle | BackgroundRectangle(SurroundingRectangle) | 背景矩形类 |
Square | Square(Rectangle) | 方形类 |
TipableVMobject | TipableVMobject(VMobject) | 尖端类 |
Line | Line(TipableVMobject) | 线形类 |
Arc | Arc(TipableVMobject) | 弧形 |
Circle | Circle(Arc) | 圆形类 |
Annulus | Annulus(Circle) | 环形类 |
animation类 | 函数 | 用途 |
---|---|---|
Animation | Animation(object) | 动作基类 |
DrawBorderThenFill | DrawBorderThenFill(Animation) | 复合类 |
Write | Write(DrawBorderThenFill) | 通常用来创建文本 |
Transform | Transform(Animation) | 将一个图形转化为另一个图形 |
FadeIn | FadeIn(Transform) | 淡入 |
FadeInFrom | FadeInFrom(Transform) | 从某位置淡入 |
FadeOut | FadeOut(Transform) | 淡出 |
ApplyMethod | ApplyMethod(Transform) | 已有图形的变化 |
GrowFromPoint | GrowFromPoint(Transform) | 从点出现 |
GrowFromCenter | GrowFromCenter(GrowFromPoint) | 从中间出现 |
ShowPartial | ShowPartial(Animation) | 抽象类 |
ShowCreation | ShowCreation(ShowPartial) | 创建并显示 |
ReplacementTransform | ReplacementTransform(Transform) | 完全更换变换 |