Animating pngs in matplotlib using ArtistAnimation

animation, matplotlib, python

Solution

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()

Problem

I have been trying to animate a series of surface plots that I created for a 2D heat flow problem using finite element method. At each time step, I saved a plot instead of the whole matrix, in order to be more efficient. I had trouble with the `FuncAnimation` in the matplotlib.animation library, so I decided to render a surface plot at each time, save the surface plot as a .png file, and then read that image using `pyplot.imread`. From there, I want to store each image into a list so that I can use the ArtistAnimation ( example). However it is not making the animation, instead I get two separate blank plots and then my surface plot .pngs when I print `imgplot` to the screen. Additionally, when I try to save the animation, I get the following error message: ``` AttributeError: 'module' object has no attribute 'save'. ``` Any help with reading in a set of .pngs from the current directory, saving them in a list, and then using ArtistAnimation to "animate" those .pngs would be greatly appreciated. I do not need anything fancy. (Note - I have to make the code automated, so unfortunately I cannot use an outside source to animate my images like iMovie or ffmpeg.) Below is my code: ``` from numpy import * from pylab import * import matplotlib.pyplot as plt import matplotlib.image as mgimg from matplotlib import animation ## Read in graphs p = 0 myimages = [] for k in range(1, len(params.t)): fname = "heatflow%03d.png" %p # read in pictures img = mgimg.imread(fname) imgplot = plt.imshow(img) myimages.append([imgplot]) p += 1 ## Make animation fig = plt.figure() animation.ArtistAnimation(fig, myimages, interval=20, blit=True, repeat_delay=1000) animation.save("animation.mp4", fps = 30) plt.show() ```

Original source