In [1]:
# This line configures matplotlib to show figures embedded in the notebook,
# instead of opening a new window for each figure.
%matplotlib inline
Matplotlib is an excellent 2D and 3D graphics library for generating scientific figures. Some of the many advantages of this library include:
One of the key features of matplotlib that I would like to emphasize, and that I think makes matplotlib highly suitable for generating figures for scientific publications is that all aspects of the figure can be controlled programmatically. This is important for reproducibility and convenient when one needs to regenerate the figure with updated data or change its appearance.
More information at the Matplotlib web page: http://matplotlib.org/
In this notebook we will use the release 2.0 of matplotlib. Since, at the time of writing it is still a release candidate, the way of installing it with conda is the following:
conda install -c conda-forge/label/rc -c conda-forge matplotlib
To get started using Matplotlib in a Python program, we will import the pyplot interface. See more information at: http://matplotlib.org/api/pyplot_api.html
In [2]:
import matplotlib.pyplot as plt
In [3]:
import numpy as np
In [5]:
# Matplotlib logo
import matplotlib.cm as cm
ax = plt.axes([0.025,0.075,0.2,0.85], polar=True)
N = 7
arc = 2. * np.pi
theta = np.arange(0.0, arc, arc/N)
radii = 10 * np.array([0.2, 0.6, 0.8, 0.7, 0.4, 0.5, 0.8])
width = np.pi / 4 * np.array([0.4, 0.4, 0.6, 0.8, 0.2, 0.5, 0.3])
bars = ax.bar(theta, radii, width=width, bottom=0.0)
for r, bar in zip(radii, bars):
bar.set_facecolor(cm.jet(r/10.))
bar.set_alpha(0.6)
for label in ax.get_xticklabels() + ax.get_yticklabels():
label.set_visible(False)
for line in ax.get_ygridlines() + ax.get_xgridlines():
line.set_lw(0.8)
line.set_alpha(0.9)
line.set_ls('-')
line.set_color('0.5')
ax.set_yticks(np.arange(1, 9, 2))
ax.set_rmax(9)
You can choose to run matplotlib either interactively or non-interactively. For the interactive mode, the plot gets updated as you go along. For non-interactive, the plot doesn’t show up until you’ve finished everything. To switch between the two:
plt.ion() # Turn interactive mode on
plt.ioff() # Turn interactive mode off
plt.show() # Show the plot when interactive mode off
Let's start with the simplest way to do a plot.
In [6]:
x = np.arange(0,1,0.1)
y = x**2
plt.plot(x,y)
plt.show()
In [7]:
plt.plot(x,y,linewidth=3)
plt.show()
In [8]:
plt.plot(x,y,linewidth=3,linestyle='dashed')
plt.show()
In [9]:
plt.plot(x,y,linewidth=3,linestyle='dashed',color='green')
plt.show()
In [10]:
plt.plot(x,y,linewidth=3,linestyle='none',color='green',marker='*')
plt.show()
In [11]:
plt.plot(x,y,linewidth=3,linestyle='none',color='green',marker='$\\beta$',markersize=10)
plt.show()
In [12]:
yerr = np.ones(x.size)*0.1
plt.errorbar(x,y,yerr=yerr);
In [13]:
yerr = np.ones(x.size)*0.1
plt.errorbar(x,y,yerr=yerr,fmt='*')
plt.show()
In matplotlib, colors can be specified in three different ways:
basic colors can be quoted by their first letter: b(lue), r(ed), g(reen), y(ellow), w(hite), (blac)k
HTML colors, any defined HTML color is valid: 'deeppink', 'lemonchiffon' (see for instance: http://htmlcolorcodes.com/)
Hexadecimal code, any string of hex codes in the form of '#rrggbb' where each pair goes from 00 to ff
In [14]:
plt.errorbar(x,y,yerr=yerr,fmt='*',color='deeppink')
plt.show()
When drawing a figure it is useful to know some nomenclature. Not surprisingly, the ensamble is called a figure.
axis are the frame surrounding the actual plot.
title on the top, xlabel and ylabel are the labels on the axes.
The range of the two axes are xlim and ylim. The scale of the two axes can be linear or logarithmic. This is done with xscale and yscale.
To deal with the various figures and axes that there can be, you have the following housekeeping functions:
# Clearing Plots
plt.cla() # Clear Current Axis
plt.clf() # Clear Current Figure
# Getting active objects
ax1 = plt.gca() # Get Current Axis
fig1 = plt.gcf() # Get Current Figure
# Make new figure
plt.figure() # Make new figure (with defaults)
plt.figure(figsize=(6,8)) # Make new figure (6”x8”)
You can (at any time in the plotting) change the range ( lim), scale (log or linear), labels or ticks on a plot. Replace x with y (or vice versa) when necessary:
# Limits and Scale
plt.xlim([0, 5]) # Set x-limits to 0 -> 5
plt.yscale(‘log’) # Set y-axis to logarithmic
# Setting Labels
plt.xlabel(‘X-axis’) # Label the X-axis
plt.title(“Title”) # Set the Axis title
# Setting Ticks
plt.xticks([0, 4, 10, 19]) # Location of x-ticks
In [15]:
plt.errorbar(x,y,yerr=yerr,fmt='*',label='Test data')
plt.legend()
plt.show()
In [16]:
plt.errorbar(x,y,yerr=yerr,fmt='*',label='Test data')
plt.legend(frameon=False)
plt.show()
Saving a figure is a one-line operation. Matplotlib will figure out what format you want by the extension of the filename:
plt.savefig('filename.pdf') # Saving as a PDF
plt.savefig('filename.png') # Saving as a PNG
plt.savefig('filename.eps') # Saving as an EPS
# Can also determine what output DPI:
plt.savefig('filename.jpg', dpi=300)
Note that EPS files do not support transparency natively.
The main idea with object-oriented programming is to have objects that one can apply functions and actions on, and no object or program states should be global. The real advantage of this approach becomes apparent when more than one figure is created, or when a figure contains more than one subplot.
To use the object-oriented API we start out very much like in the previous example, but instead of creating a new global figure instance we store a reference to the newly created figure instance in the fig
variable, and from it we create a new axis instance axes
using the add_axes
method in the Figure
class instance fig
:
In [17]:
fig = plt.figure()
axes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # left, bottom, width, height (range 0 to 1)
axes.plot(x, y, 'r')
axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('title');
Once an object (axes) is defined, all the plotting functions are just methods on the axis.
Although a little bit more code is involved, the advantage is that we now have full control of where the plot axes are placed, and we can easily add more than one axis to the figure:
In [18]:
fig = plt.figure()
axes1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # main axes
axes2 = fig.add_axes([0.2, 0.5, 0.4, 0.3]) # inset axes
# main figure
axes1.plot(x, y, 'r')
axes1.set_xlabel('x')
axes1.set_ylabel('y')
axes1.set_title('title')
# insert
axes2.plot(y, x, 'g')
axes2.set_xlabel('y')
axes2.set_ylabel('x')
axes2.set_title('insert title');
If we don't care about being explicit about where our plot axes are placed in the figure canvas, then we can use one of the many axis layout managers in matplotlib. My favorite is subplots
, which can be used like this:
In [19]:
fig, axes = plt.subplots()
axes.plot(x, y, 'r')
axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('title');
In [20]:
fig, axes = plt.subplots(nrows=1, ncols=2)
for ax in axes:
ax.plot(x, y, 'r')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('title')
That was easy, but it isn't so pretty with overlapping figure axes and labels, right?
We can deal with that by using the fig.tight_layout
method, which automatically adjusts the positions of the axes on the figure canvas so that there is no overlapping content:
In [21]:
fig, axes = plt.subplots(nrows=1, ncols=2)
for ax in axes:
ax.plot(x, y, 'r')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('title')
fig.tight_layout()
Matplotlib allows the aspect ratio, DPI and figure size to be specified when the Figure
object is created, using the figsize
and dpi
keyword arguments. figsize
is a tuple of the width and height of the figure in inches, and dpi
is the dots-per-inch (pixel per inch). To create an 800x400 pixel, 100 dots-per-inch figure, we can do:
In [22]:
fig = plt.figure(figsize=(8,4), dpi=100)
The same arguments can also be passed to layout managers, such as the subplots
function:
In [23]:
fig, axes = plt.subplots(figsize=(12,3))
axes.plot(x, y, 'r')
axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('title');
To save a figure to a file we can use the savefig
method in the Figure
class:
In [24]:
fig.savefig("filename.png")
Here we can also optionally specify the DPI and choose between different output formats:
In [25]:
fig.savefig("filename.png", dpi=200)
Matplotlib can generate high-quality output in a number formats, including PNG, JPG, EPS, SVG, PGF and PDF. For scientific papers, I recommend using PDF whenever possible. (LaTeX documents compiled with pdflatex
can include PDFs using the includegraphics
command). In some cases, PGF can also be good alternative.
Now that we have covered the basics of how to create a figure canvas and add axes instances to the canvas, let's look at how decorate a figure with titles, axis labels, and legends.
Figure titles
A title can be added to each axis instance in a figure. To set the title, use the set_title
method in the axes instance:
In [26]:
axes.set_title("title");
Axis labels
Similarly, with the methods set_xlabel
and set_ylabel
, we can set the labels of the X and Y axes:
In [27]:
axes.set_xlabel("x")
axes.set_ylabel("y");
Legends
Legends for curves in a figure can be added in two ways. One method is to use the legend
method of the axis object and pass a list/tuple of legend texts for the previously defined curves:
In [28]:
axes.legend(["curve1", "curve2", "curve3"]);
The method described above follows the MATLAB API. It is somewhat prone to errors and unflexible if curves are added to or removed from the figure (resulting in a wrongly labelled curve).
A better method is to use the label="label text"
keyword argument when plots or other objects are added to the figure, and then using the legend
method without arguments to add the legend to the figure:
In [29]:
axes.plot(x, x**2, label="curve1")
axes.plot(x, x**3, label="curve2")
axes.legend();
The advantage with this method is that if curves are added or removed from the figure, the legend is automatically updated accordingly.
The legend
function takes an optional keyword argument loc
that can be used to specify where in the figure the legend is to be drawn. The allowed values of loc
are numerical codes for the various places the legend can be drawn. See http://matplotlib.org/users/legend_guide.html#legend-location for details. Some of the most common loc
values are:
In [30]:
axes.legend(loc=0) # let matplotlib decide the optimal location
axes.legend(loc=1) # upper right corner
axes.legend(loc=2) # upper left corner
axes.legend(loc=3) # lower left corner
axes.legend(loc=4) # lower right corner
# .. many more options are available
Out[30]:
The following figure shows how to use the figure title, axis labels and legends described above:
In [31]:
fig, ax = plt.subplots()
ax.plot(x, x**2, label="y = x**2")
ax.plot(x, x**3, label="y = x**3")
ax.legend(loc=2); # upper left corner
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('title');
The figure above is functional, but it does not (yet) satisfy the criteria for a figure used in a publication. First and foremost, we need to have LaTeX formatted text, and second, we need to be able to adjust the font size to appear right in a publication.
Matplotlib has great support for LaTeX. All we need to do is to use dollar signs encapsulate LaTeX in any text (legend, title, label, etc.). For example, "$y=x^3$"
.
But here we can run into a slightly subtle problem with LaTeX code and Python text strings. In LaTeX, we frequently use the backslash in commands, for example \alpha
to produce the symbol $\alpha$. But the backslash already has a meaning in Python strings (the escape code character). To avoid Python messing up our latex code, we need to use "raw" text strings. Raw text strings are prepended with an 'r
', like r"\alpha"
or r'\alpha'
instead of "\alpha"
or '\alpha'
:
In [32]:
fig, ax = plt.subplots()
ax.plot(x, x**2, label=r"$y = \alpha^2$")
ax.plot(x, x**3, label=r"$y = \alpha^3$")
ax.legend(loc=2) # upper left corner
ax.set_xlabel(r'$\alpha$', fontsize=18)
ax.set_ylabel(r'$y$', fontsize=18)
ax.set_title('title');
We can also change the global font size and font family, which applies to all text elements in a figure (tick labels, axis labels and titles, legends, etc.):
In [33]:
# Update the matplotlib configuration parameters:
plt.rc('font', family='serif', size=18)
In [34]:
fig, ax = plt.subplots()
ax.plot(x, x**2, label=r"$y = \alpha^2$")
ax.plot(x, x**3, label=r"$y = \alpha^3$")
ax.legend(loc=2) # upper left corner
ax.set_xlabel(r'$\alpha$')
ax.set_ylabel(r'$y$')
ax.set_title('title');
A good choice of global fonts are the STIX fonts:
In [35]:
# Update the matplotlib configuration parameters:
plt.rc('font',family='STIXGeneral',size=18)
plt.rc('mathtext',fontset='stix')
In [36]:
fig, ax = plt.subplots()
ax.plot(x, x**2, label=r"$y = \alpha^2$")
ax.plot(x, x**3, label=r"$y = \alpha^3$")
ax.legend(loc=2) # upper left corner
ax.set_xlabel(r'$\alpha$')
ax.set_ylabel(r'$y$')
ax.set_title('title');
Or, alternatively, we can request that matplotlib uses LaTeX to render the text elements in the figure (this is broken in matplotlib 2.0.0rc2)
In [37]:
plt.rc('text', usetex=True)
In [38]:
fig, ax = plt.subplots()
ax.plot(x, x**2, label=r"$y = \alpha^2$")
ax.plot(x, x**3, label=r"$y = \alpha^3$")
ax.legend(loc=2) # upper left corner
ax.set_xlabel(r'$\alpha$')
ax.set_ylabel(r'$y$')
ax.set_title('title');
In [39]:
# restore
plt.rc('font',family='sans',size=12)
plt.rc('text', usetex=False)
With matplotlib, we can define the colors of lines and other graphical elements in a number of ways. First of all, we can use the MATLAB-like syntax where 'b'
means blue, 'g'
means green, etc. The MATLAB API for selecting line styles are also supported: where, for example, 'b.-' means a blue line with dots:
In [40]:
# MATLAB style line color and style
ax.plot(x, x**2, 'b.-') # blue line with dots
ax.plot(x, x**3, 'g--') # green dashed line
Out[40]:
We can also define colors by their names or RGB hex codes and optionally provide an alpha value using the color
and alpha
keyword arguments:
In [41]:
fig, ax = plt.subplots()
ax.plot(x, x+1, color="red", alpha=0.5) # half-transparant red
ax.plot(x, x+2, color="#1155dd") # RGB hex code for a bluish color
ax.plot(x, x+3, color="#15cc55") # RGB hex code for a greenish color
Out[41]:
To change the line width, we can use the linewidth
or lw
keyword argument. The line style can be selected using the linestyle
or ls
keyword arguments:
In [42]:
fig, ax = plt.subplots(figsize=(12,6))
ax.plot(x, x+1, color="blue", linewidth=0.25)
ax.plot(x, x+2, color="blue", linewidth=0.50)
ax.plot(x, x+3, color="blue", linewidth=1.00)
ax.plot(x, x+4, color="blue", linewidth=2.00)
# possible linestype options ‘-‘, ‘--’, ‘-.’, ‘:’, ‘steps’
ax.plot(x, x+5, color="red", lw=2, linestyle='-')
ax.plot(x, x+6, color="red", lw=2, ls='-.')
ax.plot(x, x+7, color="red", lw=2, ls=':')
# custom dash
line, = ax.plot(x, x+8, color="black", lw=1.50)
line.set_dashes([5, 10, 15, 10]) # format: line length, space length, ...
# possible marker symbols: marker = '+', 'o', '*', 's', ',', '.', '1', '2', '3', '4', ...
ax.plot(x, x+ 9, color="green", lw=2, ls='--', marker='+')
ax.plot(x, x+10, color="green", lw=2, ls='--', marker='o')
ax.plot(x, x+11, color="green", lw=2, ls='--', marker='s')
ax.plot(x, x+12, color="green", lw=2, ls='--', marker='1')
# marker size and color
ax.plot(x, x+13, color="purple", lw=1, ls='-', marker='o', markersize=2)
ax.plot(x, x+14, color="purple", lw=1, ls='-', marker='o', markersize=4)
ax.plot(x, x+15, color="purple", lw=1, ls='-', marker='o', markersize=8, markerfacecolor="red")
ax.plot(x, x+16, color="purple", lw=1, ls='-', marker='s', markersize=8,
markerfacecolor="yellow", markeredgewidth=2, markeredgecolor="blue");
The appearance of the axes is an important aspect of a figure that we often need to modify to make a publication quality graphics. We need to be able to control where the ticks and labels are placed, modify the font size and possibly the labels used on the axes. In this section we will look at controling those properties in a matplotlib figure.
The first thing we might want to configure is the ranges of the axes. We can do this using the set_ylim
and set_xlim
methods in the axis object, or axis('tight')
for automatrically getting "tightly fitted" axes ranges:
In [43]:
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
axes[0].plot(x, x**2, x, x**3)
axes[0].set_title("default axes ranges")
axes[1].plot(x, x**2, x, x**3)
axes[1].axis('tight')
axes[1].set_title("tight axes")
axes[2].plot(x, x**2, x, x**3)
axes[2].set_ylim([0, 0.9])
axes[2].set_xlim([0, 1])
axes[2].set_title("custom axes range");
It is also possible to set a logarithmic scale for one or both axes. This functionality is in fact only one application of a more general transformation system in Matplotlib. Each of the axes' scales are set seperately using set_xscale
and set_yscale
methods which accept one parameter (with the value "log" in this case):
In [44]:
fig, axes = plt.subplots(1, 2, figsize=(10,4))
axes[0].plot(x, x**2, x, np.exp(x))
axes[0].set_title("Normal scale")
axes[1].plot(x, x**2, x, np.exp(x))
axes[1].set_yscale("log")
axes[1].set_title("Logarithmic scale (y)");
We can explicitly determine where we want the axis ticks with set_xticks
and set_yticks
, which both take a list of values for where on the axis the ticks are to be placed. We can also use the set_xticklabels
and set_yticklabels
methods to provide a list of custom text labels for each tick location:
In [45]:
fig, ax = plt.subplots(figsize=(10, 4))
ax.plot(x, x**2, x, x**3, lw=2)
ax.set_xticks([0.1, 0.2, 0.3, 0.4, 0.5])
ax.set_xticklabels([r'$\alpha$', r'$\beta$', r'$\gamma$', r'$\delta$', r'$\epsilon$'], fontsize=18)
yticks = [0, 0.5, 1.0, 1.5]
ax.set_yticks(yticks)
ax.set_yticklabels(["$%.1f$" % y for y in yticks], fontsize=18); # use LaTeX formatted labels
There are a number of more advanced methods for controlling major and minor tick placement in matplotlib figures, such as automatic placement according to different policies. See http://matplotlib.org/api/ticker_api.html for details.
With large numbers on axes, it is often better use scientific notation:
In [46]:
fig, ax = plt.subplots(1, 1)
ax.plot(x, x**2, x, np.exp(x))
ax.set_title("scientific notation")
ax.set_yticks([0., 0.8, 10, 15])
from matplotlib import ticker
formatter = ticker.ScalarFormatter(useMathText=True)
formatter.set_scientific(True)
formatter.set_powerlimits((-1,1))
ax.yaxis.set_major_formatter(formatter)
To change the style sheet we have to act on the matplotlibrc file. For details: http://matplotlib.org/users/customizing.html
In [47]:
from matplotlib import rcParams
In [48]:
# distance between x and y axis and the numbers on the axes
rcParams['xtick.major.pad'] = 5
rcParams['ytick.major.pad'] = 5
fig, ax = plt.subplots(1, 1)
ax.plot(x, x**2, x, np.exp(x))
ax.set_yticks([0, 0.50, 1.00, 1.50])
ax.set_title("label and axis spacing")
# padding between axis label and axis numbers
ax.xaxis.labelpad = 5
ax.yaxis.labelpad = 5
ax.set_xlabel("x")
ax.set_ylabel("y");
In [49]:
# restore defaults
rcParams['xtick.major.pad'] = 3
rcParams['ytick.major.pad'] = 3
Unfortunately, when saving figures the labels are sometimes clipped, and it can be necessary to adjust the positions of axes a little bit. This can be done using subplots_adjust
:
In [50]:
fig, ax = plt.subplots(1, 1)
ax.plot(x, x**2, x, np.exp(x))
ax.set_yticks([0, .50, 1.00, 1.50])
ax.set_title("title")
ax.set_xlabel("x")
ax.set_ylabel("y")
fig.subplots_adjust(left=0.15, right=.9, bottom=0.1, top=0.9);
With the grid
method in the axis object, we can turn on and off grid lines. We can also customize the appearance of the grid lines using the same keyword arguments as the plot
function:
In [51]:
fig, axes = plt.subplots(1, 2, figsize=(10,3))
# default grid appearance
axes[0].plot(x, x**2, x, x**3, lw=2)
axes[0].grid(True)
# custom grid appearance
axes[1].plot(x, x**2, x, x**3, lw=2)
axes[1].grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5)
We can also change the properties of axis spines:
In [52]:
fig, ax = plt.subplots(figsize=(6,2))
ax.spines['bottom'].set_color('blue')
ax.spines['top'].set_color('blue')
ax.spines['left'].set_color('red')
ax.spines['left'].set_linewidth(2)
# turn off axis spine to the right
ax.spines['right'].set_color("none")
ax.yaxis.tick_left() # only ticks on the left side
Sometimes it is useful to have dual x or y axes in a figure; for example, when plotting curves with different units together. Matplotlib supports this with the twinx
and twiny
functions:
In [53]:
fig, ax1 = plt.subplots()
ax1.plot(x, x**2, lw=2, color="blue")
ax1.set_ylabel(r"area $(m^2)$", fontsize=18, color="blue")
for label in ax1.get_yticklabels():
label.set_color("blue")
ax2 = ax1.twinx()
ax2.plot(x, x**3, lw=2, color="red")
ax2.set_ylabel(r"volume $(m^3)$", fontsize=18, color="red")
for label in ax2.get_yticklabels():
label.set_color("red")
In [54]:
fig, ax = plt.subplots()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0)) # set position of x spine to x=0
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0)) # set position of y spine to y=0
xx = np.linspace(-0.75, 1., 100)
ax.plot(xx, xx**3);
In addition to the regular plot
method, there are a number of other functions for generating different kind of plots. See the matplotlib plot gallery for a complete list of available plot types: http://matplotlib.org/gallery.html. Some of the more useful ones are show below:
In [55]:
n = np.array([0,1,2,3,4,5])
In [56]:
fig, axes = plt.subplots(1, 4, figsize=(12,3))
axes[0].scatter(xx, xx + 0.25*np.random.randn(len(xx)))
axes[0].set_title("scatter")
axes[1].step(n, n**2, lw=2)
axes[1].set_title("step")
axes[2].bar(n, n**2, align="center", width=0.5, alpha=0.5)
axes[2].set_title("bar")
axes[3].fill_between(x, x**2, x**3, color="green", alpha=0.5);
axes[3].set_title("fill_between");
In [57]:
# polar plot using add_axes and polar projection
fig = plt.figure()
ax = fig.add_axes([0.0, 0.0, .6, .6], polar=True)
t = np.linspace(0, 2 * np.pi, 100)
ax.plot(t, t, color='blue', lw=3);
In [58]:
# A histogram
n = np.random.randn(100000)
fig, axes = plt.subplots(1, 2, figsize=(12,4))
axes[0].hist(n)
axes[0].set_title("Default histogram")
axes[0].set_xlim((min(n), max(n)))
axes[1].hist(n, cumulative=True, bins=50)
axes[1].set_title("Cumulative detailed histogram")
axes[1].set_xlim((min(n), max(n)));
In [59]:
# more histograms ...
n = np.random.randn(100000)
fig, axes = plt.subplots(1, 3, figsize=(12,4))
axes[0].hist(n,histtype='step')
axes[0].set_title("step style")
axes[0].set_xlim((min(n), max(n)))
axes[1].hist(n,histtype='stepfilled')
axes[1].set_title("step filled style")
axes[1].set_xlim((min(n), max(n)))
axes[2].hist(n,histtype='bar', rwidth=0.8)
axes[2].set_title("bar style")
axes[2].set_xlim((min(n), max(n)));
In [60]:
# Overplot histograms
n_bins = 10
x = np.random.randn(1000, 3)
fig, axes = plt.subplots(nrows=2, ncols=2,figsize=(12,12))
ax0, ax1, ax2, ax3 = axes.flat
colors = ['red', 'tan', 'lime']
ax0.hist(x, n_bins, normed=1, histtype='bar', color=colors, label=colors)
ax0.legend(prop={'size': 10})
ax0.set_title('bars with legend')
ax1.hist(x, n_bins, normed=1, histtype='bar', stacked=True)
ax1.set_title('stacked bar')
ax2.hist(x, n_bins, histtype='step', stacked=True, fill=True)
ax2.set_title('stepfilled')
# Make a multiple-histogram of data-sets with different length.
x_multi = [np.random.randn(n) for n in [10000, 5000, 2000]]
ax3.hist(x_multi, n_bins, histtype='bar')
ax3.set_title('different sample sizes')
plt.tight_layout()
plt.show()
Annotating text in matplotlib figures can be done using the text
function. It supports LaTeX formatting just like axis label texts and titles:
In [61]:
fig, ax = plt.subplots()
ax.plot(xx, xx**2, xx, xx**3)
ax.text(0.15, 0.2, r"$y=x^2$", fontsize=20, color="blue")
ax.text(0.65, 0.1, r"$y=x^3$", fontsize=20, color="green");
Axes can be added to a matplotlib Figure canvas manually using fig.add_axes
or using a sub-figure layout manager such as subplots
, subplot2grid
, or gridspec
:
In [62]:
fig, ax = plt.subplots(2, 3)
fig.tight_layout()
In [63]:
fig = plt.figure()
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))
fig.tight_layout()
In [64]:
import matplotlib.gridspec as gridspec
In [65]:
fig = plt.figure()
gs = gridspec.GridSpec(2, 3, height_ratios=[2,1], width_ratios=[1,2,1])
for g in gs:
ax = fig.add_subplot(g)
fig.tight_layout()
Manually adding axes with add_axes
is useful for adding insets to figures:
In [66]:
fig, ax = plt.subplots()
ax.plot(xx, xx**2, xx, xx**3)
fig.tight_layout()
# inset
inset_ax = fig.add_axes([0.2, 0.55, 0.35, 0.35]) # X, Y, width, height
inset_ax.plot(xx, xx**2, xx, xx**3)
inset_ax.set_title('zoom near origin')
# set axis range
inset_ax.set_xlim(-.2, .2)
inset_ax.set_ylim(-.005, .01)
# set axis tick locations
inset_ax.set_yticks([0, 0.005, 0.01])
inset_ax.set_xticks([-0.1,0,.1]);
Colormaps and contour figures are useful for plotting functions of two variables. In most of these functions we will use a colormap to encode one dimension of the data. There are a number of predefined colormaps. It is relatively straightforward to define custom colormaps. For a list of pre-defined colormaps, see: http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps
In [67]:
alpha = 0.7
phi_ext = 2 * np.pi * 0.5
def flux_qubit_potential(phi_m, phi_p):
return 2 + alpha - 2 * np.cos(phi_p) * np.cos(phi_m) - alpha * np.cos(phi_ext - 2*phi_p)
In [68]:
phi_m = np.linspace(0, 2*np.pi, 100)
phi_p = np.linspace(0, 2*np.pi, 100)
X,Y = np.meshgrid(phi_p, phi_m)
Z = flux_qubit_potential(X, Y).T
In [69]:
from matplotlib import cm
fig, ax = plt.subplots()
p = ax.pcolor(X/(2*np.pi), Y/(2*np.pi), Z, cmap=cm.RdBu,vmin=abs(Z).min(), vmax=abs(Z).max())
cb = fig.colorbar(p, ax=ax)
In [70]:
fig, ax = plt.subplots()
im = ax.imshow(Z, cmap=cm.RdBu, vmin=abs(Z).min(), vmax=abs(Z).max(), extent=[0, 1, 0, 1])
im.set_interpolation('bilinear')
cb = fig.colorbar(im, ax=ax)
In [71]:
fig, ax = plt.subplots()
cnt = ax.contour(Z, cmap=cm.RdBu, vmin=abs(Z).min(), vmax=abs(Z).max(), extent=[0, 1, 0, 1])
In [73]:
a = np.array([[0, 0, 0],
[1, 0, 0],
[2, 0, 0]])
plt.imshow(a,interpolation='None')
plt.colorbar();
To show it in Cartesian coordinates we have to transpose and reverse the array:
In [75]:
plt.imshow(a[:,::-1].T,interpolation='None')
plt.colorbar();
Or, shortly:
In [76]:
plt.imshow(a.T, origin='lower',interpolation='None')
plt.colorbar();
In [77]:
from matplotlib import patches
There are a large number of various patches, including Rectangles, Circles, Ellipses, and many more. Once a patch has been made using its declaration (i.e., p1=patches.Circle(…)), it needs to be added by:
ax1.add_patch(p1)
# Or if you haven’t created a variable for your axis
plt.gca().add_patch(p1)
Let's add a circle to our plot:
In [78]:
fig, ax = plt.subplots()
p1 = patches.Circle((1,0.5),radius=0.5,linewidth=4,facecolor='none',edgecolor='g')
ax.imshow(a,interpolation='None')
ax.add_patch(p1);
To use 3D graphics in matplotlib, we first need to create an instance of the Axes3D
class. 3D axes can be added to a matplotlib figure canvas in exactly the same way as 2D axes; or, more conveniently, by passing a projection='3d'
keyword argument to the add_axes
or add_subplot
methods.
In [79]:
from mpl_toolkits.mplot3d.axes3d import Axes3D
In [80]:
from matplotlib import cm
fig = plt.figure(figsize=(14,6))
# `ax` is a 3D-aware axis instance because of the projection='3d' keyword argument to add_subplot
ax = fig.add_subplot(1, 2, 1, projection='3d')
p = ax.plot_surface(X, Y, Z, rstride=4, cstride=4, linewidth=0)
# surface_plot with color grading and color bar
ax = fig.add_subplot(1, 2, 2, projection='3d')
p = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)
cb = fig.colorbar(p, shrink=0.5)
In [81]:
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(1, 1, 1, projection='3d')
p = ax.plot_wireframe(X, Y, Z, rstride=4, cstride=4)
In [82]:
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(1,1,1, projection='3d')
ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25)
cset = ax.contour(X, Y, Z, zdir='z', offset=-np.pi, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='x', offset=-np.pi, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='y', offset=3*np.pi, cmap=cm.coolwarm)
ax.set_xlim3d(-np.pi, 2*np.pi);
ax.set_ylim3d(0, 3*np.pi);
ax.set_zlim3d(-np.pi, 2*np.pi);
We can change the perspective of a 3D plot using the view_init
method, which takes two arguments: elevation
and azimuth
angle (in degrees):
In [83]:
fig = plt.figure(figsize=(12,6))
ax = fig.add_subplot(1,2,1, projection='3d')
ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25)
ax.view_init(30, 45)
ax = fig.add_subplot(1,2,2, projection='3d')
ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25)
ax.view_init(70, 30)
fig.tight_layout()
Do it in an interactive way:
In [84]:
from ipywidgets import interact
def pltwxy(az,el):
fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(1,2,1, projection='3d')
ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25)
ax.view_init(az,el)
interact(pltwxy,az=(0,100,30),el=(0,90,45));
In [85]:
fig = plt.figure(figsize=(10,6))
ax = Axes3D(fig)
X = np.arange(-4, 4, 0.25)
Y = np.arange(-4, 4, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.cm.hot)
ax.contourf(X, Y, Z, zdir='z', offset=-2, cmap=plt.cm.hot)
ax.set_zlim(-2,2);
Matplotlib has a number of "backends" which are responsible for rendering graphs. The different backends are able to generate graphics with different formats and display/event loops. There is a distinction between noninteractive backends (such as 'agg', 'svg', 'pdf', etc.) that are only used to generate image files (e.g. with the savefig
function), and interactive backends (such as Qt4Agg, GTK, MaxOSX) that can display a GUI window for interactively exploring figures.
A list of available backends are:
In [86]:
import matplotlib
print(matplotlib.rcsetup.all_backends)
The default backend, called agg
, is based on a library for raster graphics which is great for generating raster formats like PNG.
Normally we don't need to bother with changing the default backend; but sometimes it can be useful to switch to, for example, PDF or GTKCairo (if you are using Linux) to produce high-quality vector graphics instead of raster based graphics.
In [87]:
#
# RESTART THE NOTEBOOK: the matplotlib backend can only be selected before pylab is imported!
# (e.g. Kernel > Restart)
#
import matplotlib
matplotlib.use('pdf')
import matplotlib.pyplot as plt
import numpy
from IPython.display import Image, IFrame
In [88]:
#
# Now we are using the svg backend to produce SVG vector graphics
#
fig, ax = plt.subplots()
t = numpy.linspace(0, 10, 100)
ax.plot(t, numpy.cos(t)*numpy.sin(t))
plt.savefig("test.pdf")
In [89]:
#
# Show the produced PDF file.
#
IFrame("test.pdf",width=600,height=600)
Out[89]:
When we use IPython notebook it is convenient to use a matplotlib backend that outputs the graphics embedded in the notebook file. To activate this backend, somewhere in the beginning on the notebook, we add:
%matplotlib inline
Commonly, scipy and numpy are imported separately with:
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
The inline backend has a number of configuration options that can be set by using the IPython magic command %config
to update settings in InlineBackend
. For example, we can switch to SVG figures or higher resolution figures with either:
%config InlineBackend.figure_format='svg'
or:
%config InlineBackend.figure_format='retina'
For more information, type:
%config InlineBackend
In [90]:
%matplotlib inline
%config InlineBackend.figure_format='pdf'
import matplotlib.pylab as plt
import numpy
In [91]:
#
# Now we are using the SVG vector graphics displaced inline in the notebook
#
fig, ax = plt.subplots()
t = numpy.linspace(0, 10, 100)
ax.plot(t, numpy.cos(t)*numpy.sin(t))
plt.savefig("test.pdf")
In [92]:
#
# RESTART THE NOTEBOOK: the matplotlib backend can only be selected before pylab is imported!
# (e.g. Kernel > Restart)
#
import matplotlib
matplotlib.use('Qt4Agg') # or for example MacOSX
import matplotlib.pylab as plt
import numpy as np
In [93]:
# Now, open an interactive plot window with the Qt4Agg backend
fig, ax = plt.subplots()
t = np.linspace(0, 10, 100)
ax.plot(t, np.cos(t) * np.sin(t))
plt.show()
Note that when we use an interactive backend, we must call plt.show()
to make the figure appear on the screen.
In [94]:
%reload_ext version_information
%version_information numpy, matplotlib
Out[94]: