如何在数据文件更改时动态更新我的 matplotlib 图形?
Posted
技术标签:
【中文标题】如何在数据文件更改时动态更新我的 matplotlib 图形?【英文标题】:How can I dynamically update my matplotlib figure as the data file changes? 【发布时间】:2011-12-06 20:28:25 【问题描述】:我有一个 python 脚本,它读取一个数据文件并使用 matplotlib 库显示一个带有四个图的图形。数据文件每隔几秒钟就会更新一次,因为它是同时运行的不同软件的输出文件。我希望我的 matplotlib 图中的四个图每 20 秒使用更新的数据文件刷新一次。我的实现方式如下:
import pylab as pl
import time
pl.ion()
fig = pl.figure()
while True:
f = open('data.out', 'rb')
#code to parse data and plot four charts
ax = fig.add_subplot(2,2,1)
#...
ax = fig.add_subplot(2,2,4)
#...
pl.draw()
time.sleep(20)
这可行,但我失去了缩放和平移按钮的功能,如果调用 pl.show(),这些按钮通常可以工作。这不是最优的。但是,如果用 pl.show() 代替 pl.draw(),则脚本不再更新绘图。有没有办法在不完全失去缩放/平移功能的情况下动态更新绘图?
【问题讨论】:
【参考方案1】:您的代码有点太模糊,不知道发生了什么。
我可以提供这个: 如果您创建一次子图,保存所有坐标区对象,然后调用 show(),则应保留正常功能。
可以像这样对这些子图进行后续更改:
#inside while loop
for i in #subplotlist
ax[i].clear() #ax[i] is the axis object of the i'th subplot
ax[i].plot(#plotstuff)
ax[i].draw()
如果您愿意,可以手动添加缩放和平移工具栏。
【讨论】:
【参考方案2】:当您正在开发软件时,我想您可能会采用多线程方法。 因此,在这种情况下,使用无限的 while 循环是个坏主意,就像你在挂起你的主线程一样。
此外,当涉及到 GUI 时,突然干扰 GUI 内部线程(例如 wxPython)也是一个坏主意,您应该采用事件驱动的设计方法,以免突然中断其他线程(这将导致您的应用程序崩溃)。
使用计时器就可以了。
计时器将在以下脚本中执行这些操作:
1/ 调用函数清除以前的艺术家
2 / 重新绘制数据
3/ 将更改应用到画布
4/ 按以下设计方式创建另一个相同的计时器:一个计时器在完成其工作后调用另一个相同的计时器
就像我无权访问您的数据一样,我为插图创建了一个随机数据提供程序。 定义的变量 delay_repeat 允许您在几秒钟内对刷新进行编程。
import pylab as pl
import random
from threading import Timer
def dataprovider():
return [random.randint(0, 8) for i in range(8)]
def random_col():
return ['blue', 'red', 'green', 'orange'][random.randint(0,3)]
# .... #
fig = pl.figure()
axes = [fig.add_subplot(2,2,i) for i in range(1,5)]
paths = [ax.scatter(x=dataprovider(), y=dataprovider(), marker = '+', c=random_col()) for ax in axes]
# .... #
def clear_arts(paths, all_arts=-1):
if all_arts < 0:
all_arts = len(paths)
for path in paths[:all_arts]:
path.remove()
def refresh_arts(paths, delay_repeat):
# 1 - clear previous artists
clear_arts(paths,all_arts=-1)
# 2 - Get artists paths for cleaning
paths = [ax.scatter(x=dataprovider(), y=dataprovider(), marker = '+', c=random_col()) for ax in axes]
# 3 - Apply changes
fig.canvas.draw_idle()
# 4 - Create another timer
Timer(delay_repeat, refresh_arts, (paths, delay_repeat)).start()
# 4- Create a timer that will run function with arguments args and keyword arguments kwargs,
# after interval seconds have passed.
delay_repeat = 2
Timer(delay_repeat, refresh_arts, (paths, delay_repeat)).start()
# print("process continues here")
pl.show()
【讨论】:
【参考方案3】:你可以这样做。它接受 x,y 作为列表并在同一图上输出散点图和线性趋势。
from IPython.display import clear_output
from matplotlib import pyplot as plt
%matplotlib inline
def live_plot(x, y, figsize=(7,5), title=''):
clear_output(wait=True)
plt.figure(figsize=figsize)
plt.xlim(0, training_steps)
plt.ylim(0, 100)
x= [float(i) for i in x]
y= [float(i) for i in y]
if len(x) > 1:
plt.scatter(x,y, label='axis y', color='k')
m, b = np.polyfit(x, y, 1)
plt.plot(x, [x * m for x in x] + b)
plt.title(title)
plt.grid(True)
plt.xlabel('axis x')
plt.ylabel('axis y')
plt.show();
您只需要在循环中调用live_plot(x, y)
。这是它的外观:
【讨论】:
以上是关于如何在数据文件更改时动态更新我的 matplotlib 图形?的主要内容,如果未能解决你的问题,请参考以下文章