• 企业400电话
  • 网络优化推广
  • AI电话机器人
  • 呼叫中心
  • 全 部 栏 目

    网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    关于Matplotlib绘制动态实时曲线的方法改进指南
    POST TIME:2021-10-18 13:34

    很多时候,我们需要实时的绘制曲线,如实时的绘制串口接收到的数据。最先想到的解决策略是类似于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绘制动态实时曲线内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    您可能感兴趣的文章:
    • 使用matplotlib动态刷新指定曲线实例
    • Python实现曲线拟合操作示例【基于numpy,scipy,matplotlib库】
    • Python使用matplotlib绘制正弦和余弦曲线的方法示例
    • Python matplotlib绘制图形实例(包括点,曲线,注释和箭头)
    • matplotlib 曲线图 和 折线图 plt.plot()实例
    • Python matplotlib 绘制双Y轴曲线图的示例代码
    上一篇:Python基础之内置模块详解
    下一篇:python常见模块之OS模块和time模块
  • 相关文章
  • 

    关于我们 | 付款方式 | 荣誉资质 | 业务提交 | 代理合作


    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    X

    截屏,微信识别二维码

    微信号:veteran88

    (点击微信号复制,添加好友)

     打开微信