图例不适用于实时数据和 while 循环配置

Legend not working for live data and while loop configuration

我的代码从 raspberry 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

update 的末尾添加 plt.draw()(或 fig.canvas.draw_idle() 以获得更面向对象的方法)。

我认为你应该在更新函数的末尾调用 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