1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
|
************************
``matplotlib.animation``
************************
.. automodule:: matplotlib.animation
:no-members:
:no-undoc-members:
.. contents:: Table of Contents
:depth: 1
:local:
:backlinks: entry
Animation
=========
The easiest way to make a live animation in Matplotlib is to use one of the
`Animation` classes.
.. seealso::
- :ref:`animations`
.. inheritance-diagram:: matplotlib.animation.FuncAnimation matplotlib.animation.ArtistAnimation
:parts: 1
.. autosummary::
:toctree: _as_gen
:nosignatures:
Animation
FuncAnimation
ArtistAnimation
In both cases it is critical to keep a reference to the instance
object. The animation is advanced by a timer (typically from the host
GUI framework) which the `Animation` object holds the only reference
to. If you do not hold a reference to the `Animation` object, it (and
hence the timers) will be garbage collected which will stop the
animation.
To save an animation use `Animation.save`, `Animation.to_html5_video`,
or `Animation.to_jshtml`.
See :ref:`ani_writer_classes` below for details about what movie formats are
supported.
.. _func-animation:
``FuncAnimation``
-----------------
The inner workings of `FuncAnimation` is more-or-less::
for d in frames:
artists = func(d, *fargs)
fig.canvas.draw_idle()
fig.canvas.start_event_loop(interval)
with details to handle 'blitting' (to dramatically improve the live
performance), to be non-blocking, not repeatedly start/stop the GUI
event loop, handle repeats, multiple animated axes, and easily save
the animation to a movie file.
'Blitting' is a `standard technique
<https://en.wikipedia.org/wiki/Bit_blit>`__ in computer graphics. The
general gist is to take an existing bit map (in our case a mostly
rasterized figure) and then 'blit' one more artist on top. Thus, by
managing a saved 'clean' bitmap, we can only re-draw the few artists
that are changing at each frame and possibly save significant amounts of
time. When we use blitting (by passing ``blit=True``), the core loop of
`FuncAnimation` gets a bit more complicated::
ax = fig.gca()
def update_blit(artists):
fig.canvas.restore_region(bg_cache)
for a in artists:
a.axes.draw_artist(a)
ax.figure.canvas.blit(ax.bbox)
artists = init_func()
for a in artists:
a.set_animated(True)
fig.canvas.draw()
bg_cache = fig.canvas.copy_from_bbox(ax.bbox)
for f in frames:
artists = func(f, *fargs)
update_blit(artists)
fig.canvas.start_event_loop(interval)
This is of course leaving out many details (such as updating the
background when the figure is resized or fully re-drawn). However,
this hopefully minimalist example gives a sense of how ``init_func``
and ``func`` are used inside of `FuncAnimation` and the theory of how
'blitting' works.
.. note::
The zorder of artists is not taken into account when 'blitting'
because the 'blitted' artists are always drawn on top.
The expected signature on ``func`` and ``init_func`` is very simple to
keep `FuncAnimation` out of your book keeping and plotting logic, but
this means that the callable objects you pass in must know what
artists they should be working on. There are several approaches to
handling this, of varying complexity and encapsulation. The simplest
approach, which works quite well in the case of a script, is to define the
artist at a global scope and let Python sort things out. For example::
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = ax.plot([], [], 'ro')
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
plt.show()
The second method is to use `functools.partial` to pass arguments to the
function::
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from functools import partial
fig, ax = plt.subplots()
line1, = ax.plot([], [], 'ro')
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return line1,
def update(frame, ln, x, y):
x.append(frame)
y.append(np.sin(frame))
ln.set_data(x, y)
return ln,
ani = FuncAnimation(
fig, partial(update, ln=line1, x=[], y=[]),
frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
plt.show()
A third method is to use closures to build up the required
artists and functions. A fourth method is to create a class.
Examples
^^^^^^^^
* :doc:`../gallery/animation/animate_decay`
* :doc:`../gallery/animation/bayes_update`
* :doc:`../gallery/animation/double_pendulum`
* :doc:`../gallery/animation/animated_histogram`
* :doc:`../gallery/animation/rain`
* :doc:`../gallery/animation/random_walk`
* :doc:`../gallery/animation/simple_anim`
* :doc:`../gallery/animation/strip_chart`
* :doc:`../gallery/animation/unchained`
``ArtistAnimation``
-------------------
Examples
^^^^^^^^
* :doc:`../gallery/animation/dynamic_image`
Writer Classes
==============
.. inheritance-diagram:: matplotlib.animation.FFMpegFileWriter matplotlib.animation.FFMpegWriter matplotlib.animation.ImageMagickFileWriter matplotlib.animation.ImageMagickWriter matplotlib.animation.PillowWriter matplotlib.animation.HTMLWriter
:top-classes: matplotlib.animation.AbstractMovieWriter
:parts: 1
The provided writers fall into a few broad categories.
The Pillow writer relies on the Pillow library to write the animation, keeping
all data in memory.
.. autosummary::
:toctree: _as_gen
:nosignatures:
PillowWriter
The HTML writer generates JavaScript-based animations.
.. autosummary::
:toctree: _as_gen
:nosignatures:
HTMLWriter
The pipe-based writers stream the captured frames over a pipe to an external
process. The pipe-based variants tend to be more performant, but may not work
on all systems.
.. autosummary::
:toctree: _as_gen
:nosignatures:
FFMpegWriter
ImageMagickWriter
The file-based writers save temporary files for each frame which are stitched
into a single file at the end. Although slower, these writers can be easier to
debug.
.. autosummary::
:toctree: _as_gen
:nosignatures:
FFMpegFileWriter
ImageMagickFileWriter
The writer classes provide a way to grab sequential frames from the same
underlying `~matplotlib.figure.Figure`. They all provide three methods that
must be called in sequence:
- `~.AbstractMovieWriter.setup` prepares the writer (e.g. opening a pipe).
Pipe-based and file-based writers take different arguments to ``setup()``.
- `~.AbstractMovieWriter.grab_frame` can then be called as often as
needed to capture a single frame at a time
- `~.AbstractMovieWriter.finish` finalizes the movie and writes the output
file to disk.
Example::
moviewriter = MovieWriter(...)
moviewriter.setup(fig, 'my_movie.ext', dpi=100)
for j in range(n):
update_figure(j)
moviewriter.grab_frame()
moviewriter.finish()
If using the writer classes directly (not through `Animation.save`), it is
strongly encouraged to use the `~.AbstractMovieWriter.saving` context manager::
with moviewriter.saving(fig, 'myfile.mp4', dpi=100):
for j in range(n):
update_figure(j)
moviewriter.grab_frame()
to ensure that setup and cleanup are performed as necessary.
Examples
--------
* :doc:`../gallery/animation/frame_grabbing_sgskip`
.. _ani_writer_classes:
Helper Classes
==============
Animation Base Classes
----------------------
.. autosummary::
:toctree: _as_gen
:nosignatures:
Animation
TimedAnimation
Writer Registry
---------------
A module-level registry is provided to map between the name of the
writer and the class to allow a string to be passed to
`Animation.save` instead of a writer instance.
.. autosummary::
:toctree: _as_gen
:nosignatures:
MovieWriterRegistry
Writer Base Classes
-------------------
To reduce code duplication base classes
.. autosummary::
:toctree: _as_gen
:nosignatures:
AbstractMovieWriter
MovieWriter
FileMovieWriter
and mixins
.. autosummary::
:toctree: _as_gen
:nosignatures:
FFMpegBase
ImageMagickBase
are provided.
See the source code for how to easily implement new `MovieWriter` classes.
|