I try to display sensor data using set_xdata
/set_ydata
instead of plot so it refreshes faster
I found this tutorial
Problem: nothing shows up
Expected: I should see the plotted data (used to work with ax1.plot
)
import pprint
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
from matplotlib.widgets import Button # Import Button
fig,ax1 = plt.subplots(figsize=(10, 8))
# Initialize the plot lines with some dummy data
line1, = ax1.plot([0], [0], label="LEFT", color="gray")
line2, = ax1.plot([0], [0], label="RIGHT", color="gray")
line3, = ax1.plot([0], [0], label="LEFT smoothed", color="red")
line4, = ax1.plot([0], [0], label="RIGHT smoothed", color="green")
plt.title("Phil VL53L0X sensors", fontsize=20)
# setting x-axis label and y-axis label
plt.xlabel("time")
plt.ylabel("distance")
xarr = []
yarr1 = []
yarr2 = []
yarr1_s = []
yarr2_s = []
count = 0
WINDOW_SIZE = 10
MIN_DISTANCE = 20
# Create the button to clear data
def clear_data(event):
global xarr, yarr1, yarr2, count, yarr1_s, yarr2_s
xarr.clear()
yarr1.clear()
yarr2.clear()
yarr1_s.clear()
yarr2_s.clear()
count = 0
ax1.clear()
ax1.set_xlabel("Time")
ax1.set_ylabel("Distance (mm)")
ax1.legend()
plt.draw()
def animate(i):
global count
# faking data, this is usually read by a sensor returning values between 0 and 100
distance1 = count
distance2 = count
distance1 = distance1 - MIN_DISTANCE
if distance1 < 0:
distance1 = 0
distance2 = distance2 - MIN_DISTANCE
if distance2 < 0:
distance2 = 0
count += 1
# Append new data
xarr.append(count)
yarr1.append(distance1)
yarr2.append(distance2)
# Apply moving average
smoothed_distance1 = moving_average(yarr1)
smoothed_distance2 = moving_average(yarr2)
yarr1_s.append(smoothed_distance1)
yarr2_s.append(smoothed_distance2)
# Limit size of arrays to avoid excessive memory usage
if len(yarr1) > 100:
yarr1.pop(0)
yarr2.pop(0)
yarr1_s.pop(0)
yarr2_s.pop(0)
xarr.pop(0)
pprint.pprint(xarr)
pprint.pprint(yarr1)
# Update the X data (only once)
line1.set_xdata(xarr)
line2.set_xdata(xarr)
line3.set_xdata(xarr)
line4.set_xdata(xarr)
# Update the plot (without clearing it)
line1.set_ydata(yarr1)
line2.set_ydata(yarr2)
line3.set_ydata(yarr1_s)
line4.set_ydata(yarr2_s)
# Update the plot (this works)
#ax1.plot(xarr, yarr1, label="LEFT", color="gray")
#ax1.plot(xarr, yarr2, label="RIGHT", color="gray")
#ax1.plot(xarr, yarr1_s, label="LEFT s", color="red")
#ax1.plot(xarr, yarr2_s, label="RIGHT s", color="green")
fig.canvas.draw()
fig.canvas.flush_events()
time.sleep(0.1)
ani = animation.FuncAnimation(fig, animate, interval=1) # Increased interval for smoother updates
# Add a button to clear data
ax_button = plt.axes([0.8, 0.05, 0.1, 0.075])
btn = Button(ax_button, "Clear Data")
btn.on_clicked(clear_data)
plt.show()
I pprint
the data as it animates, it is clearly there.
What am I missing here?
I try to display sensor data using set_xdata
/set_ydata
instead of plot so it refreshes faster
I found this tutorial
Problem: nothing shows up
Expected: I should see the plotted data (used to work with ax1.plot
)
import pprint
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
from matplotlib.widgets import Button # Import Button
fig,ax1 = plt.subplots(figsize=(10, 8))
# Initialize the plot lines with some dummy data
line1, = ax1.plot([0], [0], label="LEFT", color="gray")
line2, = ax1.plot([0], [0], label="RIGHT", color="gray")
line3, = ax1.plot([0], [0], label="LEFT smoothed", color="red")
line4, = ax1.plot([0], [0], label="RIGHT smoothed", color="green")
plt.title("Phil VL53L0X sensors", fontsize=20)
# setting x-axis label and y-axis label
plt.xlabel("time")
plt.ylabel("distance")
xarr = []
yarr1 = []
yarr2 = []
yarr1_s = []
yarr2_s = []
count = 0
WINDOW_SIZE = 10
MIN_DISTANCE = 20
# Create the button to clear data
def clear_data(event):
global xarr, yarr1, yarr2, count, yarr1_s, yarr2_s
xarr.clear()
yarr1.clear()
yarr2.clear()
yarr1_s.clear()
yarr2_s.clear()
count = 0
ax1.clear()
ax1.set_xlabel("Time")
ax1.set_ylabel("Distance (mm)")
ax1.legend()
plt.draw()
def animate(i):
global count
# faking data, this is usually read by a sensor returning values between 0 and 100
distance1 = count
distance2 = count
distance1 = distance1 - MIN_DISTANCE
if distance1 < 0:
distance1 = 0
distance2 = distance2 - MIN_DISTANCE
if distance2 < 0:
distance2 = 0
count += 1
# Append new data
xarr.append(count)
yarr1.append(distance1)
yarr2.append(distance2)
# Apply moving average
smoothed_distance1 = moving_average(yarr1)
smoothed_distance2 = moving_average(yarr2)
yarr1_s.append(smoothed_distance1)
yarr2_s.append(smoothed_distance2)
# Limit size of arrays to avoid excessive memory usage
if len(yarr1) > 100:
yarr1.pop(0)
yarr2.pop(0)
yarr1_s.pop(0)
yarr2_s.pop(0)
xarr.pop(0)
pprint.pprint(xarr)
pprint.pprint(yarr1)
# Update the X data (only once)
line1.set_xdata(xarr)
line2.set_xdata(xarr)
line3.set_xdata(xarr)
line4.set_xdata(xarr)
# Update the plot (without clearing it)
line1.set_ydata(yarr1)
line2.set_ydata(yarr2)
line3.set_ydata(yarr1_s)
line4.set_ydata(yarr2_s)
# Update the plot (this works)
#ax1.plot(xarr, yarr1, label="LEFT", color="gray")
#ax1.plot(xarr, yarr2, label="RIGHT", color="gray")
#ax1.plot(xarr, yarr1_s, label="LEFT s", color="red")
#ax1.plot(xarr, yarr2_s, label="RIGHT s", color="green")
fig.canvas.draw()
fig.canvas.flush_events()
time.sleep(0.1)
ani = animation.FuncAnimation(fig, animate, interval=1) # Increased interval for smoother updates
# Add a button to clear data
ax_button = plt.axes([0.8, 0.05, 0.1, 0.075])
btn = Button(ax_button, "Clear Data")
btn.on_clicked(clear_data)
plt.show()
I pprint
the data as it animates, it is clearly there.
What am I missing here?
Share Improve this question edited Feb 5 at 9:28 DavidG 25.4k14 gold badges100 silver badges86 bronze badges asked Feb 4 at 18:47 philphil 527 bronze badges1 Answer
Reset to default 0I think the main problem is that you need to make sure that the axis limits are set such that they include your data. Another issue is using:
fig.canvas.draw()
fig.canvas.flush_events()
time.sleep(0.1)
in your animate
function while also using the FuncAnimation
class - you should do one or the other (see the FuncAnimation
examples here).
An working example (simplified further from your example) would be:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
from matplotlib.widgets import Button # Import Button
fig,ax1 = plt.subplots(figsize=(10, 8))
# Initialize the plot lines with some dummy data
line1, = ax1.plot([], [], label="LEFT", color="C0")
line2, = ax1.plot([], [], label="RIGHT", color="C1")
plt.title("Phil VL53L0X sensors", fontsize=20)
# setting x-axis label and y-axis label
plt.xlabel("time")
plt.ylabel("distance")
xarr = []
yarr1 = []
yarr2 = []
count = 0
WINDOW_SIZE = 10
MIN_DISTANCE = -10
# set initial x and y bounds of the plot
INI_X_BOUNDS = [-10, 10]
INI_Y_BOUNDS = [0, 10]
ax1.set_xlim(INI_X_BOUNDS)
ax1.set_ylim(INI_Y_BOUNDS)
# Create the button to clear data
def clear_data(event):
global xarr, yarr1, yarr2, count
xarr.clear()
yarr1.clear()
yarr2.clear()
count = 0
ax1.set_xlim(INI_X_BOUNDS)
ax1.set_ylim(INI_Y_BOUNDS)
def animate(i):
global count
# faking data, this is usually read by a sensor returning values between 0 and 100
distance1 = count
distance2 = count / 2
distance1 = distance1 - MIN_DISTANCE
if distance1 < 0:
distance1 = 0
distance2 = distance2 - MIN_DISTANCE
if distance2 < 0:
distance2 = 0
# Append new data
xarr.append(count)
yarr1.append(distance1)
yarr2.append(distance2)
# Limit size of arrays to avoid excessive memory usage
if len(yarr1) > 100:
yarr1.pop(0)
yarr2.pop(0)
xarr.pop(0)
# Update the X data (only once)
line1.set_data(xarr, yarr1)
line2.set_data(xarr, yarr2)
# update the upper limit on the x-y axis ranges
# play around with this as you see fit
xlims = ax1.get_xlim()
ylims = ax1.get_ylim()
if xarr[-1] > xlims[-1]:
# double x limit
ax1.set_xbound(upper=xlims[-1] * 2)
if max(yarr1[-1], yarr2[-1]) > ylims[-1]:
# double y limit
ax1.set_ybound(upper=ylims[-1] * 2)
count += 1
# using frames=None will give infinite running
ani = animation.FuncAnimation(fig, animate, frames=None, interval=0.05)
# Add a button to clear data
ax_button = plt.axes([0.8, 0.05, 0.1, 0.075])
btn = Button(ax_button, "Clear Data")
btn.on_clicked(clear_data)
plt.show()
The main things this does is:
- set the initial axes x-y bounds
- update the upper x-y bounds if the data gets out the current range (play about with this as you require)
- remove the updating of the
fig.canvas
from within theanimate
function - to simplify things, it just uses
set_data
rather thanset_xdata
andset_ydata
separately.