matplotlib animation 绘制动画

在博客python中plot实现即时数据动态显示方法中介绍了python利用matplotlib库中的plt.ion()函数实现即时数据动态显示的方法。该方法最初的目的就是为了实时监测系统,实时可视化体系统数据。目前,对于利用Python+Matplotlib实时产生数据实时显示的应用,本人还没有找到能替代它的方案。本文将面向另一种应用背景:生成(收集)数据的过程与动态显示的过程是可以分开的。也即,我们只需要在仿真程序运行完成后,得到数据动态变化的显示(或视频)就可以了。博客python中plot实现即时数据动态显示方法与本文是相互补充的。博客python中plot实现即时数据动态显示方法中的方法一般用于调试系统,在确定系统按照预期运行时,再通过本文的方法绘制动画用于成果展示。

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
  1. 根据系统下载ffmpeg builds (windows)
  2. 下载好后解压,会生成一个类似名为“ffmpeg-20180820-78d4b6b-win64-static”的文件夹。
  3. 打开你想安装的任意磁盘,例如:c盘。新建一个名为“ffmpeg”的文件夹,将第二步解压生成的文件夹中的内容全部拷贝到“ffmpeg”文件夹中:
    在这里插入图片描述
  4. 配置FFmpeg环境变量,如下图:
    在这里插入图片描述
  5. 打开命令提示符窗口。输入命令“ffmpeg –version”。如果命令提示窗口返回FFmpeg的版本信息,那么就说明安装成功了,你可以在命令提示行中任意文件夹下运行FFmpeg。

结果展示(该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

猜你喜欢

转载自blog.csdn.net/u013468614/article/details/104817578