Animating pngs in matplotlib using ArtistAnimation
Issue 1: Images are not displayed
You need to store your animation object in a variable:
my_anim = animation.ArtistAnimation(fig, myimages, interval=100)
This requirement is specific for animation
and is not consistent with other plotting function in matplotlib
, where you can usually use my_plot=plt.plot()
or plt.plot()
indifferently.
This question is further discussed here.
Issue 2: Save does not work
Without any animation
instance, it will not be possible to save a figure either. This is because the save
method
belongs to the ArtistAnimation
class. What you did was calling save
from the animation
module, this is what raised the error.
Issue 3: Two windows
The last issue is that you get two figures popping up. The reason is that when you call plt.imshow()
, it displays an image on the current figure, but since no figure has been created yet, pyplot
implicitly creates one for you.
When python later interprets the fig = plt.figure()
statement, it creates a new figure (another window) and labels it "Figure 2".
Moving this statement to the beginning of your code, solves that problem.
Here is the modified code:
import matplotlib.pyplot as plt
import matplotlib.image as mgimg
from matplotlib import animation
fig = plt.figure()
# initiate an empty list of "plotted" images
myimages = []
#loops through available png:s
for p in range(1, 4):
## Read in picture
fname = "heatflow%03d.png" %p
img = mgimg.imread(fname)
imgplot = plt.imshow(img)
# append AxesImage object to the list
myimages.append([imgplot])
## create an instance of animation
my_anim = animation.ArtistAnimation(fig, myimages, interval=1000, blit=True, repeat_delay=1000)
## NB: The 'save' method here belongs to the object you created above
#my_anim.save("animation.mp4")
## Showtime!
plt.show()
(To run the code above, just add 3 images into your working folder with name "heatflow001.png" through "heatflow003.png".)
Alternative approach using FuncAnimation
You were probably right when you first tried to use FuncAnimation
, since gathering images in a list is costly in terms of memory. I tested the code below against the one above, by comparing memory usage on the
system monitor. It appears that the FuncAnimation
approach is more efficient. I believe the difference will grow even bigger as you use more images.
Here is the second code:
from matplotlib import pyplot as plt
from matplotlib import animation
import matplotlib.image as mgimg
import numpy as np
#set up the figure
fig = plt.figure()
ax = plt.gca()
#initialization of animation, plot array of zeros
def init():
imobj.set_data(np.zeros((100, 100)))
return imobj,
def animate(i):
## Read in picture
fname = "heatflow%03d.png" % i
## here I use [-1::-1], to invert the array
# IOtherwise it plots up-side down
img = mgimg.imread(fname)[-1::-1]
imobj.set_data(img)
return imobj,
## create an AxesImage object
imobj = ax.imshow( np.zeros((100, 100)), origin='lower', alpha=1.0, zorder=1, aspect=1 )
anim = animation.FuncAnimation(fig, animate, init_func=init, repeat = True,
frames=range(1,4), interval=200, blit=True, repeat_delay=1000)
plt.show()