Insets and panels¶
Panel axes¶
It is often useful to have narrow “panels” along the edge of a larger
subplot for plotting secondary 1-dimensional datasets or summary statistics.
In proplot, you can generate panels using the panel_axes
command (or its shorthand, panel
). The panel location
is specified with a string, e.g. ax.panel('r')
or ax.panel('right')
for a right-hand side panel, and the resulting panels are instances of
CartesianAxes
. By default, the panel shares its axis limits,
axis labels, tick positions, and tick labels with the main subplot, but
this can be disabled by passing share=False
. To generate “stacked” panels,
call panel_axes
more than once. To generate several
panels at once, call panel_axes
on
the SubplotGrid
returned by subplots
.
In the first example below, the distances are automatically adjusted by the
tight layout algorithm according to the pad
keyword
(the default is rc['subplots.panelpad']
– this can be changed for an entire
figure by passing panelpad
to Figure
). In the second example,
the tight layout algorithm is overriden by manually setting the space
to 0
.
Panel widths are specified in physical units, with the default controlled
by rc['subplots.panelwidth']
. This helps preserve the look of the
figure if the figure size changes. Note that by default, panels are excluded
when centering spanning axis labels and super titles –
to include the panels, pass includepanels=True
to Figure
.
Important
Proplot adds panel axes by allocating new rows and columns in the
GridSpec
rather than “stealing” space from the parent
subplot (note that subsequently indexing the GridSpec
will
ignore the slots allocated for panels). This approach means that panels
do not affect subplot aspect ratios and
do not affect subplot spacing, which lets
proplot avoid relying on complicated “constrained layout” algorithms
and tends to improve the appearance of figures with even the
most complex arrangements of subplots and panels.
[1]:
import proplot as pplt
# Demonstrate that complex arrangements preserve
# spacing, aspect ratios, and axis sharing
gs = pplt.GridSpec(nrows=2, ncols=2)
fig = pplt.figure(refwidth=1.5, share=False)
for ss, side in zip(gs, 'tlbr'):
ax = fig.add_subplot(ss)
px = ax.panel_axes(side, width='3em')
fig.format(
xlim=(0, 1), ylim=(0, 1),
xlabel='xlabel', ylabel='ylabel',
xticks=0.2, yticks=0.2,
title='Title', suptitle='Complex arrangement of panels',
toplabels=('Column 1', 'Column 2'),
abc=True, abcloc='ul', titleloc='uc', titleabove=False,
)
[2]:
import proplot as pplt
import numpy as np
state = np.random.RandomState(51423)
data = (state.rand(20, 20) - 0.48).cumsum(axis=1).cumsum(axis=0)
data = 10 * (data - data.min()) / (data.max() - data.min())
# Stacked panels with outer colorbars
for cbarloc, ploc in ('rb', 'br'):
# Create figure
fig, axs = pplt.subplots(
nrows=1, ncols=2, refwidth=1.8, panelpad=0.8,
share=False, includepanels=True
)
axs.format(
xlabel='xlabel', ylabel='ylabel', title='Title',
suptitle='Using panels for summary statistics',
)
# Plot 2D dataset
for ax in axs:
ax.contourf(
data, cmap='glacial', extend='both',
colorbar=cbarloc, colorbar_kw={'label': 'colorbar'},
)
# Get summary statistics and settings
axis = int(ploc == 'r') # dimension along which stats are taken
x1 = x2 = np.arange(20)
y1 = data.mean(axis=axis)
y2 = data.std(axis=axis)
titleloc = 'upper center'
if ploc == 'r':
titleloc = 'center'
x1, x2, y1, y2 = y1, y2, x1, x2
# Panels for plotting the mean. Note SubplotGrid.panel() returns a SubplotGrid
# of panel axes. We use this to call format() for all the panels at once.
space = 0
width = '4em'
kwargs = {'titleloc': titleloc, 'xreverse': False, 'yreverse': False}
pxs = axs.panel(ploc, space=space, width=width)
pxs.format(title='Mean', **kwargs)
for px in pxs:
px.plot(x1, y1, color='gray7')
# Panels for plotting the standard deviation
pxs = axs.panel(ploc, space=space, width=width)
pxs.format(title='Stdev', **kwargs)
for px in pxs:
px.plot(x2, y2, color='gray7', ls='--')
Inset axes¶
Inset axes
can be generated with the inset_axes
command (or its
shorthand, inset
). To generate several insets at once, call
inset_axes
on the SubplotGrid
returned by subplots
. By default, inset axes have the
same projection as the parent axes, but you can also request a different
projection (e.g., ax.inset_axes(bounds, proj='polar')
). When
the axes are both CartesianAxes
, you can pass zoom=True
to inset_axes
to quickly add a “zoom indication” box and
lines (this uses indicate_inset_zoom
internally). The box
and line positions automatically follow the axis limits of the inset axes and parent
axes. To modify the zoom line properties, you can pass a dictionary to zoom_kw
.
[3]:
import proplot as pplt
import numpy as np
# Sample data
N = 20
state = np.random.RandomState(51423)
x, y = np.arange(10), np.arange(10)
data = state.rand(10, 10).cumsum(axis=0)
data = np.flip(data, (0, 1))
# Plot data in the main axes
fig, ax = pplt.subplots(refwidth=3)
m = ax.pcolormesh(data, cmap='Grays', levels=N)
ax.colorbar(m, loc='b', label='label')
ax.format(
xlabel='xlabel', ylabel='ylabel',
suptitle='"Zooming in" with an inset axes'
)
# Create an inset axes representing a "zoom-in"
# See the 1D plotting section for more on the "inbounds" keyword
ix = ax.inset(
[5, 5, 4, 4], transform='data', zoom=True,
zoom_kw={'ec': 'blush', 'ls': '--', 'lw': 2}
)
ix.format(
xlim=(2, 4), ylim=(2, 4), color='red8',
linewidth=1.5, ticklabelweight='bold'
)
ix.pcolormesh(data, cmap='Grays', levels=N, inbounds=False)
[3]:
<matplotlib.collections.QuadMesh at 0x7f734e24e340>