基于 interactive mode 实现 matplotlib 动态更新图片 (交互式绘图)

[toc]

最近在研究动态障碍物避障算法,在 Python 语言进行算法仿真时需要实时显示障碍物和运动物的当前位置和轨迹,利用 Anaconda 的 Python 打包集合,在 Spyder 中使用 Python3.5 语言和 matplotlib 实现路径的动态显示和交互式绘图 (和 Matlab 功能类似)。

本博客初稿完成于 2017 年,多平台维护不易,内容更新于 个人网站,请移步阅读最新内容。

背景知识

Anaconda

Anaconda 是一个用于科学计算的 Python 发行版,支持 Linux, Mac, Windows 系统,提供了包管理与环境管理的功能,可以很方便地解决多版本 python 并存、切换以及各种第三方包安装问题。

Anaconda 利用工具 / 命令 conda 来进行 package 和 environment 的管理,并且已经包含了 Python 和相关的配套工具。

matplotlib

matplotlib 是 python 最著名的绘图库,它提供了一整套和 matlab 相似的命令 API,十分适合交互式地进行制图。而且也可以方便地将它作为绘图控件,嵌入 GUI 应用程序中。其中,matplotlib 的 pyplot 子库提供了和 matlab 类似的绘图 API,方便用户快速绘制 2D 图表,它的文档相当完备,并且 Gallery 页面中有上百幅缩略图,打开之后都有源程序。

matplotlib 交互式绘图

原理

在调研 matplotlib 动态绘制曲线方法中,和 matlab 相似有 animation 方法和交互式绘图,但是 animation 方法灵活性不高,不太适合路径的实时动态显示,本文最后采用交互式绘图模(interactive mode)-- Using matplotlib in a python shell

The interactive property of the pyplot interface controls whether a figure canvas is drawn on every pyplot command. If interactive is False, then the figure state is updated on every plot command, but will only be drawn on explicit calls to draw(). When interactive is True, then every pyplot command triggers a draw.

实践

当绘图语句中加入 pl.ion () 时,表示打开了交互模式。此时 python 解释器解释完所有命令后,给你出张图,但不会结束会话,而是等着你跟他交流交流。如果你继续往代码中加入语句,run 之后,你会实时看到图形的改变。当绘图语句中加入 pl.ioff () 时或不添加 pl.ion () 时,表示打关了交互模式。此时要在代码末尾加入 pl.show () 才能显示图片。python 解释器解释完所有命令后,给你出张图,同时结束会话。如果你继续往代码中加入语句,再不会起作用,除非你关闭当前图片,重新 run。

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 25 23:28:29 2017
@author: wyl
original link: https://www.yanlongwang.net/Python/python-interactive-mode/
"""

import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import numpy as np
import math

plt.close() #clf() # 清图 cla() # 清坐标轴 close() # 关窗口
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.axis("equal") #设置图像显示的时候XY轴比例
plt.grid(True) #添加网格
plt.ion() #interactive mode on
IniObsX=0000
IniObsY=4000
IniObsAngle=135
IniObsSpeed=10*math.sqrt(2) #米/秒
print('开始仿真')
try:
for t in range(180):
#障碍物船只轨迹
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='.') #散点图
#ax.lines.pop(1) 删除轨迹
#下面的图,两船的距离
plt.pause(0.001)
except Exception as err:
print(err)