How to draw animation by taking snapshot with matplotlib?

In my project, I have many polygons to draw for each time step.

At each step, the number of polygons varies, thus it is difficult to keep Axes.patchs and translate them to make the animation.

I want to create animation with final figures (show after calling matplotlib.pyplot.show()), how to do this?

We take the sin curve as example:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig = plt.figure()
ims = []
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)
z = np.cos(x)
for i in range(1,100):
    tmpx = x[:i]
    tmpy = y[:i]
    tmpz = z[:i]
    plt.plot(tmpx, tmpz)
    im = plt.plot(tmpx, tmpy)
    ims.append(im)

ani = animation.ArtistAnimation(fig, ims, interval=200)
ani.save('/home/test.gif', writer='imagemagick')

plt.show()

There are two curves: animated-sin-curve and static-cos-curve.

  • the sin-curve is kept as Line2D objects for each step
  • the cos-curve stay static for each step.

In this way, we show different Artist object for each step.

But I want to keep the rasterized Line2D figure for each step.

I find classes of AxesImage/FigureImage, but I don't know how to save the rasterized figure and make them work.

I tried to convert figure.canvas to AxesImage with following code :

def fig2AxesImage(fig):
    import PIL.Image as Image
    fig.canvas.draw()

    w, h = fig.canvas.get_width_height()
    buf = numpy.fromstring(fig.canvas.tostring_argb(), dtype=numpy.uint8)
    buf.shape = (w, h, 4)

    # canvas.tostring_argb give pixmap in ARGB mode. Roll the ALPHA channel to have it in RGBA mode
    buf = numpy.roll(buf, 3, axis=2)
    image = Image.frombytes("RGBA", (w, h), buf.tostring())
    image = numpy.asarray(image)
    return plt.imshow(image, animated=True)

but with this way, I have to clear canvas at start of next frame, which make the final animation a blank video. (but the .jpg figures I output for each step get the right content)

Does anyone have done this before that save rasterized canvas-figures of matplotlib.pyplot.figure() as a animation Vedio?


celluloid for python 2.7

''' copy from celluloid'''

# from typing import Dict, List  # not supported by python 2.7. So comment it
from collections import defaultdict

from matplotlib.figure import Figure
from matplotlib.artist import Artist
from matplotlib.animation import ArtistAnimation

__version__ = '0.2.0'

class Camera:
    def __init__(self, figure):
        self.figure_ = figure
        self.offsets_ = { k:defaultdict(int) \
            for k in ['collections', 'patches', 'lines', 'texts', 'artists', 'images']
        }

        self.photos_ = []

    def snap(self):
        frame_artists = []
        for i, axis in enumerate(self.figure_.axes):
            if axis.legend_ is not None:
                axis.add_artist(axis.legend_)
            for name in self.offsets_:
                new_artists = getattr(axis, name)[self.offsets_[name][i]:]
                frame_artists += new_artists
                self.offsets_[name][i] += len(new_artists)
        self.photos_.append(frame_artists)

    def animate(self):
        return ArtistAnimation(self.figure_, self.photos_)