Skip to content

Moved content of API FuncAnimation to simple animation guide #27700

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/users/installing/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ precompiled wheel for your OS and Python.

For support of other GUI frameworks, LaTeX rendering, saving
animations and a larger selection of file formats, you can
install :ref:`optional dependencies <optional_dependencies>`.
install :ref:`optional dependencies <https://matplotlib.org/3.8.2/devel/dependencies.html#optional-dependencies>`.


Third-party distributions
Expand Down
145 changes: 145 additions & 0 deletions galleries/users_explain/animations/animations.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
animation is a sequence of frames where each frame corresponds to a plot on a
`~matplotlib.figure.Figure`. This tutorial covers a general guideline on
how to create such animations and the different options available.

.. inheritance-diagram:: matplotlib.animation.FuncAnimation matplotlib.animation.ArtistAnimation
:parts: 1

"""

import matplotlib.pyplot as plt
Expand All @@ -23,13 +27,27 @@
# Animation classes
# =================
#
# ``Animation`` A base class for Animations.
# The animation process in Matplotlib can be thought of in 2 different ways:
#
# - `~matplotlib.animation.FuncAnimation`: Generate data for first
# frame and then modify this data for each frame to create an animated plot.
# :doc:`TimedAnimation <https://matplotlib.org/devdocs/api/_as_gen/matplotlib.animation.TimedAnimation.html#matplotlib.animation.TimedAnimation>` subclass that makes an animation by repeatedly calling a function func.
#
#
# - `~matplotlib.animation.ArtistAnimation`: Generate a list (iterable)
# of artists that will draw in each frame in the animation.
# :doc:`TimedAnimation <https://matplotlib.org/devdocs/api/_as_gen/matplotlib.animation.TimedAnimation.html#matplotlib.animation.TimedAnimation>` subclass that creates an animation by using a fixed set of Artist objects.
#
# 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`.
#
#
# `~matplotlib.animation.FuncAnimation` is more efficient in terms of
# speed and memory as it draws an artist once and then modifies it. On the
Expand Down Expand Up @@ -63,6 +81,133 @@
# - Use `.animation.Animation.save` or `.pyplot.show` to save or show the
# animation.
#
# 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`
#
# The update function uses the ``set_*`` function for different artists to
# modify the data. The following table shows a few plotting methods, the artist
# types they return and some methods that can be used to update them.
Expand Down