4
4
Matplotlib Application Interfaces (APIs)
5
5
========================================
6
6
7
- Python is a flexible language allowing different design choices when
8
- creating an application programming interface (API). Matplotlib
9
- has seen two of these over the years (or more, depending on how you
10
- count). In addition, external libraries have their own interfaces to
11
- Matplotlib. This means that code snippets across the internet are written
12
- using different interfaces, often leading to confusion. The three major
13
- interfaces are:
14
-
15
- - an explicit interface that uses methods on a Figure or Axes object to
16
- create other Artists, and build a visualization step by step in an
17
- `imperative <https://en.wikipedia.org/wiki/Imperative_programming >`_
18
- manner.
19
- - an implicit interface that keeps track of the last Figure and Axes
20
- created, and adds Artists to the object it thinks the user wants. This
21
- interface is also imperative.
22
- - a number of downstream libraries offer a
23
- `declarative <https://en.wikipedia.org/wiki/Declarative_programming >`_
24
- interface, usually where a data object has a ``plot `` method implemented
25
- that will plot the data.
7
+ Matplotlib has two major application interfaces, or styles of using the library:
8
+
9
+ - An explicit "Axes" interface that uses methods on a Figure or Axes object to
10
+ create other Artists, and build a visualization step by step. This has also
11
+ been called an "object-oriented" interface.
12
+ - An implicit "pyplot" interface that keeps track of the last Figure and Axes
13
+ created, and adds Artists to the object it thinks the user wants.
14
+
15
+ In addition, a number of downstream libraries (like `pandas ` and `xarray `)
16
+ offer a ``plot `` method implemented directly on their data classes so that
17
+ users can call ``data.plot() ``.
18
+
19
+ The difference between these interfaces can be a bit confusing, particularly
20
+ given snippets on the web that use one or the other, or sometimes multiple
21
+ interfaces in the same example. Here we attempt to point out how the "pyplot"
22
+ and downstream interfaces relate to the explicit "Axes" interface to help users
23
+ better navigate the library.
24
+
25
+
26
+ Native Matplotlib interfaces
27
+ ----------------------------
26
28
27
29
The explicit "Axes" interface
28
- -----------------------------
30
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29
31
30
32
The "Axes" interface is how Matplotlib is implemented, and many customizations
31
- and fine-tuning end up needing to be done at this level. So even if you
32
- prefer the higher-level interfaces, it is very useful to understand that this
33
- interface exists, and how to access it.
33
+ and fine-tuning end up being done at this level.
34
34
35
- In general, using it is as easy as instantiating an instance of a
36
- `~.matplotlib.figure.Figure ` class (``fig `` below), using an
37
- `~.Figure.add_axes ` method (or similar) on that object to create an
38
- `~.matplotlib.axes.Axes ` object (``ax `` below), and then calling drawing methods
39
- on the Axes (``plot `` in this example):
35
+ This interface works by instantiating an instance of a
36
+ `~.matplotlib.figure.Figure ` class (``fig `` below), using a method
37
+ `~.Figure.subplots ` method (or similar) on that object to create one or more
38
+ `~.matplotlib.axes.Axes ` objects (``ax `` below), and then calling drawing
39
+ methods on the Axes (``plot `` in this example):
40
40
41
41
.. plot ::
42
42
:include-source:
@@ -45,35 +45,21 @@ on the Axes (``plot`` in this example):
45
45
import matplotlib.pyplot as plt
46
46
47
47
fig = plt.figure()
48
- ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
49
- l = ax.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])
50
-
51
- Note that ``plot `` itself also returns an object that can be subsequently
52
- manipulated.
48
+ ax = fig.subplots()
49
+ ax.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])
53
50
54
51
We call this an "explicit" interface because each object is explicitly
55
- referenced, and used to make the next object. Keeping handles to the
56
- objects is very flexible, and allows us to customize the objects after
57
- they are created, but before they are displayed.
58
-
59
- This is also an example of an "imperative" interface because the user tells
60
- Matplotlib what to do each step of the way. Of course Matplotlib has defaults
61
- for many things (line widths, fonts, colors, etc.), but this interface tells
62
- Matplotlib how to compose the visualization. Of course this paradigm is not
63
- pure, in that ``fig.add_axes() `` encapsulates creating many of the objects on
64
- an Axes (spines, labels, ticks) and ``ax.plot() `` encapsulates creating a
65
- line plot. But it is much more "imperative" than something like
66
- ``data.plot() `` as we will see below.
52
+ referenced, and used to make the next object. Keeping references to the objects
53
+ is very flexible, and allows us to customize the objects after they are created,
54
+ but before they are displayed.
67
55
68
56
69
57
The implicit "pyplot" interface
70
- -------------------------------
58
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
71
59
72
- The "pyplot" interface arose from Matlab, where one would just call
73
- ``plot([1, 2, 3, 4], [0, 0.5, 1, 0.2]) `` and a figure with axes would be
74
- created for you. The `~.matplotlib.pyplot ` module shadows most of the
60
+ The `~.matplotlib.pyplot ` module shadows most of the
75
61
`~.matplotlib.axes.Axes ` plotting methods to give the equivalent of
76
- the above:
62
+ the above, where the creation of the Figure and Axes is done for the user :
77
63
78
64
.. plot ::
79
65
:include-source:
@@ -84,20 +70,10 @@ the above:
84
70
plt.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2])
85
71
86
72
This can be convenient, particularly when doing interactive work or simple
87
- scripts - it saves at least a line of typing, and saves the user from having
88
- to think about figure and axes creation. However, for more complicated scripts
89
- it can be at more of a disadvantage - imagine you want to loop through a number
90
- of variables and plot them on separate Axes, it is often more straight-forward
91
- to create the Axes beforehand. It can also become ambiguous when you have
92
- multiple Figures or Axes which one is being acted on. In general the
93
- Matplotlib project recommends using the explicit interface, at least for code
94
- you want to share or preserve.
95
-
96
- Whichever interface you choose, it is helpful to decode what is happening
97
- in the pyplot interface. Matplotib retains a list of Figures, and each Figure
98
- retains a list of Axes on the figure. The most recent figure can be retrieved
99
- with `~.pyplot.gcf ` and the most recent Axes with `~.pyplot.gca `. So for a more
100
- complicated example:
73
+ scripts. A reference to the current Figure can be retrieved using
74
+ `~.pyplot.gcf ` and to the current Axes by `~.pyplot.gca `. The `~.pyplot ` module
75
+ retains a list of Figures, and each Figure retains a list of Axes on the figure
76
+ for the user so that the following are all equivalent:
101
77
102
78
.. plot ::
103
79
:include-source:
@@ -127,7 +103,7 @@ is equivalent to
127
103
ax = plt.gca()
128
104
ax.plot([3, 2, 1], [0, 0.5, 0.2])
129
105
130
- which in the explict interface would be:
106
+ In the explicit interface, this would be:
131
107
132
108
.. plot ::
133
109
:include-source:
@@ -139,22 +115,16 @@ which in the explict interface would be:
139
115
axs[0].plot([1, 2, 3], [0, 0.5, 0.2])
140
116
axs[1].plot([3, 2, 1], [0, 0.5, 0.2])
141
117
142
- The "pyplot" interface creates and uses all the same objects, that the "Axes"
143
- interface does, but it implicitly keeps track of the current Figure
144
- (``plt.gcf() ``) and Axes (``plt.gca() ``) for the user, and uses those Figures
145
- and Axes for any "pyplot" plotting methods until another Axes or Figure is
146
- selected.
147
-
148
118
Why be explicit?
149
- ~~~~~~~~~~~~~~~~
119
+ ^^^^^^^^^^^^^^^^
150
120
151
- What happens if you have to backtrack, and operate on an old axes? One that
152
- is not referenced by ``plt.gca() ``. Of course you can do this, the simplest
153
- way is to call `` subplot `` again with the same arguments. However, that quickly
154
- becomes inelegant. You can also peer into the Figure object and get its list
155
- of Axes, however, that can be misleading (colorbars are axes too!). The best
156
- solution is probably to save a handle to every axes you create, but if you
157
- do that, why not simply create the axes at the start?
121
+ What happens if you have to backtrack, and operate on an old axes that is not
122
+ referenced by ``plt.gca() ``? One simple way is to call `` subplot `` again with
123
+ the same arguments. However, that quickly becomes inelegant. You can also
124
+ inspect the Figure object and get its list of Axes objects, however, that can be
125
+ misleading (colorbars are Axes too!). The best solution is probably to save a
126
+ handle to every Axes you create, but if you do that, why not simply create the
127
+ all the Axes objects at the start?
158
128
159
129
The first approach is to call ``plt.subplot `` again:
160
130
@@ -199,7 +169,7 @@ The second is to save a handle:
199
169
plt.sca(axs[i])
200
170
plt.xlabel('Boo')
201
171
202
- But the recommended way would be to just be explicit from the outset:
172
+ However, the recommended way would be to be explicit from the outset:
203
173
204
174
.. plot ::
205
175
:include-source:
@@ -215,18 +185,14 @@ But the recommended way would be to just be explicit from the outset:
215
185
axs[i].set_xlabel('Boo')
216
186
217
187
218
- The declarative "Data" interface
219
- --------------------------------
220
-
221
- Matplotlib does not implement this interface natively. However, it is seen
222
- in `pandas `, `xarray `, and
223
- other third-party libraries. These interfaces are "declarative" in that
224
- the data object is told to plot itself, and then it uses Matplotlib behind
225
- the scenes to create the visualization.
188
+ Third-party library "Data-object" interfaces
189
+ --------------------------------------------
226
190
227
- For illustrative purposes, a downstream library may implement a simple
228
- data container that has ``x `` and ``y `` data stored together, and then
229
- impliments a ``plot `` method as so:
191
+ Some third party libraries have chosen to implement plotting for their data
192
+ objects, e.g. `data.plot() `, is seen in `pandas `, `xarray `, and other
193
+ third-party libraries. For illustrative purposes, a downstream library may
194
+ implement a simple data container that has ``x `` and ``y `` data stored together,
195
+ and then implements a ``plot `` method:
230
196
231
197
.. plot ::
232
198
:include-source:
@@ -258,16 +224,16 @@ impliments a ``plot`` method as so:
258
224
259
225
So the library can hide all the nitty-gritty from the user, and can make a
260
226
visualization appropriate to the data type, often with good labels, choices of
261
- colormaps, and other nice features.
227
+ colormaps, and other convenient features.
262
228
263
229
In the above, however, we may not have liked the title the library provided.
264
- Thankfully, they pass us back the axes object from the ``plot() `` method, and
265
- understanding the explicit Axes interface, we could manually manipulate it
266
- ``ax.set_title('My preferred title') ``.
230
+ Thankfully, they pass us back the Axes from the ``plot() `` method, and
231
+ understanding the explicit Axes interface, we could call:
232
+ ``ax.set_title('My preferred title') `` to customize the title .
267
233
268
- Many libraries also allow ``plot `` to take an optional *ax * argument.
269
- This allows us to place the visualization in an Axes of our explicit
270
- choice .
234
+ Many libraries also allow their ``plot `` methods to accept an optional *ax *
235
+ argument. This allows us to place the visualization in an Axes that we have
236
+ placed and perhaps customized .
271
237
272
238
Summary
273
239
-------
@@ -289,9 +255,10 @@ the implicit "pyplot" interface.
289
255
interface chosen.
290
256
291
257
Similarly, the declarative interfaces provided by partner libraries use the
292
- objects accessible by the Axes interface, and often accept these as arguments
258
+ objects accessible by the " Axes" interface, and often accept these as arguments
293
259
or pass them back from methods. It is usually essential to use the explicit
294
- "Axes" interface to perform any customization of the initial visualization.
260
+ "Axes" interface to perform any customization of the default visualization, or
261
+ to unpack the data into numpy arrays and pass directly to Matplotlib.
295
262
296
263
Appendix: "Axes" interface with data structures
297
264
-----------------------------------------------
@@ -309,4 +276,10 @@ Most `~.axes.Axes` methods allow yet another API addressing by passing a
309
276
fig, ax = plt.subplots()
310
277
ax.plot(x='x1', y='y1', data=data)
311
278
279
+ Appendix: "pylab" interface
280
+ ---------------------------
312
281
282
+ There is one further interface that is highly discouraged, and that is to
283
+ basically do `from matplotlib.pyplot import * `. This allows users to simply
284
+ call `plot(x, y) `. While convenient, this can lead to obvious problems if the
285
+ user unwittingly names a variable the same name as a pyplot method.
0 commit comments