python制作简单动画_把数据摇起来!⽤Python制作动画可视
化效果!
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() # 清掉图形(重设颜⾊)
return mlab.screenshot(antialiased=True)
animation = mpy.VideoClip(make_frame, duration=duration)linspace numpy
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.s(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)
animation.write_gif("wireframe.gif", fps=20)
基于 Vispy 制作动画
Vispy 是另⼀款基于 OpenGL 的交互式 3D 数据可视化库。我们可以先⽤ Vispy 做出图形和⽹格,然后⽤ MoviePy 将其制作成动画:from moviepy.editor import VideoClip
import numpy as np
from vispy import app, scene
from vispy.gloo.util import _screenshot
canvas = scene.SceneCanvas(keys='interactive')
view = al_widget.add_view()
view.set_camera('turntable', mode='perspective', up='z', distance=2,
azimuth=30., elevation=65.)
xx, yy = np.arange(-1,1,.02),np.arange(-1,1,.02)
X,Y = np.meshgrid(xx,yy)
R = np.sqrt(X**2+Y**2)
Z = lambda t : 0.1*np.sin(10*R-2*np.pi*t)
surface = scene.visuals.SurfacePlot(x= xx-0.1, y=yy+0.2, z= Z(0),
shading='smooth', color=(0.5, 0.5, 1, 1))
view.add(surface)
canvas.show()
# ⽤MoviePy转换为动画
def make_frame(t):
surface.set_data(z = Z(t)) # 更新曲⾯
<_draw(None) # 更新Vispy的画布上的 图形
return _screenshot((0,0,canvas.size[0],canvas.size[1]))[:,:,:3]
animation = VideoClip(make_frame, duration=1).resize(width=350)
animation.write_gif('sinc_vispy.gif', fps=20, opt='OptimizePlus')
下⾯是⼀些⽤ Vispy 制作的更复杂点的酷炫动画,它们是将 C 语⾔代码⽚段嵌⼊ Python 代码中,并微调 3D 着⾊器后制作⽽成:
基于 matplotlib 制作动画
虽然 2D/3D 绘图库 matplotlib 内置了动画模块,但是⽤ MoviePy 制作更轻更⾼质量的视频动画,⽽且运⾏速度更快。下⾯是⽤MoviePy 基于 matplotlib 制作动画的⽅法:
import matplotlib.pyplot as plt
import numpy as np
from moviepy.video.io.bindings import mplfig_to_npimage
import moviepy.editor as mpy
# ⽤matplotlib绘制⼀个图形
duration = 2
fig_mpl, ax = plt.subplots(1,figsize=(5,3), facecolor='white')
xx = np.linspace(-2,2,200) # x向量
zz = lambda d: np.sinc(xx**2)+np.sin(xx+d) # (变化的)Z向量
ax.set_title("Elevation in y=0")
ax.set_ylim(-1.5,2.5)
line, = ax.plot(xx, zz(0), lw=3)
# ⽤MoviePy制作动(为每个t更新曲⾯)。制作⼀个GIF
def make_frame_mpl(t):
line.set_ydata( zz(2*np.pi*t/duration)) # 更新曲⾯
return mplfig_to_npimage(fig_mpl) # 图形的RGB图像
animation =mpy.VideoClip(make_frame_mpl, duration=duration)
animation.write_gif("sinc_mpl.gif", fps=20)
Matplotlib 有很多漂亮的主题,和 Pandas、Scikit-Learn 等数字模块的兼容性也很好。我们来看⼀个 SVM 分类器,更好的理解随着训练点的数量增加时地图的变化动态:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm # sklearn = scikit-learn
from sklearn.datasets import make_moons
from moviepy.editor import VideoClip
from moviepy.video.io.bindings import mplfig_to_npimage
X, Y = make_moons(50, noise=0.1, random_state=2) # 半随机数据
fig, ax = plt.subplots(1, figsize=(4, 4), facecolor=(1,1,1))
fig.subplots_adjust(left=0, right=1, bottom=0)
xx, yy = np.meshgrid(np.linspace(-2,3,500), np.linspace(-1,2,500))
def make_frame(t):
ax.clear()
ax.axis('off')
ax.set_title("SVC classification", fontsize=16)
classifier = svm.SVC(gamma=2, C=1)
# 不断变化的权重让数据点⼀个接⼀个的出现
weights = np.minimum(1, np.maximum(0, t**2+10-np.arange(50)))
classifier.fit(X, Y, sample_weight=weights)
Z = classifier.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
vmin=-2.5, vmax=2.5, levels=np.linspace(-2,2,20))
ax.scatter(X[:,0], X[:,1], c=Y, s=50*weights, bone)
return mplfig_to_npimage(fig)
animation = VideoClip(make_frame, duration = 7)
animation.write_gif("svm.gif", fps=15)
简单来说,通过背景颜⾊我们就可以得知分类器辨识⿊⾊点和⽩⾊点属于哪⾥。刚开始并不明显,但随着越来越多的数据点出现,这些点的分布逐渐呈⽉⽛形区域。
基于 Numpy 的动画
如果是⽤ Numpy 数组(Numpy 是 Python 中的⼀个数字库),你不需要任何外部绘图库,你可以直接将数组输⼊ MoviePy ⾥。
将 Numpy 和 MoviePy 结合,可以做出很炫酷的动画效果。⽐如我们可以模拟僵⼫病毒在法国蔓延的动态图(模拟!模拟!),以⽹格形式(Numpy 数组)模拟出法国地图,在上⾯执⾏所有模拟病毒感染和扩散效果的计算。每隔⼀段时间,⼀些 Numpy 操作会将⽹格转换为有效的 RGB 图像,并将其发送⾄ MoviePy:
import urllib
import numpy as np
from scipy.ndimage.filters import convolve
import moviepy.editor as mpy
#### 从⽹络上检索地图
filename = ("/wikipedia/commons/a/aa/"
"France_-_2011_population_density_-_200_m_%C3%"
"97_200_m_square_grid_-_Dark.png")
urllib.urlretrieve(filename, "france_density.png")
#### 参数和约束条件
infection_rate = 0.3
incubation_rate = 0.1
dispersion_rates = [0, 0.07, 0.03] # for S, I, R
# 该内核会模拟⼈类/僵⼫如何⽤⼀个位置扩散⾄邻近位置
dispersion_kernel = np.array([[0.5, 1 , 0.5],
[1 , -6, 1],
[0.5, 1, 0.5]])
france = mpy.ImageClip("france_density.png").resize(width=400)
SIR = np.zeros( (3,france.h, france.w), dtype=float)
SIR[0] = _frame(0).mean(axis=2)/255
start = int(0.6*france.h), int(0.737*france.w)
SIR[1,start[0], start[1]] = 0.8 # infection in Grenoble at t=0
dt = 1.0 # ⼀次更新=实时1个⼩时
hours_per_second= 7*24 # one second in the video = one week in the model
world = {'SIR':SIR, 't':0}
> 建模
def infection(SIR, infection_rate, incubation_rate):
""" Computes the evolution of #Sane, #Infected, #Rampaging"""
S,I,R = SIR
newly_infected = infection_rate*R*S
newly_rampaging = incubation_rate*I
dS = - newly_infected

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。

发表评论