0% found this document useful (0 votes)
250 views100 pages

Matplotlib: John Hunter, Darren Dale, Eric Firing, Michael Droettboom and The Matplotlib Development Team

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
250 views100 pages

Matplotlib: John Hunter, Darren Dale, Eric Firing, Michael Droettboom and The Matplotlib Development Team

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 100

Matplotlib

Release 2.0.2

John Hunter, Darren Dale, Eric Firing, Michael Droettboom and the ma

May 10, 2017


CONTENTS

I User’s Guide 1

1 Introduction 3

2 Installing 5

3 Tutorials 11

4 Working with text 97

5 Colors 145

6 Customizing matplotlib 173

7 Interactive plots 189

8 Selected Examples 205

9 What’s new in matplotlib 239

10 GitHub Stats 339

11 License 417

12 Credits 421

II The Matplotlib API 423

13 Plotting commands summary 425

14 API Changes 433

15 The top level matplotlib module 483

16 afm (Adobe Font Metrics interface) 487

17 animation module 491

i
18 artist Module 535

19 Axes class 555

20 axis and tick API 793

21 backends 913

22 cbook 953

23 cm (colormap) 971

24 collections 975

25 colorbar 1145

26 colors 1151

27 container 1165

28 dates 1167

29 dviread 1181

30 figure 1185

31 finance 1207

32 font_manager 1219

33 gridspec 1227

34 image 1231

35 legend and legend_handler 1237

36 lines 1245

37 markers 1255

38 mathtext 1259

39 mlab 1279

40 offsetbox 1313

41 patches 1325

42 path 1367

43 patheffects 1375

44 projections 1379

ii
45 pyplot 1387

46 rcsetup 1593

47 sankey 1597

48 scale 1605

49 spines 1615

50 style 1619

51 text 1621

52 ticker 1635

53 tight_layout 1647

54 Working with transformations 1649

55 triangular grids 1671

56 type1font 1683

57 units 1685

58 widgets 1687

III The Matplotlib FAQ 1703

59 Installation 1705

60 Usage 1713

61 How-To 1725

62 Troubleshooting 1741

63 Environment Variables 1745

64 Working with Matplotlib in Virtual environments 1747

65 Working with Matplotlib on OSX 1749

IV Matplotlib AxesGrid Toolkit 1753

66 Overview of AxesGrid toolkit 1757

67 The Matplotlib AxesGrid Toolkit User’s Guide 1779

iii
68 The Matplotlib AxesGrid Toolkit API 1795

69 The Matplotlib axes_grid1 Toolkit API 1805

V mplot3d 1823

70 Matplotlib mplot3d toolkit 1825

VI Toolkits 1879

71 Mapping Toolkits 1883

72 General Toolkits 1885

73 High-Level Plotting 1889

VII External Resources 1893

74 Books, Chapters and Articles 1895

75 Videos 1897

76 Tutorials 1899

VIII The Matplotlib Developers’ Guide 1901

77 Contributing 1903

78 Developer’s tips for testing 1911

79 Developer’s tips for documenting matplotlib 1917

80 Developer’s guide for creating scales and transformations 1929

81 Developer’s tips for writing code for Python 2 and 3 1933

82 Working with Matplotlib source code 1937

83 Reviewers guideline 1957

84 Release Guide 1959

85 Matplotlib Enhancement Proposals 1965

86 Licenses 2017

87 Default Color changes 2019

iv
IX Matplotlib Examples 2023

88 animation Examples 2025

89 api Examples 2029

90 axes_grid Examples 2123

91 color Examples 2175

92 event_handling Examples 2187

93 frontpage Examples 2221

94 images_contours_and_fields Examples 2225

95 lines_bars_and_markers Examples 2237

96 misc Examples 2251

97 mplot3d Examples 2275

98 pie_and_polar_charts Examples 2323

99 pylab_examples Examples 2329

100pyplots Examples 2769

101scales Examples 2791

102shapes_and_collections Examples 2793

103showcase Examples 2799

104specialty_plots Examples 2817

105statistics Examples 2825

106style_sheets Examples 2857

107subplots_axes_and_figures Examples 2873

108tests Examples 2877

109text_labels_and_annotations Examples 2889

110ticks_and_spines Examples 2895

111units Examples 2909

112user_interfaces Examples 2935

113widgets Examples 3001

v
X Glossary 3015

Bibliography 3019

Python Module Index 3021

Index 3023

vi
Part I

User’s Guide

1
CHAPTER

ONE

INTRODUCTION

Matplotlib is a library for making 2D plots of arrays in Python. Although it has its origins in emulating
the MATLAB®1 graphics commands, it is independent of MATLAB, and can be used in a Pythonic, object
oriented way. Although Matplotlib is written primarily in pure Python, it makes heavy use of NumPy and
other extension code to provide good performance even for large arrays.
Matplotlib is designed with the philosophy that you should be able to create simple plots with just a few
commands, or just one! If you want to see a histogram of your data, you shouldn’t need to instantiate objects,
call methods, set properties, and so on; it should just work.
For years, I used to use MATLAB exclusively for data analysis and visualization. MATLAB excels at mak-
ing nice looking plots easy. When I began working with EEG data, I found that I needed to write applications
to interact with my data, and developed an EEG analysis application in MATLAB. As the application grew
in complexity, interacting with databases, http servers, manipulating complex data structures, I began to
strain against the limitations of MATLAB as a programming language, and decided to start over in Python.
Python more than makes up for all of MATLAB’s deficiencies as a programming language, but I was having
difficulty finding a 2D plotting package (for 3D VTK more than exceeds all of my needs).
When I went searching for a Python plotting package, I had several requirements:
• Plots should look great - publication quality. One important requirement for me is that the text looks
good (antialiased, etc.)
• Postscript output for inclusion with TeX documents
• Embeddable in a graphical user interface for application development
• Code should be easy enough that I can understand it and extend it
• Making plots should be easy
Finding no package that suited me just right, I did what any self-respecting Python programmer would do:
rolled up my sleeves and dived in. Not having any real experience with computer graphics, I decided to
emulate MATLAB’s plotting capabilities because that is something MATLAB does very well. This had the
added advantage that many people have a lot of MATLAB experience, and thus they can quickly get up to
steam plotting in python. From a developer’s perspective, having a fixed user interface (the pylab interface)
has been very useful, because the guts of the code base can be redesigned without affecting user code.
The Matplotlib code is conceptually divided into three parts: the pylab interface is the set of functions
provided by matplotlib.pylab which allow the user to create plots with code quite similar to MATLAB
1
MATLAB is a registered trademark of The MathWorks, Inc.

3
Matplotlib, Release 2.0.2

figure generating code (Pyplot tutorial). The Matplotlib frontend or Matplotlib API is the set of classes that
do the heavy lifting, creating and managing figures, text, lines, plots and so on (Artist tutorial). This is an
abstract interface that knows nothing about output. The backends are device-dependent drawing devices, aka
renderers, that transform the frontend representation to hardcopy or a display device (What is a backend?).
Example backends: PS creates PostScript® hardcopy, SVG creates Scalable Vector Graphics hardcopy,
Agg creates PNG output using the high quality Anti-Grain Geometry library that ships with Matplotlib,
GTK embeds Matplotlib in a Gtk+ application, GTKAgg uses the Anti-Grain renderer to create a figure and
embed it in a Gtk+ application, and so on for PDF, WxWidgets, Tkinter, etc.
Matplotlib is used by many people in many different contexts. Some people want to automatically generate
PostScript files to send to a printer or publishers. Others deploy Matplotlib on a web application server to
generate PNG output for inclusion in dynamically-generated web pages. Some use Matplotlib interactively
from the Python shell in Tkinter on Windows™. My primary use is to embed Matplotlib in a Gtk+ EEG
application that runs on Windows, Linux and Macintosh OS X.

4 Chapter 1. Introduction
CHAPTER

TWO

INSTALLING

There are many different ways to install matplotlib, and the best way depends on what operating system you
are using, what you already have installed, and how you want to use it. To avoid wading through all the
details (and potential complications) on this page, there are several convenient options.

2.1 Installing pre-built packages

2.1.1 Most platforms : scientific Python distributions

The first option is to use one of the pre-packaged python distributions that already provide matplotlib built-in.
The Continuum.io Python distribution (Anaconda or miniconda) and the Enthought distribution (Canopy)
are both excellent choices that “just work” out of the box for Windows, OSX and common Linux platforms.
Both of these distributions include matplotlib and lots of other useful tools.

2.1.2 Linux : using your package manager

If you are on Linux, you might prefer to use your package manager. matplotlib is packaged for almost every
major Linux distribution.
• Debian / Ubuntu : sudo apt-get install python-matplotlib
• Fedora / Redhat : sudo yum install python-matplotlib

2.1.3 Mac OSX : using pip

If you are on Mac OSX you can probably install matplotlib binaries using the standard Python installation
program pip. See Installing OSX binary wheels.

2.1.4 Windows

If you don’t already have Python installed, we recommend using one of the scipy-stack compatible Python
distributions such as WinPython, Python(x,y), Enthought Canopy, or Continuum Anaconda, which have
matplotlib and many of its dependencies, plus other useful packages, preinstalled.
For standard Python installations, install matplotlib using pip:

5
Matplotlib, Release 2.0.2

python -m pip install -U pip setuptools


python -m pip install matplotlib

In case Python 2.7 or 3.4 are not installed for all users, the Microsoft Visual C++ 2008 (64 bit or 32 bit for
Python 2.7) or Microsoft Visual C++ 2010 (64 bit or 32 bit for Python 3.4) redistributable packages need to
be installed.
Matplotlib depends on Pillow for reading and saving JPEG, BMP, and TIFF image files. Matplotlib requires
MiKTeX and GhostScript for rendering text with LaTeX. FFmpeg, avconv, mencoder, or ImageMagick are
required for the animation module.
The following backends should work out of the box: agg, tkagg, ps, pdf and svg. For other backends you
may need to install pycairo, PyQt4, PyQt5, PySide, wxPython, PyGTK, Tornado, or GhostScript.
TkAgg is probably the best backend for interactive use from the standard Python shell or IPython. It is
enabled as the default backend for the official binaries. GTK3 is not supported on Windows.
The Windows wheels (*.whl) on the PyPI download page do not contain test data or example
code. If you want to try the many demos that come in the matplotlib source distribution, down-
load the *.tar.gz file and look in the examples subdirectory. To run the test suite, copy the
lib\matplotlib\tests and lib\mpl_toolkits\tests directories from the source distribution to sys.
prefix\Lib\site-packages\matplotlib and sys.prefix\Lib\site-packages\mpl_toolkits
respectively, and install nose, mock, Pillow, MiKTeX, GhostScript, ffmpeg, avconv, mencoder, ImageMag-
ick, and Inkscape.

2.2 Installing from source

If you are interested in contributing to matplotlib development, running the latest source code, or just like to
build everything yourself, it is not difficult to build matplotlib from source. Grab the latest tar.gz release file
from the PyPI files page, or if you want to develop matplotlib or just need the latest bugfixed version, grab
the latest git version Source install from git.
The standard environment variables CC, CXX, PKG_CONFIG are respected. This means you can set them if
your toolchain is prefixed. This may be used for cross compiling.

export CC=x86_64-pc-linux-gnu-gcc
export CXX=x86_64-pc-linux-gnu-g++
export PKG_CONFIG=x86_64-pc-linux-gnu-pkg-config

Once you have satisfied the requirements detailed below (mainly python, numpy, libpng and freetype), you
can build matplotlib.

cd matplotlib
python setup.py build
python setup.py install

We provide a setup.cfg file that goes with setup.py which you can use to customize the build process. For
example, which default backend to use, whether some of the optional libraries that matplotlib ships with are
installed, and so on. This file will be particularly useful to those packaging matplotlib.

6 Chapter 2. Installing
Matplotlib, Release 2.0.2

If you have installed prerequisites to nonstandard places and need to inform matplotlib where they are,
edit setupext.py and add the base dirs to the basedir dictionary entry for your sys.platform. e.g., if
the header to some required library is in /some/path/include/someheader.h, put /some/path in the
basedir list for your platform.

2.2.1 Build requirements

These are external packages which you will need to install before installing matplotlib. If you are building on
OSX, see Building on OSX. If you are building on Windows, see Building on Windows. If you are installing
dependencies with a package manager on Linux, you may need to install the development packages (look
for a “-dev” postfix) in addition to the libraries themselves.

Required Dependencies

python 2.7, 3.4, 3.5 or 3.6 Download python.


numpy 1.7.1 (or later) array support for python (download numpy)
setuptools Setuptools provides extensions for python package installation.
dateutil 1.1 or later Provides extensions to python datetime handling. If using pip, easy_install or in-
stalling from source, the installer will attempt to download and install python_dateutil from PyPI.
pyparsing Required for matplotlib’s mathtext math rendering support. If using pip, easy_install or in-
stalling from source, the installer will attempt to download and install pyparsing from PyPI.
libpng 1.2 (or later) library for loading and saving PNG files (download). libpng requires zlib.
pytz Used to manipulate time-zone aware datetimes. https://pypi.python.org/pypi/pytz
FreeType 2.3 or later Library for reading true type font files. If using pip, easy_install or installing from
source, the installer will attempt to locate FreeType in expected locations. If it cannot, try installing
pkg-config, a tool used to find required non-python libraries.
cycler 0.10.0 or later Composable cycle class used for constructing style-cycles
six Required for compatibility between python 2 and python 3

Dependencies for python 2

functools32 Required for compatibility if running on Python 2.7.


subprocess32 Optional, unix only. Backport of the subprocess standard library from 3.2+ for Python 2.7.
It provides better error messages and timeout support.

Optional GUI framework

These are optional packages which you may want to install to use matplotlib with a user interface toolkit.
See What is a backend? for more details on the optional matplotlib backends and the capabilities they
provide.

2.2. Installing from source 7


Matplotlib, Release 2.0.2

tk 8.3 or later, not 8.6.0 or 8.6.1 The TCL/Tk widgets library used by the TkAgg backend.
Versions 8.6.0 and 8.6.1 are known to have issues that may result in segfaults when closing multiple
windows in the wrong order.
pyqt 4.4 or later The Qt4 widgets library python wrappers for the Qt4Agg backend
pygtk 2.4 or later The python wrappers for the GTK widgets library for use with the GTK or GTKAgg
backend
wxpython 2.8 or later The python wrappers for the wx widgets library for use with the WX or WXAgg
backend

Optional external programs

ffmpeg/avconv or mencoder Required for the animation module to be save out put to movie formats.
ImageMagick Required for the animation module to be able to save to animated gif.

Optional dependencies

Pillow If Pillow is installed, matplotlib can read and write a larger selection of image file formats.
pkg-config A tool used to find required non-python libraries. This is not strictly required, but can make
installation go more smoothly if the libraries and headers are not in the expected locations.

Required libraries that ship with matplotlib

agg 2.4 The antigrain C++ rendering engine. matplotlib links against the agg template source statically, so
it will not affect anything on your system outside of matplotlib.
qhull 2012.1 A library for computing Delaunay triangulations.
ttconv truetype font utility

2.2.2 Building on Linux

It is easiest to use your system package manager to install the dependencies.


If you are on Debian/Ubuntu, you can get all the dependencies required to build matplotlib with:

sudo apt-get build-dep python-matplotlib

If you are on Fedora/RedHat, you can get all the dependencies required to build matplotlib by first installing
yum-builddep and then running:

su -c "yum-builddep python-matplotlib"

This does not build matplotlib, but it does get the install the build dependencies, which will make building
from source easier.

8 Chapter 2. Installing
Matplotlib, Release 2.0.2

2.2.3 Building on OSX

The build situation on OSX is complicated by the various places one can get the libpng and freetype re-
quirements (darwinports, fink, /usr/X11R6) and the different architectures (e.g., x86, ppc, universal) and
the different OSX version (e.g., 10.4 and 10.5). We recommend that you build the way we do for the OSX
release: get the source from the tarball or the git repository and follow the instruction in README.osx.

2.2.4 Building on Windows

The Python shipped from https://www.python.org is compiled with Visual Studio 2008 for versions before
3.3, Visual Studio 2010 for 3.3 and 3.4, and Visual Studio 2015 for 3.5 and 3.6. Python extensions are
recommended to be compiled with the same compiler.
Since there is no canonical Windows package manager, the methods for building freetype, zlib, and libpng
from source code are documented as a build script at matplotlib-winbuild.

2.2. Installing from source 9


Matplotlib, Release 2.0.2

10 Chapter 2. Installing
CHAPTER

THREE

TUTORIALS

3.1 Introductory

3.1.1 Pyplot tutorial

matplotlib.pyplot is a collection of command style functions that make matplotlib work like MATLAB.
Each pyplot function makes some change to a figure: e.g., creates a figure, creates a plotting area in a figure,
plots some lines in a plotting area, decorates the plot with labels, etc. In matplotlib.pyplot various states
are preserved across function calls, so that it keeps track of things like the current figure and plotting area,
and the plotting functions are directed to the current axes (please note that “axes” here and in most places in
the documentation refers to the axes part of a figure and not the strict mathematical term for more than one
axis).

import matplotlib.pyplot as plt


plt.plot([1,2,3,4])
plt.ylabel('some numbers')
plt.show()

11
Matplotlib, Release 2.0.2

4.0

3.5

3.0
some numbers

2.5

2.0

1.5

1.0
0.0 0.5 1.0 1.5 2.0 2.5 3.0

You may be wondering why the x-axis ranges from 0-3 and the y-axis from 1-4. If you provide a single
list or array to the plot() command, matplotlib assumes it is a sequence of y values, and automatically
generates the x values for you. Since python ranges start with 0, the default x vector has the same length as
y but starts with 0. Hence the x data are [0,1,2,3].
plot() is a versatile command, and will take an arbitrary number of arguments. For example, to plot x
versus y, you can issue the command:

plt.plot([1, 2, 3, 4], [1, 4, 9, 16])

For every x, y pair of arguments, there is an optional third argument which is the format string that indicates
the color and line type of the plot. The letters and symbols of the format string are from MATLAB, and you
concatenate a color string with a line style string. The default format string is ‘b-‘, which is a solid blue line.
For example, to plot the above with red circles, you would issue

import matplotlib.pyplot as plt


plt.plot([1,2,3,4], [1,4,9,16], 'ro')
plt.axis([0, 6, 0, 20])
plt.show()

12 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

20.0
17.5
15.0
12.5
10.0
7.5
5.0
2.5
0.0
0 1 2 3 4 5 6

See the plot() documentation for a complete list of line styles and format strings. The axis() command
in the example above takes a list of [xmin, xmax, ymin, ymax] and specifies the viewport of the axes.
If matplotlib were limited to working with lists, it would be fairly useless for numeric processing. Generally,
you will use numpy arrays. In fact, all sequences are converted to numpy arrays internally. The example
below illustrates a plotting several lines with different format styles in one command using arrays.

import numpy as np
import matplotlib.pyplot as plt

# evenly sampled time at 200ms intervals


t = np.arange(0., 5., 0.2)

# red dashes, blue squares and green triangles


plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^')
plt.show()

3.1. Introductory 13
Matplotlib, Release 2.0.2

100

80

60

40

20

0
0 1 2 3 4 5

Controlling line properties

Lines have many attributes that you can set: linewidth, dash style, antialiased, etc; see matplotlib.lines.
Line2D. There are several ways to set line properties
• Use keyword args:
plt.plot(x, y, linewidth=2.0)

• Use the setter methods of a Line2D instance. plot returns a list of Line2D objects; e.g., line1,
line2 = plot(x1, y1, x2, y2). In the code below we will suppose that we have only one line
so that the list returned is of length 1. We use tuple unpacking with line, to get the first element of
that list:
line, = plt.plot(x, y, '-')
line.set_antialiased(False) # turn off antialising

• Use the setp() command. The example below uses a MATLAB-style command to set multiple
properties on a list of lines. setp works transparently with a list of objects or a single object. You can
either use python keyword arguments or MATLAB-style string/value pairs:
lines = plt.plot(x1, y1, x2, y2)
# use keyword args
plt.setp(lines, color='r', linewidth=2.0)

14 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

# or MATLAB style string value pairs


plt.setp(lines, 'color', 'r', 'linewidth', 2.0)

Here are the available Line2D properties.

Property Value Type


alpha float
animated [True | False]
antialiased or aa [True | False]
clip_box a matplotlib.transform.Bbox instance
clip_on [True | False]
clip_path a Path instance and a Transform instance, a Patch
color or c any matplotlib color
contains the hit testing function
dash_capstyle ['butt' | 'round' | 'projecting']
dash_joinstyle ['miter' | 'round' | 'bevel']
dashes sequence of on/off ink in points
data (np.array xdata, np.array ydata)
figure a matplotlib.figure.Figure instance
label any string
linestyle or ls [ '-' | '--' | '-.' | ':' | 'steps' | ...]
linewidth or lw float value in points
lod [True | False]
marker [ '+' | ',' | '.' | '1' | '2' | '3' | '4' ]
markeredgecolor or mec any matplotlib color
markeredgewidth or mew float value in points
markerfacecolor or mfc any matplotlib color
markersize or ms float
markevery [ None | integer | (startind, stride) ]
picker used in interactive line selection
pickradius the line pick selection radius
solid_capstyle ['butt' | 'round' | 'projecting']
solid_joinstyle ['miter' | 'round' | 'bevel']
transform a matplotlib.transforms.Transform instance
visible [True | False]
xdata np.array
ydata np.array
zorder any number

To get a list of settable line properties, call the setp() function with a line or lines as argument
In [69]: lines = plt.plot([1, 2, 3])

In [70]: plt.setp(lines)
alpha: float
animated: [True | False]
antialiased or aa: [True | False]

3.1. Introductory 15
Matplotlib, Release 2.0.2

...snip

Working with multiple figures and axes

MATLAB, and pyplot, have the concept of the current figure and the current axes. All plotting com-
mands apply to the current axes. The function gca() returns the current axes (a matplotlib.axes.Axes
instance), and gcf() returns the current figure (matplotlib.figure.Figure instance). Normally, you
don’t have to worry about this, because it is all taken care of behind the scenes. Below is a script to create
two subplots.

import numpy as np
import matplotlib.pyplot as plt

def f(t):
return np.exp(-t) * np.cos(2*np.pi*t)

t1 = np.arange(0.0, 5.0, 0.1)


t2 = np.arange(0.0, 5.0, 0.02)

plt.figure(1)
plt.subplot(211)
plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k')

plt.subplot(212)
plt.plot(t2, np.cos(2*np.pi*t2), 'r--')
plt.show()

16 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

1.0
0.5
0.0
0.5
0 1 2 3 4 5
1.0
0.5
0.0
0.5
1.0
0 1 2 3 4 5

The figure() command here is optional because figure(1) will be created by default, just as a
subplot(111) will be created by default if you don’t manually specify any axes. The subplot() com-
mand specifies numrows, numcols, fignum where fignum ranges from 1 to numrows*numcols. The
commas in the subplot command are optional if numrows*numcols<10. So subplot(211) is identical
to subplot(2, 1, 1). You can create an arbitrary number of subplots and axes. If you want to place
an axes manually, i.e., not on a rectangular grid, use the axes() command, which allows you to specify
the location as axes([left, bottom, width, height]) where all values are in fractional (0 to 1) co-
ordinates. See pylab_examples example code: axes_demo.py for an example of placing axes manually and
pylab_examples example code: subplots_demo.py for an example with lots of subplots.
You can create multiple figures by using multiple figure() calls with an increasing figure number. Of
course, each figure can contain as many axes and subplots as your heart desires:

import matplotlib.pyplot as plt


plt.figure(1) # the first figure
plt.subplot(211) # the first subplot in the first figure
plt.plot([1, 2, 3])
plt.subplot(212) # the second subplot in the first figure
plt.plot([4, 5, 6])

plt.figure(2) # a second figure


plt.plot([4, 5, 6]) # creates a subplot(111) by default

plt.figure(1) # figure 1 current; subplot(212) still current

3.1. Introductory 17
Matplotlib, Release 2.0.2

plt.subplot(211) # make subplot(211) in figure1 current


plt.title('Easy as 1, 2, 3') # subplot 211 title

You can clear the current figure with clf() and the current axes with cla(). If you find it annoying that
states (specifically the current image, figure and axes) are being maintained for you behind the scenes, don’t
despair: this is just a thin stateful wrapper around an object oriented API, which you can use instead (see
Artist tutorial)
If you are making lots of figures, you need to be aware of one more thing: the memory required for a figure
is not completely released until the figure is explicitly closed with close(). Deleting all references to the
figure, and/or using the window manager to kill the window in which the figure appears on the screen, is not
enough, because pyplot maintains internal references until close() is called.

Working with text

The text() command can be used to add text in an arbitrary location, and the xlabel(), ylabel() and
title() are used to add text in the indicated locations (see Text introduction for a more detailed example)

import numpy as np
import matplotlib.pyplot as plt

# Fixing random state for reproducibility


np.random.seed(19680801)

mu, sigma = 100, 15


x = mu + sigma * np.random.randn(10000)

# the histogram of the data


n, bins, patches = plt.hist(x, 50, normed=1, facecolor='g', alpha=0.75)

plt.xlabel('Smarts')
plt.ylabel('Probability')
plt.title('Histogram of IQ')
plt.text(60, .025, r'$\mu=100,\ \sigma=15$')
plt.axis([40, 160, 0, 0.03])
plt.grid(True)
plt.show()

18 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Histogram of IQ
0.030

0.025 = 100, = 15

0.020
Probability

0.015

0.010

0.005

0.000
40 60 80 100 120 140 160
Smarts
All of the text() commands return an matplotlib.text.Text instance. Just as with with lines above,
you can customize the properties by passing keyword arguments into the text functions or using setp():

t = plt.xlabel('my data', fontsize=14, color='red')

These properties are covered in more detail in Text properties and layout.

Using mathematical expressions in text

matplotlib accepts TeX equation expressions in any text expression. For example to write the expression
σi = 15 in the title, you can write a TeX expression surrounded by dollar signs:

plt.title(r'$\sigma_i=15$')

The r preceding the title string is important – it signifies that the string is a raw string and not to treat
backslashes as python escapes. matplotlib has a built-in TeX expression parser and layout engine, and ships
its own math fonts – for details see Writing mathematical expressions. Thus you can use mathematical text
across platforms without requiring a TeX installation. For those who have LaTeX and dvipng installed, you
can also use LaTeX to format your text and incorporate the output directly into your display figures or saved
postscript – see Text rendering With LaTeX.

3.1. Introductory 19
Matplotlib, Release 2.0.2

Annotating text

The uses of the basic text() command above place text at an arbitrary position on the Axes. A common use
for text is to annotate some feature of the plot, and the annotate() method provides helper functionality
to make annotations easy. In an annotation, there are two points to consider: the location being annotated
represented by the argument xy and the location of the text xytext. Both of these arguments are (x,y)
tuples.

import numpy as np
import matplotlib.pyplot as plt

ax = plt.subplot(111)

t = np.arange(0.0, 5.0, 0.01)


s = np.cos(2*np.pi*t)
line, = plt.plot(t, s, lw=2)

plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5),


arrowprops=dict(facecolor='black', shrink=0.05),
)

plt.ylim(-2,2)
plt.show()

2.0
1.5 local max

1.0
0.5
0.0
0.5
1.0
1.5
2.0
0 1 2 3 4 5

In this basic example, both the xy (arrow tip) and xytext locations (text location) are in data coordinates.

20 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

There are a variety of other coordinate systems one can choose – see Basic annotation and Advanced Anno-
tation for details. More examples can be found in pylab_examples example code: annotation_demo.py.

Logarithmic and other nonlinear axes

matplotlib.pyplot supports not only linear axis scales, but also logarithmic and logit scales. This is
commonly used if data spans many orders of magnitude. Changing the scale of an axis is easy:
plt.xscale(‘log’)
An example of four plots with the same data and different scales for the y axis is shown below.
import numpy as np
import matplotlib.pyplot as plt

from matplotlib.ticker import NullFormatter # useful for `logit` scale

# Fixing random state for reproducibility


np.random.seed(19680801)

# make up some data in the interval ]0, 1[


y = np.random.normal(loc=0.5, scale=0.4, size=1000)
y = y[(y > 0) & (y < 1)]
y.sort()
x = np.arange(len(y))

# plot with various axes scales


plt.figure(1)

# linear
plt.subplot(221)
plt.plot(x, y)
plt.yscale('linear')
plt.title('linear')
plt.grid(True)

# log
plt.subplot(222)
plt.plot(x, y)
plt.yscale('log')
plt.title('log')
plt.grid(True)

# symmetric log
plt.subplot(223)
plt.plot(x, y - y.mean())
plt.yscale('symlog', linthreshy=0.01)
plt.title('symlog')
plt.grid(True)

# logit

3.1. Introductory 21
Matplotlib, Release 2.0.2

plt.subplot(224)
plt.plot(x, y)
plt.yscale('logit')
plt.title('logit')
plt.grid(True)
# Format the minor tick labels of the y-axis into empty strings with
# `NullFormatter`, to avoid cumbering the axis with too many labels.
plt.gca().yaxis.set_minor_formatter(NullFormatter())
# Adjust the subplot layout, because the logit one may take more space
# than usual, due to y-tick labels like "1 - 10^{-3}"
plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25,
wspace=0.35)

plt.show()

linear log
1.0 100
0.8
0.6 10 1
0.4
0.2 10 2
0.0
0 250 500 750 0 250
symlog logit500 750

10 1 1 10 3
10 2 0.99
0 0.90
0.50
10 2 0.10
10 1 0.01
100
0 250 500 750 0 250 500 750
It is also possible to add your own scale, see Developer’s guide for creating scales and transformations for
details.

3.1.2 Image tutorial

22 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Startup commands

First, let’s start IPython. It is a most excellent enhancement to the standard Python prompt, and it ties in
especially well with Matplotlib. Start IPython either at a shell, or the IPython Notebook now.
With IPython started, we now need to connect to a GUI event loop. This tells IPython where (and how) to
display plots. To connect to a GUI loop, execute the %matplotlib magic at your IPython prompt. There’s
more detail on exactly what this does at IPython’s documentation on GUI event loops.
If you’re using IPython Notebook, the same commands are available, but people commonly use a specific
argument to the %matplotlib magic:

In [1]: %matplotlib inline

This turns on inline plotting, where plot graphics will appear in your notebook. This has important implica-
tions for interactivity. For inline plotting, commands in cells below the cell that outputs a plot will not affect
the plot. For example, changing the color map is not possible from cells below the cell that creates a plot.
However, for other backends, such as qt4, that open a separate window, cells below those that create the plot
will change the plot - it is a live object in memory.
This tutorial will use matplotlib’s imperative-style plotting interface, pyplot. This interface maintains global
state, and is very useful for quickly and easily experimenting with various plot settings. The alternative is
the object-oriented interface, which is also very powerful, and generally more suitable for large application
development. If you’d like to learn about the object-oriented interface, a great place to start is our FAQ on
usage. For now, let’s get on with the imperative-style approach:

In [2]: import matplotlib.pyplot as plt


In [3]: import matplotlib.image as mpimg
In [4]: import numpy as np

Importing image data into Numpy arrays

Loading image data is supported by the Pillow library. Natively, matplotlib only supports PNG images. The
commands shown below fall back on Pillow if the native read fails.
The image used in this example is a PNG file, but keep that Pillow requirement in mind for your own data.
Here’s the image we’re going to play with:

3.1. Introductory 23
Matplotlib, Release 2.0.2

It’s a 24-bit RGB PNG image (8 bits for each of R, G, B). Depending on where you get your data, the other
kinds of image that you’ll most likely encounter are RGBA images, which allow for transparency, or single-
channel grayscale (luminosity) images. You can right click on it and choose “Save image as” to download
it to your computer for the rest of this tutorial.
And here we go...

In [5]: img=mpimg.imread('stinkbug.png')
Out[5]:
array([[[ 0.40784314, 0.40784314, 0.40784314],
[ 0.40784314, 0.40784314, 0.40784314],
[ 0.40784314, 0.40784314, 0.40784314],
...,
[ 0.42745098, 0.42745098, 0.42745098],
[ 0.42745098, 0.42745098, 0.42745098],
[ 0.42745098, 0.42745098, 0.42745098]],

...,
[[ 0.44313726, 0.44313726, 0.44313726],
[ 0.4509804 , 0.4509804 , 0.4509804 ],
[ 0.4509804 , 0.4509804 , 0.4509804 ],
...,
[ 0.44705883, 0.44705883, 0.44705883],

24 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

[ 0.44705883, 0.44705883, 0.44705883],


[ 0.44313726, 0.44313726, 0.44313726]]], dtype=float32)

Note the dtype there - float32. Matplotlib has rescaled the 8 bit data from each channel to floating point
data between 0.0 and 1.0. As a side note, the only datatype that Pillow can work with is uint8. Matplotlib
plotting can handle float32 and uint8, but image reading/writing for any format other than PNG is limited
to uint8 data. Why 8 bits? Most displays can only render 8 bits per channel worth of color gradation. Why
can they only render 8 bits/channel? Because that’s about all the human eye can see. More here (from a
photography standpoint): Luminous Landscape bit depth tutorial.
Each inner list represents a pixel. Here, with an RGB image, there are 3 values. Since it’s a black and white
image, R, G, and B are all similar. An RGBA (where A is alpha, or transparency), has 4 values per inner list,
and a simple luminance image just has one value (and is thus only a 2-D array, not a 3-D array). For RGB
and RGBA images, matplotlib supports float32 and uint8 data types. For grayscale, matplotlib supports only
float32. If your array data does not meet one of these descriptions, you need to rescale it.

Plotting numpy arrays as images

So, you have your data in a numpy array (either by importing it, or by generating it). Let’s render it. In
Matplotlib, this is performed using the imshow() function. Here we’ll grab the plot object. This object
gives you an easy way to manipulate the plot from the prompt.
In [6]: imgplot = plt.imshow(img)

0
50
100
150
200
250
300
350
0 100 200 300 400 500

3.1. Introductory 25
Matplotlib, Release 2.0.2

You can also plot any numpy array.

Applying pseudocolor schemes to image plots

Pseudocolor can be a useful tool for enhancing contrast and visualizing your data more easily. This is
especially useful when making presentations of your data using projectors - their contrast is typically quite
poor.
Pseudocolor is only relevant to single-channel, grayscale, luminosity images. We currently have an RGB
image. Since R, G, and B are all similar (see for yourself above or in your data), we can just pick one
channel of our data:

In [7]: lum_img = img[:,:,0]

This is array slicing. You can read more in the Numpy tutorial.

In [8]: plt.imshow(lum_img)

0
50
100
150
200
250
300
350
0 100 200 300 400 500

Now, with a luminosity (2D, no color) image, the default colormap (aka lookup table, LUT), is applied. The
default is called viridis. There are plenty of others to choose from.

In [9]: plt.imshow(lum_img, cmap="hot")

26 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

0
50
100
150
200
250
300
350
0 100 200 300 400 500

Note that you can also change colormaps on existing plot objects using the set_cmap() method:

In [10]: imgplot = plt.imshow(lum_img)


In [11]: imgplot.set_cmap('nipy_spectral')

3.1. Introductory 27
Matplotlib, Release 2.0.2

0
50
100
150
200
250
300
350
0 100 200 300 400 500

Note: However, remember that in the IPython notebook with the inline backend, you can’t make changes
to plots that have already been rendered. If you create imgplot here in one cell, you cannot call set_cmap()
on it in a later cell and expect the earlier plot to change. Make sure that you enter these commands together
in one cell. plt commands will not change plots from earlier cells.

There are many other colormap schemes available. See the list and images of the colormaps.

Color scale reference

It’s helpful to have an idea of what value a color represents. We can do that by adding color bars.

In [12]: imgplot = plt.imshow(lum_img)


In [13]: plt.colorbar()

28 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

0.8
0
0.7
50
0.6
100
150 0.5
200 0.4
250 0.3
300
0.2
350
0 100 200 300 400 500 0.1
0.0

This adds a colorbar to your existing figure. This won’t automatically change if you change you switch to a
different colormap - you have to re-create your plot, and add in the colorbar again.

Examining a specific data range

Sometimes you want to enhance the contrast in your image, or expand the contrast in a particular region
while sacrificing the detail in colors that don’t vary much, or don’t matter. A good tool to find interesting
regions is the histogram. To create a histogram of our image data, we use the hist() function.

In [14]: plt.hist(lum_img.ravel(), bins=256, range=(0.0, 1.0), fc='k', ec='k')

3.1. Introductory 29
Matplotlib, Release 2.0.2

8000

6000

4000

2000

0
0.0 0.2 0.4 0.6 0.8 1.0

Most often, the “interesting” part of the image is around the peak, and you can get extra contrast by clipping
the regions above and/or below the peak. In our histogram, it looks like there’s not much useful information
in the high end (not many white things in the image). Let’s adjust the upper limit, so that we effectively
“zoom in on” part of the histogram. We do this by passing the clim argument to imshow. You could also do
this by calling the set_clim() method of the image plot object, but make sure that you do so in the same
cell as your plot command when working with the IPython Notebook - it will not change plots from earlier
cells.

In [15]: imgplot = plt.imshow(lum_img, clim=(0.0, 0.7))

30 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Before After
0 0
100 100
200 200
300 300
0 200 400 0 200 400

0.1 0.3 0.5 0.7 0.1 0.3 0.5 0.7

Array Interpolation schemes

Interpolation calculates what the color or value of a pixel “should” be, according to different mathematical
schemes. One common place that this happens is when you resize an image. The number of pixels change,
but you want the same information. Since pixels are discrete, there’s missing space. Interpolation is how
you fill that space. This is why your images sometimes come out looking pixelated when you blow them
up. The effect is more pronounced when the difference between the original image and the expanded image
is greater. Let’s take our image and shrink it. We’re effectively discarding pixels, only keeping a select few.
Now when we plot it, that data gets blown up to the size on your screen. The old pixels aren’t there anymore,
and the computer has to draw in pixels to fill that space.
We’ll use the Pillow library that we used to load the image also to resize the image.

In [16]: from PIL import Image


In [17]: img = Image.open('../_static/stinkbug.png')
In [18]: img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place
In [19]: imgplot = plt.imshow(img)

3.1. Introductory 31
Matplotlib, Release 2.0.2

10

20

30

40

0 10 20 30 40 50 60

Here we have the default interpolation, bilinear, since we did not give imshow() any interpolation argument.
Let’s try some others:

In [20]: imgplot = plt.imshow(img, interpolation="nearest")

32 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

10

20

30

40

0 10 20 30 40 50 60

In [21]: imgplot = plt.imshow(img, interpolation="bicubic")

3.1. Introductory 33
Matplotlib, Release 2.0.2

10

20

30

40

0 10 20 30 40 50 60

Bicubic interpolation is often used when blowing up photos - people tend to prefer blurry over pixelated.

3.1.3 Customizing Location of Subplot Using GridSpec

GridSpec specifies the geometry of the grid that a subplot will be placed. The number of
rows and number of columns of the grid need to be set. Optionally, the subplot layout
parameters (e.g., left, right, etc.) can be tuned.
SubplotSpec specifies the location of the subplot in the given GridSpec.
subplot2grid() a helper function that is similar to subplot() but uses 0-based indexing
and let subplot to occupy multiple cells.

Basic Example of using subplot2grid

To use subplot2grid(), you provide geometry of the grid and the location of the subplot in the grid. For
a simple single-cell subplot:

ax = plt.subplot2grid((2, 2), (0, 0))

is identical to

34 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

ax = plt.subplot(2, 2, 1)

Note that, unlike Matplotlib’s subplot, the index starts from 0 in GridSpec.
To create a subplot that spans multiple cells,

ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2)


ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)

For example, the following commands

ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3)


ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
ax4 = plt.subplot2grid((3, 3), (2, 0))
ax5 = plt.subplot2grid((3, 3), (2, 1))

creates

subplot2grid

ax1

ax2

ax3

ax4 ax5

GridSpec and SubplotSpec

You can create GridSpec explicitly and use them to create a subplot.
For example,

3.1. Introductory 35
Matplotlib, Release 2.0.2

ax = plt.subplot2grid((2, 2), (0, 0))

is equal to

import matplotlib.gridspec as gridspec


gs = gridspec.GridSpec(2, 2)
ax = plt.subplot(gs[0, 0])

A GridSpec instance provides array-like (2d or 1d) indexing that returns the SubplotSpec instance. For a
SubplotSpec that spans multiple cells, use slice.

ax2 = plt.subplot(gs[1, :-1])


ax3 = plt.subplot(gs[1:, -1])

The above example becomes

gs = gridspec.GridSpec(3, 3)
ax1 = plt.subplot(gs[0, :])
ax2 = plt.subplot(gs[1, :-1])
ax3 = plt.subplot(gs[1:, -1])
ax4 = plt.subplot(gs[-1, 0])
ax5 = plt.subplot(gs[-1, -2])

GridSpec

ax1

ax2

ax3

ax4 ax5

36 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Adjust GridSpec layout

When a GridSpec is explicitly used, you can adjust the layout parameters of subplots that are created from
the GridSpec.

gs1 = gridspec.GridSpec(3, 3)
gs1.update(left=0.05, right=0.48, wspace=0.05)

This is similar to subplots_adjust(), but it only affects the subplots that are created from the given
GridSpec.
The code below

gs1 = gridspec.GridSpec(3, 3)
gs1.update(left=0.05, right=0.48, wspace=0.05)
ax1 = plt.subplot(gs1[:-1, :])
ax2 = plt.subplot(gs1[-1, :-1])
ax3 = plt.subplot(gs1[-1, -1])

gs2 = gridspec.GridSpec(3, 3)
gs2.update(left=0.55, right=0.98, hspace=0.05)
ax4 = plt.subplot(gs2[:, :-1])
ax5 = plt.subplot(gs2[:-1, -1])
ax6 = plt.subplot(gs2[-1, -1])

creates

GridSpec w/ different subplotpars

ax1 ax5

ax4

ax2 ax3 ax6

3.1. Introductory 37
Matplotlib, Release 2.0.2

GridSpec using SubplotSpec

You can create GridSpec from the SubplotSpec, in which case its layout parameters are set to that of the
location of the given SubplotSpec.

gs0 = gridspec.GridSpec(1, 2)

gs00 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[0])


gs01 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[1])

GirdSpec Inside GridSpec

ax1 ax5

ax4

ax2 ax3 ax6

A Complex Nested GridSpec using SubplotSpec

Here’s a more sophisticated example of nested GridSpec where we put a box around each cell of the outer
4x4 grid, by hiding appropriate spines in each of the inner 3x3 grids.

38 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

GridSpec with Varying Cell Sizes

By default, GridSpec creates cells of equal sizes. You can adjust relative heights and widths of rows and
columns. Note that absolute values are meaningless, only their relative ratios matter.

gs = gridspec.GridSpec(2, 2,
width_ratios=[1, 2],
height_ratios=[4, 1]
)

ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])

3.1. Introductory 39
Matplotlib, Release 2.0.2

ax3 = plt.subplot(gs[2])
ax4 = plt.subplot(gs[3])

ax1 ax2

ax3 ax4

3.1.4 Tight Layout guide

tight_layout automatically adjusts subplot params so that the subplot(s) fits in to the figure area. This is an
experimental feature and may not work for some cases. It only checks the extents of ticklabels, axis labels,
and titles.

Simple Example

In matplotlib, the location of axes (including subplots) are specified in normalized figure coordinates. It can
happen that your axis labels or titles (or sometimes even ticklabels) go outside the figure area, and are thus
clipped.

plt.rcParams['savefig.facecolor'] = "0.8"

def example_plot(ax, fontsize=12):


ax.plot([1, 2])
ax.locator_params(nbins=3)
ax.set_xlabel('x-label', fontsize=fontsize)
ax.set_ylabel('y-label', fontsize=fontsize)

40 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

ax.set_title('Title', fontsize=fontsize)

plt.close('all')
fig, ax = plt.subplots()
example_plot(ax, fontsize=24)

Title
2.0
y-label

1.5

1.0
0.0 0.5 1.0
x-label
To prevent this, the location of axes needs to be adjusted. For subplots, this can be done by adjusting the
subplot params (Move the edge of an axes to make room for tick labels). Matplotlib v1.1 introduces a new
command tight_layout() that does this automatically for you.

plt.tight_layout()

3.1. Introductory 41
Matplotlib, Release 2.0.2

Title
2.0
y-label

1.5

1.0
0.0 0.5 1.0
x-label
When you have multiple subplots, often you see labels of different axes overlapping each other.

plt.close('all')
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)

42 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Title Title
2.0 2.0
y-label

y-label
1.5 1.5

1.0 1.0
0.0 Title
0.5 1.0 0.0 Title
0.5 1.0
2.0 x-label 2.0 x-label
y-label

y-label

1.5 1.5

1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label
tight_layout() will also adjust spacing between subplots to minimize the overlaps.

plt.tight_layout()

3.1. Introductory 43
Matplotlib, Release 2.0.2

Title Title
2.0 2.0
y-label

y-label
1.5 1.5

1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label
Title Title
2.0 2.0
y-label

y-label
1.5 1.5

1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label
tight_layout() can take keyword arguments of pad, w_pad and h_pad. These control the extra padding
around the figure border and between subplots. The pads are specified in fraction of fontsize.

plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)

44 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Title Title
2.0 2.0
y-label

y-label
1.5 1.5

1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label
Title Title
2.0 2.0
y-label

y-label

1.5 1.5

1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label
tight_layout() will work even if the sizes of subplots are different as far as their grid specification is
compatible. In the example below, ax1 and ax2 are subplots of a 2x2 grid, while ax3 is of a 1x2 grid.

plt.close('all')
fig = plt.figure()

ax1 = plt.subplot(221)
ax2 = plt.subplot(223)
ax3 = plt.subplot(122)

example_plot(ax1)
example_plot(ax2)
example_plot(ax3)

plt.tight_layout()

3.1. Introductory 45
Matplotlib, Release 2.0.2

Title Title
2.0 2.0
y-label

1.5

1.0
0.0 0.5 1.0

y-label
x-label 1.5
Title
2.0
y-label

1.5

1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label
It works with subplots created with subplot2grid(). In general, subplots created from the gridspec (Cus-
tomizing Location of Subplot Using GridSpec) will work.

plt.close('all')
fig = plt.figure()

ax1 = plt.subplot2grid((3, 3), (0, 0))


ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2)
ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)

example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)

plt.tight_layout()

46 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Title Title
2.0 2.0
y-label

y-label
1.5 1.5
1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label
Title Title
2.0 2.0
y-label

y-label
1.5 1.5

1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label
Although not thoroughly tested, it seems to work for subplots with aspect != “auto” (e.g., axes with images).

arr = np.arange(100).reshape((10,10))

plt.close('all')
fig = plt.figure(figsize=(5,4))

ax = plt.subplot(111)
im = ax.imshow(arr, interpolation="none")

plt.tight_layout()

3.1. Introductory 47
Matplotlib, Release 2.0.2

0 2 4 6 8

Caveats

• tight_layout() only considers ticklabels, axis labels, and titles. Thus, other artists may be clipped
and also may overlap.
• It assumes that the extra space needed for ticklabels, axis labels, and titles is independent of original
location of axes. This is often true, but there are rare cases where it is not.
• pad=0 clips some of the texts by a few pixels. This may be a bug or a limitation of the current
algorithm and it is not clear why it happens. Meanwhile, use of pad at least larger than 0.3 is recom-
mended.

Use with GridSpec

GridSpec has its own tight_layout() method (the pyplot api tight_layout() also works).

plt.close('all')
fig = plt.figure()

import matplotlib.gridspec as gridspec

gs1 = gridspec.GridSpec(2, 1)
ax1 = fig.add_subplot(gs1[0])
ax2 = fig.add_subplot(gs1[1])

48 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

example_plot(ax1)
example_plot(ax2)

gs1.tight_layout(fig)

Title
2.0
y-label

1.5

1.0
0.0 0.5 1.0
x-label
Title
2.0
y-label

1.5

1.0
0.0 0.5 1.0
x-label
You may provide an optional rect parameter, which specifies the bounding box that the subplots will be fit
inside. The coordinates must be in normalized figure coordinates and the default is (0, 0, 1, 1).

gs1.tight_layout(fig, rect=[0, 0, 0.5, 1])

3.1. Introductory 49
Matplotlib, Release 2.0.2

Title
2.0
y-label

1.5

1.0
0.0 0.5 1.0
x-label
Title
2.0
y-label

1.5

1.0
0.0 0.5 1.0
x-label
For example, this can be used for a figure with multiple gridspecs.

gs2 = gridspec.GridSpec(3, 1)

for ss in gs2:
ax = fig.add_subplot(ss)
example_plot(ax)
ax.set_title("")
ax.set_xlabel("")

ax.set_xlabel("x-label", fontsize=12)

gs2.tight_layout(fig, rect=[0.5, 0, 1, 1], h_pad=0.5)

50 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Title 2.0
2.0

y-label
1.5
y-label

1.5
1.0
0.0 0.5 1.0
2.0
1.0
0.0 0.5 1.0

y-label
x-label 1.5
Title
2.0 1.0
0.0 0.5 1.0
2.0
y-label

1.5
y-label

1.5

1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label
We may try to match the top and bottom of two grids

top = min(gs1.top, gs2.top)


bottom = max(gs1.bottom, gs2.bottom)

gs1.update(top=top, bottom=bottom)
gs2.update(top=top, bottom=bottom)

While this should be mostly good enough, adjusting top and bottom may require adjustment of hspace also.
To update hspace & vspace, we call tight_layout() again with updated rect argument. Note that the rect
argument specifies the area including the ticklabels, etc. Thus, we will increase the bottom (which is 0 for
the normal case) by the difference between the bottom from above and the bottom of each gridspec. Same
thing for the top.

top = min(gs1.top, gs2.top)


bottom = max(gs1.bottom, gs2.bottom)

gs1.tight_layout(fig, rect=[None, 0 + (bottom-gs1.bottom),


0.5, 1 - (gs1.top-top)])
gs2.tight_layout(fig, rect=[0.5, 0 + (bottom-gs2.bottom),
None, 1 - (gs2.top-top)],
h_pad=0.5)

3.1. Introductory 51
Matplotlib, Release 2.0.2

Title
2.0 2.0

y-label
1.5
y-label

1.5
1.0
0.0 0.5 1.0
1.0 2.0
0.0 0.5 1.0

y-label
x-label 1.5
Title
2.0 1.0
0.0 0.5 1.0
2.0
y-label

1.5
y-label

1.5
1.0 1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label

Use with AxesGrid1

While limited, the axes_grid1 toolkit is also supported.

plt.close('all')
fig = plt.figure()

from mpl_toolkits.axes_grid1 import Grid


grid = Grid(fig, rect=111, nrows_ncols=(2,2),
axes_pad=0.25, label_mode='L',
)

for ax in grid:
example_plot(ax)
ax.title.set_visible(False)

plt.tight_layout()

52 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

y-label 2.0

1.5

1.0
2.0
y-label

1.5

1.0
0.0 0.5 1.0 0.0 0.5 1.0
x-label x-label

Colorbar

If you create a colorbar with the colorbar() command, the created colorbar is an instance of Axes, not
Subplot, so tight_layout does not work. With Matplotlib v1.1, you may create a colorbar as a subplot using
the gridspec.

plt.close('all')
arr = np.arange(100).reshape((10,10))
fig = plt.figure(figsize=(4, 4))
im = plt.imshow(arr, interpolation="none")

plt.colorbar(im, use_gridspec=True)

plt.tight_layout()

3.1. Introductory 53
Matplotlib, Release 2.0.2

0
80
2
60
4

6 40

8 20

0 2 4 6 8
0

Another option is to use AxesGrid1 toolkit to explicitly create an axes for colorbar.

plt.close('all')
arr = np.arange(100).reshape((10,10))
fig = plt.figure(figsize=(4, 4))
im = plt.imshow(arr, interpolation="none")

from mpl_toolkits.axes_grid1 import make_axes_locatable


divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", "5%", pad="3%")
plt.colorbar(im, cax=cax)

plt.tight_layout()

54 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

0
80
2
60
4
40
6
20
8
0
0 2 4 6 8

3.2 Intermediate

3.2.1 Artist tutorial

There are three layers to the matplotlib API. The matplotlib.backend_bases.FigureCanvas is the area
onto which the figure is drawn, the matplotlib.backend_bases.Renderer is the object which knows
how to draw on the FigureCanvas, and the matplotlib.artist.Artist is the object that knows how to
use a renderer to paint onto the canvas. The FigureCanvas and Renderer handle all the details of talking
to user interface toolkits like wxPython or drawing languages like PostScript®, and the Artist handles all
the high level constructs like representing and laying out the figure, text, and lines. The typical user will
spend 95% of their time working with the Artists.
There are two types of Artists: primitives and containers. The primitives represent the standard graphical
objects we want to paint onto our canvas: Line2D, Rectangle, Text, AxesImage, etc., and the containers
are places to put them (Axis, Axes and Figure). The standard use is to create a Figure instance, use
the Figure to create one or more Axes or Subplot instances, and use the Axes instance helper methods
to create the primitives. In the example below, we create a Figure instance using matplotlib.pyplot.
figure(), which is a convenience method for instantiating Figure instances and connecting them with
your user interface or drawing toolkit FigureCanvas. As we will discuss below, this is not necessary –
you can work directly with PostScript, PDF Gtk+, or wxPython FigureCanvas instances, instantiate your
Figures directly and connect them yourselves – but since we are focusing here on the Artist API we’ll
let pyplot handle some of those details for us:

3.2. Intermediate 55
Matplotlib, Release 2.0.2

import matplotlib.pyplot as plt


fig = plt.figure()
ax = fig.add_subplot(2,1,1) # two rows, one column, first plot

The Axes is probably the most important class in the matplotlib API, and the one you will be working with
most of the time. This is because the Axes is the plotting area into which most of the objects go, and the
Axes has many special helper methods (plot(), text(), hist(), imshow()) to create the most common
graphics primitives (Line2D, Text, Rectangle, Image, respectively). These helper methods will take your
data (e.g., numpy arrays and strings) and create primitive Artist instances as needed (e.g., Line2D), add
them to the relevant containers, and draw them when requested. Most of you are probably familiar with the
Subplot, which is just a special case of an Axes that lives on a regular rows by columns grid of Subplot
instances. If you want to create an Axes at an arbitrary location, simply use the add_axes() method which
takes a list of [left, bottom, width, height] values in 0-1 relative figure coordinates:
fig2 = plt.figure()
ax2 = fig2.add_axes([0.15, 0.1, 0.7, 0.3])

Continuing with our example:


import numpy as np
t = np.arange(0.0, 1.0, 0.01)
s = np.sin(2*np.pi*t)
line, = ax.plot(t, s, color='blue', lw=2)

In this example, ax is the Axes instance created by the fig.add_subplot call above (remember Subplot
is just a subclass of Axes) and when you call ax.plot, it creates a Line2D instance and adds it to the
Axes.lines list. In the interactive ipython session below, you can see that the Axes.lines list is length
one and contains the same line that was returned by the line, = ax.plot... call:
In [101]: ax.lines[0]
Out[101]: <matplotlib.lines.Line2D instance at 0x19a95710>

In [102]: line
Out[102]: <matplotlib.lines.Line2D instance at 0x19a95710>

If you make subsequent calls to ax.plot (and the hold state is “on” which is the default) then additional
lines will be added to the list. You can remove lines later simply by calling the list methods; either of these
will work:
del ax.lines[0]
ax.lines.remove(line) # one or the other, not both!

The Axes also has helper methods to configure and decorate the x-axis and y-axis tick, tick labels and axis
labels:
xtext = ax.set_xlabel('my xdata') # returns a Text instance
ytext = ax.set_ylabel('my ydata')

When you call ax.set_xlabel, it passes the information on the Text instance of the XAxis. Each Axes
instance contains an XAxis and a YAxis instance, which handle the layout and drawing of the ticks, tick
labels and axis labels.

56 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Try creating the figure below.

a sine wave
1.0
0.5
volts

0.0
0.5
1.0
0.0 0.2 0.4 0.6 0.8 1.0
60
40
20
0
4 3 2 1 0 1 2 3 4
time (s)

Customizing your objects

Every element in the figure is represented by a matplotlib Artist, and each has an extensive list of proper-
ties to configure its appearance. The figure itself contains a Rectangle exactly the size of the figure, which
you can use to set the background color and transparency of the figures. Likewise, each Axes bounding
box (the standard white box with black edges in the typical matplotlib plot, has a Rectangle instance that
determines the color, transparency, and other properties of the Axes. These instances are stored as mem-
ber variables Figure.patch and Axes.patch (“Patch” is a name inherited from MATLAB, and is a 2D
“patch” of color on the figure, e.g., rectangles, circles and polygons). Every matplotlib Artist has the
following properties

3.2. Intermediate 57
Matplotlib, Release 2.0.2

Property Description
alpha The transparency - a scalar from 0-1
animated A boolean that is used to facilitate animated drawing
axes The axes that the Artist lives in, possibly None
clip_box The bounding box that clips the Artist
clip_on Whether clipping is enabled
clip_path The path the artist is clipped to
contains A picking function to test whether the artist contains the pick point
figure The figure instance the artist lives in, possibly None
label A text label (e.g., for auto-labeling)
picker A python object that controls object picking
transform The transformation
visible A boolean whether the artist should be drawn
zorder A number which determines the drawing order
rasterized Boolean; Turns vectors into rastergraphics: (for compression & eps transparency)
Each of the properties is accessed with an old-fashioned setter or getter (yes we know this irritates Python-
istas and we plan to support direct access via properties or traits but it hasn’t been done yet). For example,
to multiply the current alpha by a half:
a = o.get_alpha()
o.set_alpha(0.5*a)

If you want to set a number of properties at once, you can also use the set method with keyword arguments.
For example:
o.set(alpha=0.5, zorder=2)

If you are working interactively at the python shell, a handy way to inspect the Artist properties is to use
the matplotlib.artist.getp() function (simply getp() in pylab), which lists the properties and their
values. This works for classes derived from Artist as well, e.g., Figure and Rectangle. Here are the
Figure rectangle properties mentioned above:
In [149]: matplotlib.artist.getp(fig.patch)
alpha = 1.0
animated = False
antialiased or aa = True
axes = None
clip_box = None
clip_on = False
clip_path = None
contains = None
edgecolor or ec = w
facecolor or fc = 0.75
figure = Figure(8.125x6.125)
fill = 1
hatch = None
height = 1
label =
linewidth or lw = 1.0
picker = None

58 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

transform = <Affine object at 0x134cca84>


verts = ((0, 0), (0, 1), (1, 1), (1, 0))
visible = True
width = 1
window_extent = <Bbox object at 0x134acbcc>
x = 0
y = 0
zorder = 1

The docstrings for all of the classes also contain the Artist properties, so you can consult the interactive
“help” or the artist Module for a listing of properties for a given object.

Object containers

Now that we know how to inspect and set the properties of a given object we want to configure, we need to
know how to get at that object. As mentioned in the introduction, there are two kinds of objects: primitives
and containers. The primitives are usually the things you want to configure (the font of a Text instance,
the width of a Line2D) although the containers also have some properties as well – for example the Axes
Artist is a container that contains many of the primitives in your plot, but it also has properties like the
xscale to control whether the xaxis is ‘linear’ or ‘log’. In this section we’ll review where the various
container objects store the Artists that you want to get at.

Figure container

The top level container Artist is the matplotlib.figure.Figure, and it contains everything in the
figure. The background of the figure is a Rectangle which is stored in Figure.patch. As you add
subplots (add_subplot()) and axes (add_axes()) to the figure these will be appended to the Figure.
axes. These are also returned by the methods that create them:

In [156]: fig = plt.figure()

In [157]: ax1 = fig.add_subplot(211)

In [158]: ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3])

In [159]: ax1
Out[159]: <matplotlib.axes.Subplot instance at 0xd54b26c>

In [160]: print fig.axes


[<matplotlib.axes.Subplot instance at 0xd54b26c>, <matplotlib.axes.Axes instance at␣
,→0xd3f0b2c>]

Because the figure maintains the concept of the “current axes” (see Figure.gca and Figure.sca) to
support the pylab/pyplot state machine, you should not insert or remove axes directly from the axes list, but
rather use the add_subplot() and add_axes() methods to insert, and the delaxes() method to delete.
You are free however, to iterate over the list of axes or index into it to get access to Axes instances you want
to customize. Here is an example which turns all the axes grids on:

3.2. Intermediate 59
Matplotlib, Release 2.0.2

for ax in fig.axes:
ax.grid(True)

The figure also has its own text, lines, patches and images, which you can use to add primitives directly. The
default coordinate system for the Figure will simply be in pixels (which is not usually what you want) but
you can control this by setting the transform property of the Artist you are adding to the figure.
More useful is “figure coordinates” where (0, 0) is the bottom-left of the figure and (1, 1) is the top-right of
the figure which you can obtain by setting the Artist transform to fig.transFigure:

In [191]: fig = plt.figure()

In [192]: l1 = matplotlib.lines.Line2D([0, 1], [0, 1],


transform=fig.transFigure, figure=fig)

In [193]: l2 = matplotlib.lines.Line2D([0, 1], [1, 0],


transform=fig.transFigure, figure=fig)

In [194]: fig.lines.extend([l1, l2])

In [195]: fig.canvas.draw()

Here is a summary of the Artists the figure contains

60 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Figure attribute Description


axes A list of Axes instances (includes Subplot)
patch The Rectangle background
images A list of FigureImages patches - useful for raw pixel display
legends A list of Figure Legend instances (different from Axes.legends)
lines A list of Figure Line2D instances (rarely used, see Axes.lines)
patches A list of Figure patches (rarely used, see Axes.patches)
texts A list Figure Text instances

Axes container

The matplotlib.axes.Axes is the center of the matplotlib universe – it contains the vast majority of all
the Artists used in a figure with many helper methods to create and add these Artists to itself, as well
as helper methods to access and customize the Artists it contains. Like the Figure, it contains a Patch
patch which is a Rectangle for Cartesian coordinates and a Circle for polar coordinates; this patch
determines the shape, background and border of the plotting region:

ax = fig.add_subplot(111)
rect = ax.patch # a Rectangle instance
rect.set_facecolor('green')

When you call a plotting method, e.g., the canonical plot() and pass in arrays or lists of values, the method
will create a matplotlib.lines.Line2D() instance, update the line with all the Line2D properties passed
as keyword arguments, add the line to the Axes.lines container, and returns it to you:

In [213]: x, y = np.random.rand(2, 100)

In [214]: line, = ax.plot(x, y, '-', color='blue', linewidth=2)

plot returns a list of lines because you can pass in multiple x, y pairs to plot, and we are unpacking the first
element of the length one list into the line variable. The line has been added to the Axes.lines list:

In [229]: print ax.lines


[<matplotlib.lines.Line2D instance at 0xd378b0c>]

Similarly, methods that create patches, like bar() creates a list of rectangles, will add the patches to the
Axes.patches list:

In [233]: n, bins, rectangles = ax.hist(np.random.randn(1000), 50, facecolor='yellow')

In [234]: rectangles
Out[234]: <a list of 50 Patch objects>

In [235]: print len(ax.patches)

You should not add objects directly to the Axes.lines or Axes.patches lists unless you know exactly
what you are doing, because the Axes needs to do a few things when it creates and adds an object. It sets the
figure and axes property of the Artist, as well as the default Axes transformation (unless a transformation is
set). It also inspects the data contained in the Artist to update the data structures controlling auto-scaling,

3.2. Intermediate 61
Matplotlib, Release 2.0.2

so that the view limits can be adjusted to contain the plotted data. You can, nonetheless, create objects
yourself and add them directly to the Axes using helper methods like add_line() and add_patch().
Here is an annotated interactive session illustrating what is going on:

In [261]: fig = plt.figure()

In [262]: ax = fig.add_subplot(111)

# create a rectangle instance


In [263]: rect = matplotlib.patches.Rectangle( (1,1), width=5, height=12)

# by default the axes instance is None


In [264]: print rect.get_axes()
None

# and the transformation instance is set to the "identity transform"


In [265]: print rect.get_transform()
<Affine object at 0x13695544>

# now we add the Rectangle to the Axes


In [266]: ax.add_patch(rect)

# and notice that the ax.add_patch method has set the axes
# instance
In [267]: print rect.get_axes()
Axes(0.125,0.1;0.775x0.8)

# and the transformation has been set too


In [268]: print rect.get_transform()
<Affine object at 0x15009ca4>

# the default axes transformation is ax.transData


In [269]: print ax.transData
<Affine object at 0x15009ca4>

# notice that the xlimits of the Axes have not been changed
In [270]: print ax.get_xlim()
(0.0, 1.0)

# but the data limits have been updated to encompass the rectangle
In [271]: print ax.dataLim.bounds
(1.0, 1.0, 5.0, 12.0)

# we can manually invoke the auto-scaling machinery


In [272]: ax.autoscale_view()

# and now the xlim are updated to encompass the rectangle


In [273]: print ax.get_xlim()
(1.0, 6.0)

# we have to manually force a figure draw


In [274]: ax.figure.canvas.draw()

62 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

There are many, many Axes helper methods for creating primitive Artists and adding them to their respec-
tive containers. The table below summarizes a small sampling of them, the kinds of Artist they create,
and where they store them
Helper method Artist Container
ax.annotate - text annotations Annotate ax.texts
ax.bar - bar charts Rectangle ax.patches
ax.errorbar - error bar plots Line2D and Rectangle ax.lines and ax.patches
ax.fill - shared area Polygon ax.patches
ax.hist - histograms Rectangle ax.patches
ax.imshow - image data AxesImage ax.images
ax.legend - axes legends Legend ax.legends
ax.plot - xy plots Line2D ax.lines
ax.scatter - scatter charts PolygonCollection ax.collections
ax.text - text Text ax.texts
In addition to all of these Artists, the Axes contains two important Artist containers: the XAxis and
YAxis, which handle the drawing of the ticks and labels. These are stored as instance variables xaxis and
yaxis. The XAxis and YAxis containers will be detailed below, but note that the Axes contains many
helper methods which forward calls on to the Axis instances so you often do not need to work with them
directly unless you want to. For example, you can set the font color of the XAxis ticklabels using the Axes
helper method:

for label in ax.get_xticklabels():


label.set_color('orange')

Below is a summary of the Artists that the Axes contains


Axes attribute Description
artists A list of Artist instances
patch Rectangle instance for Axes background
collections A list of Collection instances
images A list of AxesImage
legends A list of Legend instances
lines A list of Line2D instances
patches A list of Patch instances
texts A list of Text instances
xaxis matplotlib.axis.XAxis instance
yaxis matplotlib.axis.YAxis instance

Axis containers

The matplotlib.axis.Axis instances handle the drawing of the tick lines, the grid lines, the tick labels
and the axis label. You can configure the left and right ticks separately for the y-axis, and the upper and
lower ticks separately for the x-axis. The Axis also stores the data and view intervals used in auto-scaling,
panning and zooming, as well as the Locator and Formatter instances which control where the ticks are
placed and how they are represented as strings.
Each Axis object contains a label attribute (this is what pylab modifies in calls to xlabel() and

3.2. Intermediate 63
Matplotlib, Release 2.0.2

ylabel()) as well as a list of major and minor ticks. The ticks are XTick and YTick instances, which
contain the actual line and text primitives that render the ticks and ticklabels. Because the ticks are dynam-
ically created as needed (e.g., when panning and zooming), you should access the lists of major and minor
ticks through their accessor methods get_major_ticks() and get_minor_ticks(). Although the ticks
contain all the primitives and will be covered below, Axis instances have accessor methods that return the
tick lines, tick labels, tick locations etc.:

In [285]: axis = ax.xaxis

In [286]: axis.get_ticklocs()
Out[286]: array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])

In [287]: axis.get_ticklabels()
Out[287]: <a list of 10 Text major ticklabel objects>

# note there are twice as many ticklines as labels because by


# default there are tick lines at the top and bottom but only tick
# labels below the xaxis; this can be customized
In [288]: axis.get_ticklines()
Out[288]: <a list of 20 Line2D ticklines objects>

# by default you get the major ticks back


In [291]: axis.get_ticklines()
Out[291]: <a list of 20 Line2D ticklines objects>

# but you can also ask for the minor ticks


In [292]: axis.get_ticklines(minor=True)
Out[292]: <a list of 0 Line2D ticklines objects>

Here is a summary of some of the useful accessor methods of the Axis (these have corresponding setters
where useful, such as set_major_formatter)
Accessor method Description
get_scale The scale of the axis, e.g., ‘log’ or ‘linear’
get_view_interval The interval instance of the axis view limits
get_data_interval The interval instance of the axis data limits
get_gridlines A list of grid lines for the Axis
get_label The axis label - a Text instance
get_ticklabels A list of Text instances - keyword minor=True|False
get_ticklines A list of Line2D instances - keyword minor=True|False
get_ticklocs A list of Tick locations - keyword minor=True|False
get_major_locator The matplotlib.ticker.Locator instance for major ticks
get_major_formatter The matplotlib.ticker.Formatter instance for major ticks
get_minor_locator The matplotlib.ticker.Locator instance for minor ticks
get_minor_formatter The matplotlib.ticker.Formatter instance for minor ticks
get_major_ticks A list of Tick instances for major ticks
get_minor_ticks A list of Tick instances for minor ticks
grid Turn the grid on or off for the major or minor ticks
Here is an example, not recommended for its beauty, which customizes the axes and tick properties

64 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

import numpy as np
import matplotlib.pyplot as plt

# plt.figure creates a matplotlib.figure.Figure instance


fig = plt.figure()
rect = fig.patch # a rectangle instance
rect.set_facecolor('lightgoldenrodyellow')

ax1 = fig.add_axes([0.1, 0.3, 0.4, 0.4])


rect = ax1.patch
rect.set_facecolor('lightslategray')

for label in ax1.xaxis.get_ticklabels():


# label is a Text instance
label.set_color('red')
label.set_rotation(45)
label.set_fontsize(16)

for line in ax1.yaxis.get_ticklines():


# line is a Line2D instance
line.set_color('green')
line.set_markersize(25)
line.set_markeredgewidth(3)

plt.show()

3.2. Intermediate 65
Matplotlib, Release 2.0.2

1.0
0.8
0.6
0.4
0.2
0.0
0.0
0.2
0.4
0.6
0.8
1.0

Tick containers

The matplotlib.axis.Tick is the final container object in our descent from the Figure to the Axes to
the Axis to the Tick. The Tick contains the tick and grid line instances, as well as the label instances for
the upper and lower ticks. Each of these is accessible directly as an attribute of the Tick. In addition, there
are boolean variables that determine whether the upper labels and ticks are on for the x-axis and whether the
right labels and ticks are on for the y-axis.
Tick attribute Description
tick1line Line2D instance
tick2line Line2D instance
gridline Line2D instance
label1 Text instance
label2 Text instance
gridOn boolean which determines whether to draw the gridline
tick1On boolean which determines whether to draw the 1st tickline
tick2On boolean which determines whether to draw the 2nd tickline
label1On boolean which determines whether to draw the 1st tick label
label2On boolean which determines whether to draw the 2nd tick label
Here is an example which sets the formatter for the right side ticks with dollar signs and colors them green
on the right side of the yaxis

66 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

# Fixing random state for reproducibility


np.random.seed(19680801)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(100*np.random.rand(20))

formatter = ticker.FormatStrFormatter('$%1.2f ')


ax.yaxis.set_major_formatter(formatter)

for tick in ax.yaxis.get_major_ticks():


tick.label1On = False
tick.label2On = True
tick.label2.set_color('green')

plt.show()

$100.00

$80.00

$60.00

$40.00

$20.00

0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5

3.2. Intermediate 67
Matplotlib, Release 2.0.2

3.2.2 Legend guide

This legend guide is an extension of the documentation available at legend() - please ensure you are
familiar with contents of that documentation before proceeding with this guide.
This guide makes use of some common terms, which are documented here for clarity:
legend entry A legend is made up of one or more legend entries. An entry is made up of exactly one key
and one label.
legend key The colored/patterned marker to the left of each legend label.
legend label The text which describes the handle represented by the key.
legend handle The original object which is used to generate an appropriate entry in the legend.

Controlling the legend entries

Calling legend() with no arguments automatically fetches the legend handles and their associated labels.
This functionality is equivalent to:

handles, labels = ax.get_legend_handles_labels()


ax.legend(handles, labels)

The get_legend_handles_labels() function returns a list of handles/artists which exist on the Axes
which can be used to generate entries for the resulting legend - it is worth noting however that not all artists
can be added to a legend, at which point a “proxy” will have to be created (see Creating artists specifically
for adding to the legend (aka. Proxy artists) for further details).
For full control of what is being added to the legend, it is common to pass the appropriate handles directly
to legend():

line_up, = plt.plot([1,2,3], label='Line 2')


line_down, = plt.plot([3,2,1], label='Line 1')
plt.legend(handles=[line_up, line_down])

In some cases, it is not possible to set the label of the handle, so it is possible to pass through the list of
labels to legend():

line_up, = plt.plot([1,2,3], label='Line 2')


line_down, = plt.plot([3,2,1], label='Line 1')
plt.legend([line_up, line_down], ['Line Up', 'Line Down'])

Creating artists specifically for adding to the legend (aka. Proxy artists)

Not all handles can be turned into legend entries automatically, so it is often necessary to create an artist
which can. Legend handles don’t have to exists on the Figure or Axes in order to be used.
Suppose we wanted to create a legend which has an entry for some data which is represented by a red color:

68 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

import matplotlib.patches as mpatches


import matplotlib.pyplot as plt

red_patch = mpatches.Patch(color='red', label='The red data')


plt.legend(handles=[red_patch])

plt.show()

1.0
The red data

0.8

0.6

0.4

0.2

0.0
0.0 0.2 0.4 0.6 0.8 1.0

There are many supported legend handles, instead of creating a patch of color we could have created a line
with a marker:

import matplotlib.lines as mlines


import matplotlib.pyplot as plt

blue_line = mlines.Line2D([], [], color='blue', marker='*',


markersize=15, label='Blue stars')
plt.legend(handles=[blue_line])

plt.show()

3.2. Intermediate 69
Matplotlib, Release 2.0.2

1.0
Blue stars

0.8

0.6

0.4

0.2

0.0
0.0 0.2 0.4 0.6 0.8 1.0

Legend location

The location of the legend can be specified by the keyword argument loc. Please see the documentation at
legend() for more details.
The bbox_to_anchor keyword gives a great degree of control for manual legend placement. For example,
if you want your axes legend located at the figure’s top right-hand corner instead of the axes’ corner, simply
specify the corner’s location, and the coordinate system of that location:

plt.legend(bbox_to_anchor=(1, 1),
bbox_transform=plt.gcf().transFigure)

More examples of custom legend placement:

import matplotlib.pyplot as plt

plt.subplot(211)
plt.plot([1,2,3], label="test1")
plt.plot([3,2,1], label="test2")
# Place a legend above this subplot, expanding itself to
# fully use the given bounding box.
plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
ncol=2, mode="expand", borderaxespad=0.)

70 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

plt.subplot(223)
plt.plot([1,2,3], label="test1")
plt.plot([3,2,1], label="test2")
# Place a legend to the right of this smaller subplot.
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)

plt.show()

test1 test2
3.0
2.5
2.0
1.5
1.0
0.00 0.25 0.50 0.75 1.00 1.25 1.50 1.75 2.00
3.0 test1
test2
2.5
2.0
1.5
1.0
0 1 2

Multiple legends on the same Axes

Sometimes it is more clear to split legend entries across multiple legends. Whilst the instinctive approach
to doing this might be to call the legend() function multiple times, you will find that only one legend ever
exists on the Axes. This has been done so that it is possible to call legend() repeatedly to update the legend
to the latest handles on the Axes, so to persist old legend instances, we must add them manually to the Axes:

import matplotlib.pyplot as plt

line1, = plt.plot([1,2,3], label="Line 1", linestyle='--')


line2, = plt.plot([3,2,1], label="Line 2", linewidth=4)

# Create a legend for the first line.


first_legend = plt.legend(handles=[line1], loc=1)

3.2. Intermediate 71
Matplotlib, Release 2.0.2

# Add the legend manually to the current Axes.


ax = plt.gca().add_artist(first_legend)

# Create another legend for the second line.


plt.legend(handles=[line2], loc=4)

plt.show()

3.00 Line 1
2.75
2.50
2.25
2.00
1.75
1.50
1.25
1.00 Line 2
0.00 0.25 0.50 0.75 1.00 1.25 1.50 1.75 2.00

Legend Handlers

In order to create legend entries, handles are given as an argument to an appropriate HandlerBase subclass.
The choice of handler subclass is determined by the following rules:
1. Update get_legend_handler_map() with the value in the handler_map keyword.
2. Check if the handle is in the newly created handler_map.
3. Check if the type of handle is in the newly created handler_map.
4. Check if any of the types in the handle‘s mro is in the newly created handler_map.
For completeness, this logic is mostly implemented in get_legend_handler().

72 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

All of this flexibility means that we have the necessary hooks to implement custom handlers for our own
type of legend key.
The simplest example of using custom handlers is to instantiate one of the existing HandlerBase subclasses.
For the sake of simplicity, let’s choose matplotlib.legend_handler.HandlerLine2D which accepts a
numpoints argument (note numpoints is a keyword on the legend() function for convenience). We can
then pass the mapping of instance to Handler as a keyword to legend.

import matplotlib.pyplot as plt


from matplotlib.legend_handler import HandlerLine2D

line1, = plt.plot([3,2,1], marker='o', label='Line 1')


line2, = plt.plot([1,2,3], marker='o', label='Line 2')

plt.legend(handler_map={line1: HandlerLine2D(numpoints=4)})

3.00
2.75
2.50
2.25
Line 1
2.00 Line 2
1.75
1.50
1.25
1.00
0.00 0.25 0.50 0.75 1.00 1.25 1.50 1.75 2.00

As you can see, “Line 1” now has 4 marker points, where “Line 2” has 2 (the default). Try the above code,
only change the map’s key from line1 to type(line1). Notice how now both Line2D instances get 4
markers.
Along with handlers for complex plot types such as errorbars, stem plots and histograms, the default
handler_map has a special tuple handler (HandlerTuple) which simply plots the handles on top of
one another for each item in the given tuple. The following example demonstrates combining two legend
keys on top of one another:

3.2. Intermediate 73
Matplotlib, Release 2.0.2

import matplotlib.pyplot as plt


from numpy.random import randn

z = randn(10)

red_dot, = plt.plot(z, "ro", markersize=15)


# Put a white cross over some of the data.
white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3, markersize=15)

plt.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"])

2.0
Attr A
1.5 Attr A+B

1.0
0.5
0.0
0.5
1.0
1.5

0 2 4 6 8

Implementing a custom legend handler

A custom handler can be implemented to turn any handle into a legend key (handles don’t necessarily need
to be matplotlib artists). The handler must implement a “legend_artist” method which returns a single artist
for the legend to use. Signature details about the “legend_artist” are documented at legend_artist().

import matplotlib.pyplot as plt


import matplotlib.patches as mpatches

class AnyObject(object):
pass

74 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

class AnyObjectHandler(object):
def legend_artist(self, legend, orig_handle, fontsize, handlebox):
x0, y0 = handlebox.xdescent, handlebox.ydescent
width, height = handlebox.width, handlebox.height
patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red',
edgecolor='black', hatch='xx', lw=3,
transform=handlebox.get_transform())
handlebox.add_artist(patch)
return patch

plt.legend([AnyObject()], ['My first handler'],


handler_map={AnyObject: AnyObjectHandler()})

1.0
My first handler

0.8

0.6

0.4

0.2

0.0
0.0 0.2 0.4 0.6 0.8 1.0

Alternatively, had we wanted to globally accept AnyObject instances without needing to manually set the
handler_map keyword all the time, we could have registered the new handler with:
from matplotlib.legend import Legend
Legend.update_default_handler_map({AnyObject: AnyObjectHandler()})

Whilst the power here is clear, remember that there are already many handlers implemented and what you
want to achieve may already be easily possible with existing classes. For example, to produce elliptical
legend keys, rather than rectangular ones:
from matplotlib.legend_handler import HandlerPatch
import matplotlib.pyplot as plt

3.2. Intermediate 75
Matplotlib, Release 2.0.2

import matplotlib.patches as mpatches

class HandlerEllipse(HandlerPatch):
def create_artists(self, legend, orig_handle,
xdescent, ydescent, width, height, fontsize, trans):
center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent
p = mpatches.Ellipse(xy=center, width=width + xdescent,
height=height + ydescent)
self.update_prop(p, orig_handle, legend)
p.set_transform(trans)
return [p]

c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green",


edgecolor="red", linewidth=3)
plt.gca().add_patch(c)

plt.legend([c], ["An ellipse, not a rectangle"],


handler_map={mpatches.Circle: HandlerEllipse()})

1.0
An ellipse, not a rectangle

0.8

0.6

0.4

0.2

0.0
0.0 0.2 0.4 0.6 0.8 1.0

Known examples of using legend

Here is a non-exhaustive list of the examples available involving legend being used in various ways:

76 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

• lines_bars_and_markers example code: scatter_with_legend.py


• api example code: legend_demo.py
• pylab_examples example code: contourf_hatching.py
• pylab_examples example code: figlegend_demo.py
• pylab_examples example code: scatter_symbol.py

3.3 Advanced

3.3.1 Transformations Tutorial

Like any graphics packages, matplotlib is built on top of a transformation framework to easily move be-
tween coordinate systems, the userland data coordinate system, the axes coordinate system, the figure
coordinate system, and the display coordinate system. In 95% of your plotting, you won’t need to think
about this, as it happens under the hood, but as you push the limits of custom figure generation, it helps
to have an understanding of these objects so you can reuse the existing transformations matplotlib makes
available to you, or create your own (see matplotlib.transforms). The table below summarizes the ex-
isting coordinate systems, the transformation object you should use to work in that coordinate system, and
the description of that system. In the Transformation Object column, ax is a Axes instance, and fig is
a Figure instance.
Co- Transfor- Description
ordi- mation
nate Object
data ax. The userland data coordinate system, controlled by the xlim and ylim
transData
axes ax. The coordinate system of the Axes; (0,0) is bottom left of the axes, and (1,1) is
transAxes top right of the axes.
figure fig. The coordinate system of the Figure; (0,0) is bottom left of the figure, and (1,1)
transFigureis top right of the figure.
displayNone This is the pixel coordinate system of the display; (0,0) is the bottom left of the
display, and (width, height) is the top right of the display in pixels. Alternatively,
the identity transform (matplotlib.transforms.IdentityTransform())
may be used instead of None.
All of the transformation objects in the table above take inputs in their coordinate system, and transform
the input to the display coordinate system. That is why the display coordinate system has None for the
Transformation Object column – it already is in display coordinates. The transformations also know
how to invert themselves, to go from display back to the native coordinate system. This is particularly
useful when processing events from the user interface, which typically occur in display space, and you want
to know where the mouse click or key-press occurred in your data coordinate system.

3.3. Advanced 77
Matplotlib, Release 2.0.2

Data coordinates

Let’s start with the most commonly used coordinate, the data coordinate system. Whenever you add data to
the axes, matplotlib updates the datalimits, most commonly updated with the set_xlim() and set_ylim()
methods. For example, in the figure below, the data limits stretch from 0 to 10 on the x-axis, and -1 to 1 on
the y-axis.

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0, 10, 0.005)


y = np.exp(-x/2.) * np.sin(2*np.pi*x)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y)
ax.set_xlim(0, 10)
ax.set_ylim(-1, 1)

plt.show()

1.00
0.75
0.50
0.25
0.00
0.25
0.50
0.75
1.00
0 2 4 6 8 10

You can use the ax.transData instance to transform from your data to your display coordinate system,
either a single point or a sequence of points as shown below:

78 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

In [14]: type(ax.transData)
Out[14]: <class 'matplotlib.transforms.CompositeGenericTransform'>

In [15]: ax.transData.transform((5, 0))


Out[15]: array([ 335.175, 247. ])

In [16]: ax.transData.transform([(5, 0), (1,2)])


Out[16]:
array([[ 335.175, 247. ],
[ 132.435, 642.2 ]])

You can use the inverted() method to create a transform which will take you from display to data coordi-
nates:

In [41]: inv = ax.transData.inverted()

In [42]: type(inv)
Out[42]: <class 'matplotlib.transforms.CompositeGenericTransform'>

In [43]: inv.transform((335.175, 247.))


Out[43]: array([ 5., 0.])

If your are typing along with this tutorial, the exact values of the display coordinates may differ if you have
a different window size or dpi setting. Likewise, in the figure below, the display labeled points are probably
not the same as in the ipython session because the documentation figure size defaults are different.

1.00
0.75
data = (5.0, 0.0)
0.50
0.25
0.00 display = (281.9, 222.8)
0.25
0.50
0.75
1.00
0 2 4 6 8 10

3.3. Advanced 79
Matplotlib, Release 2.0.2

Note: If you run the source code in the example above in a GUI backend, you may also find that the two
arrows for the data and display annotations do not point to exactly the same point. This is because the
display point was computed before the figure was displayed, and the GUI backend may slightly resize the
figure when it is created. The effect is more pronounced if you resize the figure yourself. This is one good
reason why you rarely want to work in display space, but you can connect to the 'on_draw' Event to
update figure coordinates on figure draws; see Event handling and picking.

When you change the x or y limits of your axes, the data limits are updated so the transformation yields a
new display point. Note that when we just change the ylim, only the y-display coordinate is altered, and
when we change the xlim too, both are altered. More on this later when we talk about the Bbox.

In [54]: ax.transData.transform((5, 0))


Out[54]: array([ 335.175, 247. ])

In [55]: ax.set_ylim(-1,2)
Out[55]: (-1, 2)

In [56]: ax.transData.transform((5, 0))


Out[56]: array([ 335.175 , 181.13333333])

In [57]: ax.set_xlim(10,20)
Out[57]: (10, 20)

In [58]: ax.transData.transform((5, 0))


Out[58]: array([-171.675 , 181.13333333])

Axes coordinates

After the data coordinate system, axes is probably the second most useful coordinate system. Here the
point (0,0) is the bottom left of your axes or subplot, (0.5, 0.5) is the center, and (1.0, 1.0) is the top right.
You can also refer to points outside the range, so (-0.1, 1.1) is to the left and above your axes. This coordinate
system is extremely useful when placing text in your axes, because you often want a text bubble in a fixed,
location, e.g., the upper left of the axes pane, and have that location remain fixed when you pan or zoom.
Here is a simple example that creates four panels and labels them ‘A’, ‘B’, ‘C’, ‘D’ as you often see in
journals.

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
for i, label in enumerate(('A', 'B', 'C', 'D')):
ax = fig.add_subplot(2,2,i+1)
ax.text(0.05, 0.95, label, transform=ax.transAxes,
fontsize=16, fontweight='bold', va='top')

plt.show()

80 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

1.0 1.0
0.8
A 0.8
B
0.6 0.6
0.4 0.4
0.2 0.2
0.0 0.0
0.00 0.25 0.50 0.75 1.00 0.00 0.25 0.50 0.75 1.00
1.0 1.0
0.8
C 0.8
D
0.6 0.6
0.4 0.4
0.2 0.2
0.0 0.0
0.00 0.25 0.50 0.75 1.00 0.00 0.25 0.50 0.75 1.00

You can also make lines or patches in the axes coordinate system, but this is less useful in my experience
than using ax.transAxes for placing text. Nonetheless, here is a silly example which plots some random
dots in data space, and overlays a semi-transparent Circle centered in the middle of the axes with a radius
one quarter of the axes – if your axes does not preserve aspect ratio (see set_aspect()), this will look like
an ellipse. Use the pan/zoom tool to move around, or manually change the data xlim and ylim, and you
will see the data move, but the circle will remain fixed because it is not in data coordinates and will always
remain at the center of the axes.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig = plt.figure()
ax = fig.add_subplot(111)
x, y = 10*np.random.rand(2, 1000)
ax.plot(x, y, 'go') # plot some data in data coordinates

circ = patches.Circle((0.5, 0.5), 0.25, transform=ax.transAxes,


facecolor='yellow', alpha=0.5)
ax.add_patch(circ)

plt.show()

3.3. Advanced 81
Matplotlib, Release 2.0.2

10

0
0 2 4 6 8 10

Blended transformations

Drawing in blended coordinate spaces which mix axes with data coordinates is extremely useful, for
example to create a horizontal span which highlights some region of the y-data but spans across the x-axis
regardless of the data limits, pan or zoom level, etc. In fact these blended lines and spans are so useful, we
have built in functions to make them easy to plot (see axhline(), axvline(), axhspan(), axvspan())
but for didactic purposes we will implement the horizontal span here using a blended transformation. This
trick only works for separable transformations, like you see in normal Cartesian coordinate systems, but not
on inseparable transformations like the PolarTransform.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.transforms as transforms

fig = plt.figure()
ax = fig.add_subplot(111)

x = np.random.randn(1000)

ax.hist(x, 30)
ax.set_title(r'$\sigma=1 \/ \dots \/ \sigma=2$', fontsize=16)

# the x coords of this transformation are data, and the

82 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

# y coord are axes


trans = transforms.blended_transform_factory(
ax.transData, ax.transAxes)

# highlight the 1..2 stddev region with a span.


# We want x to be in data coordinates and y to
# span from 0..1 in axes coords
rect = patches.Rectangle((1,0), width=1, height=1,
transform=trans, color='yellow',
alpha=0.5)

ax.add_patch(rect)

plt.show()

=1 =2
100

80

60

40

20

0
3 2 1 0 1 2 3 4

Note: The blended transformations where x is in data coords and y in axes coordinates is so useful
that we have helper methods to return the versions mpl uses internally for drawing ticks, ticklabels, etc.
The methods are matplotlib.axes.Axes.get_xaxis_transform() and matplotlib.axes.Axes.
get_yaxis_transform(). So in the example above, the call to blended_transform_factory() can
be replaced by get_xaxis_transform:

trans = ax.get_xaxis_transform()

3.3. Advanced 83
Matplotlib, Release 2.0.2

Using offset transforms to create a shadow effect

One use of transformations is to create a new transformation that is offset from another transformation, e.g.,
to place one object shifted a bit relative to another object. Typically you want the shift to be in some physical
dimension, like points or inches rather than in data coordinates, so that the shift effect is constant at different
zoom levels and dpi settings.
One use for an offset is to create a shadow effect, where you draw one object identical to the first just to the
right of it, and just below it, adjusting the zorder to make sure the shadow is drawn first and then the object
it is shadowing above it. The transforms module has a helper transformation ScaledTranslation. It is
instantiated with:
trans = ScaledTranslation(xt, yt, scale_trans)

where xt and yt are the translation offsets, and scale_trans is a transformation which scales xt and
yt at transformation time before applying the offsets. A typical use case is to use the figure fig.
dpi_scale_trans transformation for the scale_trans argument, to first scale xt and yt specified in
points to display space before doing the final offset. The dpi and inches offset is a common-enough use
case that we have a special helper function to create it in matplotlib.transforms.offset_copy(),
which returns a new transform with an added offset. But in the example below, we’ll create the offset
transform ourselves. Note the use of the plus operator in:
offset = transforms.ScaledTranslation(dx, dy,
fig.dpi_scale_trans)
shadow_transform = ax.transData + offset

showing that can chain transformations using the addition operator. This code says: first apply the data
transformation ax.transData and then translate the data by dx and dy points. In typography, a‘point
<https://en.wikipedia.org/wiki/Point_%28typography%29>‘_ is 1/72 inches, and by specifying your offsets
in points, your figure will look the same regardless of the dpi resolution it is saved in.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.transforms as transforms

fig = plt.figure()
ax = fig.add_subplot(111)

# make a simple sine wave


x = np.arange(0., 2., 0.01)
y = np.sin(2*np.pi*x)
line, = ax.plot(x, y, lw=3, color='blue')

# shift the object over 2 points, and down 2 points


dx, dy = 2/72., -2/72.
offset = transforms.ScaledTranslation(dx, dy,
fig.dpi_scale_trans)
shadow_transform = ax.transData + offset

# now plot the same data with our offset transform;


# use the zorder to make sure we are below the line

84 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

ax.plot(x, y, lw=3, color='gray',


transform=shadow_transform,
zorder=0.5*line.get_zorder())

ax.set_title('creating a shadow effect with an offset transform')


plt.show()

creating a shadow effect with an offset transform


1.00
0.75
0.50
0.25
0.00
0.25
0.50
0.75
1.00
0.00 0.25 0.50 0.75 1.00 1.25 1.50 1.75 2.00

The transformation pipeline

The ax.transData transform we have been working with in this tutorial is a composite of three different
transformations that comprise the transformation pipeline from data -> display coordinates. Michael
Droettboom implemented the transformations framework, taking care to provide a clean API that segre-
gated the nonlinear projections and scales that happen in polar and logarithmic plots, from the linear affine
transformations that happen when you pan and zoom. There is an efficiency here, because you can pan and
zoom in your axes which affects the affine transformation, but you may not need to compute the potentially
expensive nonlinear scales or projections on simple navigation events. It is also possible to multiply affine
transformation matrices together, and then apply them to coordinates in one step. This is not true of all
possible transformations.
Here is how the ax.transData instance is defined in the basic separable axis Axes class:

self.transData = self.transScale + (self.transLimits + self.transAxes)

3.3. Advanced 85
Matplotlib, Release 2.0.2

We’ve been introduced to the transAxes instance above in Axes coordinates, which maps the (0,0), (1,1)
corners of the axes or subplot bounding box to display space, so let’s look at these other two pieces.
self.transLimits is the transformation that takes you from data to axes coordinates; i.e., it maps your
view xlim and ylim to the unit space of the axes (and transAxes then takes that unit space to display space).
We can see this in action here

In [80]: ax = subplot(111)

In [81]: ax.set_xlim(0, 10)


Out[81]: (0, 10)

In [82]: ax.set_ylim(-1,1)
Out[82]: (-1, 1)

In [84]: ax.transLimits.transform((0,-1))
Out[84]: array([ 0., 0.])

In [85]: ax.transLimits.transform((10,-1))
Out[85]: array([ 1., 0.])

In [86]: ax.transLimits.transform((10,1))
Out[86]: array([ 1., 1.])

In [87]: ax.transLimits.transform((5,0))
Out[87]: array([ 0.5, 0.5])

and we can use this same inverted transformation to go from the unit axes coordinates back to data coor-
dinates.

In [90]: inv.transform((0.25, 0.25))


Out[90]: array([ 2.5, -0.5])

The final piece is the self.transScale attribute, which is responsible for the optional non-linear scaling
of the data, e.g., for logarithmic axes. When an Axes is initially setup, this is just set to the identity trans-
form, since the basic matplotlib axes has linear scale, but when you call a logarithmic scaling function like
semilogx() or explicitly set the scale to logarithmic with set_xscale(), then the ax.transScale at-
tribute is set to handle the nonlinear projection. The scales transforms are properties of the respective xaxis
and yaxis Axis instances. For example, when you call ax.set_xscale('log'), the xaxis updates its
scale to a matplotlib.scale.LogScale instance.
For non-separable axes the PolarAxes, there is one more piece to consider, the projection transformation.
The transData matplotlib.projections.polar.PolarAxes is similar to that for the typical separable
matplotlib Axes, with one additional piece transProjection:

self.transData = self.transScale + self.transProjection + \


(self.transProjectionAffine + self.transAxes)

transProjection handles the projection from the space, e.g., latitude and longitude for map data, or radius
and theta for polar data, to a separable Cartesian coordinate system. There are several projection examples
in the matplotlib.projections package, and the best way to learn more is to open the source for those
packages and see how to make your own, since matplotlib supports extensible axes and projections. Michael

86 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

Droettboom has provided a nice tutorial example of creating a hammer projection axes; see api example
code: custom_projection_example.py.

3.3.2 Path Tutorial

The object underlying all of the matplotlib.patch objects is the Path , which supports the standard set of
moveto, lineto, curveto commands to draw simple and compound outlines consisting of line segments and
splines. The Path is instantiated with a (N,2) array of (x,y) vertices, and a N-length array of path codes. For
example to draw the unit rectangle from (0,0) to (1,1), we could use this code

import matplotlib.pyplot as plt


from matplotlib.path import Path
import matplotlib.patches as patches

verts = [
(0., 0.), # left, bottom
(0., 1.), # left, top
(1., 1.), # right, top
(1., 0.), # right, bottom
(0., 0.), # ignored
]

codes = [Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
]

path = Path(verts, codes)

fig = plt.figure()
ax = fig.add_subplot(111)
patch = patches.PathPatch(path, facecolor='orange', lw=2)
ax.add_patch(patch)
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
plt.show()

3.3. Advanced 87
Matplotlib, Release 2.0.2

2.0
1.5
1.0
0.5
0.0
0.5
1.0
1.5
2.0
2.0 1.5 1.0 0.5 0.0 0.5 1.0 1.5 2.0

The following path codes are recognized


Code Vertices Description
STOP 1 (ignored) A marker for the end of the entire path (currently not required and
ignored)
MOVETO 1 Pick up the pen and move to the given vertex.
LINETO 1 Draw a line from the current position to the given vertex.
CURVE3 2 (1 control point, 1 Draw a quadratic Bézier curve from the current position, with the
endpoint) given control point, to the given end point.
CURVE4 3 (2 control points, Draw a cubic Bézier curve from the current position, with the given
1 endpoint) control points, to the given end point.
CLOSEPOLY1 (point itself is Draw a line segment to the start point of the current polyline.
ignored)

Bézier example

Some of the path components require multiple vertices to specify them: for example CURVE 3 is a bézier
curve with one control point and one end point, and CURVE4 has three vertices for the two control points
and the end point. The example below shows a CURVE4 Bézier spline – the bézier curve will be contained
in the convex hull of the start point, the two control points, and the end point

import matplotlib.pyplot as plt


from matplotlib.path import Path

88 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

import matplotlib.patches as patches

verts = [
(0., 0.), # P0
(0.2, 1.), # P1
(1., 0.8), # P2
(0.8, 0.), # P3
]

codes = [Path.MOVETO,
Path.CURVE4,
Path.CURVE4,
Path.CURVE4,
]

path = Path(verts, codes)

fig = plt.figure()
ax = fig.add_subplot(111)
patch = patches.PathPatch(path, facecolor='none', lw=2)
ax.add_patch(patch)

xs, ys = zip(*verts)
ax.plot(xs, ys, 'x--', lw=2, color='black', ms=10)

ax.text(-0.05, -0.05, 'P0')


ax.text(0.15, 1.05, 'P1')
ax.text(1.05, 0.85, 'P2')
ax.text(0.85, -0.05, 'P3')

ax.set_xlim(-0.1, 1.1)
ax.set_ylim(-0.1, 1.1)
plt.show()

3.3. Advanced 89
Matplotlib, Release 2.0.2

P1
1.0
P2
0.8

0.6

0.4

0.2

0.0 P0 P3
0.0 0.2 0.4 0.6 0.8 1.0

Compound paths

All of the simple patch primitives in matplotlib, Rectangle, Circle, Polygon, etc, are implemented with
simple path. Plotting functions like hist() and bar(), which create a number of primitives, e.g., a bunch
of Rectangles, can usually be implemented more efficiently using a compound path. The reason bar creates
a list of rectangles and not a compound path is largely historical: the Path code is comparatively new and
bar predates it. While we could change it now, it would break old code, so here we will cover how to create
compound paths, replacing the functionality in bar, in case you need to do so in your own code for efficiency
reasons, e.g., you are creating an animated bar plot.
We will make the histogram chart by creating a series of rectangles for each histogram bar: the rectangle
width is the bin width and the rectangle height is the number of datapoints in that bin. First we’ll create
some random normally distributed data and compute the histogram. Because numpy returns the bin edges
and not centers, the length of bins is 1 greater than the length of n in the example below:

# histogram our data with numpy


data = np.random.randn(1000)
n, bins = np.histogram(data, 100)

We’ll now extract the corners of the rectangles. Each of the left, bottom, etc, arrays below is len(n),
where n is the array of counts for each histogram bar:

90 Chapter 3. Tutorials
Matplotlib, Release 2.0.2

# get the corners of the rectangles for the histogram


left = np.array(bins[:-1])
right = np.array(bins[1:])
bottom = np.zeros(len(left))
top = bottom + n

Now we have to construct our compound path, which will consist of a series of MOVETO, LINETO and
CLOSEPOLY for each rectangle. For each rectangle, we need 5 vertices: 1 for the MOVETO, 3 for the LINETO,
and 1 for the CLOSEPOLY. As indicated in the table above, the vertex for the closepoly is ignored but we still
need it to keep the codes aligned with the vertices:

nverts = nrects*(1+3+1)
verts = np.zeros((nverts, 2))
codes = np.ones(nverts, int) * path.Path.LINETO
codes[0::5] = path.Path.MOVETO
codes[4::5] = path.Path.CLOSEPOLY
verts[0::5,0] = left
verts[0::5,1] = bottom
verts[1::5,0] = left
verts[1::5,1] = top
verts[2::5,0] = right
verts[2::5,1] = top
verts[3::5,0] = right
verts[3::5,1] = bottom

All that remains is to create the path, attach it to a PathPatch, and add it to our axes:

barpath = path.Path(verts, codes)


patch = patches.PathPatch(barpath, facecolor='green',
edgecolor='yellow', alpha=0.5)
ax.add_patch(patch)

Here is the result

3.3. Advanced 91
Matplotlib, Release 2.0.2

35

30

25

20

15

10

0
3 2 1 0 1 2 3 4

3.3.3 Path effects guide

Matplotlib’s patheffects module provides functionality to apply a multiple draw stage to any Artist which
can be rendered via a Path .
Artists which can have a path effect applied to them include Patch , Line2D, Collection and even Text.
Each artist’s path effects can be controlled via the set_path_effects method (set_path_effects),
which takes an iterable of AbstractPathEffect instances.
The simplest path effect is the Normal effect, which simply draws the artist without any effect:

import matplotlib.pyplot as plt


import matplotlib.patheffects as path_effects

fig = plt.figure(figsize=(5, 1.5))


text = fig.text(0.5, 0.5, 'Hello path effects world!\nThis is the normal '
'path effect.\nPretty dull, huh?',
ha='center', va='center', size=20)
text.set_path_effects([path_effects.Normal()])
plt.show()

92 Chapter 3. Tutorials

You might also like