Skip to content

Commit 76270ac

Browse files
committed
Add tutorial text
1 parent 88e3bcc commit 76270ac

File tree

1 file changed

+105
-28
lines changed

1 file changed

+105
-28
lines changed

tutorials/introductory/animation_tutorial.py

Lines changed: 105 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,66 @@
33
Animations using matplotlib
44
===========================
55
6-
Animations in matplotlib can be created using the `~matplotlib.Animation`
7-
module. This module provides 2 main animation classes -
8-
`~matplotlib.animation.FuncAnimation` and
9-
`~matplotlib.animation.ArtistAnimation`.
6+
Based on its plotting functionality, matplotlib also provides an interface to
7+
generate animations using the :class:`~matplotlib.animation` module. An
8+
animation is a sequence of frames where each frame corresponds to a plot on a
9+
:class:`~matplotlib.figure.Figure`. This tutorial covers a general guideline on
10+
how to create such animations and the different options available.
1011
"""
1112

1213
import matplotlib.pyplot as plt
1314
import matplotlib.animation as animation
1415
import numpy as np
1516

1617
###############################################################################
18+
# Animation Classes
19+
# =================
20+
#
21+
# The process of animation can be thought about in 2 different ways:
22+
#
23+
# 1. Generate data for first frame and then modify this data for each frame to
24+
# create an animated plot.
25+
# 2. Generate a list (iterable) of plots (/images) that will each be a frame in
26+
# the animation.
27+
#
28+
# Both of these thought processes can be translated into matplotlib using the
29+
# :class:`~matplotlib.animation`'s :class:`~matplotlib.animation.FuncAnimation`
30+
# and :class:`~matplotlib.animation.ArtistAnimation` classes respectively.
31+
#
1732
# :class:`~matplotlib.animation.FuncAnimation`
1833
# --------------------------------------------
34+
#
35+
# :class:`~matplotlib.animation.FuncAnimation` class allows us to create an
36+
# animation by passing a function that iteratively modifies the data of a plot.
37+
# This is achieved by using the *setter* methods on various
38+
# :class:`~matplotlib.artist.Artist`
39+
# (examples: :class:`~matplotlib.line.Line2D`,
40+
# :class:`~matplotlib.collections.PathCollection`, etc.). A usual
41+
# :class:`~matplotlib.animation.FuncAnimation` object takes a
42+
# :class:`~matplotlib.figure.Figure` that we want to animate and a function
43+
# *func* that modifies the data plotted on the figure. It uses the *frames*
44+
# parameter to determine the length of the animation. The *interval* parameter
45+
# is used to determine time in milliseconds between drawing of two frames.
46+
# (This is different than *fps* in `.animation.save` that we will
47+
# cover later). We will now look at some examples of using
48+
# :class:`~matplotlib.animation.FuncAnimation` with different artists.
1949

20-
# :class:`~matplotlib.animation.FuncAnimation` uses a user-provided function by
21-
# repeatedly calling the function with at a regular *interval*. This allows
22-
# dynamic generation of data by using generators.
23-
24-
25-
def init():
26-
ax.set_ylim(-1, 1)
27-
ax.set_xlim(0, 10)
28-
xdata.clear()
29-
ydata.clear()
30-
line.set_data(xdata, ydata)
31-
return line,
50+
###############################################################################
51+
# Animating :class:`~matplotlib.lines.Line2D`
52+
# ---------------------------------------------------------
53+
#
54+
# `.pyplot.plot` returns a :class:`~matplotlib.lines.Line2D` collection. The
55+
# data on this collection can be modified by using the
56+
# `.lines.Line2D.set_data` function. Therefore we can use this to modify the
57+
# plot using the function for every frame.
3258

3359
fig, ax = plt.subplots()
34-
line, = ax.plot([], [], lw=2)
35-
ax.grid()
60+
rng = np.random.default_rng()
61+
3662
xdata, ydata = [], []
63+
line, = ax.plot(xdata, ydata, c='b')
64+
ax.grid()
65+
ax.set_ylim(-1, 1)
3766

3867

3968
def update(frame):
@@ -45,17 +74,20 @@ def update(frame):
4574
ax.set_xlim(xmin, 2*xmax)
4675
ax.figure.canvas.draw()
4776
line.set_data(xdata, ydata)
48-
4977
return line,
5078

5179
ani = animation.FuncAnimation(
52-
fig=fig, func=update, frames=240, init_func=init, interval=30
80+
fig=fig, func=update, interval=30
5381
)
5482
plt.show()
5583

5684
###############################################################################
57-
# Animating :class:`~matplotlib.lines.PathCollection`
58-
# ---------------------------------------------------
85+
# Animating :class:`~matplotlib.collections.PathCollection`
86+
# ---------------------------------------------------------
87+
#
88+
# `.pyplot.scatter` returns a :class:`~matplotlib.collections.PathCollection`
89+
# that can similarly be modified by using the
90+
# `.collections.PathCollection.set_offsets` function.
5991

6092
fig, ax = plt.subplots()
6193
rng = np.random.default_rng()
@@ -84,6 +116,10 @@ def update(frame):
84116
###############################################################################
85117
# Animating :class:`~matplotlib.image.AxesImage`
86118
# ---------------------------------------------------
119+
#
120+
# When we plot an image using `.pyplot.imshow`, it returns an
121+
# :class:`~matplotlib.image.AxesImage` object. The data in this object can also
122+
# similarly be modified by using the `.image.AxesImage.set_data` method.
87123

88124
fig, ax = plt.subplots()
89125
rng = np.random.default_rng()
@@ -97,16 +133,17 @@ def update(frame):
97133
return aximg,
98134

99135
ani = animation.FuncAnimation(
100-
fig=fig, func=update, frames=240, interval=200
136+
fig=fig, func=update, frames=None, interval=200
101137
)
102138
plt.show()
103139

104140
###############################################################################
105141
# :class:`~matplotlib.animation.ArtistAnimation`
106142
# ----------------------------------------------
107143
#
108-
# :class:`~matplotlib.animation.ArtistAnimation` uses a list of artists to
109-
# iterate over and animate.
144+
# On the other hand, :class:`~matplotlib.animation.ArtistAnimation` can be used
145+
# to generate animations if we have data on various different artists. This
146+
# list of artists is then converted frame by frame into an animation.
110147

111148

112149
fig, ax = plt.subplots()
@@ -125,9 +162,40 @@ def update(frame):
125162
ani = animation.ArtistAnimation(fig=fig, artists=artists, repeat_delay=1000)
126163
plt.show()
127164

165+
###############################################################################
166+
# :class:`~matplotlib.animation.FuncAnimation` is more efficient in terms of
167+
# speed and memory as it draws an artist once and then modifies it. On the
168+
# other hand :class:`~matplotlib.animation.ArtistAnimation` is flexible as it
169+
# allows any iterable of artists to be animated in a sequence.
170+
128171
###############################################################################
129172
# Animation Writers
130-
# -------------------------------------------
173+
# -----------------
174+
#
175+
# Animation objects can be saved to disk using various multimedia writers
176+
# (ex: Pillow, *ffpmeg*, *imagemagick*). Not all video formats are supported
177+
# by all writers. A list of supported formats for each writer can be found at
178+
# the end of this tutorial. There are 4 major types of writers:
179+
#
180+
# 1. :class:`~matplotlib.animation.PillowWriter` - Uses the Pillow library to
181+
# create the animation.
182+
#
183+
# 2. :class:`~matplotlib.animation.HTMLWriter` - Used to create JS-based
184+
# animations.
185+
#
186+
# 3. Pipe-based writers - :class:`~matplotlib.animation.FFMpegWriter` and
187+
# :class:`~matplotlib.animation.ImageMagickWriter` are pipe based writers.
188+
# These writers pipe each frame to the utility (*ffmpeg* / *imagemagick*) which
189+
# then stitches all of them together to create the animation.
190+
#
191+
# 4. File-based writers - :class:`~matplotlib.animation.FFMpegFileWriter` and
192+
# :class:`~matplotlib.animation.ImageMagickFileWriter` are examples of
193+
# file-based writers. These writers are slower than their standard writers but
194+
# are more useful for debugging as they save each frame in a file before
195+
# stitching them together into an animation.
196+
#
197+
# Below we see examples for how to use different writers with
198+
# `.animation.Animation.save`
131199

132200
fig, ax = plt.subplots()
133201
ax.grid()
@@ -153,8 +221,6 @@ def update(frame):
153221
# ani.save(filename="/tmp/pillow_example.gif", writer="pillow")
154222
# ani.save(filename="/tmp/pillow_example.apng", writer="pillow")
155223

156-
# Why does HTMLWriter documentation have a variable named
157-
# supported_formats = ['png', 'jpeg', 'tiff', 'svg']
158224
# ani.save(filename="/tmp/html_example.html", writer="html")
159225
# ani.save(filename="/tmp/html_example.htm", writer="html")
160226
# ani.save(filename="/tmp/html_example.png", writer="html")
@@ -167,3 +233,14 @@ def update(frame):
167233

168234
# Imagemagick
169235
# ani.save(filename="/tmp/imagemagick_example.gif", writer="imagemagick")
236+
237+
###############################################################################
238+
#
239+
# ================================================ =============================
240+
# Writer Supported Formats
241+
# ================================================ =============================
242+
# :class:`~matplotlib.animation.PillowWriter` .gif, .apng
243+
# :class:`~matplotlib.animation.HTMLWriter` .htm, .html, .png
244+
# :class:`~matplotlib.animation.FFMpegWriter` All formats supported by *ffmpeg*
245+
# :class:`~matplotlib.animation.ImageMagickWriter` .gif
246+
# ================================================ =============================

0 commit comments

Comments
 (0)