I'm trying to plot real-time temperature data with the animation module from matplotlib in Python. I get the temperature data via USB connection from a Lake Shore 224 temperature monitor
Here is my adjusted code (source: https://learn.sparkfun.com/tutorials/graph-sensor-data-with-python-and-matplotlib/update-a-graph-in-real-time):
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from lakeshore import Model224
# You can ignore the following try and except block, it's a workaround for a different small problem
try:
from IPython import get_ipython
get_ipython().magic('clear')
get_ipython().magic('reset -f')
except:
pass
# Create figure for plotting
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs = []
ys = []
myinstrument = Model224()
# This function is called periodically from FuncAnimation
def animate(i, xs, ys):
# Read temperature from port A
temperature_A = myinstrument.get_kelvin_reading('A')
# Add x and y to lists
xs.append(dt.datetime.now().strftime('%H:%M:%S.%f'))
ys.append(temperature_A)
# Limit x and y lists to 20 items
xs = xs[-20:]
ys = ys[-20:]
# Draw x and y lists
ax.clear()
ax.plot(xs, ys)
# Format plot
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.ylabel('Temperature [K]')
# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig = fig, func = animate, fargs=(xs,ys), interval=10000, blit = True)
plt.show()
However, I get the following error message:
RuntimeError: The animation function must return a sequence of Artist objects.
At first, I did set as described in this case here:
blit = False
Which gives me no error message, but a blank white plot. Interestingly, it never enters the animate-Function.
Afterwards, I adjusted the code and added:
blit = True
To the function input, I got at least the following plot:
And I get the RuntimeError described above.
Still, I'm expecting a real-time temperature graph just like in the original source.
When using blitting, as per the documentation, you need to return the artists that change. The general approach for using FuncAnimation
is to create a blank plot and save the Line2D
object that it returns. Each loop you can update the data for that line using line.set_data()
and then return the line for blitting. When using FuncAnimation
properly, you don't need to worry about clearing the figure.
Since I don't have a sensor, I just produced some data at the start and slowly plot that in my example below.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
plt.close("all")
rng = np.random.default_rng(42)
N = 1000
xdata = np.linspace(0, 10, N)
ydata = np.sin(5*xdata)
fig, ax = plt.subplots()
line, = ax.plot([], [])
plt.xticks(rotation=45, ha="right")
ax.set_ylabel("Temperature [K]")
ax.set_ylim(-1.5, 1.5)
xs = []
ys = []
def animate(i, xs, ys):
xs.append(xdata[i])
ys.append(ydata[i])
xs = xs[-20:]
ys = ys[-20:]
line.set_data(xs, ys)
ax.set_xlim(min(xs), max(xs))
return line,
ani = animation.FuncAnimation(fig, animate, frames=N, fargs=(xs, ys), interval=10, blit=True)
fig.show()