关于Matplotlib绘制动态实时曲线的方法改进指南

 更新时间:2021年06月07日 09:46:33   作者:脑荼地  
这篇文章主要给大家介绍了关于Matplotlib绘制动态实时曲线的相关资料,matplotlib是python里最popular的画图工具,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

很多时候,我们需要实时的绘制曲线,如实时的绘制串口接收到的数据。最先想到的解决策略是类似于Matlab种的drawnow函数。

在python中Matplotlib库有着和Matlan绘图库相似的功能,但是并没有drawnow这样的函数。

已有的解决方案

通过网上现有的资料 基于Python实现matplotlib中动态更新图片(交互式绘图) ,可以通过打开Matplotlib的交互模式来实现实时绘图的目的,此时需要用到函数matplotlib.pyplot.ion

存在的问题

通过上述方法实时绘图,存在一个严重的问题:随着时间推移,CPU消耗越大,费时越多,最终导致程序卡顿。这显然无法满足我们实时绘图的要求。

以下通过time模块计算每一步的耗时,直观地表现这一现象。

def Method(point):
   es_time = np.zeros([point]) 
   fig=plt.figure()
   ax=fig.add_subplot(1,1,1)
   ax.axis("equal") #设置图像显示的时候XY轴比例
   ax.set_xlabel('Horizontal Position')
   ax.set_ylabel('Vertical Position')
   ax.set_title('Vessel trajectory')
   plt.grid(True) #添加网格
   plt.ion()  #interactive mode on
   IniObsX=0000
   IniObsY=4000
   IniObsAngle=135
   IniObsSpeed=10*math.sqrt(2)   #米/秒
   print('开始仿真')
   for t in range(point):
       t0 = time.time()
       #障碍物船只轨迹
       obsX=IniObsX+IniObsSpeed*math.sin(IniObsAngle/180*math.pi)*t
       obsY=IniObsY+IniObsSpeed*math.cos(IniObsAngle/180*math.pi)*t
       ax.scatter(obsX,obsY,c='b',marker='.')  #散点图
       #下面的图,两船的距离
       plt.pause(0.001)
       es_time[t] = 1000*(time.time() - t0)
   return es_time

耗时结果


Method

很显然每步绘图时间与绘图点数呈线性相关的趋势,且随着点数增加,时间消耗越多。可以想象,当绘图的点数到达上万乃至亿的时候,那电脑就卡住了。

分析原因

个人猜测出现上述这种现象的原因,是由代码ax.scatter(obsX,obsY,c='b',marker='.')造成的。这段代码每一循环一次就新画一条曲线,而不清除之前的曲线,这就必然导致越往后循环所花费的CPU资源内存资源越多,最终机器卡死。

改进方法

既然原因是因为不断重复画图所致,导致机器资源的累积消耗,所以想到的第一个解决方法,那就是每次画图前,清除之前的曲线。

根据上述思想,在每一次的画图代码ax.scatter(obsX,obsY,c='b',marker='.')前加上清除代码plt.cla()。即:

        plt.cla()
        ax.plot(obsX,obsY,'-g',marker='*')  #散点图

可是这样做之后就会存在新的问题:之前定义的坐标轴,标题,图例等等信息就都被清除了。解决方法则,需要在每一步的循环中,重新定义这些信息。

完整代码

def Method_Improve(point):
    def initial(ax):
        ax.axis("equal") #设置图像显示的时候XY轴比例
        ax.set_xlabel('Horizontal Position')
        ax.set_ylabel('Vertical Position')
        ax.set_title('Vessel trajectory')
        plt.grid(True) #添加网格
        return ax
    
    es_time = np.zeros([point]) 
    fig=plt.figure()
    ax=fig.add_subplot(1,1,1)
    ax = initial(ax)
    plt.ion()  #interactive mode on
    IniObsX=0000
    IniObsY=4000
    IniObsAngle=135
    IniObsSpeed=10*math.sqrt(2)   #米/秒
    print('开始仿真')
    obsX = [0,]
    obsY = [4000,]
    for t in range(point):
        t0 = time.time()
        #障碍物船只轨迹
        obsX.append(IniObsX+IniObsSpeed*math.sin(IniObsAngle/180*math.pi)*t)
        obsY.append(IniObsY+IniObsSpeed*math.cos(IniObsAngle/180*math.pi)*t)
        plt.cla()
        ax = initial(ax)
        ax.plot(obsX,obsY,'-g',marker='*')  #散点图
        #下面的图,两船的距离
        plt.pause(0.001)
        es_time[t] = 1000*(time.time() - t0)
    return es_time

耗时结果


Method_Improve

显然循环次数与耗时不再呈正相关趋势,可以说是在一定误差范围内,耗时保持稳定。

改进方法的改进

改进方法中仍存在一个问题:由于每次循环都需要清除坐标轴信息,那么每次循环也必须再重新设置坐标轴信息。显然这种做法,导致了额外的算力消耗,那能否有新的方法,规避这种问题呢?答案显然是有的。

但是解决思路还是得从原始问题出发,即重复画图,导致资源的累积消耗。所以令一种新的思路:只画一条(需要数量的)曲线,每次循环更改这些曲线的数据。

那么按照上述思路之后,只需程序开头定义好坐标轴信息,而不需要每次循环内清除重设坐标轴信息。

具体做法,就是获取曲线的句柄,进行修改,即有:

        line.set_xdata(obsX)
        line.set_ydata(obsY)

完整代码:

def ImprovedMethod_Improve(point):    
    es_time = np.zeros([point]) 
    fig=plt.figure()
    ax=fig.add_subplot(1,1,1)

    ax.set_xlabel('Horizontal Position')
    ax.set_ylabel('Vertical Position')
    ax.set_title('Vessel trajectory')
    
    line = ax.plot([0,0],[4000,4000],'-g',marker='*')[0]
    plt.grid(True) #添加网格
    plt.ion()  #interactive mode on
    IniObsX=0000
    IniObsY=4000
    IniObsAngle=135
    IniObsSpeed=10*math.sqrt(2)   #米/秒
    print('开始仿真')
    obsX = [0,]
    obsY = [4000,]
    for t in range(point):
        t0 = time.time()
        #障碍物船只轨迹
        obsX.append(IniObsX+IniObsSpeed*math.sin(IniObsAngle/180*math.pi)*t)
        obsY.append(IniObsY+IniObsSpeed*math.cos(IniObsAngle/180*math.pi)*t)
        
        line.set_xdata(obsX)
        line.set_ydata(obsY)
        ax.set_xlim([-200,10*point+200])
        ax.set_ylim([3800-10*point,4200])
        #下面的图,两船的距离
        plt.pause(0.001)
        es_time[t] = 1000*(time.time() - t0)
    return es_time


三种方法对比

总结

到此这篇关于Matplotlib绘制动态实时曲线的文章就介绍到这了,更多相关Matplotlib绘制动态实时曲线内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python中的pass语句使用方法讲解

    Python中的pass语句使用方法讲解

    这篇文章主要介绍了Python中的pass语句使用方法讲解,是Python入门学习中的基础知识,需要的朋友可以参考下
    2015-05-05
  • Python使用asyncio.Queue进行任务调度的实现

    Python使用asyncio.Queue进行任务调度的实现

    本文主要介绍了Python使用asyncio.Queue进行任务调度的实现,它可以用于任务调度和数据交换,文中通过示例代码介绍的非常详细,感兴趣的可以了解一下
    2024-02-02
  • python 杀死自身进程的实现方法

    python 杀死自身进程的实现方法

    今天小编就为大家分享一篇python 杀死自身进程的实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • python 如何将数据写入本地txt文本文件的实现方法

    python 如何将数据写入本地txt文本文件的实现方法

    这篇文章主要介绍了python 如何将数据写入本地txt文本文件的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • python3+RobotFramework环境搭建过程

    python3+RobotFramework环境搭建过程

    之前用的python2.7+robotframework进行的自动化测试,python3的还没尝试,今天尝试了下,搭建环境的时候也是各种报错,今天给大家分享下python3+RobotFramework环境搭建过程,感兴趣的朋友一起看看吧
    2023-08-08
  • 基于Python实现帕累托图的示例详解

    基于Python实现帕累托图的示例详解

    帕累托图是一种特殊的直方图, 在项目管理知识体系中属于质量管理的工具。本文为大家整理了Python实现帕累托图的方法,需要的可以参考一下
    2023-03-03
  • Python超详细讲解内存管理机制

    Python超详细讲解内存管理机制

    本章主要介绍Pyhon的内存管理,以Pyhon的计数机制作为引入,介绍Pyhon的内存管理方式,感兴趣的朋友来看看吧
    2022-06-06
  • Pytorch建模过程中的DataLoader与Dataset示例详解

    Pytorch建模过程中的DataLoader与Dataset示例详解

    这篇文章主要介绍了Pytorch建模过程中的DataLoader与Dataset,同时PyTorch针对不同的专业领域,也提供有不同的模块,例如 TorchText, TorchVision, TorchAudio,这些模块中也都包含一些真实数据集示例,本文给大家介绍的非常详细,需要的朋友参考下吧
    2023-01-01
  • Python中字符串去空格的五种方法介绍与对比

    Python中字符串去空格的五种方法介绍与对比

    在 Python 中,去除字符串中的空格是一个常见的操作,这篇文章小编将为大家盘点一下python中常用的的去空格的方法,需要的可以参考一下
    2025-02-02
  • Python的面向对象思想分析

    Python的面向对象思想分析

    这篇文章主要介绍了Python的面向对象思想分析,以实例形式较为详细的分析了封装,继承,多态的具体用法,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-01-01

最新评论