关于Matplotlib绘制动态实时曲线的方法改进指南
作者:脑荼地 发布时间:2021-03-17 23:48:10
很多时候,我们需要实时的绘制曲线,如实时的绘制串口接收到的数据。最先想到的解决策略是类似于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
三种方法对比
总结
来源:https://www.jianshu.com/p/1a25ce4563ec


猜你喜欢
- 1. 变量每个变量都存储了一个值在程序中可以随时修改变量,但Python将始终记录变量的最新值message = "Hello H
- union all在MySQL5.6下的表现Part1:MySQL5.6.25[root@HE1 ~]# MySQL -uroot -pEn
- rpclib 是一个非常好用的 python webservice 库,可以动态的生成 wsdl, 不过这个项目已经基本停止,并被一个新的项
- 一,利用键盘响应,在不刷新本页面的情况下验证表单输入是否合法用户通过onkeydown和onkeyup事件来触发响应事件。使用方法和oncl
- 选择排序选择排序是一种简单的比较排序算法,它的算法思路是首先从数组中寻找最小(大)的元素,然后放到数组中的第一位,接下来继续从未排序的元素中
- 原本运行正常的ASP页面,今天突然提示: 代码如下: Microsoft VBScript 运行时错误 错误 '800a01a8&
- 代码使用说明1970-2270文件夹是保存图像和json文件(也就是需要进行转换的文件)det文件夹是保存单个json对应的txt(因为np
- 一般情况下,tensorflow里面变量初始化过程为: #variables ........... #......
- 几天写过两篇使用VPS的安全性设置的博文,其实不管我们如何设置安全,及时的备份VPS数据才是最为重要的。因为VPS与主机不同,主机可能很多时
- 本文实例讲述了PHP实现的杨辉三角求解算法。分享给大家供大家参考,具体如下:♥ 前言对于 杨辉三角 是什么的问题,请参考百度百科的详细解释:
- 简介一个基于Python的程序,使用tkinter模块创建一个GUI界面,在Checklistbox中列出系统中正在运行的进程的名称和PID
- 示例:# -*- coding:utf-8 -*-import jsonstrtest = {"中故宫":"好
- ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony(和谐之意,显然没有跟上我国的步伐,我
- 一、前言return一直中,每中语言中其没没有很大差别,就不多说了。(shell语言return的是退出状态,可能差别是比较大的)最早看到y
- 近期接手越来越多的东西,发布和运维的工作相当机械,加上频率还蛮高,导致时间浪费还是优点多。修复bug什么的,测试,提交版本库(2分钟),ss
- 引言最近公司换了电脑,系统也从 win7 升级到 win11,开发环境都重新安装了一遍,然后在 idea 用mvn 执行打包命令 mvn c
- 看此博客之前建议先看看B站的视频python数据结构与算法系列课程,该课程中未实现双向循环链表的操作,所以我按照该视频的链表思路实现了双向循
- sysbench是一个模块化的、跨平台、多线程基准测试工具,主要用于评估测试各种不同系统参数下的数据库负载情况。目前sysbench代码托管
- 前言最近经常用到一个.py程序,但是每次在不同电脑上用,希望能把Python脚本发布为脱离Python平台运行的可执行程序,比如单个exe。
- wm_concat、listagg、xmlagg、pivot函数一、wm_concat函数(oracle12g版本开始不支持)语法:sele