这篇文章主要为大家展示了“Matplotlib如何绘制动态实时曲线”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Matplotlib如何绘制动态实时曲线”这篇文章吧。
很多时候,我们需要实时的绘制曲线,如实时的绘制串口接收到的数据。最先想到的解决策略是类似于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如何绘制动态实时曲线”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。