Matplotlib Tutorial

Advanced Python School in Zurich, September 2013

Basic plotting

Anscombe dataset

In [31]:
x = np.array([10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5])
y = np.array([8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26, 10.84, 4.82, 5.68])

plt.plot(x, y, 'o')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Anscombe dataset')
Out[31]:
<matplotlib.text.Text at 0x1073584d0>

Linear regression

In [32]:
a, b = np.polyfit(x, y, 1)
plt.plot(x, y, 'o')
plt.plot(x, a * x + b, '-')
Out[32]:
[<matplotlib.lines.Line2D at 0x1070af490>]

Multiple datasets

In [33]:
xvec =  np.array([[10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5],
               [10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5],
               [10, 8, 13, 9, 11, 14, 6, 4, 12, 7, 5],
               [8,8,8,8,8,8,8,19,8,8,8]]).T
yvec = np.array([[8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26, 10.84, 4.82, 5.68],
              [9.14, 8.14, 8.74, 8.77, 9.26, 8.10, 6.13, 3.10, 9.13, 7.26, 4.74],
              [7.46, 6.77, 12.74, 7.11, 7.81, 8.84, 6.08, 5.39, 8.15, 6.42, 5.73],
              [6.58, 5.76, 7.71, 8.84, 8.47, 7.04, 5.25, 12.50, 5.56, 7.91, 6.89]]).T

plt.plot(xvec, yvec, 'o');

Visual encodings

Length (plt.bar)

In [34]:
plt.title('length')
plt.bar(x, y, 1)
Out[34]:
<Container object of 11 artists>

Position and color (plt.scatter)

In [35]:
plt.title('position and color')
plt.scatter(x, y, c=y, s=100)
Out[35]:
<matplotlib.collections.PathCollection at 0x10790ba90>

Position and size (plt.scatter)

In [36]:
plt.title('position and size')
plt.scatter(x, y, s=y*20, facecolor='none')
Out[36]:
<matplotlib.collections.PathCollection at 0x107931050>

Length and angle (plt.polar)

In [37]:
theta = (x - x.min())*1./(x.max()-x.min())*2*np.pi

theta = np.vstack([theta, theta])
radius = np.vstack([np.zeros(len(y)), y])

plt.polar(theta, radius, 'b');

Creating visual style

Using style arguments

In [38]:
plt.plot(x, y, 'o', markersize=10, mfc='k')
plt.xlabel('x', size=16)
plt.ylabel('y', size=16)
plt.title('Anscombe dataset', size=16, weight='bold')
Out[38]:
<matplotlib.text.Text at 0x107364c50>

Customising globals

In [39]:
rc_defaults = matplotlib.rcParams.copy()
In [63]:
import matplotlib
matplotlib.rcParams.update({'xtick.labelsize' : 16,
                            'ytick.labelsize' : 16,
                            'axes.labelsize' : 16,
                            'axes.titlesize' : 18,
                            'lines.markersize' : 10,
                            'lines.linestyle' : 'None',
                            'lines.marker' : 'o',
                            'lines.markerfacecolor' : 'k'})

plt.plot(x, y)
plt.xlabel('x')
plt.ylabel('y')
plt.title('Anscombe dataset')
Out[63]:
<matplotlib.text.Text at 0x10aa3cf90>
In [71]:
matplotlib.rcParams.update(rc_defaults)

Using object-oriented API

In [42]:
ax = plt.subplot(111)
line, = plt.plot(x, y, 'o')
line.set_markersize(10)
line.set_mfc('k')

ticklabels = ax.get_xticklabels()
ticklabels[0].set_size(15)
ticklabels[-1].set_size(15)

plt.setp(ticklabels[1:-1], visible=False)
Out[42]:
[None, None, None, None]

Adding grid

In [75]:
plt.plot(x, y, 'ko')
plt.grid(axis='y', which='major', ls='-', lw=0.5)

Configuring spines

In [66]:
ax = plt.subplot(111)
plt.plot(x, y, 'ko', ms=10, clip_on=False)

ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_position(('outward', 20))
ax.spines['left'].set_position('center')

ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')

Annotating plots

Adding legend

In [103]:
p1, = plt.plot(xvec[:,0], yvec[:, 0], 'bo', label='dataset 1')
p2, = plt.plot(xvec[:,1], yvec[:, 1], 'ro', label='dataset 2')

#inset legend
l1 = plt.legend(frameon=False, loc='lower right')
#external legend
l2 = plt.legend((p1, p2), ('new label 1', 'new label 2'),
                ncol=2, numpoints=1,
                loc='upper left', bbox_to_anchor=(0, -0.1))
plt.gca().add_artist(l1) # re-insert first legend
Out[103]:
<matplotlib.legend.Legend at 0x10b057bd0>

Placing text

In [67]:
ax = plt.subplot(111)

plt.plot(x, y, 'bo')

plt.text(5, 10, 'Text in\ndata coords', 
         transform=ax.transData, # data coordinates (default)
         size=15, va='top')
plt.text(0.8, 0.1, 'Text in\naxes coords', 
         transform=ax.transAxes, # axes coordinates
         ma='right', ha='right', size=15)
Out[67]:
<matplotlib.text.Text at 0x106b7edd0>

Arrows

In [46]:
ax = plt.subplot(111)

plt.plot(xvec[:,2], yvec[:,2], 'ko')

ax.annotate("Outlier",
                xy=(13, 12.74), xycoords='data',
                xytext=(10, 11), textcoords='data',
                arrowprops=dict(arrowstyle="->",
                                color='r',
                                shrinkA=2, shrinkB=5,
                                connectionstyle='angle,angleA=180,angleB=90,rad=0'
                                )
            )
Out[46]:
<matplotlib.text.Annotation at 0x107d1c210>

Color

Heatmaps and colorbars

In [47]:
plt.imshow(yvec.T, interpolation='nearest')
plt.gray()
plt.colorbar(orientation='horizontal')
Out[47]:
<matplotlib.colorbar.Colorbar instance at 0x107da1128>

Color scales

In [68]:
fig, axes = plt.subplots(nrows=3, figsize=(6,2))
fig.subplots_adjust(hspace=0.4)
c = np.linspace(0, 1, 50)[None, :]

cmaps = [('Sequential','PuBu'),
         ('Diverging', 'RdBu'),
         ('Qualitative', 'Accent')]

for ax, (cname, cmap) in zip(axes, cmaps):
    ax.imshow(c, interpolation='nearest', aspect='auto', cmap=cmap)
    ax.set_ylabel(cname, rotation=0)
    ax.set_xticks([])
    ax.set_yticks([])

Custom color maps

In [49]:
from matplotlib import colors

cmap1 = colors.LinearSegmentedColormap.from_list('smooth', ['r', 'y', 'b'])
cmap2 = colors.LinearSegmentedColormap.from_list('segmented', ['r', 'y', 'b'], N=6)

fig, axes = plt.subplots(nrows=2, figsize=(6,1))
for ax, cmap in zip(axes, [cmap1, cmap2]):
    ax.imshow(c, interpolation='nearest', aspect='auto', cmap=cmap)
    ax.set_xticks([]), ax.set_yticks([])
    ax.set_ylabel(cmap.name, rotation=0)

Discretise color maps

In [50]:
def cmap_discretise(cmap, n_levels):
    original_cmap = plt.get_cmap(cmap)
    colors_i = np.concatenate((np.linspace(0, 1., n_levels), (0.,0.,0.,0.)))
    colors_rgba = original_cmap(colors_i)
    indices = np.linspace(0, 1., n_levels+1)
    cdict = {}
    for ki,key in enumerate(('red','green','blue')):
        cdict[key] = [(indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) 
                      for i in xrange(n_levels+1)] 
    discrete_cmap = colors.LinearSegmentedColormap('discrete', cdict, 1024)
    return discrete_cmap

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10, 5))
cmap = cmap_discretise('PuBu', 4)
img1 = ax1.imshow(yvec.T, interpolation='nearest', cmap='PuBu')
img2 = ax2.imshow(yvec.T, interpolation='nearest',  cmap=cmap)

Figure layout

Subplots

In [51]:
fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=True, figsize=(8,4))

ax1.plot(xvec[:, 1], yvec[:, 1], 'ko')
ax2.plot(xvec[:, 2], yvec[:, 2], 'ko')
Out[51]:
[<matplotlib.lines.Line2D at 0x106756090>]

Gridplot

In [52]:
from matplotlib import gridspec
gs = gridspec.GridSpec(4,4)

for i in range(4):
    for j in range(4):
        if i == j:
            continue
        ax = plt.subplot(gs[i, j])
        ax.plot(yvec[:, i], yvec[:, j], '.')
        plt.setp(ax.get_xticklabels(), visible=False)
        plt.setp(ax.get_yticklabels(), visible=False)

Complex layouts

In [53]:
gs = gridspec.GridSpec(2, 2)

gs_topright = gridspec.GridSpecFromSubplotSpec(2, 2, gs[0,0])

for i in range(3):
    plt.subplot(gs[i+1])
for i in range(4):
    plt.subplot(gs_topright[i])
In [53]:

Escaping the flatland

Subplots

In [54]:
for i in range(4):
    plt.subplot(2, 2, i+1)
    plt.plot(xvec[:, i], yvec[:, i], 'o')

Multiple encodings

In [55]:
plt.scatter(xvec[:, 0], yvec[:, 2], s=yvec[:, 1]*20, c=yvec[:, 0])
plt.gray()

Parallel coordinates

In [56]:
plt.subplots_adjust()
<matplotlib.figure.Figure at 0x1079dc710>