ProPlot’s core mission is to improve upon the parts of matplotlib that tend to be cumbersome or repetitive for power users. This page enumerates the stickiest of these limitations and describes how ProPlot addresses them.
Less typing, more plotting¶
Power users often need to change lots of plot settings all at once. In matplotlib, this requires calling a series of one-liner setter methods.
This workflow is quite verbose – it tends to require “boilerplate code” that gets copied and pasted a hundred times. It can also be confusing – it is often unclear whether properties are applied from an
Axes setter (e.g.
YAxis setter (e.g.
Spine setter (e.g.
set_bounds), a random “bulk” setter (e.g.
tick_params), or whether they require tinkering with several different objects. Also, one often needs to loop through lists of subplots to apply identical settings to each subplot.
ProPlot introduces the
format method for changing arbitrary settings in bulk. Think of this as an expanded and thoroughly documented version of the
For even more efficiency,
be used to locally apply various rcParams and Bulk global settings to particular axes,
The subplot container class can be used to identically apply
settings to several axes at once, and Class constructor functions
are used by
format (and in several other places)
to concisely generate complex, verbose class instances like
Together, these features significantly reduce the amount of code needed to create highly customized figures. As an example, it is trivial to see that
import proplot as plot f, axs = plot.subplots(ncols=2) axs.format(linewidth=1, color='gray') axs.format(xticks=20, xtickminor=True, xlabel='x axis', ylabel='y axis')
…is much more succinct than
import matplotlib.pyplot as plt import matplotlib.ticker as mticker from matplotlib import rcParams rcParams['axes.linewidth'] = 1 rcParams['axes.color'] = 'gray' fig, axs = plt.subplots(ncols=2) for ax in axs: ax.xaxis.set_major_locator(mticker.MultipleLocator(10)) ax.tick_params(width=1, color='gray', labelcolor='gray') ax.tick_params(axis='x', which='minor', bottom=True) ax.set_xlabel('x axis', color='gray') ax.set_ylabel('y axis', color='gray') plt.style.use('default') # restore
Class constructor functions¶
Matplotlib and cartopy introduce a bunch of classes with verbose names like
LambertAzimuthalEqualArea. Since plotting code has a half life of about 30 seconds, typing out all of these extra class names and import statements can be a major drag.
Certain parts of the matplotlib API were designed with this in mind. Backend classes, native axes projections, axis scales, box style classes, arrow style classes, and arc style classes are referenced with “registered” string names, as are basemap projection types. If these are already “registered”, why not “register” everything else?
In ProPlot, tick locators, tick formatters, axis scales, cartopy projections, colormaps, and property cyclers are all “registered”. This is done by creating several constructor functions and passing various keyword argument through the constructor functions. This may seem “unpythonic” but it is absolutely invaluable when writing plotting code.
Each constructor function accepts various other input types for your convenience. For
example, scalar numbers passed to
MultipleLocator instance, lists of strings passed
Formatter returns a
FixedFormatter instance, and
Cycle accept colormap names, individual colors, and lists of colors. When a class instance is passed to the relevant constructor function, it is simply returned. See X and Y axis settings, Colormaps, and Color cycles for details.
The below table lists the constructor functions and the keyword arguments that use them.
1d plotting methods
2d plotting methods
2d plotting methods
now accept instances of
ScaleBase thanks to a monkey patch
applied by ProPlot.
Automatic dimensions and spacing¶
Matplotlib plots tend to require lots of “tweaking” when you have more than one subplot in the figure. This is partly because you must specify the physical dimensions of the figure, while the dimensions of the individual subplots are more important:
The subplot aspect ratio is usually more relevant than the figure aspect ratio, e.g. for map projections.
The subplot width and height control the evident thickness of text and other content plotted inside the axes.
Matplotlib has a tight layout algorithm to keep you from having to “tweak” the spacing, but the algorithm cannot apply different amounts of spacing between different subplot row and column boundaries. This is a silly limitation that often results in unnecessary whitespace, and can be a major problem when you want to put e.g. a legend on the outside of a subplot.
In ProPlot, you can specify the physical dimensions of a reference subplot instead of the figure by passing
Figure. The default behavior is
axwidth=2 (inches). If the aspect ratio mode for the reference subplot is set to
'equal', as with Geographic and polar plots and
imshow plots, the existing aspect will be used instead.
Figure dimensions are constrained as follows:
axheightare used, the figure width and height are calculated automatically.
widthis used, the figure height is calculated automatically.
heightis used, the figure width is calculated automatically.
figsizeis used, the figure dimensions are fixed.
By default, ProPlot also uses a custom tight layout algorithm that automatically determines the
GridSpec parameters. This algorithm is simpler and more precise because:
GridSpecclass permits variable spacing between rows and columns. It turns out this is critical for putting Colorbars and legends on the outside of subplots.
Figures are restricted to have only one
GridSpecper figure. This is done by requiring users to draw all of their subplots at once with
subplots, and it considerably simplifies the algorithm (see GH#50 for details).
See Subplots features for details.
Outer colorbars and legends¶
In matplotlib, it is difficult to draw
legends on the outside of subplots. It is very easy to mess up the subplot aspect ratios and the colorbar widths. It is even more difficult to draw
legends that reference more than one subplot:
Matplotlib has no capacity for drawing colorbar axes that span multiple plots – you have to create the axes yourself. This requires so much tinkering that most users just add identical colorbars to every single subplot!
Legends that span multiple plots tend to require manual positioning and tinkering with the
GridSpecspacing, just like legends placed outside of individual subplots.
ProPlot introduces a brand new engine for drawing colorbars and legends along the outside of individual subplots and along contiguous subplots on the edge of the figure:
legenddraws the colorbar or legend along the outside of the axes.
legenddraws the colorbar or legend along the edge of the figure, centered relative to the subplot grid rather than figure coordinates.
Outer colorbars and legends don’t mess up the subplot layout or subplot aspect ratios, since
GridSpecpermits variable spacing between subplot rows and columns. This is critical e.g. if you have a colorbar between columns 1 and 2 but nothing between columns 2 and 3.
Axescolorbar widths are specified in physical units rather than relative units. This makes colorbar thickness independent of figure size and easier to get just right.
The colorbar and legend commands also add several new features, like colorbars-from-lines and centered-row legends. And to make
colorbar consistent with
legend, you can also now draw inset colorbars. See Colorbars and legends for details.
The subplot container class¶
subplots returns a 2D
ndarray, a 1D
ndarray, or the axes itself. This inconsistent behavior can be confusing.
subplots returns a
This container lets you call arbitrary methods on arbitrary subplots all at once, which can be useful when you want to style your subplots identically (e.g.
subplot_grid class also
unifies the behavior of the three possible
matplotlib.pyplot.subplots return values:
subplot_gridpermits 2d indexing, e.g.
subplotscan generate figures with arbitrarily complex subplot geometry, this 2d indexing is useful only when the arrangement happens to be a clean 2d matrix.
listsubclass, it also supports 1d indexing, e.g.
axs. The default order can be switched from row-major to column-major by passing
subplot_gridbehaves like a scalar when it is singleton. So if you just made a single axes with
f, axs = plot.subplots(), calling
axs.commandis equivalent to
See The basics for details.
New and improved plotting methods¶
Certain plotting tasks are quite difficult to accomplish
with the default matplotlib API. The
packages offer improvements, but it would be nice
to have this functionality build right into matplotlib.
There is also room for improvement that none of these packages
ProPlot adds various
Axes plotting methods
along with several brand new features designed to
make your life easier.
fill_betweenx. The new
pcolormeshand draws ticks at the center of each box.
parametricmethod draws parametric line plots, where the parametric coordinate is denoted with colormap colors.
barhaccept 2D arrays and stack or group successive columns. Soon you will be able to use different colors for positive/negative bars.
fill_betweenxnow accept 2D arrays and stack or overlay successive columns. You can also use different colors for positive/negative data.
All 1d plotting methods accept a
cyclekeyword argument interpreted by
colorbarkeyword arguments for populating legends and colorbars at the specified location with the result of the plotting command. See Color cycles and Colorbars and legends.
All 2d plotting methods accept a
cmapkeyword argument interpreted by
normkeyword argument interpreted by
Norm, and an optional
colorbarkeyword argument for drawing on-the-fly colorbars with the resulting mappable. See Colormaps and Colorbars and legends.
All 2d plotting methods accept a
labelskeyword argument. This is used to draw contour labels or grid box labels on heatmap plots. Labels are colored black or white according to the luminance of the underlying filled contour or grid box color. See 2d plotting for details.
ProPlot fixes the irritating white-lines-between-filled-contours, white-lines-between-pcolor-patches, and white-lines-between-colorbar-patches vector graphic issues.
Matplotlib requires coordinate centers for contour plots and edges for pcolor plots. If you pass centers to pcolor, matplotlib treats them as edges and silently trims one row/column of your data. ProPlot changes this behavior:
If edges are passed to
contourf, centers are calculated from the edges
If centers are passed to
pcolormesh, edges are estimated from the centers.
Xarray and pandas integration¶
When you pass the array-like
pandas.Series containers to matplotlib plotting commands, the metadata is ignored. To create plots that are automatically labeled with this metadata, you must use
This approach is fine for quick plots, but not ideal.
It requires learning a different syntax from matplotlib, and tends to encourage using the
pyplot API rather than the object-oriented API.
These tools also introduce features that would be useful additions to matplotlib
in their own right, without requiring special data containers and
an entirely separate API.
ProPlot reproduces most of the
pandas.Series.plot features on the
Axes plotting methods themselves.
any plotting method automatically updates the
axis tick labels, axis labels, subplot titles, and colorbar and legend labels
from the metadata. This can be disabled by passing
autoformat=False to the plotting method or to
Also, as described in New and improved plotting methods, ProPlot implements certain
features like grouped bar plots, layered area plots, heatmap plots,
and on-the-fly colorbars and legends from the
pandas APIs directly on the
Cartopy and basemap integration¶
There are two widely-used engines
for plotting geophysical data with matplotlib:
Using cartopy tends to be quite verbose and involve lots of boilerplate code,
while basemap is outdated and requires you to use plotting commands on a separate
basemap plotting commands assume
map projection coordinates unless specified otherwise. For most of us, this
choice is very frustrating, since geophysical data are usually stored in
longitude-latitude or “Plate Carrée” coordinates.
ProPlot integrates various
This lets you apply all kinds of geographic plot settings, like coastlines, continents, political boundaries, and meridian and parallel gridlines.
overrides various plotting methods:
transform=ccrs.PlateCarree()is the new default for all
latlon=Trueis the new default for all
globe=Truecan be passed to any 2D plotting command to enforce global coverage over the poles and across the longitude boundaries.
See Geographic and polar plots for details.
Note that active development on basemap will halt after 2020.
For now, cartopy is
missing several features
offered by basemap – namely, flexible meridian and parallel gridline labels,
drawing physical map scales, and convenience features for adding background images like
the “blue marble”. But once these are added to cartopy, ProPlot may remove the
basemap integration features.
Colormaps and property cycles¶
In matplotlib, colormaps are implemented with the
They are hard to edit and hard to create from scratch.
In ProPlot, it is easy to manipulate colormaps and property cycles:
Colormapconstructor function can be used to slice and merge existing colormaps and/or generate brand new ones.
Cycleconstructor function can be used to make color cycles from colormaps! These cycles can be applied by passing the
cyclekeyword argument to plotting commands or changing the
rc.cyclesetting. See Color cycles for details.
LinearSegmentedColormapclasses include several new methods, e.g.
concatenate, and have a much nicer REPL representation.
PerceptuallyUniformColormapclass is used to make Perceptually uniform colormaps. These have smooth, aesthetically pleasing color transitions represent your data accurately.
Importing ProPlot also makes all colormap names case-insensitive, and colormaps can be reversed or cyclically shifted by 180 degrees simply by appending
'_shifted' to the colormap name. This is powered by the
CmapDict dictionary, which replaces matplotlib’s native colormap database.
Smarter colormap normalization¶
In matplotlib, when
extend='neither' is passed to
colorbar , the colormap colors reserved for “out-of-bounds” values are truncated. The problem is that matplotlib discretizes colormaps by generating a low-resolution lookup table (see
LinearSegmentedColormap for details).
This approach cannot be fine-tuned and creates an unnecessary copy of the colormap.
It is clear that the task discretizing colormap colors should be left to the normalizer, not the colormap itself. Matplotlib provides
BoundaryNorm for this purpose, but it is seldom used and its features are limited.
In ProPlot, all colormap visualizations are automatically discretized with the
BinNorm class. This reads the
extend property passed to your plotting command and chooses colormap indices so that your colorbar levels always traverse the full range of colormap colors.
BinNorm also applies arbitrary continuous normalizer requested by the user, e.g.
LogNorm, before discretization. Think of
BinNorm as a “meta-normalizer” – other normalizers perform the continuous transformation step, while this performs the discretization step.
Bulk global settings¶
In matplotlib, there are several
rcParams that you often
want to set all at once, like the tick lengths and spine colors.
It is also often desirable to change these settings for individual subplots
or individual blocks of code rather than globally.
In ProPlot, you can use the
rc object to
change lots of settings at once with convenient shorthands.
This is meant to replace matplotlib’s
dictionary. Settings can be changed with
plot.rc.key = value,
plot.rc[key] = value,
plot.rc.update(...), with the
format method, or with the
For details, see Configuring proplot. The most notable bulk settings are described below.
The color for axes bounds, ticks, and labels.
The width of axes bounds and ticks.
Font size for “small” labels.
Font size for “large” labels.
Padding between ticks and labels.
Ratio between major and minor tick lengths.
Margin width when limits not explicitly set.
Physical units engine¶
Matplotlib requires users to use
inches for the figure size
figsize. This must be confusing for users outside
of the U.S.
Matplotlib also uses figure-relative units for the margins
top, and axes-relative units
for the column and row spacing
Relative units tend to require “tinkering” with meaningless numbers until you find the
right one… and then if your figure size changes, you have to adjust them again.
ProPlot introduces the physical units engine
hspace, and arguments
in a few other places. Acceptable units include inches, centimeters,
millimeters, pixels, points,
picas, em-heights, and light years (because why not?).
Em-heights are particularly useful, as labels already
present can be useful rulers for figuring out the amount
of space needed.
units is also used to convert settings
rc from arbitrary physical units
to points – for example,
See Configuring proplot for details.
The .proplot folder¶
In matplotlib, it can be difficult to design your
own colormaps and color cycles, and there is no builtin
way to save them for future use. It is also quite
difficult to get matplotlib to use custom
.otf font files, which may be desirable when you are
working on Linux servers with limited font selections.
ProPlot automatically adds colormaps, color cycles, and font files
saved in the
folders in your home directory.
You can save colormaps and color
cycles to these folders simply by passing
To manually load from these folders, e.g. if you have added
files to these folders but you do not want to restart your
ipython session, simply call