In the solution below I showcase a bigger example (with also bar plot) that may help people understand better what should be done for other cases. After the code I explain some details and answer the bonus question.
import matplotlib
matplotlib.use('Qt5Agg') #use Qt5 as backend, comment this line for default backend
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(0, 100))
N = 4
lines = [plt.plot([], [])[0] for _ in range(N)] #lines to animate
rectangles = plt.bar([0.5,1,1.5],[50,40,90],width=0.1) #rectangles to animate
patches = lines + list(rectangles) #things to animate
def init():
#init lines
for line in lines:
line.set_data([], [])
#init rectangles
for rectangle in rectangles:
rectangle.set_height(0)
return patches #return everything that must be updated
def animate(i):
#animate lines
for j,line in enumerate(lines):
line.set_data([0, 2], [10 * j,i])
#animate rectangles
for j,rectangle in enumerate(rectangles):
rectangle.set_height(i/(j+1))
return patches #return everything that must be updated
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
Explanation
The idea is to plot what you need and then reuse the artists (see more here) returned by matplotlib
. This is done by first plotting a dummy sketch of what you want and keeping the objects matplotlib
gives you. Then on your init
and animate
functions you can update the objects that need to be animated.
Note that in plt.plot([], [])[0]
we get a single line artist, thus I collect them with [plt.plot([], [])[0] for _ in range(N)]
. On the other hand plt.bar([0.5,1,1.5],[50,40,90],width=0.1)
returns a container that can be iterated for the rectangle artists. list(rectangles)
just convert this container into a list to be concatenated with lines
.
I separate the lines from the rectangles because they are updated differently (and are different artists) but init
and animate
return all of them.
Answer to bonus question:
line, = plt.plot([], [])
assign the first element of the list returned byplt.plot
to the veriableline
.line = plt.plot([], [])
just assign the whole list (of only one element).