Importing Matplotlib's pylab

In [9]:
# pylab is a nice interface to all that is matplotlib
import matplotlib.pyplot as plt
import numpy as np

# Should plots pop up as you type? Use interactive on/off plt.ion() or plt.ioff()
In [7]:
# if you want the plots to appear in the notebook
%matplotlib inline

Basic Plotting

Basic components of the figure environment:

In [3]:
from IPython.display import Image

There are several ways to make a figure: (for documentation type e.g, plt.figure?)

In [4]:
# basic
fig = plt.figure()
ax = plt.axes()
# plt.figure?
# plt.axes?
In [5]:
# my favorite:
fig, ax = plt.subplots()
# plt.subplots?
# fig, ax = plt.subplots(ncols=2)
# fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(8,8))
In [6]:
# clear them:
plt.close()  # close the most recent window
In [4]:
# define something to plot
y = np.sin(np.linspace(0, 2*np.pi, 20))
x = np.arange(20)

Line Plots

'-' solid line style '--' dashed line style '-.' dash-dot line style ':' dotted line style 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post'

Try these:

In [8]:
fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(14, 14))
# plt.plot?
ax[0, 0].plot(x, y)
ax[0, 1].plot(x, y, ':')
ax[0, 2].plot(x, y, linestyle=':')
ax[1, 0].plot(x, y, linestyle='steps')
ax[1, 1].plot(x, y, linestyle='steps-pre:')
ax[1, 2].plot(x, y, linestyle='steps-pre-')
ax[1, 2].plot(x, y, linestyle='steps-mid-')
ax[1, 2].plot(x, y, linestyle='steps-post-')
[<matplotlib.lines.Line2D at 0x10d089210>]

Scatter plots using markers

``'.'`` point marker ``','`` pixel marker ``'o'`` circle marker ``'*'`` star marker ``'x'`` x marker ``'D'`` diamond marker ``'d'`` thin_diamond marker

In [9]:
fig, ax = plt.subplots(ncols=2, figsize=(14, 4))
ax[0].plot(x, y, 'o')
ax[1].plot(x, y, 'o', ms=30, mec='white', alpha=0.3)
[<matplotlib.lines.Line2D at 0x107f69ad0>]

Scatter using plt.scatter

Scatter is useful because you can set the individual color or marker sizes as arrays.

In [10]:
# A scatter plot that uses colors picked by the y value (you must set the color map)
fig, ax = plt.subplots(ncols=2, figsize=(14,4))

ax[0].scatter(x, y, c=y,, s=150)

# Same as above, with the marker size set by the array z
z = np.random.random(20) * 1000
ax[1].scatter(x, y, c=y,, s=z)
<matplotlib.collections.PathCollection at 0x1095c8810>

Error Bars

In [11]:
xerr = np.sqrt(x)
yerr = 0.1
fig, ax = plt.subplots(ncols=3, figsize=(16, 4))
ax[0].errorbar(x, y, xerr=xerr, yerr=yerr)
# no error caps, color the error bars differently than the data:
ax[1].errorbar(x, y, xerr=xerr, yerr=yerr, capsize=0, ecolor='gray')
# don't plot values? Just error bars? set fmt='none'
ax[2].errorbar(x, y, xerr=xerr, yerr=yerr, capsize=0, ecolor='gray', fmt='none')
<Container object of 3 artists>


Matplotlib has a plt.hist function that can create histograms and plot them.

In [10]:
x = np.random.normal(size=10000)
y = np.random.normal(size=10000)

fig, ax = plt.subplots(ncols=2, figsize=(14, 4))
h, bins, p = ax[0].hist(x, bins=20)

h, xe, ye, p = ax[1].hist2d(x, y, bins=20,

Personally, I prefer to use np.histogram with plt.plot using linestyle='steps-pre' since I'm usually using the binned data at some other point in the code.

In [13]:
fig, ax = plt.subplots()
h, bins = np.histogram(x, bins=20)
ax.plot(bins[1:], h, linestyle='steps-pre')

Plotting with Data

In [14]:
from import fits
# replace this with the file you downloaded
fitsfile = 'hlsp_angst_hst_acs-wfc_10605-ugc-5336_f555w-f814w_v1_gst.fits'
In [15]:
hdu =
data = hdu[1].data
photsys = hdu[0].header['CAMERA']  # survey used ACS and WFPC2

# the magnitude fields in the fits file are named MAG[1 or 2]_[ACS or WFPC2] 
mag1 = data['MAG1_%s' % photsys]
mag2 = data['MAG2_%s' % photsys]

mag1_err = data['MAG1_ERR']
mag2_err = data['MAG2_ERR']

color = mag1 - mag2
color_err = np.sqrt(data['MAG1_ERR'] ** 2 + data['MAG2_ERR'] ** 2)

Scatter: Color Magnitude Diagram

In [16]:
# these fits file contains stars that are recovered in only one filter
# stars not recovered are given values >= 90. No need to plot them, messes up the autoscaling.
good, = np.nonzero((np.abs(color) < 30) & (np.abs(mag2) < 30))

fig, ax = plt.subplots(figsize=(8, 8))
ax.plot(color[good], mag2[good], '.', color='black', ms=3)

# CMDs have yaxis reversed, a simple way to reverse axis depend on autoscaling
(30.0, 18.0)

Error Bars: On the Color Magnitude Diagram

With fmt = 'none' we can simply overplot error bars and no replot the data. This is a good option for a general CMD function with the option of overploting uncertainties

In [17]:
fig, ax = plt.subplots(figsize=(8, 8))
ax.plot(color[good], mag2[good], '.', color='black', ms=3)

# CMDs have yaxis reversed, a simple way to reverse axis depend on autoscaling

ax.errorbar(color[good], mag2[good], fmt='none', lw=1, xerr=color_err[good],
            yerr=mag2_err[good], capsize=0, ecolor='gray')
<Container object of 3 artists>

1D Histogram: Luminosity Function

In [18]:
binsize = 0.1
mbin = np.arange(mag2.min(), mag2.max(), binsize) 
lf, bins = np.histogram(mag2, bins=mbin)
fig, ax = plt.subplots(ncols=2, figsize=(14, 4))

[ax[i].plot(bins[1:], lf, linestyle='steps-pre') for i in range(2)]

# maybe you want a log scale
for i, yscale in enumerate(['log', 'linear']):

2D Histogram with Imshow: Hess Diagram

In [19]:
cbin = np.arange(color.min(), color.max(), binsize)
hess, cbin, mbin = np.histogram2d(color, mag2, bins=[cbin, mbin])

# Set the extent of the image
extent = [np.min(cbin), np.max(cbin), np.max(mbin), np.min(mbin)]

fig, ax = plt.subplots(ncols=2, figsize=(14, 4))

im = ax[0].imshow(hess.T,, interpolation='nearest',
                  extent=extent, aspect='auto')

# Perhaps you want log bin counts
from matplotlib.colors import LogNorm
im = ax[1].imshow(hess.T,, interpolation='nearest',
                  extent=extent, aspect='auto', norm=LogNorm())


Matplotlib has a few ways of customizing the plotting environment.

  • rcParams: Global default settings
  • mplstyle files: Quick runtime edits of rcParams
In [20]:
# some code for the next sections
import os

def directory_check(directory):
    """check if a directory exists, if not print the mkdir command to create it"""
    if not os.path.isdir(directory):
        print 'Need to make the directory.'
        print 'mkdir', directory
        print '%s exists' % directory

def plot_demo():
    """make a plot for a demo"""
    fig, ax = plt.subplots()
    ax.plot(np.sin(np.linspace(0, 2*np.pi)))
    ax.plot(np.sin(np.linspace(0, 2*np.pi)), 'o')
    return ax


To see what the current setup is, find the matplotlibrc file in your matplotlib data path: install_dir/python?.?/site-packages/matplotlib/

In [21]:
print 'matplotlib data path:', mpl.get_data_path()
mplrc = os.path.join(mpl.get_data_path(), 'matplotlibrc')
matplotlib data path: /Users/rosenfield/anaconda/lib/python2.7/site-packages/matplotlib/mpl-data
In [22]:
# In terminal use 'cat' to see the contents of the matplotlibrc file, or open it.
print '$ cat %s' % mplrc
$ cat /Users/rosenfield/anaconda/lib/python2.7/site-packages/matplotlib/mpl-data/matplotlibrc

To make changes to matplotlibrc, you will first have to copy it to your matplotlib user directory, or any changes will be overwritten with future matplotlib installs/upgrades.

In [23]:
# Quick check if you may need to create the directory .matplotlib
user_mpl_path = os.path.join(os.environ['HOME'], '.matplotlib')
/Users/rosenfield/.matplotlib exists

Copy the default matplotlibrc to your matplotlib user directory and then follow directions within the matplotlibrc file

In [24]:
print 'cp %s %s/matplotlibrc' % (mplrc, user_mpl_path)
cp /Users/rosenfield/anaconda/lib/python2.7/site-packages/matplotlib/mpl-data/matplotlibrc /Users/rosenfield/.matplotlib/matplotlibrc

To see all available options (uncomment):

In [25]:

Mpl Styles

Say you want to plot a few different styles, one for your paper, another for your presenation. In that case, you don't need to make many changes to the matplotlibrc file. You can create your own style files that overide rcParams, either for a given plot command, or thoughout an entire script.

Some styles are available by default:

In [26]:
[u'grayscale', u'bmh', u'dark_background', u'ggplot', u'fivethirtyeight', u'presentation']

to set a default style for the entire session:

In [ ]:
# default parameters
In [27]:
# set all future plots to use bmh'bmh')
<matplotlib.axes._subplots.AxesSubplot at 0x10b354b10>

Use a style once, and go back to default style afterwards:

In [28]:
# plot each of the available styles
for style in
        ax = plot_demo()
In [29]:
# back to bmh
<matplotlib.axes._subplots.AxesSubplot at 0x10bf789d0>

Make your own style file

Just like the matplotlibrc file, the easiest way to make your own style file is to copy an existing one, place it in your matplotlib user directory, and edit at will.

The style files are located in install_dir/python?.?/site-packages/matplotlib/mpl-data/stylelib

In [30]:
stylelib_path = os.path.join(mpl.get_data_path(), 'stylelib')
print 'mpl style path:', stylelib_path
print 'mpl style files:', os.listdir(stylelib_path)
mpl style path: /Users/rosenfield/anaconda/lib/python2.7/site-packages/matplotlib/mpl-data/stylelib
mpl style files: [u'bmh.mplstyle', u'dark_background.mplstyle', u'fivethirtyeight.mplstyle', u'ggplot.mplstyle', u'grayscale.mplstyle']

Open them, check them out, copy your favorite to the directory keeping the .mplstyle file extension

NOTE: ~/.matplotlib/stylelib/ files overide those in mpl-data/stylelib of the same name

In [31]:
# Quick check if you may need to create the directory stylelib
user_stylelib_path = os.path.join(os.environ['HOME'], '.matplotlib', 'stylelib')
/Users/rosenfield/.matplotlib/stylelib exists

In the terminal, copy one of these to your user directory

In [32]:
# for copy and paste ease, here are the full paths
for s in os.listdir(stylelib_path):
    print os.path.join(stylelib_path, s)

An example presentation syle that I adapted from the fivethirtyeight style

In [33]:
%%file presentation.mplstyle
# Author: Phil Rosenfield
# Adapted from: 
# Author: Cameron Davidson-Pilon, replicated styles from
# See

lines.linewidth: 3
lines.solid_capstyle: butt

legend.frameon: False
legend.numpoints: 1
legend.fontsize: 16

axes.color_cycle: 000000, 30a2da, fc4f30, e5ae38, 6d904f, 8b8b8b
axes.axisbelow: true
axes.edgecolor: f0f0f0
axes.linewidth: 3.0
axes.titlesize: 24
axes.labelsize: 20

patch.edgecolor: f0f0f0
patch.linewidth: 0.5

font.size: 14.0

figure.figsize: 8, 8  # square figures (inches)
figure.subplot.left: 0.08
figure.subplot.right: 0.95 
figure.subplot.bottom: 0.07
figure.facecolor: ffffff

xtick.labelsize : 16
ytick.labelsize : 16

text.usetex: True
text.latex.unicode: False

image.aspect: 1.0
image.cmap: Blues
Overwriting presentation.mplstyle

You can copy that to your directory (you may need to restart this kernel to have python find it):

In [34]:
print 'cp %s %s/' % (os.path.join(os.getcwd(), 'presentation.mplstyle'), user_stylelib_path)
cp /Users/rosenfield/Work/action/aas/scwkshop/2015-01-03-aas/intermediate/matplotlib/presentation.mplstyle /Users/rosenfield/.matplotlib/stylelib/

Putting it all Together

Here is a script that pulls together many topics discussed today and yesterday.

In [5]:
#!/usr/bin/env python
Script to make CMD, LF, or Hess diagram from a binary fits table
Written by: Phil Rosenfield
import argparse
from import fits
import matplotlib.pyplot as plt
import numpy as np
import sys

def plot_cmd(color, mag, color_err=None, mag_err=None, ax=None):
    Plot a Color Magnitude diagram with uncertainties
    color, mag : color and magnitude arrays
    color_err, mag_err: uncertainties in color and mag
    ax : axes instance
    ax : axes instance

    if ax is None:
        fig, ax = plt.subplots(figsize=(8, 8))

    ax.plot(color, mag, '.', ms=3)

    if color_err is not None and mag_err is not None:
        ax.errorbar(color, mag, fmt='none', lw=1, xerr=color_err,
                    yerr=mag_err, capsize=0, ecolor='gray')

    # reverse yaxis
    return ax

def plot_lf(mag, binsize, mbin=None, yscale='log'):
    Make a Luminosty function (binned magnitude) plot
    mag : array
        magnitude array to be binned
    binsize : float
        width of magnitude bins
    mbin : array
        right edges of magnitude bins
    yscale : str
        plt.set_yscale option

    ax : axes instance
    if mbin is None:
        mbin = np.arange(mag.min(), mag.max(), binsize)
    lf, bins = np.histogram(mag, bins=mbin)
    fig, ax = plt.subplots()
    ax.plot(bins[1:], lf, linestyle='steps-pre')
    return ax
def make_hess(color, mag, binsize, cbinsize=None, mbin=None, cbin=None):
    Compute a hess diagram (surface-density CMD) on photometry data.

    color : array
        color values

    mag : array
        magnitude values

    binsize, cbinsize: float, float
        width of mag, color bins in magnitudes

    cbin : array
        the right edges of the color bins

    mbin : array
        the right edges of the magnitude bins

    cbin : array
        the centers of the color bins

    mbin : array
        the centers of the magnitude bins

    hess : 2d array
        The Hess diagram values

    if mbin is None:
        mbin = np.arange(mag.min(), mag.max(), binsize)

    if cbin is None:
        if cbinsize is None:
            cbinsize = binsize
        cbin = np.arange(color.min(), color.max(), cbinsize)

    hess, cbin, mbin = np.histogram2d(color, mag, bins=[cbin, mbin])
    return hess, cbin, mbin

def plot_hess(color, mag, binsize, ax=None, colorbar=False,
              vmin=None, vmax=None, cbinsize=None, im_kwargs={}):
    Plot a hess diagram with imshow.
    color : array
        color array to be binned
    mag : array
        magnitude array to be binned

    binsize, cbinsize : float, float
        width of magnitude, color bins
    colorbar : bool
        option to also plot the colorbar
    vmin, vmax : float, float or None, None
        lower and upper limits sent to matplotlib.colors.LogNorm
    im_kwargs : dict
        dictionary passed to imshow by default:
        defaults = {'norm': LogNorm(vmin=vmin, vmax=vmax),
                    'interpolation': 'nearest',
                    'extent' [limits of mag and color]
                    'aspect': 'auto'}
    ax : axes instance
    from matplotlib.colors import LogNorm
    if ax is None:
        fig, ax = plt.subplots()

    hess, cbin, mbin = make_hess(color, mag, binsize, cbinsize=cbinsize)
    extent = [np.min(cbin), np.max(cbin), np.max(mbin), np.min(mbin)]
    vmax = vmax or hess.max()

    defaults = {'norm': LogNorm(vmin=vmin, vmax=vmax),
                'interpolation': 'nearest',
                'extent': extent,
                'aspect': 'auto'}

    kwargs = dict(defaults.items() + im_kwargs.items())

    im = ax.imshow(hess.T, **kwargs)

    if colorbar is True:

    return ax

def load_data(fitsfile, yfilt='I'):
    Load color, magnitude and uncertainties from binary fits table
    fitsfile : string or file object
        path to binary fits table or object to be read by
    yfilt : string
        filter to use as mag (V or I)

    color, mag : arrays of color and magnitude
    color_error, mag_err : arrays of summed quadriture uncertainies and magnitude uncertainties

    hdu =
    data = hdu[1].data
    photsys = hdu[0].header['CAMERA']

    # the magnitude fields in the fits file are named MAG{1,2}_[photsys]
    mag1 = data['MAG1_%s' % photsys]
    mag2 = data['MAG2_%s' % photsys]
    color = mag1 - mag2

    color_err = np.sqrt(data['MAG1_ERR'] ** 2 + data['MAG2_ERR'] ** 2)

    # choose what gets the yaxis V or I
    if yfilt.upper() == 'I':
        mag = mag2
        ymag = 'MAG2'
        mag = mag1
        ymag = 'MAG1'

    # the error fields in the fits file are named [MAG]_ERR
    mag_err = data['%s_ERR' % ymag]

    return color, mag, color_err, mag_err

def main(argv):
    parser = argparse.ArgumentParser(description="Generate a plot of a fits file")

    parser.add_argument('-p', '--plottype', type=str, default='cmd',
                        help='which plot to make: CMD, hess, or LF')

    parser.add_argument('-f', '--filters', type=str, default=None,
                        help='comma separated V and I filter names for plot labels')

    parser.add_argument('-y', '--yfilter', type=str, default='I',
                        help='plot V or I for LF or on y axis for cmd, Hess')

    parser.add_argument('-m', '--binsize', type=float, default=0.05,
                        help='hess diagram or LF mag binsize')

    parser.add_argument('-c', '--cbinsize', type=float, default=0.1,
                        help='hess diagram color binsize')

    parser.add_argument('-xlim', '--xlim', type=list, default=None,
                        help='comma separated x axis min, max')

    parser.add_argument('-ylim', '--ylim', type=list, default=None,
                        help='comma separated y axis min, max')

    parser.add_argument('-yscale', '--yscale', type=str, default='log',
                        help='y axis scale for LF')

    parser.add_argument('-x', '--colorbar', action='store_true',
                        help='add the hess diagram colorbar')

    parser.add_argument('-outfile', '--outfile', type=str, default='data_plot.png',
                        help='the name of the output file')

    parser.add_argument('-style', '--style', type=str, default='ggplot',
                        help='the name of the matplotlib style')

    parser.add_argument('file', type=argparse.FileType('r'),
                        help='the name of the fits file')

    args = parser.parse_args(argv)

    # set the plot style

    if args.filters is not None:
        filter1, filter2 = args.filters.split(',')
        print('warning: using V, I as default filter names')
        filter1 = 'V'
        filter2 = 'I'
    yfilt = args.yfilter
    color, mag, color_err, mag_err = load_data(args.file, yfilt=yfilt)
    # the fits file contains stars that are recovered in only one filter
    # stars not recovered are given values >= 90. No need to plot em.
    good, = np.nonzero((np.abs(color) < 30) & (np.abs(mag) < 30))    
    if args.plottype.lower() == 'cmd':    
        ax = plot_cmd(color[good], mag[good], color_err=color_err[good], mag_err=mag_err[good])

    if args.plottype.lower() == 'hess':
        ax = plot_hess(color[good], mag[good], colorbar=args.colorbar,
                       binsize=args.binsize, cbinsize=args.cbinsize)

    if args.plottype.lower() == 'lf':
        ax = plot_lf(mag[good], args.binsize, yscale=args.yscale)

        # make axis labels
        ax.set_xlabel(r'$%s$' % yfilt)
        # make axis labels for cmd, hess
        if args.filters is not None:
            if yfilt == 'I':
                yfilt = filter2
                yfilt = filter1

        ax.set_ylabel(r'$%s$' % yfilt)
        ax.set_xlabel(r'$%s-%s$' % (filter1, filter2))

    if args.ylim is not None:
        ylim = np.array(''.join(args.ylim).split(','), dtype=float)
    if args.xlim is not None:
        xlim = np.array(''.join(args.xlim).split(','), dtype=float)

    print('wrote %s' % args.outfile)

if __name__ == "__main__":
In [36]:
! chmod u+x
In [37]:
!./ -h
usage: [-h] [-p PLOTTYPE] [-f FILTERS] [-y YFILTER] [-m BINSIZE]
                     [-c CBINSIZE] [-xlim XLIM] [-ylim YLIM] [-yscale YSCALE]
                     [-x] [-outfile OUTFILE]
                     [-style {grayscale,bmh,dark_background,ggplot,fivethirtyeight,presentation}]

Generate a plot of a fits file

positional arguments:
  file                  the name of the fits file

optional arguments:
  -h, --help            show this help message and exit
  -p PLOTTYPE, --plottype PLOTTYPE
                        which plot to make: CMD, hess, or LF
  -f FILTERS, --filters FILTERS
                        comma separated V and I filter names for plot labels
  -y YFILTER, --yfilter YFILTER
                        plot V or I for LF or on y axis for cmd, Hess
  -m BINSIZE, --binsize BINSIZE
                        hess diagram or LF mag binsize
  -c CBINSIZE, --cbinsize CBINSIZE
                        hess diagram color binsize
  -xlim XLIM, --xlim XLIM
                        comma separated x axis min, max
  -ylim YLIM, --ylim YLIM
                        comma separated y axis min, max
  -yscale YSCALE, --yscale YSCALE
                        y axis scale for LF
  -x, --colorbar        add the hess diagram colorbar
  -outfile OUTFILE, --outfile OUTFILE
                        the name of the output file
  -style {grayscale,bmh,dark_background,ggplot,fivethirtyeight,presentation}, --style {grayscale,bmh,dark_background,ggplot,fivethirtyeight,presentation}
                        the name of the matplotlib style
In [4]:
! ./ -x -p hess -style presentation -f F555W,F814W -outfile hess_presentation.png hlsp_angst_hst_acs-wfc_10605-ugc-5336_f555w-f814w_v1_gst.fits
wrote hess_presentation.png


(IMO this is an advanced topic) Read more here

Real quickly, if you need to run a python script over ssh you might not want plots to be popping up, especially if you don't have X forwarding enabled. In these cases, specify the backend as "Agg".

You must put this statement above any other matplotlib import

In [39]:
import matplotlib as mpl
/Users/rosenfield/anaconda/lib/python2.7/site-packages/matplotlib/ UserWarning:  This call to matplotlib.use() has no effect
because the backend has already been chosen;
matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
or matplotlib.backends is imported for the first time.



Matplotlib plotting Gallaries

More on matplotlib styles

Pythonic access to color palettes

Simulate colorblindness

Find color palettes

General Python Resources

Python tutorials

Interfaces with Matplotlib



In [39]: