`_. For
example, you can change the alignment of the text with respect to the
coordinates with the `verticalalignment` and `horizontal alignment`
(or `va` and `ha`) keywords::
plt.text(-2, 0.45, r'$\mu=0,\ \sigma=1$', ha='right', color='g')
We've also added an extra keyword `label` to the ``hist()`` call. This
will be used to label the curve if we later decide to add a
legend. Let's do that now using ``legend()``::
plt.legend(loc='best')
Type ``plt.legend?`` and take a look at the different keyword options that
let you customise the legend. `loc='best'` means it will magically
choose a location to minimise overlap with the plotted data.
.. admonition:: Exercise: Overlaying histograms
Make an additional normal distribution with a mean of 1, then make
a new plot where the two distributions are overlayed. Use a
different color and choose the opacities (keyword `alpha`) so it
looks reasonable. Finally, make a legend that identifies the two
distributions.
Hints:
- You might want to use the ``bin`` parameter with an
``np.arange(min, max, step)`` so both histograms are binned the
same.
- The ``histtype`` parameter may also prove useful depending on
your taste.
.. raw:: html
Click to Show/Hide Solution
::
plt.clf()
x2 = np.random.normal(1, 1, size=10000)
bins = np.arange(-4, 5, 0.2)
out = plt.hist(x, bins=bins, normed=1, facecolor='g', alpha=0.5,
histtype='stepfilled', label=r'$\mu=0,\ \sigma=1$')
out = plt.hist(x2, bins=bins, normed=1, facecolor='r', alpha=0.5,
histtype='stepfilled', label=r'$\mu=1,\ \sigma=1$')
plt.legend(loc='best')
.. raw:: html
Using mathematical expressions in text
======================================
matplotlib accepts TeX equation expressions in any text expression.
For example, to write the expression :math:`\sigma_i=15` in the title
you can write a TeX expression surrounded by dollar signs::
plt.title(r'$\sigma_i=15$')
The ``r`` preceeding the title string is important -- it signifies
that the string is a *raw* string and not to treate backslashes as
python escapes. matplotlib has a built-in TeX expression parser and
layout engine, and ships its own math fonts -- for details see the
`mathtext-tutorial
`_. 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 the
`usetex-tutorial
`_.
Annotating text
===============
The uses of the basic `text()`_ command above place text at an
arbitrary position on the Axes. A common use case of 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::
plt.clf()
t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*pi*t)
lines = plt.plot(t, s, lw=2)
plt.annotate('Local maximum', xy=(2, 1), xytext=(3, 1.5),
arrowprops=dict(facecolor='black', shrink=0.05, width=2))
plt.ylim(-2,2)
.. image:: pyplot_annotate.png
:scale: 70
In this basic example, both the ``xy`` (arrow tip) and ``xytext``
locations (text location) are in data coordinates. There are a
variety of other coordinate systems one can choose -- see the
`annotations tutorial
`_. More
examples can be found `here
`_
Making contour plots and saving figures
=======================================
Contour plots can be made using the `contour()` command, and they can
then be labelled with `clabel()`::
def gaussian_2d(x, y, x0, y0, xsig, ysig):
return np.exp(-0.5*(((x-x0) / xsig)**2 + ((y-y0) / ysig)**2))
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = gaussian_2d(X, Y, 0., 0., 1., 1.)
Z2 = gaussian_2d(X, Y, 1., 1., 1.5, 0.5)
# difference of Gaussians
Z = 10.0 * (Z2 - Z1)
# Create a contour plot with labels using default colors. The
# inline argument to clabel will control whether the labels are draw
# over the line segments of the contour, removing the lines beneath
# the label
plt.clf()
CS = plt.contour(X, Y, Z)
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')
.. image:: contour.png
:scale: 70
Once you've made plots, they can be saved with `savefig`. They can be
saved as jpg, png, pdf, ps, svg and other formats; the format is
inferred from the suffix of the filename::
plt.savefig('contour.pdf')
png format is generally best for putting in talks. For papers and
posters it's better to use a vector format like ps, pdf or svg. There
can be small differences between the plot you see on the screen and a
saved pdf or ps version, so check the saved version looks as you
expect. (Often the saved vector format version will look better!)
You can also save a plot using the button in the plotting window.
.. admonition:: Exercise: Make a contour plot
Make a contour plot of a single 2d gaussian centred on 0,0. You
should show only 2 contours that are both coloured black. Label the
inner contour with '99%' and the outer contour with '95%'. You
might want to take a look at the `fmt` keyword in the help for
`clabel()` to see how to give your own contour labels, and take
note that the values of each contour level are stored in
`CS.levels`.
.. raw:: html
Click to Show/Hide Solution
::
x = np.linspace(-2.0, 2.0)
y = np.linspace(-2.0, 2.0)
X, Y = np.meshgrid(x, y)
Z = gaussian_2d(X, Y, 0, 0, 1., 1.)
plt.figure()
CS = plt.contour(X, Y, Z, 2, colors='k')
fmt = {CS.levels[0]: '95%', CS.levels[1]: '99%'}
plt.clabel(CS, fmt=fmt)
.. raw:: html
Other 2-d plots
===============
A deeper tutorial on plotting 2-d image data will have to wait for another
day:
- To plot images take a look at at the `image tutorial
`_
- `APLpy`_ allows you to easily make publication quality images for
astronomical fits images incorporating WCS information.
Plotting 3-d data
=================
Matplotlib supports plotting 3-d data through the
``mpl_toolkits.mplot3d`` module. Let's take a look at an example of
the 3-d viewer that is available::
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
def gaussian_2d(x, y):
return np.exp(-0.5*(x**2 + y**2))
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
vals = np.linspace(-3, 3)
x,y = np.meshgrid(vals, vals)
z = gaussian_2d(x, y)
ax.plot_wireframe(x, y, z, color='0.3', lw=0.5)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
To get more information check out the `mplot3d tutorial
`_.
Putting it all together
=======================
Let's use some of what we've learned over the past few lessons to plot
a 2d distribution, overlay some contours, and show the 1d histograms
corresponding to each dimension. You should understand everything
that's going on here - if you don't, please ask!::
# the random data
x = np.random.randn(1e5)
y = np.random.randn(1e5)
# start with a rectangular figure
plt.figure(figsize=(6, 6))
# define the axes positions
left = bottom = 0.1
width = height = 0.7
ax_main = plt.axes([left, bottom, width, height])
ax_top = plt.axes([left, bottom + height, width, 0.15])
ax_right = plt.axes([left + width, bottom, 0.15, height])
# plot the data points
ax_main.plot(x, y, '.', markersize=0.5)
# now let's overplot some contours. First we have to make a 2d
# histogram of the point distribution.
vals, xedges, yedges = np.histogram2d(x, y, bins=30)
# Now we have the bin edges, but we want to find the bin centres to
# plot the contour positions - they're half way between the edges:
xbins = 0.5 * (xedges[:-1] + xedges[1:])
ybins = 0.5 * (yedges[:-1] + yedges[1:])
# now plot the contours
ax_main.contour(xbins, ybins, vals.T, 4, colors='k', zorder=10)
# finally plot 1d histograms for the top and right axes.
bins = np.arange(-3, 3.1, 0.1)
ax_top.hist(x, bins=bins, histtype='stepfilled')
ax_right.hist(y, bins=bins, orientation='horizontal', histtype='stepfilled')
# make all the limits consistent
ax_top.set_xlim(-3, 3)
ax_right.set_ylim(-3, 3)
ax_main.set_xlim(-3, 3)
ax_main.set_ylim(-3, 3)
# remove the tick labels for the top and right axes.
ax_top.set_xticklabels([])
ax_top.set_yticklabels([])
ax_right.set_xticklabels([])
ax_right.set_yticklabels([])
plt.draw()