Source code for mpltools.animation

"""
Animation class.

This implementation is a interface for Matplotlib's FuncAnimation class, but
with different interface for:

* Easy reuse of animation code.

* Logical separation of setup parameter (passed to `__init__`) and animation
  parameters (passed to `animate`).

* Unlike Matplotlib's animation class, this Animation class clearly must be
  assigned to a variable (in order to call the `animate` method). The
  FuncAnimation object needs to be assigned to a variable so that it isn't
  garbage-collected, but this requirement is confusing, and easily forgotten,
  because the user never uses the animation object directly.


"""
import warnings
import matplotlib.animation as _animation


__all__ = ['Animation']


[docs]class Animation(object): """Base class to create animation objects. To create an animation, simply subclass `Animation` and override the `__init__` method to create a plot (`self.fig` needs to be assigned to the figure object here), and override `update` with a generator that updates the plot: .. code-block:: python class RandomPoints(Animation): def __init__(self, width=10): self.fig, self.ax = plt.subplots() self.width = width self.ax.axis([0, width, 0, width]) self.num_frames = 20 def update(self): artists = [] self.ax.lines = [] # Clean up plot when repeating animation. for i in np.arange(self.num_frames): x, y = np.random.uniform(0, self.width, size=2) artists.append(self.ax.plot(x, y, 'ro')) yield artists pts = RandomPoints() pts.animate() Note: if you want to use blitting (see docstring for `Animation.animate`), You must yield a sequence of artists in `update`. This Animation class does not subclass any of Matplotlib's animation classes because the `__init__` method takes arguments for creating the plot, while `animate` method is what accepts arguments that alter the animation. """
[docs] def __init__(self): """Initialize plot for animation. Replace this method to initialize the plot. The only requirement is that you must create a figure object assigned to `self.fig`. """ raise NotImplementedError
[docs] def init_background(self): """Initialize background artists. Note: This method is passed to `FuncAnimation` as `init_func`. """ pass
[docs] def update(self): """Update frame. Replace this method to with a generator that updates artists and calls an empty `yield` when updates are complete. """ raise NotImplementedError
[docs] def animate(self, **kwargs): """Run animation. Parameters ---------- interval : float, defaults to 200 Time delay, in milliseconds, between frames. repeat : {True | False} If True, repeat animation when the sequence of frames is completed. repeat_delay : None Delay in milliseconds before repeating the animation. blit : {False | True} If True, use blitting to optimize drawing. Unsupported by some backends. init_background : function If None, the results of drawing from the first item in the frames sequence will be used. This can also be added as a class method instead of passing to `animate`. save_count : int If saving a movie, `save_count` determines number of frames saved. If not defined, use `num_frames` attribute (if defined); otherwise, set to 100 frames. """ reusable_generator = lambda: iter(self.update()) kwargs['init_background'] = self.init_background self._warn_num_frames = False if hasattr(self, 'num_frames') and 'save_count' not in kwargs: kwargs['save_count'] = self.num_frames if 'save_count' not in kwargs: kwargs['save_count'] = 100 self._warn_num_frames = True self._ani = _GenAnimation(self.fig, reusable_generator, **kwargs)
[docs] def save(self, filename, **kwargs): """Saves a movie file by drawing every frame. Parameters ---------- filename : str The output filename. writer : :class:`matplotlib.animation.MovieWriter` or str Class for writing movie from animation. If string, must be 'ffmpeg' or 'mencoder', which identifies the MovieWriter class used. If None, use 'animation.writer' rcparam. fps : float The frames per second in the movie. If None, use the animation's specified `interval` to set the frames per second. dpi : int Dots per inch for the movie frames. codec : Video codec to be used. Not all codecs are supported by a given writer. If None, use 'animation.codec' rcparam. bitrate : int Kilobits per seconds in the movie compressed movie. A higher value gives a higher quality movie, but at the cost of increased file size. If None, use `animation.bitrate` rcparam. extra_args : list List of extra string arguments passed to the underlying movie utility. If None, use 'animation.extra_args' rcParam. metadata : dict Metadata to include in the output file. Some keys that may be of use include: title, artist, genre, subject, copyright, comment. """ if not hasattr(self, '_ani'): raise RuntimeError("Run `animate` method before calling `save`!") return if self._warn_num_frames: msg = "%s `num_frames` attribute. Animation may be truncated." warnings.warn(msg % self.__class__.__name__) self._ani.save(filename, **kwargs)
class _GenAnimation(_animation.FuncAnimation): def __init__(self, fig, frames, init_background=None, save_count=None, **kwargs): self._iter_gen = frames self._init_func = init_background self.save_count = save_count if save_count is not None else 100 # Dummy args and function for compatibility with FuncAnimation self._args = () self._func = lambda args: args self._save_seq = [] _animation.TimedAnimation.__init__(self, fig, **kwargs) # Clear saved seq since TimedAnimation.__init__ adds a single frame. self._save_seq = []