【问题标题】:Matplotlib live graph capable of handling long times between data updatesMatplotlib 实时图能够处理数据更新之间的长时间
【发布时间】:2019-07-11 06:09:59
【问题描述】:

我注意到,每一种以不断增加的长度绘制连续更新数据(我发现)的解决方案都有一个巨大的挫折——如果数据没有立即出现,matplotlib 窗口就会冻结(说没有响应)。以此为例:

from matplotlib import pyplot as plt
from matplotlib import animation
from random import randint
from time import sleep
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
line, = ax.plot([])
x = []
y = []
def animate(i):
    x.append(i)
    y.append(randint(0,10))
    for i in range(100000000):
        # Do calculations to attain next data point
        pass
    line.set_data(x, y)
    return line,

anim = animation.FuncAnimation(fig, animate,
                               frames=200, interval=20, blit=True)
plt.show()

此代码在 animate 函数中没有数据采集 for 循环的情况下工作正常,但在那里,图形窗口冻结。也拿这个:

plt.ion()
x = []

for i in range(1000):
    x.append(randint(0,10))
    for i in range(100000000):
        # Do calculations to attain next data point
        pass
    plt.plot(x)
    plt.pause(0.001)

也会冻结。 (感谢上帝,因为使用这种方法几乎不可能关闭,因为图表不断在所有内容前面弹出。我不建议取消睡眠)

这也是:

plt.ion()
x = []

for i in range(1000):
    x.append(randint(0,10))
    for i in range(100000000):
        # Do calculations to attain next data point
        pass
    plt.plot(x)
    plt.draw()
    plt.pause(0.001)
    plt.clf()

还有这个:(复制自https://stackoverflow.com/a/4098938/9546874

import matplotlib.pyplot as plt
import numpy as np
from time import sleep
x = np.linspace(0, 6*np.pi, 100)
y = np.sin(x)

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma

for phase in np.linspace(0, 10*np.pi, 500):
    line1.set_ydata(np.sin(x + phase))
    for i in range(100000000):
        # Do calculations to attain next data point
        pass
    fig.canvas.draw()
    fig.canvas.flush_events()

这是一个大问题,因为认为所有数据都会以一致的时间间隔出现是幼稚的。我只想要一个在数据到来时更新的图表,并且不会在停机时间内崩溃。请记住,数据之间的间隔可能会发生变化,可能是 2 秒或 5 分钟。

编辑:

经过进一步测试,FuncAnimation 可以使用,但它非常hacky,仍然有点坏。如果将interval 增加到animate 的预期时间以上,它会起作用,但是每次平移或缩放图形时,所有数据都会消失,直到下一次更新。因此,一旦有了视图,就无法触摸它。

编辑:

为了清晰起见,将 sleep 更改为 for 循环

【问题讨论】:

  • 我喜欢这个解决方案:stackoverflow.com/a/15724978
  • 这是 GUI 的固有问题。一方面,您需要响应式 GUI,这意味着事件循环需要不断运行。另一方面,您想要执行广泛的计算。为了满足这两个要求,事件循环和计算需要在不同的线程中运行。这将显示在Python update Matplotlib from threads

标签: python matplotlib


【解决方案1】:

更新的答案: 问题是数据获取或生成和 matplotlib 窗口在同一个线程上运行,因此前者阻塞了后者。为了克服这个问题,将数据采集转移到一个单独的过程中,如this example 所示。除了进程和管道,您还可以使用线程和队列。

【讨论】:

  • 这不是重点,我使用sleep 作为一些代码块的占位符,这可能需要长达 2 秒的时间。为了清楚起见,我已将 sleep 替换为此类。
  • 我认为这就是重点。睡眠或您现在放入示例中的 for 循环在 tkinter 的主循环上执行,从而使程序无响应。您必须异步进行数据采集。这通过 plt.pause 与 sleep 进行了演示。
  • 你的意思是线程收集数据,并使用plt.pause等待线程返回? matplotlib 是否还有其他函数可以动态等待线程返回,而不是等待硬编码的时间?
  • 是的,基本想法是在单独的线程上获取您的数据。也许this example 有帮助。
  • 我刚刚通过在data = np.random.random(2) 之前插入sleep(5) 来测试linked example 的方法,模拟新数据将仅每5 秒到达一次,并且matplotlib 窗口保持完美响应。跨度>
【解决方案2】:

查看这个使用睡眠的例子,它运行良好:

=^..^=

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation


fig, ax = plt.subplots()
x = np.arange(0, 2*np.pi, 0.01)
line, = ax.plot(x)


def animate(i):
    y_data = 0
    for j in range(10):
        y_data = np.random.uniform(-1, j, 1)

    line.set_ydata(y_data)
    plt.pause(1)
    return line,


ani = animation.FuncAnimation(
    fig, animate, interval=2, blit=True, save_count=50)


plt.ylim(-2, 11)
plt.show()

【讨论】:

  • 虽然窗口不再卡在“无响应”上,但现在速度非常慢。还有其他解决方案吗?它仍然无法使用。这些数据也有固定长度,而我将使用的数据不会(我已经在上面更新了)
  • @Recessive 嗯..不明白你的问题。这一切的预期结果是什么?
  • 这只是显示图形的实际窗口非常慢。移动图形窗口需要很长时间,而且它经常冻结我的屏幕,因此我无法使用光标。
  • @Recessive 您需要对窗口进行任何操作,例如:调整大小、缩放?
  • 是的,但是当我的屏幕冻结时,这些都不是什么大问题
猜你喜欢
  • 1970-01-01
  • 2018-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-31
相关资源
最近更新 更多