Reputation: 261
Maybe you can help me. I'm trying to animate some bars together with a plot in matplotlib. For example, here's some code (only the bars) which is working fine:
from matplotlib import pyplot as plt
from matplotlib.animation import ArtistAnimation
import numpy as np
fig = plt.figure()
x = [1,2,3,4,5]
y = [5,7,2,5,3]
y_steps = []
for i in range(len(y)):
y_steps.append(np.linspace(0, y[i], 50))
data = []
for i in range(len(y_steps[0])):
data.append([y_steps[j][i] for j in range(len(y))])
ims = []
for i in range(len(y_steps[0])):
pic = plt.bar(x, data[i], color='c')
ims.append(pic)
anim = ArtistAnimation(fig, ims, interval=40)
plt.show()
But now I want some lines to grow together with the bars. I've tried a lot and googled a lot, but I am not able to make it work. For your understandig, I'm pasting my idea (of the not-working-code) here:
from matplotlib import pyplot as plt
from matplotlib.animation import ArtistAnimation
import numpy as np
fig = plt.figure()
x = [1,2,3,4,5]
y = [5,7,2,5,3]
y_steps = []
for i in range(len(y)):
y_steps.append(np.linspace(0, y[i], 50))
data = []
for i in range(len(y_steps[0])):
data.append([y_steps[j][i] for j in range(len(y))])
ims = []
for i in range(len(y_steps[0])):
pic_1 = plt.bar(x, data[i], color='c')
pic_2 = plt.plot(x, data[i], color='r')
ims.append([pic_1, pic_2])
anim = ArtistAnimation(fig, ims, interval=40)
plt.show()
It looks like all the pictures, saved in ims, are shown at once and there's no animation.
Maybe someone of you can help me. Thanks a lot.
Upvotes: 2
Views: 4966
Reputation: 880249
When using ArtistAnimation(fig, ims, ...)
, ims
is expected to be a list of Artists.
[pic_1, pic_2]
is a list, not an Artist.
ims.append([pic_1, pic_2])
appends the list as a single object to ims
.
The simplest way to fix the problem is to change ims.append([pic_1, pic_2])
to
ims.extend([pic_1, pic_2])
because ims.extend([pic_1, pic_2])
appends pic_1
and pic_2
into ims
separately.
You can see the difference between append
and extend
by playing with this example:
In [41]: x = []
In [42]: x.append([1, 2])
In [43]: x
Out[43]: [[1, 2]] # x is a list containing 1 item which happens to be a list
In [44]: y = []
In [45]: y.extend([1,2])
In [46]: y
Out[46]: [1, 2] # y is a list containing 2 items
Although that provides a quick fix, the result is rather "blinky".
To make a smoother animation, avoid calling plt.bar
and plt.plot
so many times.
It is more efficient to call each once, and then use the Rectangle.set_height
and Line2D.set_data
methods to modify the existing Rectangles
and Line2Ds
:
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
fig = plt.figure()
x = [1,2,3,4,5]
y = [5,7,2,5,3]
data = np.column_stack([np.linspace(0, yi, 50) for yi in y])
rects = plt.bar(x, data[0], color='c')
line, = plt.plot(x, data[0], color='r')
plt.ylim(0, max(y))
def animate(i):
for rect, yi in zip(rects, data[i]):
rect.set_height(yi)
line.set_data(x, data[i])
return rects, line
anim = animation.FuncAnimation(fig, animate, frames=len(data), interval=40)
plt.show()
Upvotes: 4