本来想着使用亿图生成一张一张图片做成gif来演示算法, 但是最近发现一个演示算法的好东西: Manim. 这是一个python的库, 专门用来生成复杂的数学图形和动画. 那么接下来一段时间我准备和大家分享一下Manim的使用.
这篇文章简单介绍了Manim的使用, 帮助小白快速上手. 接下来, 我们将直接进入实际操作部分.
使用Manim之前需要安装, 执行命令pip install manim即可. 如果对环境搭建有疑问, 可以在网上搜索相关教程. 如果仍有问题, 欢迎留言, 我会考虑撰写一篇详细的环境搭建教程.
画一个圆
新建一个文件create_circle.py
复制下面代码:
from manim import *
class CreateCircle(Scene):
def construct(self):
circle = Circle() # 创建一个圆
circle.set_fill(PINK, opacity=0.5) # 设置颜色和透明度
self.play(Create(circle)) # 在画布上播放创建圆的动画
CreateCircle继承了Scene, Scene就表示一个画布. 类中重写了construct()方法.
Circle是一个Mobject, Mobject就表示一个图形.
所有的动画都要在Scene子类中的重写的construct()中实现.
控制台执行命令:
manim -pql create_circle.py CreateCircle
就可以看到动画了.
从一个正方形转换成圆形
新建一个文件square_to_circle.py
复制下面代码:
from manim import *
class SquareToCircle(Scene):
def construct(self):
circle = Circle() # 创建一个圆
circle.set_fill(PINK, opacity=0.5) # 设置颜色和透明度
square = Square() # 创建一个正方形
square.rotate(PI / 4) # 逆时针旋转45度
self.play(Create(square)) # 播放动画: 创建正方形
self.play(Transform(square, circle)) # 播放动画: 正方形转换成圆
self.play(FadeOut(square)) # 播放动画: 正方形消失
注意代码第14行传入的参数是square而非circle. 因为13行执行的转换代码是让square对象的形状变成圆形, 而非指向了一个新对象.
Square和Circle一样都是Mobject的子类.
Create, Transform, FadeOut. 都是Animation的子类.
控制台执行命令:
manim -pql square_to_circle.py SquareToCircle
动画:
定位Mobject
新建一个文件square_and_circle.py
复制下面代码:
from manim import *
class SquareAndCircle(Scene):
def construct(self):
circle = Circle()
circle.set_fill(PINK, opacity=0.5)
square = Square()
square.set_fill(BLUE, opacity=0.5)
# 正方形在圆的右面
# RIGHT表示正方形在圆的右面. 其他可选值: LEFT, UP, DOWN
# buff=0.5表示使用一个小的距离缓冲
square.next_to(circle, RIGHT, buff=0.5)
self.play(Create(circle), Create(square)) # 同时播放两个动画: 创建圆, 创建正方形
Scene类的play()方法同时传入2个Animation对象就表示同时执行2个动画.
控制台执行命令:
manim -pql square_and_circle.py SquareAndCircle
动画:
使用.animate让静态变成动态
新建一个文件animate.py
复制下面代码:
from manim import *
class AnimatedSquareToCircle(Scene):
def construct(self):
circle = Circle()
square = Square()
self.play(Create(square))
self.play(square.animate.rotate(PI / 4)) # 播放动画: 将正方形逆时针旋转45度
self.play(Transform(square, circle))
self.play(square.animate.set_fill(PINK, opacity=0.5)) # 播放动画: 将圆形上色
.animate是Mobject的方法, 在调用修改Mobject的方法前面添加.animate就会让这个修改变成动画.
控制台执行命令:
manim -pql animate.py AnimatedSquareToCircle
动画:
.animate的怪癖
新建一个文件different_rotations.py
复制下面代码:
from manim import *
class DifferentRotations(Scene):
def construct(self):
# shift(2 * LEFT)表示向左移动2个单位
left_square = Square(color=BLUE, fill_opacity=0.7).shift(2 * LEFT)
right_square = Square(color=GREEN, fill_opacity=0.7).shift(2 * RIGHT)
# 第一个参数是.animate实现的动画, 第二个参数是直接使用Animation的子类Rotate实现动画
# run_time=2 表示动画的持续时间为2秒
self.play(left_square.animate.rotate(PI), Rotate(right_square, angle=PI), run_time=2)
# 在动画播放完毕后, 场景会暂停一段时间, 默认是1秒
self.wait()
控制台执行命令:
manim -pql different_rotations.py DifferentRotations
动画:
奇怪了, 为什么左面的正方形没有旋转呢?
因为当使用.animate时, Manim实际上会获取Mobject的开始状态和结束状态, 并在中间添加过渡效果.
在实际使用时, 如果出现了这种情况, 可以使用传统的Rotate动画对象来产生旋转效果.
Transform 和 ReplacementTransform
Transform和ReplacementTransform都用来表示变换, 区别在于:
- Transform(a, b)是将图形a的点和颜色等属性转换成图形b的点和颜色等属性.
- ReplacementTransform是将图形b代替了图形a.
下面的代码, transform()方法和replacement_transform()的效果是一样的.
class TwoTransforms(Scene):
def transform(self):
a = Circle()
b = Square()
c = Triangle()
self.play(Transform(a, b))
self.play(Transform(a, c))
self.play(FadeOut(a))
def replacement_transform(self):
a = Circle()
b = Square()
c = Triangle()
self.play(ReplacementTransform(a, b))
self.play(ReplacementTransform(b, c))
self.play(FadeOut(c))
def construct(self):
self.transform()
self.wait(0.5)
self.replacement_transform()
然而, 在某些场景更推荐使用Transform, 因为可以避免使用变量保存变换后的形状. 示例代码如下:
from manim import *
class TransformCycle(Scene):
def construct(self):
a = Circle()
t1 = Square()
t2 = Triangle()
self.add(a)
self.wait()
for t in [t1,t2]:
self.play(Transform(a,t))
总结
- Mobject表示图形, 它的子类: Circle, Square, Triangle
- Mobject的方法:
-
- set_fill(): 填充颜色, 透明度
- rotate(): 旋转
- next_to(): 设置相对位置
- .animate: 放在Mobject其他方法前面, 让静态变成动态
- Scene表示画板, 它的方法:
-
- play(): 播放动画
- wait(): 在播放动画过程中暂停
- Animation表示动画, 它的子类: Create, Transform, FadeOut, ReplacementTransform
如果你觉得本篇内容对你有用, 欢迎关注我的微信公众号: 算法铁金库, 我会持续更新Manim的教程.