Python 中有很多不错的数据可视化库,但是极少能渲染 GIF 图或视频动画效果。本文就分享一下如何用 MoviePy 作为其他可视化库的通用插件,制作动画可视化效果,毕竟这年头,没图不行,有动图更好。
MoviePy 能让我们用函数 make_frame(t) 自定义动画,函数会返回和时间 t 的视频帧(以秒为单位):
from moviepy.editor import VideoClip
def make_frame(t):
""" returns an image of the frame at time t """
# ... 用任意库创建帧
return frame_for_time_t # (Height x Width x 3) Numpy array
animation = VideoClip(make_frame, duration=3) # 3-second clip
# 支持导出为多种格式
animation.write_videofile("my_animation.mp4", fps=24) # 导出为视频
animation.write_gif("my_animation.gif", fps=24) # 导出为GIF
本文会涵盖 MayaVi、vispy、matplotlib、NumPy 和 Scikit-image 这些库。
基于 Mayavi 制作动画
Mayavi 是一个 Python 模块,可以制作交互式 3D 数据可视化。在第一个例子中,我们会将一个高度随着时间 t 不断变化的表面制作成动画:
import numpy as np
import mayavi.mlab as mlab
import moviepy.editor as mpy
duration= 2 # duration of the animation in seconds (it will loop)
# 用Mayavi制作一个图形
fig_myv = mlab.figure(size=(220,220), bgcolor=(1,1,1))
X, Y = np.linspace(-2,2,200), np.linspace(-2,2,200)
XX, YY = np.meshgrid(X,Y)
ZZ = lambda d: np.sinc(XX**2+YY**2)+np.sin(XX+d)
# 用MoviePy将图形转换为动画,编写动画GIF
def make_frame(t):
mlab.clf() # 清掉图形(重设颜色)
mlab.mesh(YY,XX,ZZ(2*np.pi*t/duration), figure=fig_myv)
return mlab.screenshot(antialiased=True)
animation = mpy.VideoClip(make_frame, duration=duration)
animation.write_gif("sinc.gif", fps=20)
另外一个例子是,制作一个坐标和观看角度都随着时间不断变化的线框网动画:
import numpy as np
import mayavi.mlab as mlab
import moviepy.editor as mpy
duration = 2 # duration of the animation in seconds (it will loop)
# 用Mayavi制作一个图形
fig = mlab.figure(size=(500, 500), bgcolor=(1,1,1))
u = np.linspace(0,2*np.pi,100)
xx,yy,zz = np.cos(u), np.sin(3*u), np.sin(u) # 点
l = mlab.plot3d(xx,yy,zz, representation="wireframe", tube_sides=5,
line_width=.5, tube_radius=0.2, figure=fig)
# 用MoviePy将图形转换为动画,编写动画GIF
def make_frame(t):
""" Generates and returns the frame for time t. """
y = np.sin(3*u)*(0.2+0.5*np.cos(2*np.pi*t/duration))
l.mlab_source.set(y = y) # change y-coordinates of the mesh
mlab.view(azimuth= 360*t/duration, distance=9) # 相机视角
return mlab.screenshot(antialiased=True) # 返回RGB图形
animation = mpy.VideoClip(make_frame, duration=duration).resize(0.5)
# 视频生成花费10秒, GIF 生成花费25秒
animation.write_videofile("wireframe.mp4", fps=20)</