Subplots
Automatic figure size
By default, ProPlot automatically determines the suitable figure size given the geometry of your subplot grid and the size of a “reference” subplot. ProPlot can also determine the suitable figure height given a fixed figure width, and figure width given a fixed figure height.
This algorithm is controlled by the following subplots
keyword arguments:
ref
sets the reference subplot number (default is1
, i.e. the subplot in the upper left corner).aspect
sets the reference subplot aspect ratio (default is1
). You can also use the built-in matplotlibset_aspect
method.axwidth
andaxheight
set the physical dimensions of the reference subplot (default isaxwidth=2
). If one is specified, the other is calculated to satisfyaspect
. If both are specified,aspect
is ignored. The dimensions of the figure are determined automatically.width
andheight
set the physical dimensions of the figure. If one is specified, the other is calculated to satisfyaspect
and the subplot spacing. If both are specified (or if the matplotlibfigsize
parameter is specified),aspect
is ignored.journal
constrains the physical dimensions of the figure so it meets requirements for submission to an academic journal. For example, figures created withjournal='nat1'
are sized as single-column Nature figures. See this table for the list of available journal specifications (feel free to add to this table by submitting a PR).
The below examples demonstrate the default behavior of the automatic figure sizing algorithm, and how it can be controlled with subplots
keyword arguments.
Important
The automatic figure size algorithm has the following notable properties:
For very simple subplot grids (i.e. subplots created with the
ncols
andnrows
arguments), the argumentsaspect
,axwidth
, andaxheight
apply to every subplot in the figure – not just the reference subplot.When the reference subplot aspect ratio has been fixed (e.g. with
ax.set_aspect(1)
) or is set to'equal'
(as with map projections andimshow
images), the fixed aspect ratio is used and thesubplots
aspect
parameter is ignored. This is critical for getting the figure size right when working with grids of images and grids of projections.When
colorbar
s andpanel
s are present in the figure, their physical widths are preserved during figure resizing. ProPlot specifies their widths in physical units to help avoid colorbars that look “too skinny” or “too fat”.
[1]:
import proplot as plot
import numpy as np
# Auto sized grid of cartopy projections
fig, axs = plot.subplots(ncols=2, nrows=3, proj='robin')
axs.format(
land=True, landcolor='k',
suptitle='Auto figure sizing with grid of cartopy projections'
)
# Auto sized grid of images
state = np.random.RandomState(51423)
fig, axs = plot.subplots(ncols=3, nrows=2, axwidth=1.7)
colors = state.rand(15, 12, 3).cumsum(axis=2)
colors /= colors.max()
axs.imshow(colors)
axs.format(
suptitle='Auto figure sizing with grid of images'
)
[2]:
import proplot as plot
# Change the reference subplot width
suptitle = 'Effect of subplot width on figure size'
for axwidth in ('4cm', '6cm'):
fig, axs = plot.subplots(ncols=2, axwidth=axwidth,)
axs[0].format(
suptitle=suptitle,
title=f'axwidth = {axwidth}', titleweight='bold',
titleloc='uc', titlecolor='red9',
)
# Change the reference subplot aspect ratio
for aspect in (1, (3, 2)):
fig, axs = plot.subplots(ncols=2, nrows=2, axwidth=1.6, aspect=aspect)
axs[0].format(
suptitle='Effect of subplot aspect ratio on figure size',
title=f'aspect = {aspect}', titleweight='bold',
titleloc='uc', titlecolor='red9',
)
[3]:
import proplot as plot
# Change the reference subplot in presence of unequal width/height ratios
for ref in (1, 2):
fig, axs = plot.subplots(
ref=ref, nrows=3, ncols=3, wratios=(3, 2, 2),
axwidth=1.1,
)
axs[ref - 1].format(
suptitle='Effect of reference subplot on figure size',
title='reference', titleweight='bold',
titleloc='uc', titlecolor='red9'
)
# Change the reference subplot in a complex grid
for ref in (1, 2):
fig, axs = plot.subplots(
[[1, 2], [1, 3]],
ref=ref, axwidth=1.8, span=False
)
axs[ref - 1].format(
suptitle='Effect of reference subplot on figure size',
title='reference', titleweight='bold',
titleloc='uc', titlecolor='red9'
)
Automatic subplot spacing
In addition to automatic figure sizing, by default ProPlot applies a tight layout algorithm to every figure. This algorithm automatically adjusts the space between subplot rows and columns and the figure edge to accommodate labels. It can be disabled by passing tight=False
to subplots
. While matplotlib has its own tight layout algorithm, ProPlot’s algorithm may change the figure size to accommodate the correct spacing and permits variable spacing between subsequent subplot rows and columns (see the new GridSpec
class for details).
The tight layout algorithm can also be overridden. When you use any of the spacing arguments left
, right
, top
, bottom
, wspace
, or hspace
, that value is always respected. For example:
left='2em'
fixes the left margin width, while the right, bottom, and top margin widths are determined automatically.wspace='1em'
fixes the spaces between subplot columns, while the spaces between subplot rows are determined automatically.wspace=('3em', None)
fixes the space between the first two columns of a three-column plot, while the space between the second two columns is determined automatically.
The below examples demonstrate how the tight layout algorithm permits variable spacing between subplot rows and columns.
[4]:
import proplot as plot
# Automatic spacing for all margins and between all columns and rows
fig, axs = plot.subplots(nrows=3, ncols=3, axwidth=1.1, share=0)
# Formatting that stress-tests the algorithm
axs[4].format(
title='title\ntitle\ntitle',
suptitle='Tight layout with variable row-column spacing'
)
axs[1].format(ylabel='ylabel\nylabel\nylabel')
axs[:4:2].format(xlabel='xlabel\nxlabel\nxlabel')
axs.format(
rowlabels=['Row 1', 'Row 2', 'Row 3'],
collabels=['Column 1', 'Column 2', 'Column 3']
)
[5]:
import proplot as plot
# Manual spacing for certain margins and between certain columns and rows
fig, axs = plot.subplots(
ncols=4, nrows=3, axwidth=1.1, span=False,
bottom='5em', right='5em', # margin spacing overrides
wspace=(0, 0, None), hspace=(0, None), # column and row spacing overrides
)
# Formatting that stress-tests the algorithm
axs.format(
xlim=(-1.5, 1.5), ylim=(-1.5, 1.5), xlocator=1, ylocator=1,
suptitle='Tight layout with user overrides',
rowlabels=['Row 1', 'Row 2', 'Row 3'],
collabels=['Column 1', 'Column 2', 'Column 3', 'Column 4']
)
axs[0, :].format(xtickloc='top')
axs[2, :].format(xtickloc='both')
axs[:, 1].format(ytickloc='neither')
axs[:, 2].format(ytickloc='right')
axs[:, 3].format(ytickloc='both')
axs[-1, :].format(title='Title\nTitle\nTitle', xlabel='xlabel')
axs[:, 0].format(ylabel='ylabel\nylabel')
Axis sharing
Redundant labels are a common problem for figures with lots of subplots. To address this, matplotlib.pyplot.subplots
includes sharex
and sharey
keywords that permit sharing axis limits, ticks, and tick labels between like rows and columns of subplots. ProPlot expands upon this feature by (1) adding an option for sharing labels in the same row or column of the GridSpec
, controlled by the spanx
and spany
keywords, and (2) adding four axis-sharing “levels,” controlled by the sharex
and sharey
keywords. The axis-sharing levels are defined as follows:
Level
0
disables axis sharing.Level
1
shares duplicate x and y axis labels, but nothing else.Level
2
is the same as1
, but the x and y axis limits, ticks, and scales are also shared.Level
3
is the same as2
, but the x and y tick labels are also shared.
Axis and label sharing works for arbitrarily complex grids of subplots. The below examples demonstrate the effect of various axis and label sharing settings on the appearance of simple subplot grids.
[6]:
import proplot as plot
import numpy as np
N = 50
M = 40
state = np.random.RandomState(51423)
colors = plot.Colors('grays_r', M, left=0.1, right=0.8)
datas = []
for scale in (1, 3, 7, 0.2):
data = scale * (state.rand(N, M) - 0.5).cumsum(axis=0)[N // 2:, :]
datas.append(data)
# Same plot with different sharing and spanning settings
for share in (0, 1, 2, 3):
fig, axs = plot.subplots(
ncols=4, aspect=1, axwidth=1.06,
sharey=share, spanx=share // 2
)
for ax, data in zip(axs, datas):
on = ['off', 'on'][share // 2]
ax.plot(data, cycle=colors)
ax.format(
suptitle=f'Sharing level {share}, spanning labels {on}',
grid=False, xlabel='spanning', ylabel='shared'
)
[7]:
import proplot as plot
import numpy as np
plot.rc.reset()
plot.rc.cycle = 'Set3'
state = np.random.RandomState(51423)
titles = ['With redundant labels', 'Without redundant labels']
# Same plot with and without default sharing settings
for mode in (0, 1):
fig, axs = plot.subplots(
nrows=4, ncols=4, share=3 * mode,
span=1 * mode, axwidth=1
)
for ax in axs:
ax.plot((state.rand(100, 20) - 0.4).cumsum(axis=0))
axs.format(
xlabel='xlabel', ylabel='ylabel', suptitle=titles[mode],
abc=True, abcloc='ul',
grid=False, xticks=25, yticks=5
)
A-b-c subplot labels
ProPlot can be used to add “a-b-c” labels to subplots. This is possible because subplots
assigns unique number
s to each subplot. If you passed an array to subplots
, the subplot numbers correspond to the numbers in the array. If you used the ncols
and nrows
keyword arguments, the number order is row-major by default but can be switched to column-major by passing order='F'
to subplots
. The number order also determines the subplot order in the SubplotsContainer
returned by subplots
.
To turn on “a-b-c” labels, set [rc.abc](https://proplot.readthedocs.io/en/latest/configuration.html?highlight=abc#rc-proplot)
to True
or pass abc=True
to format
(see the format command for details). To change the label style, modify [rc[‘abc.style’]](https://proplot.readthedocs.io/en/latest/configuration.html?highlight=abc.style#rc-proplot)
or pass e.g. abcstyle='A.'
to format
. You can also modify the “a-b-c” label location, weight, and size with the [rc[‘abc.loc’]](https://proplot.readthedocs.io/en/latest/configuration.html?highlight=abc.loc#rc-proplot)
, [rc[‘abc.weight’]](https://proplot.readthedocs.io/en/latest/configuration.html?highlight=abc.weight#rc-proplot)
, and [rc[‘abc.size’]](https://proplot.readthedocs.io/en/latest/configuration.html?highlight=abc.size#rc-proplot)
settings.
[8]:
import proplot as plot
fig, axs = plot.subplots(nrows=8, ncols=8, axwidth=0.7, space=0)
axs.format(
abc=True, abcloc='ur', xlabel='x axis', ylabel='y axis',
xticks=[], yticks=[], suptitle='Subplot labels demo'
)
Arbitrary physical units
ProPlot supports arbitrary physical units for controlling the figure width
and height
, the reference subplot axwidth
and axheight
, the gridspec spacing values left
, right
, bottom
, top
, wspace
, and hspace
, and in a few other places, e.g. panel
and colorbar
widths. This feature is powered by the units
function.
If a sizing argument is numeric, the units are inches or points; if it is string, the units are converted to inches or points by units
. A table of acceptable units is found in the units
documentation. They include centimeters, millimeters, pixels, em-heights), en-heights), and points).
[9]:
import proplot as plot
import numpy as np
with plot.rc.context(fontsize='12px'):
fig, axs = plot.subplots(
ncols=3, width='15cm', height='3in',
wspace=('10pt', '20pt'), right='10mm'
)
cmap = plot.Colormap('Mono')
cb = fig.colorbar(
cmap, loc='b', extend='both', label='colorbar',
width='2em', extendsize='3em', shrink=0.8,
)
pax = axs[2].panel('r', width='5en')
pax.format(xlim=(0, 1))
axs.format(
suptitle='Arguments with arbitrary units',
xlabel='x axis', ylabel='y axis',
xlim=(0, 1), ylim=(0, 1),
)