«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Построение графиков в реальном времени с помощью pyplot

Построение графиков в реальном времени с помощью pyplot

Опубликовано 8 ноября 2024 г.
Просматривать:571

Real-time plotting with pyplot

Я хотел построить график некоторых данных, которые я получил с помощью простого приложения для опроса. Раньше я возился с pyplot, но не пробовал создавать что-либо с нуля. К счастью, он очень популярен, и на StackOverflow и других сайтах можно найти массу примеров.

Я выполнил поиск и начал с этого SO-ответа, связанного с обновлением графика с течением времени.

import matplotlib.pyplot as plt
import numpy as np

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

x = np.linspace(0, 6*np.pi, 100)
y = np.sin(x)

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))
    fig.canvas.draw()
    fig.canvas.flush_events()

Этот код анимирует изменение фазы синусоидальной волны.

Первые две строки импортируют библиотеки, которые я хочу использовать: matplotlib.pyplot выполняет построение графиков и обработку графического интерфейса.

Метод ion(), насколько я понимаю (хотя может и нет), заставляет pyplot управлять графическим интерфейсом. Вы также можете использовать его внутри программы tkinter или использовать для создания статических изображений, но в нашем случае имеет смысл позволить ему обрабатывать графический интерфейс графика за нас. (Это то, что позже делает вызовlush_events(): разрешает интерактивность с окном рисунка.)

В этом примере используется метод numpy linspace() для создания значений x. Он возвращает массив numpy, который представляет собой необычный список Python.

Причина использования np.sin вместо math.sin — широковещательная рассылка. Это числовой термин для применения функции к каждому элементу списка. На самом деле мне пришло в голову, что того же самого можно было бы достичь и без numpy, используя карту:

map(lambda n: math.sin(n), x)

Но numpy-трансляция удобна и проста в использовании.

Теперь наступает настройка pyplot. Сначала создадим новую «фигуру» (рис). Добавьте к этому рисунку подграфик (топор) — их может быть много. 111 имеет довольно эзотерическую интерпретацию: «создайте сетку 1x1 и поместите этот подграфик в первую ячейку».

В этот подграфик (или набор осей) строится линия с использованием переданных значений x и y. (Точки соединяются прямыми линиями и отображаются непрерывно.) «r-» — это сокращенный способ обозначения сплошной красной линии. Мы могли бы указать несколько строк, поэтому методplot() возвращает кортеж; приведенный выше код использует распаковку кортежа для извлечения нужного нам значения.

Это хорошее начало, но мне нужно со временем расширить ось X. Этот код также не обновляет границы оси Y при необходимости — он привязан к любым границам, которые он рассчитывает для первого графика. Еще немного поисков привели меня к этому ТАК-ответу. Цитирую их:

Вам потребуется обновить dataLim осей, а затем обновить viewLim осей на основе dataLim. Соответствующими методами являются axes.relim() и ax.autoscale_view().

Конечно, звучит хорошо. На основе их примера я создал демонстрационный график, который растет как по x, так и по y.

import matplotlib.pyplot as plt
import numpy as np
from threading import Thread
from time import sleep

x = list(map(lambda x: x / 10, range(-100, 100)))
x_next_max = 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-')[0] # Returns a tuple of line objects

growth = 0

while True:
    x.append(x_next_max / 10)
    x_next_max  = 1
    line1.set_xdata(x)
    line1.set_ydata(np.sin(x)   np.sin(np.divide(x, 100))   np.divide(x, 100))
    ax.relim()
    ax.autoscale()
    fig.canvas.draw()
    fig.canvas.flush_events()

    sleep(0.1)

Теперь я чего-то добиваюсь. Но это блокирующий цикл, и мне нужно, чтобы мои данные время от времени обновлялись. Если бы у меня было несколько потоков, мне пришлось бы беспокоиться о потокобезопасности при обновлении переменных. В этом случае я могу лениться, потому что знаю, что переменная обновляется только раз в 5 минут (или как часто запускается функция опроса); нет опасности перезаписи переменной в середине строки кода.

import matplotlib.pyplot as plt
import numpy as np
from threading import Timer
from time import sleep

x = list(map(lambda x: x / 10, range(-100, 100)))
x_next_max = 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-')[0] # Plot returns a tuple of line objects

growth = 0
new_x = None

dT = 1

def grow():
    global new_x, x_next_max
    while True:
        new_x = x   [x_next_max / 10]
        x_next_max  = 1
        sleep(dT) # grow every dT seconds

t = Thread(target=grow)
t.start()

while True:

    if new_x:
        x = new_x
        new_x = None
        line1.set_xdata(x)
        line1.set_ydata(np.sin(x)   np.sin(np.divide(x, 100))   np.divide(x, 100))
        ax.relim()
        ax.autoscale()
        fig.canvas.draw()

    fig.canvas.flush_events()

    sleep(0.1)

График обновляется только тогда, когда поток роста присваивает значение new_x. Обратите внимание, что вызовlush_events() находится за пределами оператора if, поэтому он вызывается часто.

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/paxfeline/real-time-plotting-with-pyplot-2b3g?1. Если обнаружено какое-либо нарушение прав, свяжитесь с [email protected], чтобы удалить ее.
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3