So, you need to include a contour plot in some publication of yours, little one? There are two things that you must learn. But beware! The first will raise your spirits, while the second will quicken your descent into madness. These facts I address to you, should you stand to read them: (1) matplotlib has a really customisable contour plot implementation; (2) the convenience functions are few, and the necessary keyword arguments are confusing.
I’m prepping a bunch of contour plots for a publication in a quick letter at the moment, and want to improve their legibility. This involves things like making all of the lines thicker, increasing the font size of the labels (both on the axes and on the contours themselves), and changing the contour scaling. Some of these modifications have proven more difficult than others with matplotlib, so I thought I’d jot down a couple of examples here for reference. (The matplotlib contour examples are useful, but don’t cover everything.)
First of all, let’s change the width and length of the ticks on each axis, and the size of the font of the labels for each tick.
import pylab as P
MP_LINEWIDTH = 2.4
MP_TICKSIZE = 10.
for tick in P.gca().xaxis.get_major_ticks():
The call to
P.rc() changes the thickness of all of the axis lines on the plot (i.e. it changes the global properties, and isn’t restricted to just one plot). The other stuff could probably be done using calls to
rc(), but that’s an exercise for another time.
An example of a customised contour plot in matplotlib.
The loop is over all major ticks on the x axis of the current subplot. (The call to
gca() gets the current set of plot axes, but of course you could use the
xaxis.get_minor_ticks() method from any previously-defined axes object.) The object
tick1line is the x-axis at the bottom of the plot, and
tick2line is at the top.
Inside the loop, I’m setting the font size of the tick label (the number that appears below each tick), the width of the tick (using the
markeredgewidth property), and the length of the tick (using
markersize). You can also do things like hiding certain ticks, hiding certain labels (especially useful if you want to remove the tick label at the origin, because it overlaps with the label for the other axis there), changing the appearance of gridlines (somewhat unintuitively), and so on. There’s a list of all the tick-related objects that you can change here.
This will only change the tick styles for the minor ticks on the x axis. To cover all of the ticks on the plot, you’ll need to loop through all the minor ticks using
P.gca().xaxis.get_minor_ticks() too, and then do both major and minor ticks for the y axis (using
P.gca().yaxis) as well.
Changing which values contours are drawn at, and how they are labeled
To change where the contours are drawn, you need to change the contour locator. This is a keyword argument to
contour(), and requires a ticker object. There’s a list of built-in tickers here. In the example below, I wanted a log scaling for my plots, so I used
It’s also useful to be able to change the labels that are added to the contours.For this, you need to use the
clabel() function (which controls contour labels) and manipulate the formatter, using the
fmt keyword. A list of formatters is given here, with more documentation on them (including formatter-specific keyword arguments for further customisation) given further down that page. Particularly useful formatters include:
LogFormatterMathtext (which add LaTeX mathmode labels, especially useful for numbers with exponents)
FormatStrFormatter (which lets you use a C-like format string to determine how significant figures, signs, etc. are displayed)
FuncFormatter (which lets you define a custom function to handle string formatting)
Setting the font size of the contour label is as easy as changing the
fontsize keyword of
Finally, a subtlety of
contour() is its use of the
linewidths keyword, rather than
linewidth (as with other pylab functions). It works exactly the same otherwise.
from matplotlib import ticker
ctr = P.contour(X, Y, Z, locator=ticker.LogLocator(), colors='k', linewidths=3.0)
P.clabel(ctr, inline=1, fontsize=20., fmt=ticker.LogFormatterMathtext())