manim使用记录

just for play

Posted by Doni Daniel on March 25, 2020

#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. 使用时应导入库文件

    1
    
     import manimlib.imports import *
    
  2. 文件名与类名应保持一致
  3. 必须继承自 Scene 或其子类
  4. 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()

###结果展示

####提炼知识点

  1. 整体程序有三个步骤:创建实例,定位初始位置,播放实例
  2. 定位方法使用: UP DOWN LEFT RIGHT
  3. 调用 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)

###结果展示

####提炼知识点

  1. 定位使用 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)

###结果展示

####提炼知识点

  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)

####结果展示

####提炼知识点

  1. 函数作图继承的父类是 GraphScene
  2. 新配置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) 完全更换变换