I am attempting to show a sort of plot refresh on a sequence of array. Each array is an instance of the sequence and for each of them I want to plot the relative array, plus its smoothed version, like that: these frames should be showed in sequence thanks to the animation function Anyway the following error " AttributeError: 'list' object has no attribute 'get_zorder' " arises when I return the relative lines from the animation function. I tried solutions from other questions and channels but nothing really worked. Here is the code:
import random
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from scipy.signal import savgol_filter
n_instances = 1000 # the instances that will be generated
instances_duration = 100 # the duration of each of them
# starting the data matrix
process_instances = np.zeros((n_instances, instances_duration))
# starting the filtered data matrix
filtered_instances = np.zeros((n_instances, instances_duration))
np.random.seed(2)
for i in range(n_instances):
# creating the instance as a random array
current_instance = np.random.normal(0, 1, instances_duration)
# assigning to the relative matrix
process_instances[i, :] = current_instance
# filtering and assigning to the relative matrix
filtered_instances[i, :] = savgol_filter(current_instance, 11, 3)
# managing the plots
fig, axs = plt.subplots()
axs.set_ylim([-3, 3])
axs.set_xlim([0, instances_duration])
axs.grid(True)
lines = axs.plot(process_instances[0, :], alpha=0.3, label='original') # starting the main lines
lines_filt = axs.plot(filtered_instances[0, :], label='filtered') # starting the filtered lines
axs.legend()
def animate(frame):
# updating lines
for columns, line in enumerate(lines):
line.set_ydata(process_instances[frame, :])
# updating filtered lines
for columns, line in enumerate(lines_filt):
line.set_ydata(filtered_instances[frame, :])
print("Showing frame number: " + str(frame))
return [lines, lines_filt]
animation = FuncAnimation(fig, animate, interval=1000, blit=True, repeat=True)
animation.event_source.start()
plt.show()
Only minor changes are necessary. Mainly, you have to unpack the Line2D objects for the animation loop
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from scipy.signal import savgol_filter
n_instances = 1000 # the instances that will be generated
instances_duration = 100 # the duration of each of them
# starting the data matrix
process_instances = np.zeros((n_instances, instances_duration))
# starting the filtered data matrix
filtered_instances = np.zeros((n_instances, instances_duration))
np.random.seed(2)
for i in range(n_instances):
# creating the instance as a random array
current_instance = np.random.normal(0, 1, instances_duration)
# assigning to the relative matrix
process_instances[i, :] = current_instance
# filtering and assigning to the relative matrix
filtered_instances[i, :] = savgol_filter(current_instance, 11, 3)
# managing the plots
fig, axs = plt.subplots()
axs.set_ylim([-3, 3])
axs.set_xlim([0, instances_duration])
axs.grid(True)
#unpack the Line2D artists
lines, = axs.plot(process_instances[0, :], alpha=0.3, label='original') # starting the main lines
lines_filt, = axs.plot(filtered_instances[0, :], label='filtered') # starting the filtered lines
axs.legend()
def animate(frame):
# updating lines
lines.set_ydata(process_instances[frame, :])
# updating filtered lines
lines_filt.set_ydata(filtered_instances[frame, :])
print("Showing frame number: " + str(frame))
#return the Line2D artists for blitting
return lines, lines_filt,
animation = FuncAnimation(fig, animate, interval=1000, blit=True, repeat=True)
animation.event_source.start()
plt.show()