Reputation: 14660
I am trying to learn some of Matplotlib's animation features.
Consider this attempt at trying to draw animate the increase in amplitude of both the sine and cosine curves.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ims = []
x = np.linspace(0,10,20)
for i in range(60):
y1 = map (lambda t: i*np.sin(t) , x)
y2 = map (lambda t: i*np.cos(t) , x)
im1 = plt.plot(x, y1, 'bo-')
im2 = plt.plot(x, y2, 'go-')
ims.extend([im1,im2])
ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True, repeat_delay=1000)
plt.show()
This draws for me an alternating set of blue sine curves and green cosine curves. If you try to plot them, you will see that the resulting plot is a kind of a very fast alternating set of images between sine and cosine.
I am aware that it is probably the ims.extend([im1,im2])
which is the offending command here. However, when in place of .extend
I used .append()
so that that ims
becomes a list of list of images I get the error
Traceback (most recent call last):
File "dynamic_image.py", line 29, in <module>
ani.save("movie.mp4")
File "/usr/local/lib/python2.7/dist-packages/matplotlib/animation.py", line 1254, in save
anim._init_draw()
File "/usr/local/lib/python2.7/dist-packages/matplotlib/animation.py", line 1618, in _init_draw
artist.set_visible(False)
AttributeError: 'list' object has no attribute 'set_visible'
Upvotes: 1
Views: 1109
Reputation: 3056
The issue is that the value returned from plt.plot
is a list. For example, im1
will be something like this:
[<matplotlib.lines.Line2D at 0x11a0f62e8>]
When you add artists to your list, you are adding two artists separately. So change this line:
ims.extend([im1,im2])
To this:
ims.extend([im1 + im2])
Now the length of ims
is 60 instead of 120 and the cosine and sine will be plotted together.
I wrote a library to make this easier called celluloid. It is a black box so if your goal is to learn matplotlib you may want to skip. Please also read the limitations if you decide to use it. Here's what the code would look like to replicate your animation:
from celluloid import Camera
fig = plt.figure()
camera = Camera(fig)
x = np.linspace(0,10,20)
for i in range(60):
plt.plot(x, i*np.sin(x), 'go-')
plt.plot(x, i*np.cos(x), 'bo-')
camera.snap()
ani = camera.animate(interval=50, blit=True, repeat_delay=1000)
Upvotes: 2
Reputation: 1356
I'm not sure the reason, but if you only want the result, you can try the following code. If you do need to know the reason, let's wait to see if someone else can answer it.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.linspace(0, 10, 50)
line1, = ax.plot(x, np.sin(x), 'bo-')
line2, = ax.plot(x, np.cos(x), 'go-')
ax.set_ylim(-60, 60)
def init():
line1.set_ydata([np.nan] * len(x))
line2.set_ydata([np.nan] * len(x))
return [line1, line2]
def animate(i):
line1.set_ydata(i * np.sin(x))
line2.set_ydata(i * np.cos(x))
return [line1, line2]
ani = animation.FuncAnimation(fig, animate, init_func=init,
blit=True, frames=60, repeat=True,
interval=50, repeat_delay=1000)
ani.save('result.mp4')
Upvotes: 2