I am making a live plotter to show the analog changes from an Arduino Sensor. The Arduino prints a value to the serial with a Baudrate of 9600. The Python code looks as following:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import serial
import time
ser = serial.Serial("com3", 9600)
ser.readline()
optimal_frequency = 100
fig = plt.figure(figsize=(6, 6))
ax1 = fig.add_subplot(1, 1, 1)
# the following arrays must be initialized outside the loop
xar = []
yar = []
print(time.ctime())
def animate(i):
global b, xar, yar # otherwise a
for i in range(optimal_frequency):
a = str(ser.readline(), 'utf-8')
try:
b = float(a)
except ValueError:
ser.readline()
xar.append(str(time.time()))
yar.append(b)
ax1.clear()
ax1.plot(xar, yar)
ani = animation.FuncAnimation(fig, animate, interval=optimal_frequency)
plt.show()
A get an ok response time in the plot, but when I have been plotting over 20 minutes the reaction times increase to about 1 min. I.e. it takes 1 min forthe graph to get updated with the new values. I have also tried with PyQtGraph but that is delayed from a start.
Besides the delay for times over 20 minutes, I am getting some overshoots and undershoots in the plot.
Any help?
as mentioned in the comments, you are doing two things wrong:
ax.plot()
at every iteration.what you want to do instead is:
in an initialization function, create an empty Line2D object
then in your update function (
animate()
), you useline.set_data()
to update the coordinates of your points. However, to maintain performance, you have to keep the size of your arrays to a reasonable size, and so you will have to drop the older data as newer data comes inCheck out some tutorials like this one. There are also plenty of questions on SO that already answers your question. For instance, this answer contains all the elements you need to get your code working.