Figure tight layout

Matplotlib has a tight layout algorithm that adjusts the space between subplots and around the figure edge to accomodate labels and plotted content.

ProPlot introduces a new tight layout algorithm that permits variable figure dimensions and variable spacing between subplot rows and columns (see FlexibleGridSpec). This allows the algorithm to preserve subplot aspect ratios, colorbar and panel widths, and optionally, subplot physical dimensions, all without producing extra whitespace. It is applied to all figured by default – to turn it off, pass tight=False to Figure or change the rc.tight setting.

Reference axes

To fix the figure dimension(s), pass width, height, and/or figsize to subplots. To fix the reference subplot dimension(s), use axwidth, axheight, and/or aspect. To set the reference subplot, use ref (default is 1, i.e. the subplot in the upper left corner). When you specify just width or axwidth, the subplot and figure heights are adjusted automatically to accommodate aspect. When you specify just height or axheight, the subplot and figure widths are adjusted automatically.

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

The below examples are stress tests of this algorithm. They also illustrate how changing the “reference axes” can affect the figure appearence.

[1]:
import proplot as plot
for ref in (1,2):
    f, axs = plot.subplots(ref=ref, nrows=3, ncols=3, aspect=1, axwidth=1.1, wratios=(3,2,2), share=0)
    axs[ref-1].format(title='reference axes', titleweight='bold', titleloc='uc', titlecolor='red9')
    axs[4].format(title='title\ntitle\ntitle', suptitle='Tight layout with simple grids')
    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'])
_images/tight_4_0.svg
_images/tight_4_1.svg
[2]:
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=(1.5,1,1.5),
        ref=ref, axwidth=1.1, span=False)
    axs[ref-1].format(title='reference axes', titleweight='bold', titleloc='uc', titlecolor='red9')
    axs.format(xlabel='xlabel', ylabel='ylabel', suptitle='Super title')
    axs[0].format(xlabel='xlabel\nxlabel\nxlabel')
    axs[1].format(ylabel='ylabel\nylabel\nylabel', ytickloc='both', yticklabelloc='both', ctitle='Title')
    axs[2:4].format(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'])
_images/tight_5_0.svg
_images/tight_5_1.svg

Overriding the algorithm

When you pass a spacing argument like left, right, top, bottom, wspace, or hspace to Figure or FlexibleGridSpec, that value is always respected – the tight layout algorithm will not change it.

For example, if you pass left='2em' to subplots, the left margin is fixed but the right, bottom, and top margins are determined automatically. Similarly, 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 figure width and height are constrained similarly. If you pass both a figure width and height or a subplot axwidth and axheight, the aspect is ignored. If you just pass one of the width, height, axwidth, or axheight, the aspect ratio is preserved and the other dimension is adjusted accordingly.

Manual figure layout

The figure layout can also be configured manually. 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-squares, points, and picas.

[3]:
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='12cm', 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')
_images/tight_10_0.svg