使用matplotlib的动画模块快速更新曲线

讨论 我不是赌鬼
Lv5 宗师级炼丹师
发布在 Matplotlib   3704   0
讨论 我不是赌鬼   3704   0

    这方面很多人没接触过,所以我们先讲背景,再说说其他博客的情况,接着才是上效果图与代码,最后解析。

    五年前,我接触到一个项目,本想用matplotlib做不断迭代的数据的监控,但是没有成功,折线图更新速度很慢,转而使用pyqtgraph库来实现数据的快速更新。

    这次的切入点是matplotlib的animation模块,该模块一般会被用来做动画演示。各个论坛上讲解该模块时使用的例子往往是构造一个横坐标x的序列,再写出一个f(x),使用动画模块将x快速更新,生成不同的y=f(x),高速刷新窗口中的点(x,y),其中写的比较好的是Python+Matplotlib制作动画

    二阶摆钟(官方例子)

    但显然,动画的长度是有限的,函数是确定的。而物联网数据监控的数据长度是无限的,函数可能有,也可能没有,本着有问题找文档的原则,我查到了官方示波器满足我们的需求。本文会对例程做一些简化,加些注释,讲解如何通过animation将实时数据以高刷新率显示到界面上。

    import numpy as np
    from matplotlib.lines import Line2D
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    class Scope:
        def __init__(self, ax):
            #导入一个坐标系
            self.ax = ax
            #确定t与y的初始值
            self.tdata = [0]
            self.ydata = [0]
            #以t为横坐标,以y为纵坐标画2D折线图
            self.line = Line2D(self.tdata, self.ydata)
            #将折线图导入坐标系中
            self.ax.add_line(self.line)
    
    
        def update(self, y):
            #t每时每刻都在增加,为了使曲线完整,
            #需要在每次数据更新时重新设置xlim,并更新
            self.maxt=self.tdata[-1]+1
            self.ax.set_xlim(0, self.maxt)
            #重绘子图画布,使坐标轴的改变生效
            #绘图程序很浪费时间,最好不要在update里加入其他绘图函数
            #大家可以尝试隐藏这段代码对比速度
            self.ax.figure.canvas.draw()
    
            #将新的t与y放到数列中,重写折线数值
            self.tdata.append(self.maxt)
            self.ydata.append(y)
            self.line.set_data(self.tdata,self.ydata)
    
            #返回被更新的折线
            return self.line,
    
    #构造生成器,每次被调用都会产生一个随机值
    #这个随机值可以用各种设备输出值来替代
    def emitter():
        while True:
            yield np.random.rand(1)
    
    #生成一个包含子图的figure,并返回figure,axes元组
    fig, ax = plt.subplots()
    #使用ax作为被不断更新的坐标系
    scope = Scope(ax)
    
    # 使用动画模块,图像为fig保持不变(可以简单地认为是背景),
    # 每过一个interval(ms),会调用一次生成器emitter,并将生成的值传入scope.update中
    # scope.update会返回一条新的折线,该模块会将新的折线绘制在图像中并显示出来。
    # blit用来开启某种动画的渲染
    ani = animation.FuncAnimation(fig, scope.update, emitter, interval=10,
                                  blit=True)
    
    #制作gif
    #ani.save('test.gif',writer='pillow',fps=10)
    
    plt.show()

    Emmm,其实该说的都已经写在备注里了,如果您对yield,生成器等相关概念有疑惑,请尝试努力学习这方面内容。需要注意的是,之所以动画更新速度很快,是因为动画只更新图像的一小部分内容。如果在upadte()中加入self.ax.figure.canvas.draw()等函数来更新图像的其他部分,会增加很大的时间消耗,所以无特别需求,请勿添加。

    matplotlib动画可以应用在很多地方,掌握了动画的核心要点,就可以让自己的演示图片骚到飞起。下图为动画在机器学习可视化方面的应用

    版权声明:作者保留权利,不代表意本站立场。如需转载请联系本站以及作者。

    参与讨论

    回复《 使用matplotlib的动画模块快速更新曲线

    EditorJs 编辑器

    沙发,很寂寞~
    反馈
    to-top--btn