I am writing a project in python that includes animation with matplotlib. The thing is I have to visualize a window divided into two rows and two columns, so 4 subplots. In ax[0,0]
, ax[0,1]
and ax[1,0]
I have matrices. In ax[1][1]
a 2D line plot.
The animation of the subplots with the matrices are working properly, but the line one does not.
The error is:
list object has no attribute set_data
The code is really long, so I will do a schematization. Could you please tell me what I did wrong?
rows, cols = 2, 3
fig, ax = plt.subplots(nrows=rows, ncols=cols, num=None, figsize=(16, 12), dpi=80, facecolor='w', edgecolor='k')
# Initialization of matrices MATR1, MATR2, MATR3 all cells set to 0 #
# Coordinates lists for the line plot
x_time = []
y_values = []
index = count()
im = list()
im.append(ax[0][0].imshow(MATR1, cmap='Reds', animated=True))
im.append(ax[0][1].imshow(MATR2, cmap='Greens', animated=True))
im.append(ax[1][0].imshow(MATR3, animated=True))
im.append(ax[1][1].plot(x_time, y_values, animated=True))
def animate(i):
ax[1][1].cla()
# Here a lot of code that determines the values that are inserted into the matrices and the value
# to add in the y_values coordinates list for the line #
x_time.append(next(index))
y_values.append(len(ind_list))
im[0].set_array(MATR1)
im[1].set_array(MATR2)
im[2].set_array(MATR3)
im[4].set_data(x_time, y_erbpopulation) # ERROR FROM HERE
return im
ani = FuncAnimation(fig, update, frames=NUMDAYS-1, interval=10, blit=True, repeat=False)
Updated question:
After making some of the suggested changes, my animation is still not showing. See my updated code below.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
fig, ax = plt.subplots(2,2, num=None, figsize=(16, 12), dpi=80, facecolor='w', edgecolor='k')
MATR1 = np.zeros((100, 100))
MATR2 = np.zeros((100, 100))
MATR3 = np.zeros((100, 100))
# Coordinates lists for the line plot
x_time = []
y_values = []
im = list()
im.append(ax[0][0].imshow(MATR1, cmap='Reds', animated=True))
im.append(ax[0][1].imshow(MATR2, cmap='Greens', animated=True))
im.append(ax[1][0].imshow(MATR3, animated=True))
im.append(ax[1][1].plot(x_time, y_values, animated=True)[0])
def animate(i):
ax[1][1].cla()
# Here a lot of code that determines the values that are inserted into the matrices and the value
# to add in the y_values coordinates list for the line, let's say now i+5 #
x_time.append(i)
y_values.append(i+5)
im[0].set_array(MATR1)
im[1].set_array(MATR2)
im[2].set_array(MATR3)
im[4].set_data(x_time, y_values)
return im
ani = FuncAnimation(fig, update, frames=100, interval=10, blit=True, repeat=False)
If you look at the matplotlib plotting documentation you'll see that ax.plot
returns a list of Line2D
objects. In this case, that list contains just a single object. But, you're appending the list to im
when you only want the Line2D
object. So, you simply need to index the first value of the return as so:
im.append(ax[1][1].plot(x_time, y_values, animated=True)[0])
Updated solution:
animated=True
is not what you think, it's for manually created animations with blotting (see here). So, those should be removed.ax[1,1].cla()
. Using set_data
will handle the update.import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
plt.close("all")
fig, ax = plt.subplots(2, 2, figsize=(16, 12),)
MATR1 = np.random.random((100, 100))
MATR2 = np.random.random((100, 100))
MATR3 = np.random.random((100, 100))
x_time = []
y_values = []
im = []
im.append(ax[0][0].imshow(MATR1, cmap='Reds'))
im.append(ax[0][1].imshow(MATR2, cmap='Greens'))
im.append(ax[1][0].imshow(MATR3))
im.append(ax[1][1].plot(x_time, y_values)[0])
ax[1,1].set_xlim(0, 100)
ax[1,1].set_ylim(5, 105)
def animate(i):
x_time.append(i)
y_values.append(i+5)
im[0].set_array(MATR1)
im[1].set_array(MATR2)
im[2].set_array(MATR3)
im[3].set_data(x_time, y_values)
return im
ani = FuncAnimation(fig, animate, frames=100, interval=10, blit=True, repeat=False)