Матплотлиб "Реальное время" зарисовка на питоне - PullRequest
0 голосов
/ 06 февраля 2019

Я на питоне 3.7.Я пытаюсь прочитать данные с последовательного порта, это будет 7 разных байтов.Затем я хотел бы разместить каждый отдельный байт на отдельном участке.Я хочу читать последовательный порт каждые 500 мс, и каждый раз, когда я читаю, добавляю новые данные на участки.Каждое чтение дает еще одну информацию для построения на каждом участке.Это в основном показания датчика.

Вот код, который я написал:

со времени импорта, сна, импорта, последовательного импорта, matplotlib.pyplot как plt

f=plt.figure(1)
ax=[0 for x in range(7)]
for i in range(0,7):
    ax[i]=f.add_subplot(4,2,1+i)

ser = serial.Serial('COM3', 115200) # Establish the connection on a specific port
counter = 0 
byte=ser.readline() #first line not to be plotted
while True:
    counter +=1
    ser.write(b'9') # send a command to the arduino
    byte=ser.read(7) #read 7 bytes back
    for i in range(0,7):
        ax[i].plot(counter, byte[i]) # Trying to plot the new values to each different subplots
    plt.pause(0.01)
    sleep(.5) # Delay for one half of a second

На рисунке показанои ось x и ось y адаптируются к значению, которое я хочу указать, но на графике нет никаких данных вообще.Если я использую Scatter вместо графика, он работает, но тогда он менее универсален, и я не могу нарисовать тот тип графика, который мне нужен.Я также пытаюсь воспроизвести проблему, не используя последовательные данные, а просто отображая точки списка одну за другой следующим образом:

import matplotlib.pyplot as plt
from time import sleep

f=plt.figure()
series=[[4,3,2,1],[8,7,6,5],[12,11,10,9]]
counter=0
ax=[0 for x in range(7)]

for i in range(0,3):
    ax[i]=f.add_subplot(4,2,1+i)


for j in range (0,4):
    counter=counter+1
    for i in range(0,3):
        ax[i].plot(counter,series[i][j])
    plt.pause(0.01)
    sleep(1)

И он делает то же самое, окончательное изображение, которое я имею награфик таков: enter image description here Который показывает, что ось взяла то, что я хотел построить, но ничего не изобразил.Дело в том, что я не хочу очищать весь график и перерисовывать все, потому что для датчика данных у меня будет около 30 дней данных для отображения в непрерывном режиме.Что я делаю не так с кодом, который я написал?

РЕДАКТИРОВАТЬ: После комментария ImportanceOfBeingErnest я попытался реализовать ответ, данный здесь .Код тогда:

from time import sleep
import serial
import matplotlib.pyplot as plt
import numpy

plt.ion()
f=plt.figure()
ax=[0 for x in range(7)]
lines=[0 for x in range(7)]
for i in range(0,7):
    ax[i]=f.add_subplot(4,2,1+i)
    lines[i]=ax[0].plot([],[])


def update_line(hl, new_datax, new_datay):
    hl.set_xdata(numpy.append(hl.get_xdata(), new_datax))
    hl.set_ydata(numpy.append(hl.get_ydata(), new_datay))
    plt.draw()

ser = serial.Serial('COM3', 115200) # Establish the connection on a specific port
counter = 0 
byte=ser.readline() #first line not to be plotted
while True:
    counter +=1
    ser.write(b'9') # send a command to the arduino
    byte=ser.read(7) #read 7 bytes back
    for i in range(0,7):
        update_line(lines[i][0], counter, byte[i]) # Trying to plot the new values to each different subplots
    plt.pause(0.01)
    sleep(.5) # Delay for one half of a second

Но все равно ничего не показывает.Я думаю, что мне не хватает сюжета и / или где-нибудь очистить, но после нескольких попыток я не могу заставить его работать.

1 Ответ

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

Как человек, который работал в оптической лаборатории и изо всех сил пытался заставить Matplotlib выполнять построение графиков в реальном времени, я чувствую вашу боль , и я настоятельно рекомендую выбрать для этой цели что-то отличное от Matplotlib (например, * 1003).*).

Тем не менее, я получил Matplotlib для выполнения некоторых графиков в режиме реального времени на основе данных датчика.Я обнаружил, что это глючит. Вот некоторые мысли , а также решение, которое использует matplotlib:

Используйте словари, где это возможно. Почему?Поскольку доступ к словарям быстрый, и я считаю, что ключ словаря для этих целей проще использовать, чем индекс списка.

Использовать списки вместо массивов NumPy. Почему?Потому что каждый раз, когда вы изменяете размер или добавляете массив NumPy, он должен быть полностью переписан как новый объект в памяти.Это очень дорого.Размеры списков могут быть изменены и добавлены за незначительную стоимость.

В приведенном ниже коде используются случайные данные для имитации входных данных датчика и упрощения поиска и устранения неисправностей.

1.Импорт

from time import sleep
import matplotlib.pyplot as plt
import numpy as np
#import serial

2.Настройте ваши объекты matplotlib и контейнеры данных

# specify how many points to show on the x-axis
xwidth = 10

# use real-time plotting
plt.ion()

# setup each of the subplots
ax = []
fig, ax[0:7] = plt.subplots(7, 1, sharex=False, sharey=False)

# set up each of the lines/curves to be plotted on their respective subplots
lines = {index: Axes_object.plot([],[])[0] for index, Axes_object in enumerate(ax)}

# cache background of each plot for fast re-drawing, AKA Blit
ax_bgs = {index: fig.canvas.copy_from_bbox(Axes_object.bbox) 
          for index, Axes_object in enumerate(ax)}

# initial drawing of the canvas
fig.canvas.draw()

# setup variable to contain incoming serial port data
y_data = {index:[0] for index in range(len(ax))}
x_data = [-1]

3.Напишите функции для обновления графика и обновления ваших контейнеров данных

def update_data(new_byte, ):
    x_data.append(x_data[-1] + 1)
    for i, val in enumerate(new_byte): 
        y_data[i].append(val)

def update_graph():
    for i in y_data.keys():
        # update each line object
        lines[i].set_data(x_data, y_data[i])

        # try to set new axes limits
        try:
            ax[i].set_xlim([x_data[-1] - xwidth, x_data[-1]])
            if max(y_data[i][-xwidth:]) > ax[i].get_ylim()[1]:
                new_min = min(y_data[i][-xwidth:])
                new_max = max(y_data[i][-xwidth:])
                ax[i].set_ylim([new_min-abs(new_min)*0.2, new_max+abs(new_max)*0.2])
        except:
            continue

    fig.canvas.draw()

4.Наконец, запустите цикл

#ser = serial.Serial('COM3', 115200) # Establish the connection on a specific port
#byte=ser.readline() #first line not to be plotted


while x_data[-1] < 30:
    # ser.write(b'9') # send a command to the arduino
    # byte=ser.read(7) #read 7 bytes back
    byte = np.random.rand(7)

    update_data(byte)
    update_graph()

    sleep(.1) # Delay for an arbitrary amount of time

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...