10

In a matplotlib figure I would like to enumerate all (sub)plots with a), b), c) and so on. Is there a way to do this automatically?

So far I use the individual plots' titles, but that is far from ideal as I want the number to be left aligned, while an optional real title should be centered on the figure.

Se Norm
  • 1,715
  • 5
  • 23
  • 40
  • As a side note, each axes actually has three titles (left, right, center), but I don't remember if that was in 1.3 or still just on master. – tacaswell Mar 19 '14 at 14:50

3 Answers3

7
import string
from itertools import cycle
from six.moves import zip

def label_axes(fig, labels=None, loc=None, **kwargs):
    """
    Walks through axes and labels each.

    kwargs are collected and passed to `annotate`

    Parameters
    ----------
    fig : Figure
         Figure object to work on

    labels : iterable or None
        iterable of strings to use to label the axes.
        If None, lower case letters are used.

    loc : len=2 tuple of floats
        Where to put the label in axes-fraction units
    """
    if labels is None:
        labels = string.ascii_lowercase

    # re-use labels rather than stop labeling
    labels = cycle(labels)
    if loc is None:
        loc = (.9, .9)
    for ax, lab in zip(fig.axes, labels):
        ax.annotate(lab, xy=loc,
                    xycoords='axes fraction',
                    **kwargs)

example usage:

from matplotlib import pyplot as plt
fig, ax_lst = plt.subplots(3, 3)
label_axes(fig, ha='right')
plt.draw()

fig, ax_lst = plt.subplots(3, 3)
label_axes(fig, ha='left')
plt.draw()

This seems useful enough to me that I put this in a gist : https://gist.github.com/tacaswell/9643166

sjrowlinson
  • 3,297
  • 1
  • 18
  • 35
tacaswell
  • 84,579
  • 22
  • 210
  • 199
2

I wrote a function to do this automatically, where the label is introduced as a legend:

import numpy
import matplotlib.pyplot as plt

def setlabel(ax, label, loc=2, borderpad=0.6, **kwargs):
    legend = ax.get_legend()
    if legend:
        ax.add_artist(legend)
    line, = ax.plot(numpy.NaN,numpy.NaN,color='none',label=label)
    label_legend = ax.legend(handles=[line],loc=loc,handlelength=0,handleheight=0,handletextpad=0,borderaxespad=0,borderpad=borderpad,frameon=False,**kwargs)
    label_legend.remove()
    ax.add_artist(label_legend)
    line.remove()

fig,ax = plt.subplots()
ax.plot([1,2],[1,2])
setlabel(ax, '(a)')
plt.show()

The location of the label can be controlled with loc argument, the distance to the axis can be controlled with borderpad argument (negative value pushes the label to be outside the figure), and other options available to legend also can be used, such as fontsize. The above script gives such figure: setlabel

Hongcheng Ni
  • 427
  • 1
  • 4
  • 11
0

A super quick way to do this is to take advantage of the fact that chr() casts integers to characters. Since a-z fall in the range 97-122, one can do the following:

import matplotlib.pyplot as plt

fig,axs = plt.subplots(2,2)
for i,ax in enumerate(axs.flat, start=97):
  ax.plot([0,1],[0,1])
  ax.text(0.05,0.9,chr(i)+')', transform=ax.transAxes)

which produces:

subplots

compuphys
  • 1,289
  • 12
  • 28