繁体   English   中英

如何在数据文件更改时动态更新我的 matplotlib 图?

[英]How can I dynamically update my matplotlib figure as the data file changes?

我有一个 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(),脚本将不再更新绘图。 有没有办法在不完全失去缩放/平移功能的情况下动态更新绘图?

你的代码有点太模糊,不知道发生了什么。

我可以提供:如果您创建一次子图,保存所有轴对象,然后调用 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()

如果您愿意,可以手动添加用于缩放和平移的工具栏。

当您正在开发软件时,我想您可能有一种多线程方法。 因此,在这种情况下,使用无限 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()

你可以这样做。 它接受 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) 这是它的外观: 在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM