My code takes a continuously updating input from raspberry pi, which is then plotted onto a graph. I'm trying to use the legend to display the current frequency (most recent output of y_data) however I can't seem to get it to display. Placing plt.legend()
just before plt.show()
results in a display, however freezing of the graph. Any help would be greatly appreciated.
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
I think you should call fig.canvas.draw()
at the end of the update function, not in the middle of it. I'm not sure why you add all the artists again in the update function, so you may leave that out. Concerning the legend, It's probably best to create it once at the beginning and inside the update function only update the relevant text.
Commenting out all the GPIO stuff, this is a version which works fine for me:
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