matplotlib animation 绘制动画
在博客python中plot实现即时数据动态显示方法中介绍了python利用matplotlib库中的
plt.ion()
函数实现即时数据动态显示的方法。该方法最初的目的就是为了实时监测系统,实时可视化体系统数据。目前,对于利用Python+Matplotlib实时产生数据实时显示的应用,本人还没有找到能替代它的方案。本文将面向另一种应用背景:生成(收集)数据的过程与动态显示的过程是可以分开的。也即,我们只需要在仿真程序运行完成后,得到数据动态变化的显示(或视频)就可以了。博客python中plot实现即时数据动态显示方法与本文是相互补充的。博客python中plot实现即时数据动态显示方法中的方法一般用于调试系统,在确定系统按照预期运行时,再通过本文的方法绘制动画用于成果展示。
- 博客python中plot实现即时数据动态显示方法:用于实时监测系统,实时数据可视化,一般用于系统调试过程;
- 本文基于matplotlib animation 绘制动画的方法:一般用于成果展示。生成各种格式的视频,gif动态图等。
文章目录
1. 机缘
昨天晚上逛B站被这条与新冠病毒传播模拟有关的视频(【实验模拟】不要给病毒反弹的机会!)吸引,看得出来这是个有情怀的阿婆主,所以多看了一眼。循着阿婆主留下的源码地址,我下载下来看了看。InfectSim。嚯嚯,这个代码一印入眼帘立马一股杀气袭来。下面是代码的开头,孤陋寡闻了,在python3中中文可以当变量名
。
我饶有兴趣的把代码复制到jupyter notebook里,还真可以运行。后面的动态显示代码也是基于matplotlib,并且生成的动画可以保存,这是与博客python中plot实现即时数据动态显示方法的区别之一。博客python中plot实现即时数据动态显示方法中实现动态显示,并不会自动保留历史显示信息,我需要在跑程序的同时打开录屏软件,对界面实时显示的图像进行录制,形成可展示的成果。而阿婆主的代码直接生成了可重复播放的视频。这在很多情况下就比博客python中plot实现即时数据动态显示方法方便有效。例如,写这篇博客就比写之前的博客轻松许多,因为运行完程序直接可以生成gif动态图。所以,记录下来方便自己以后查阅。
对于编程来说,几个经典例程胜过一切!!!下面给出线型、散点、3D散点的应用例子。每个例子会给对程序中的关键代码进行解释,并给出需要依赖的包的安装程序(主要是在windows系统下,生成gif,mp4时需要用到的某些依赖软件,例如:ffmpeg,imagemagick)。
例一: 线型动画生成
示例程序
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
%matplotlib inline
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = ax.plot([], [], 'r-', animated=False)
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
return ln, # 千万别少了这里的逗号!!!!!
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128), init_func=init, blit=True)
ani.save('test_animation.gif',writer='imagemagick') # 保存 gif
# ani.save('test_animation.mp4') # 保存 mp4
# HTML(ani.to_html5_video()) # 直接jupyter notebook 网页内播放,也是mp4格式,可另存为
安装依赖软件
当保存gif时,需要调用imagemagick软件。当要保存为mp4格式或用HTML播放时,需要调用ffmpeg。
ubuntu
- ffmpeg
sudo apt install ffmpeg
- imagemagick
sudo apt-get install imagemagick
windows 10
- ffmpeg
- 根据系统下载ffmpeg builds (windows)
- 下载好后解压,会生成一个类似名为“ffmpeg-20180820-78d4b6b-win64-static”的文件夹。
- 打开你想安装的任意磁盘,例如:c盘。新建一个名为“ffmpeg”的文件夹,将第二步解压生成的文件夹中的内容全部拷贝到“ffmpeg”文件夹中:
- 配置FFmpeg环境变量,如下图:
- 打开命令提示符窗口。输入命令“ffmpeg –version”。如果命令提示窗口返回FFmpeg的版本信息,那么就说明安装成功了,你可以在命令提示行中任意文件夹下运行FFmpeg。
- imagemagick
下载ImageMagick-7.0.10-0-Q16-x64-dll.exe,并安装即可。
结果展示(该gif动态图由程序直接生成并保存于本地)
示例二:二维散点动态图
示例程序
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML
import numpy as np
%matplotlib inline
plt.style.use('seaborn-pastel')
fig = plt.figure()
class AnimatedScatter(object):
def __init__(self, numpoints=5):
self.numpoints = numpoints
self.stream = self.data_stream()
self.angle = 0
self.fig = plt.figure()
self.fig.canvas.mpl_connect('draw_event',self.forceUpdate)
self.ax = self.fig.add_subplot(111)
self.ani = animation.FuncAnimation(self.fig, self.update, interval=100,
init_func=self.setup_plot, frames=200)
def change_angle(self):
self.angle = (self.angle + 1)%360
def forceUpdate(self, event):
self.scat.changed()
def setup_plot(self):
X = next(self.stream)
c = ['b', 'r', 'g', 'y', 'm']
self.scat = self.ax.scatter(X[:,0], X[:,1] , c=c, s=200)
self.ax.axis([-10, 10, -10, 10])
return self.scat,
def data_stream(self):
data = np.zeros(( self.numpoints , 2 ))
xy = data[:,:2]
while True:
xy += 2 * (np.random.random(( self.numpoints,2)) - 0.5)
yield data
def update(self, i):
data = next(self.stream)
self.scat._offsets = ( data )
return self.scat,
def show(self):
plt.show()
a = AnimatedScatter()
a.ani.save('test_animation.gif',writer='imagemagick') # 保存gif...
# a.ani.save('test_animation.mp4') # 保存MP4
# HTML(a.ani.to_html5_video()) # 直接jupyter notebook 网页内播放,也是mp4格式,可另存为
结果展示
示例三:三维散点动态图
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
FLOOR = -10
CEILING = 10
class AnimatedScatter(object):
def __init__(self, numpoints=5):
self.numpoints = numpoints
self.stream = self.data_stream()
self.angle = 0
self.fig = plt.figure()
self.fig.canvas.mpl_connect('draw_event',self.forceUpdate)
self.ax = self.fig.add_subplot(111,projection = '3d')
self.ani = animation.FuncAnimation(self.fig, self.update, interval=100,
init_func=self.setup_plot, frames=200)
def change_angle(self):
self.angle = (self.angle + 1)%360
def forceUpdate(self, event):
self.scat.changed()
def setup_plot(self):
X = next(self.stream)
c = ['b', 'r', 'g', 'y', 'm']
self.scat = self.ax.scatter(X[:,0], X[:,1], X[:,2] , c=c, s=200)
self.ax.set_xlim3d(FLOOR, CEILING)
self.ax.set_ylim3d(FLOOR, CEILING)
self.ax.set_zlim3d(FLOOR, CEILING)
return self.scat,
def data_stream(self):
data = np.zeros(( self.numpoints , 3 ))
xyz = data[:,:3]
while True:
xyz += 2 * (np.random.random(( self.numpoints,3)) - 0.5)
yield data
def update(self, i):
data = next(self.stream)
self.scat._offsets3d = ( np.ma.ravel(data[:,0]) , np.ma.ravel(data[:,1]) , np.ma.ravel(data[:,2]) )
return self.scat,
def show(self):
plt.show()
a = AnimatedScatter()
a.ani.save('test_animation.gif',writer='imagemagick') # 保存gif...
# a.ani.save('test_animation.mp4') # 保存MP4
# HTML(a.ani.to_html5_video()) # 直接jupyter notebook 网页内播放,也是mp4格式,可另存为
结果展示
最后
还是希望疫情早点过去!
by Toby, 2020-3-12
上一篇: JavaScript 显示剩余时间函数
下一篇: C语言程序输入一个三位数取个位十位百位