Matplotlib Chinese User Guide 3.5 Dense Layout Guide

Dense Layout Guidelines

original: Tight Layout guide Translator: flying dragon protocol: CC BY-NC-SA 4.0

tight_layout will automatically adjust the parameters of the subimage to fill the entire image area. This is an experimental feature and may not work in some cases. It only checks the axis labels, tick labels and title parts.

simple example

In matplotlib, the location of axes (including subplots) is specified in normalized figure coordinates. What can happen is that your axis labels or titles (and sometimes even tick labels) will extend beyond the graph area and thus get cut off.

plt.rcParams['savefig.facecolor'] = "0.8"

def example_plot(ax, fontsize=12):
     ax.plot([1, 2])
     ax.locator_params(nbins=3)
     ax.set_xlabel('x-label', fontsize=fontsize)
     ax.set_ylabel('y-label', fontsize=fontsize)
     ax.set_title('Title', fontsize=fontsize)

plt.close('all')
fig, ax = plt.subplots()
example_plot(ax, fontsize=24)
copy

To avoid it, the position of the axes needs to be adjusted. For subgraphs, this can be done by adjusting the subgraph parameters ( Move one side of the axes to make room for the tick labels ). Matplotlib v1.1 introduced a new command, tight_layout(), which automatically takes care of this for you.

plt.tight_layout()
copy

When you have multiple subplots, you will often see labels for different axes stacked together.

plt.close('all')
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
copy

tight_layout() also adjusts the spacing between subplots to reduce stacking.

tight_layout() can accept keyword arguments pad , w_pad , or h_pad which are extra margins between image borders and subplots. Margins are specified in font size units.

plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
copy

tight_layout() will work even if the subplots are of different sizes, as long as the grid specifications are compatible. In the example below, ax1 and ax2 are subplots of a 2x2 grid, but ax3 is a 1x2 grid.

plt.close('all')
fig = plt.figure()

ax1 = plt.subplot(221)
ax2 = plt.subplot(223)
ax3 = plt.subplot(122)

example_plot(ax1)
example_plot(ax2)
example_plot(ax3)

plt.tight_layout()
copy

It works for subplots created with subplot2grid(). In general, from the gridspec ( Use GridSpec to customize the position of sub-layouts ) also works fine.

plt.close('all')
fig = plt.figure()

ax1 = plt.subplot2grid((3, 3), (0, 0))
ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2)
ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)

example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)

plt.tight_layout()
copy

Although not thoroughly tested, it looks like it also works for subplots with aspect not auto (e.g. axes with images).

arr = np.arange(100).reshape((10,10))

plt.close('all')
fig = plt.figure(figsize=(5,4))

ax = plt.subplot(111)
im = ax.imshow(arr, interpolation="none")

plt.tight_layout()
copy

warn

  • tight_layout() only considers tick labels, axis labels and titles. Therefore, other artists may be truncated and overlapped as well.
  • It assumes that the extra space required for tick labels, axis labels and titles has nothing to do with the original position of the axes. This is usually true, but not in rare cases.
  • pad=0 cuts some text by a few pixels. This may be a bug or limitation of the current algorithm, and it's not clear why it happens. Also, an interval greater than at least 0.3 is recommended.

Used with GridSpec

GridSpec has its own tight_layout() method (tight_layout() of the pyplot API also works).

plt.close('all')
fig = plt.figure()

import matplotlib.gridspec as gridspec

gs1 = gridspec.GridSpec(2, 1)
ax1 = fig.add_subplot(gs1[0])
ax2 = fig.add_subplot(gs1[1])

example_plot(ax1)
example_plot(ax2)

gs1.tight_layout(fig)
copy

You can provide an optional rect parameter specifying the bounding box to be filled by the subplot. The coordinates must be normalized graphics coordinates, the default value is (0, 0, 1, 1).

gs1.tight_layout(fig, rect=[0, 0, 0.5, 1])
copy

For example, this can be used for graphs with multiple gridspecs.

gs2 = gridspec.GridSpec(3, 1)

for ss in gs2:
    ax = fig.add_subplot(ss)
    example_plot(ax)
    ax.set_title("")
    ax.set_xlabel("")

ax.set_xlabel("x-label", fontsize=12)

gs2.tight_layout(fig, rect=[0.5, 0, 1, 1], h_pad=0.5)
copy

We can try to match the top and bottom of the two grids.

top = min(gs1.top, gs2.top)
bottom = max(gs1.bottom, gs2.bottom)

gs1.update(top=top, bottom=bottom)
gs2.update(top=top, bottom=bottom)
copy

While this should be good enough, adjusting the top and bottom may require adjusting the hspace as well. To update hspace and vspace, we call tight_layout() again with the updated rect parameter. Note that the area specified by the rect parameter includes the tick labels. So we increment the bottom (normally 0) by the difference between the bottom of each gridspec. Same goes for the top.

top = min(gs1.top, gs2.top)
bottom = max(gs1.bottom, gs2.bottom)

gs1.tight_layout(fig, rect=[None, 0 + (bottom-gs1.bottom),
                            0.5, 1 - (gs1.top-top)])
gs2.tight_layout(fig, rect=[0.5, 0 + (bottom-gs2.bottom),
                            None, 1 - (gs2.top-top)],
                 h_pad=0.5)
copy

Used with AxesGrid1

Although limited, the axes_grid1 toolkit is also supported

plt.close('all')
fig = plt.figure()

from mpl_toolkits.axes_grid1 import Grid
grid = Grid(fig, rect=111, nrows_ncols=(2,2),
            axes_pad=0.25, label_mode='L',
            )

for ax in grid:
    example_plot(ax)
    ax.title.set_visible(False)

plt.tight_layout()
copy

color bar

If you create a colorbar using the colorbar command, the created colorbar is an instance of Axes instead of Subplot, so tight_layout has no effect. In Matplotlib v1.1 you can use gridspec to create colorbars as subplots.

plt.close('all')
arr = np.arange(100).reshape((10,10))
fig = plt.figure(figsize=(4, 4))
im = plt.imshow(arr, interpolation="none")

plt.colorbar(im, use_gridspec=True)

plt.tight_layout()
copy

![])http://matplotlib.org/_images/tight_layout_guide-14.png

Another option is to explicitly create an axes for the colorbar, using the AxesGrid1 toolkit:

plt.close('all')
arr = np.arange(100).reshape((10,10))
fig = plt.figure(figsize=(4, 4))
im = plt.imshow(arr, interpolation="none")

from mpl_toolkits.axes_grid1 import make_axes_locatable
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", "5%", pad="3%")
plt.colorbar(im, cax=cax)

plt.tight_layout()
copy

Tags: Python MATLAB numpy

Posted by runthis on Thu, 01 Dec 2022 14:01:37 +0530