Subplots features

Automatic layout

By default, ProPlot automatically determines the suitable figure width and height for your subplot grid. The figure dimensions are constrained by the dimensions of the reference subplot. In practice, this usually sets the properties for all subplots, unless your subplots have different aspect ratios or your subplot grid is very complex.

This feature is controlled by a variety of subplots keyword arguments.

  • To set the reference subplot, use ref (default is 1, i.e. the subplot in the upper left corner). To set the refernce subplot aspect ratio, use aspect (default is 1).

  • If you use either axwidth or axheight, both figure dimensions are determined automatically and the reference subplot aspect ratio is preserved (default is axwidth=2).

  • If you use either width or height, the other figure dimension is determined automatically and the reference subplot aspect ratio is preserved.

  • If you use both width and height (or figsize, which is a (width, height) tuple), the figure dimensions are fixed and the reference subplot aspect ratio is not preserved.

  • When the ref subplot aspect ratio mode is set to 'equal', as with Geographic and polar plots and imshow plots, the existing aspect will be used instead of the input aspect.

By default, ProPlot also applies a tight layout algorithm to every figure. This algorithm automatically adjusts the space between subplot rows and columns and the figure edge to accomadate labels. Matplotlib has its own tight layout algorithm, but ProPlot’s algorithm may change the figure dimensions (depending on the keyword arguments you passed to subplots) and permits variable spacing between subsequent subplot rows and columns, thanks to the new GridSpec class.

ProPlot’s tight layout algorithm can also be easily overridden. When you pass a spacing argument like left, right, top, bottom, wspace, or hspace to subplots, that value is always respected.

  • If you pass left='2em' to subplots, the left margin is fixed but the right, bottom, and top margins are determined automatically.

  • If you pass wspace=('3em', None) and ncols=3 to subplots, the space between the first two columns is fixed, while the space between the second two columns is determined automatically.

The below examples are stress tests of the tight layout algorithm and demonstrate how “reference axes” affect the figure appearence. Note that since ProPlot colorbar and panel widths are specified in physical units, they are held fixed during resizing. This helps us avoid colorbars that look “too skinny” or “too fat”.

import proplot as plot
for ref in (1, 2):
    f, axs = plot.subplots(
        ref=ref, nrows=3, ncols=3, wratios=(3, 2, 2),
        axwidth=1.1, share=0)
        title='reference axes', titleweight='bold',
        titleloc='uc', titlecolor='red9')
        suptitle='Tight layout with simple grids')
    axs.format(rowlabels=['Row 1', 'Row 2', 'Row 3'],
               collabels=['Column 1', 'Column 2', 'Column 3'])
import proplot as plot
for ref in (4, 2):
    f, axs = plot.subplots(
        [[1, 1, 2], [3, 3, 2], [4, 5, 5], [4, 6, 6]],
        hratios=(1, 1, 2, 2), wratios=(3, 2, 3),
        ref=ref, axwidth=1.1, span=False)
        title='reference axes', titleweight='bold',
        titleloc='uc', titlecolor='red9')
    axs.format(xlabel='xlabel', ylabel='ylabel', suptitle='Super title')
        ylabel='ylabel\nylabel\nylabel', ytickloc='both',
        yticklabelloc='both', ctitle='Title')
        yformatter='null', ctitle='Title',
        ytickloc='both', yticklabelloc='both')
    axs[4:].format(yformatter='null', xlabel='xlabel\nxlabel\nxlabel')
    axs.format(suptitle='Tight layout with complex grids', rowlabels=[
               'Row 1', 'Row 2', 'Row 3'], collabels=['Column 1', 'Column 2'])

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.

If a sizing argument is numeric, the units are inches or points, and if string, the units are interpreted by units. A table of acceptable units is found in the units documentation. They include centimeters, millimeters, pixels, em-heights, and points.

import proplot as plot
import numpy as np
with plot.rc.context(small='12px', large='15px', linewidth='0.5mm'):
    f, axs = plot.subplots(
        ncols=3, width='13cm', height='2in',
        wspace=('10pt', '20pt'), right='10mm')
panel = axs[2].panel_axes('r', width='2em')
axs.format(suptitle='Arguments with arbitrary units',
           xlabel='x axis', ylabel='y axis')

Subplot numbers and labels

ProPlot assigns unique numbers to subplots. The number order determines the order the subplots appear in the subplot_grid and the order of “a-b-c” labels generated by format. If you did not provide a 2D array, the number order is row-major by default but can be made column-major by passing order='F' to subplots. The “a-b-c” label position and style can be changed with format.

import proplot as plot
f, 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='Flush subplot grid')

Shared and spanning labels

Matplotlib has an “axis sharing” feature that holds axis limits the same for axes within a grid of subplots. But this has no effect on the axis labels and tick labels, which can lead to lots of redundancies.

To help you eliminate these redundancies, ProPlot introduces four axis-sharing options and a new spanning label option, controlled by the share, sharex, sharey, span, spanx, and spany subplots keyword args. “Sharing level” 1 hides inner x and y axis labels. “Sharing level” 2 is the same as 1, but the x and y axis limits are locked. “Sharing level” 3 is the same as 2, but the x and y tick labels are hidden. “Spanning labels” are centered x and y axis labels used for subplots whose spines are on the same row or column. See the below example.

Note that the the “shared” and “spanning” axes are determined automatically based on the extent of each subplot in the GridSpec. Since ProPlot uses just one GridSpec per figure, this can be done with zero ambiguity.

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:, :]
for share in (0, 1, 2, 3):
    f, axs = plot.subplots(ncols=4, aspect=1, axwidth=1.2,
                           sharey=share, spanx=share//2)
    for ax, data in zip(axs, datas):
        ax.plot(data, cycle=colors)
        ax.format(suptitle=f'Axis-sharing level: {share}, spanning labels {["off","on"][share//2]}',
                  grid=False, xlabel='spanning', ylabel='shared')
import proplot as plot
import numpy as np
plot.rc.cycle = 'Set3'
state = np.random.RandomState(51423)
titles = ['With redundant labels', 'Without redundant labels']
for mode in (0, 1):
    f, 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))
        xlabel='xlabel', ylabel='ylabel', suptitle=titles[mode],
        abc=mode, abcloc='ul',
        grid=False, xticks=25, yticks=5)