Beautiful Plots in Python

Note: The configurations, code, and images in this post are all available on GitHub at this repository, with a Jupyter notebook available here.

The Python matplotlib module is a very complete (if somewhat inelegant) way to plot just about any data you could want. Here’s a short list of things Matplotlib can do:

However, the defaults for matplotlib are not particularly aesthetically pleasing. Here is an example of some data plotted with the default settings:

fig, ax = plt.subplots()
ax.plot(xs, ys)
ax.legend(loc='lower left')
ax.set_title('Qualitatively Different Lines')
ax.set_xlabel('This is the x-axis')
ax.set_ylabel('Random but decaying values')

Default plot

The colors are ugly, the lines are thin, and, well, it could be worse, but it could also be a lot better.

There are a number of libraries out there that provide “upgrades” to the default styles and/or provide more options for more styles or colors (Palettable provides some lovely schemes), but I just wanted a straightforward style that would “just work”. I took the 9 colors from the ColorBrewer 2.0 “Set1” scheme, and set them as the default palette. Combining that with some thicker lines gives a much prettier plot, in my opinion12:

import mutedcolors
# Use the "muted" style I created (see below for installation)
style.use('stylelib/muted.mplstyle')
... # (Plot like above)

qualitative plot

I also created a rainbow-like colormap from this palette that goes green-blue-purple-red-orange, and created a function that will generate N colors to pair with N lines, and this allows for nice sequential plotting:

# Register new colormaps from the `mutedcolors` package
mutedcolors.new_cmaps()
# Iterate over data sets and colors at the same time, pulling colors from the
# new "grormute" (i.e., green-orange-muted) color map
for n,color,y in mutedcolors.eczip(ys.T, cmap='grormute', start=1):
    ax.plot(xs, y, color=color, label='Plot %s' % n)
... # add axes labels, legend, etc. like above

Diverging plot

Smaller Plots for Better Presentation

Another thing I’ve found is that, surprisingly, using a smaller figure size for your plots makes them more presentable. The reason for this is that the axes, labels, and lines correspondingly increase in size relative to the size of the figure. While I may already know exactly what the axes are and want to concentrate on the data in the graph, the audience / reader need to be able to see the axes themselves and read them. Here is an example:

with style.context('stylelib/small.mplstyle'):
    fig, ax = plt.subplots()
    for n,color,y in mutedcolors.eczip(ys.T, cmap='grormute', start=1):
        ax.plot(xs, y, color=color, label='Plot %s' % n)

Using Transparency

Another thing that can really make a lot of data more readable and more aesthetically pleasing is a good use of transparency. Let’s imagine each line in our data is actually the median of 20 different runs, and we want to show the variability in all these runs. We could plot each previous run as a full line, but this will get very busy… unless we use a narrower line with some transparency, so that it mostly fades into the background and leaves the median lines in the foreground. Here is an example:

for n,color,yset in mutedcolors.eczip(ys.T, cmap='grormute', start=1):
    ax.plot(xs, yset, 
            color=color,
            linewidth=1, 
            linestyle='-',
            alpha=1.5 / N_in_set)
    ax.plot(xs, np.median(yset, axis=-1),
            color=color,
            label='Plot %s' % n,
            linewidth=3,
            linestyle='-',
            alpha=1.0)

Transparency plot

Summary

Use thicker lines and good colors.

My muted style has some good defaults that I use.

I like my grormute color map, and have a function for taking series of lines and a color map and “zipping” them together. See here.

For more choices, see palettable, although it can be overwhelming.

For presentations and papers, use a smaller figure size.

This makes it easier for an audience member to read the axes labels.

An example style for that is here.

Use transparency to give some data prominence over others.

  1. To use my styles (muted or small), you can either download them into some folder, and access them with style.use('/path/to/muted.mplstyle'), or you can download them into $HOME/.config/matplotlib/stylesheet, and then access them with style.use('muted')

  2. If $HOME/.config/matplotlib/stylesheet does not exist, you may need to create it. Similarly, $HOME/.config/matplotlib is the default location for the matplotlib config directory on OSX or Linux; if its not there (or you’re on Windows), you can find it with matplotlib.get_configdir(). See the documentation for more details.