Живой график Matplotlib, способный обрабатывать длительные промежутки времени между обновлениями данных - PullRequest
0 голосов
/ 11 июля 2019

Я заметил, что каждое решение для построения непрерывно обновляемых данных (я обнаружил) с непрерывно увеличивающейся длиной имеет одну огромную задержку: если данных нет сразу, окно 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, но при этом окно графика зависает. Возьмите это также:

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 минут.

EDIT:

После дальнейшего тестирования можно использовать FuncAnimation, но он очень хакерский и все еще немного сломан. Если вы увеличите interval до ожидаемого времени animate, оно будет работать, но каждый раз, когда вы перемещаете или масштабируете график, все данные исчезают до следующего обновления. Поэтому, когда у вас есть вид, вы не можете его коснуться.

Edit:

Для ясности изменен сон на цикл for

Ответы [ 2 ]

1 голос
/ 11 июля 2019

Обновленный ответ: Проблема заключается в том, что сбор или генерация данных и окно matplotlib выполняются в одном потоке, поэтому первый блокирует второй.Чтобы преодолеть это, переместите сбор данных в отдельный процесс, как показано в в этом примере .Вместо процессов и каналов вы также можете использовать потоки и очереди.

0 голосов
/ 11 июля 2019

Посмотрите этот пример с использованием сна, он работает хорошо:

= ^ .. ^ =

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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...