2016-12-13 5 views
0

В моем коде постоянно обновляется ввод малины pi, который затем отображается на графике. Я пытаюсь использовать легенду, чтобы отображать текущую частоту (самый последний вывод y_data), однако я не могу заставить ее отображать ее. Размещение plt.legend() непосредственно перед plt.show() приводит к отображению, однако замораживание графика. Любая помощь будет принята с благодарностью.Легенда не работает для данных в реальном времени и в конфигурации контура

import matplotlib 
matplotlib.use('qt5agg') 
from matplotlib.figure import Figure 
import matplotlib.pyplot as plt 
import RPi.GPIO as GPIO 
import time 
import numpy as np 

x_data = [] 
y_data = [] 

GPIO.setmode(GPIO.BCM)    
INPUT_PIN = 26      
GPIO.setup(INPUT_PIN, GPIO.IN) 

fig, ax = plt.subplots() 
line, = plt.plot([],[], 'k-',label = 'data', drawstyle = 'steps') 
avr, = plt.plot([],[], 'g--',label = 'mean') 
plt.show(block = False) 

def update(x_data, y_data, average): 

    line.set_ydata(y_data) 
    line.set_xdata(x_data) 
    avr.set_xdata(x_data) 
    avr.set_ydata([average]*len(x_data)) 
    fig.canvas.draw() 
    ax.draw_artist(ax.patch) 
    ax.draw_artist(line) 
    ax.draw_artist(avr) 
    ax.relim() 
    ax.autoscale_view() 
    data = round(y_data[-1], 1) 
    ax.legend((line, avr), (data, 'mean')) 
    fig.canvas.update() 
    fig.canvas.flush_events() 

while True:        #Begin continuous loop 
    NUM_CYCLES = 10      #Loops to be averaged over 
    start = time.time() 
    for impulse_count in range(NUM_CYCLES): 
     GPIO.wait_for_edge(INPUT_PIN, GPIO.FALLING) 
    duration = time.time() - start  #seconds to run for loop 

    frequency = NUM_CYCLES/duration #Frequency in Hz 
    bpm = (frequency/1000)*60   #Frequency/no. of cogs per breath * min 

    x_data.append(time.time()) #add new data to data lists 
    y_data.append(bpm)    

    average = sum(y_data)/float(len(y_data)) 
    update(x_data,y_data, average)  #call function to update graph contents 

ответ

0

Думаю, вам нужно позвонить fig.canvas.draw() в конце функции обновления, а не посередине. Я не уверен, почему вы добавляете всех художников в функцию обновления, поэтому вы можете это исключить. Что касается легенды, то, вероятно, лучше всего создать ее один раз в начале и внутри функции обновления только обновить соответствующий текст.

Комментирование всех вещей GPIO, это версия, которая работает для меня:

import matplotlib 
#matplotlib.use('qt5agg') 
from matplotlib.figure import Figure 
import matplotlib.pyplot as plt 
#import RPi.GPIO as GPIO 
import time 
import numpy as np 

x_data = [] 
y_data = [] 

#GPIO.setmode(GPIO.BCM)    
#INPUT_PIN = 26      
#GPIO.setup(INPUT_PIN, GPIO.IN) 

fig, ax = plt.subplots() 
line, = plt.plot([],[], 'k-',label = 'data', drawstyle = 'steps') 
avr, = plt.plot([],[], 'g--',label = 'mean') 
# add legend already at the beginning 
legend = ax.legend((line, avr), (0.0, 'mean')) 
plt.show(block = False) 

def update(x_data, y_data, average): 

    line.set_ydata(y_data) 
    line.set_xdata(x_data) 
    avr.set_xdata(x_data) 
    avr.set_ydata([average]*len(x_data)) 
    #fig.canvas.draw() <- use this at the end 
    #ax.draw_artist(ax.patch) # useless? 
    #ax.draw_artist(line)  # useless? 
    #ax.draw_artist(avr)  # useless? 

    ax.relim() 
    ax.autoscale_view() 
    data = round(y_data[-1], 1) 
    # only update legend here 
    legend.get_texts()[0].set_text(str(data)) 

    #fig.canvas.update() # <- what is this one needed for? 
    fig.canvas.draw() 
    fig.canvas.flush_events() 


while True:        #Begin continuous loop 
    NUM_CYCLES = 10      #Loops to be averaged over 
    start = time.time() 
    #for impulse_count in range(NUM_CYCLES): 
    # GPIO.wait_for_edge(INPUT_PIN, GPIO.FALLING) 
    a = np.random.rand(700,800) # <- just something that takes a little time 

    duration = time.time() - start  #seconds to run for loop 

    frequency = NUM_CYCLES/duration #Frequency in Hz 
    bpm = (frequency/1000)*60   #Frequency/no. of cogs per breath * min 

    x_data.append(time.time()) #add new data to data lists 
    y_data.append(bpm)    

    average = sum(y_data)/float(len(y_data)) 
    update(x_data,y_data, average)  #call function to update graph contents 
+0

Все работает, однако мне нужно, чтобы мое значение data в моей легенде было постоянно обновляемым значением частоты. Set_text дает мне строковые «данные», а не число, вычисленное непосредственно перед ним. –

+0

Альтернативно, если был способ отображения постоянно обновляемого раздела текста, который не должен использовать функцию легенды, которая была бы превосходной. –

+0

Строка 'legend.get_texts() [0] .set_text (str (data))' делает именно то, что вам нужно, т. Е. Показывает последнее значение в 'y_data', округленное до одного десятичного знака в легенде. Поскольку 'set_text()' может обрабатывать значения float, вы можете оставить команду 'str', если это сделает вас более комфортным. Если вам не нужна легенда, но чистый текст, вы можете, конечно, использовать команду ['text'] (http://matplotlib.org/users/text_intro.html) вместо легенды. – ImportanceOfBeingErnest

0

Добавить plt.draw() (или fig.canvas.draw_idle() для более ОО подход) в конце update.

+0

ли, что решить проблему размещения легенды на рисунок? – ImportanceOfBeingErnest

+0

@ImportanceOfBeingErnest Это для меня. Я ничего не изменил, кроме как удалить материал «GPIO» и заменить «GPIO.wait_for_edge» на 'time.sleep'. – Goyo

+0

Достаточно честный. Это не сработало для меня, поэтому я отправил свой ответ. Возможно, это связано с «qt5agg», которого у меня нет. – ImportanceOfBeingErnest