Skip to content

Commit 7a0657b

Browse files
committed
DOC: cleanup constrained layout tutorial [skip actions] [skip azp] [skip appveyor]
DOC: CL - axes->Axes
1 parent d1f321f commit 7a0657b

File tree

2 files changed

+82
-72
lines changed

2 files changed

+82
-72
lines changed

examples/subplots_axes_and_figures/colorbar_placement.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
"""
2+
.. _colorbar_placement:
3+
24
=================
35
Placing Colorbars
46
=================

tutorials/intermediate/constrainedlayout_guide.py

+80-72
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,46 @@
33
Constrained Layout Guide
44
================================
55
6-
How to use constrained-layout to fit plots within your figure cleanly.
6+
Use *constrained layout* to fit plots within your figure cleanly.
77
8-
*constrained_layout* automatically adjusts subplots and decorations like
9-
legends and colorbars so that they fit in the figure window while still
10-
preserving, as best they can, the logical layout requested by the user.
8+
*Constrained layout* automatically adjusts subplots so that decorations like tick
9+
labels, legends, and colorbars do not overlap, while still preserving the
10+
logical layout requested by the user.
1111
12-
*constrained_layout* is similar to
13-
:doc:`tight_layout</tutorials/intermediate/tight_layout_guide>`,
14-
but uses a constraint solver to determine the size of axes that allows
15-
them to fit.
12+
*Constrained layout* is similar to :doc:`Tight
13+
layout</tutorials/intermediate/tight_layout_guide>`, but is substantially more
14+
flexible. It handles colorbars placed on multiple Axes
15+
(:ref:`colorbar_placement`) nested layouts (`~.Figure.subfigures`) and Axes that
16+
span rows or columns (`~.pyplot.subplot_mosaic`), striving to align spines from
17+
Axes in the same row or column. In addition, :ref:`Compressed layout
18+
<compressed_layout>` will try and move fixed aspect-ratio Axes closer together.
19+
These features are described in this document, as well as some
20+
:ref:`implementation details <cl_notes_on_algorithm>` discussed at the end.
1621
17-
*constrained_layout* typically needs to be activated before any axes are
18-
added to a figure. Two ways of doing so are
22+
*Constrained layout* typically needs to be activated before any Axes are added to
23+
a figure. Two ways of doing so are
1924
20-
* using the respective argument to :func:`~.pyplot.subplots` or
21-
:func:`~.pyplot.figure`, e.g.::
25+
* using the respective argument to `~.pyplot.subplots`,
26+
`~.pyplot.figure`, `~.pyplot.subplot_mosaic` e.g.::
2227
2328
plt.subplots(layout="constrained")
2429
25-
* activate it via :ref:`rcParams<customizing-with-dynamic-rc-settings>`,
26-
like::
30+
* activate it via :ref:`rcParams<customizing-with-dynamic-rc-settings>`, like::
2731
2832
plt.rcParams['figure.constrained_layout.use'] = True
2933
3034
Those are described in detail throughout the following sections.
3135
32-
Simple Example
36+
.. warning::
37+
38+
Calling ``plt.tight_layout()`` will turn off *constrained layout*!
39+
40+
Simple example
3341
==============
3442
35-
In Matplotlib, the location of axes (including subplots) are specified in
36-
normalized figure coordinates. It can happen that your axis labels or
37-
titles (or sometimes even ticklabels) go outside the figure area, and are thus
43+
In Matplotlib, the location of Axes (including subplots) are specified in
44+
normalized figure coordinates. It can happen that your axis labels or titles
45+
(or sometimes even ticklabels) go outside the figure area, and are thus
3846
clipped.
3947
"""
4048

@@ -67,18 +75,18 @@ def example_plot(ax, fontsize=12, hide_labels=False):
6775
example_plot(ax, fontsize=24)
6876

6977
# %%
70-
# To prevent this, the location of axes needs to be adjusted. For
78+
# To prevent this, the location of Axes needs to be adjusted. For
7179
# subplots, this can be done manually by adjusting the subplot parameters
7280
# using `.Figure.subplots_adjust`. However, specifying your figure with the
73-
# # ``layout="constrained"`` keyword argument will do the adjusting
74-
# # automatically.
81+
# ``layout="constrained"`` keyword argument will do the adjusting
82+
# automatically.
7583

7684
fig, ax = plt.subplots(layout="constrained")
7785
example_plot(ax, fontsize=24)
7886

7987
# %%
8088
# When you have multiple subplots, often you see labels of different
81-
# axes overlapping each other.
89+
# Axes overlapping each other.
8290

8391
fig, axs = plt.subplots(2, 2, layout=None)
8492
for ax in axs.flat:
@@ -93,21 +101,19 @@ def example_plot(ax, fontsize=12, hide_labels=False):
93101
example_plot(ax)
94102

95103
# %%
104+
#
96105
# Colorbars
97106
# =========
98107
#
99-
# If you create a colorbar with `.Figure.colorbar`,
100-
# you need to make room for it. ``constrained_layout`` does this
101-
# automatically. Note that if you specify ``use_gridspec=True`` it will be
102-
# ignored because this option is made for improving the layout via
103-
# ``tight_layout``.
108+
# If you create a colorbar with `.Figure.colorbar`, you need to make room for
109+
# it. *Constrained layout* does this automatically. Note that if you
110+
# specify ``use_gridspec=True`` it will be ignored because this option is made
111+
# for improving the layout via ``tight_layout``.
104112
#
105113
# .. note::
106114
#
107115
# For the `~.axes.Axes.pcolormesh` keyword arguments (``pc_kwargs``) we use a
108-
# dictionary. Below we will assign one colorbar to a number of axes each
109-
# containing a `~.cm.ScalarMappable`; specifying the norm and colormap
110-
# ensures the colorbar is accurate for all the axes.
116+
# dictionary to keep the calls consistent across this document.
111117

112118
arr = np.arange(100).reshape((10, 10))
113119
norm = mcolors.Normalize(vmin=0., vmax=100.)
@@ -118,17 +124,17 @@ def example_plot(ax, fontsize=12, hide_labels=False):
118124
fig.colorbar(im, ax=ax, shrink=0.6)
119125

120126
# %%
121-
# If you specify a list of axes (or other iterable container) to the
127+
# If you specify a list of Axes (or other iterable container) to the
122128
# ``ax`` argument of ``colorbar``, constrained_layout will take space from
123-
# the specified axes.
129+
# the specified Axes.
124130

125131
fig, axs = plt.subplots(2, 2, figsize=(4, 4), layout="constrained")
126132
for ax in axs.flat:
127133
im = ax.pcolormesh(arr, **pc_kwargs)
128134
fig.colorbar(im, ax=axs, shrink=0.6)
129135

130136
# %%
131-
# If you specify a list of axes from inside a grid of axes, the colorbar
137+
# If you specify a list of Axes from inside a grid of Axes, the colorbar
132138
# will steal space appropriately, and leave a gap, but all subplots will
133139
# still be the same size.
134140

@@ -142,7 +148,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
142148
# Suptitle
143149
# =========
144150
#
145-
# ``constrained_layout`` can also make room for `~.Figure.suptitle`.
151+
# *Constrained layout* can also make room for `~.Figure.suptitle`.
146152

147153
fig, axs = plt.subplots(2, 2, figsize=(4, 4), layout="constrained")
148154
for ax in axs.flat:
@@ -180,7 +186,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
180186
# however, that the legend's ``get_in_layout`` status will have to be
181187
# toggled again to make the saved file work, and we must manually
182188
# trigger a draw if we want constrained_layout to adjust the size
183-
# of the axes before printing.
189+
# of the Axes before printing.
184190

185191
fig, axs = plt.subplots(1, 2, figsize=(4, 2), layout="constrained")
186192

@@ -234,13 +240,13 @@ def example_plot(ax, fontsize=12, hide_labels=False):
234240
#
235241

236242
# %%
237-
# Padding and Spacing
243+
# Padding and spacing
238244
# ===================
239245
#
240-
# Padding between axes is controlled in the horizontal by *w_pad* and
246+
# Padding between Axes is controlled in the horizontal by *w_pad* and
241247
# *wspace*, and vertical by *h_pad* and *hspace*. These can be edited
242248
# via `~.layout_engine.ConstrainedLayoutEngine.set`. *w/h_pad* are
243-
# the minimum space around the axes in units of inches:
249+
# the minimum space around the Axes in units of inches:
244250

245251
fig, axs = plt.subplots(2, 2, layout="constrained")
246252
for ax in axs.flat:
@@ -274,7 +280,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
274280

275281
# %%
276282
# GridSpecs also have optional *hspace* and *wspace* keyword arguments,
277-
# that will be used instead of the pads set by ``constrained_layout``:
283+
# that will be used instead of the pads set by *constrained layout*:
278284

279285
fig, axs = plt.subplots(2, 2, layout="constrained",
280286
gridspec_kw={'wspace': 0.3, 'hspace': 0.2})
@@ -313,7 +319,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
313319
# file. They all have the prefix ``figure.constrained_layout``:
314320
#
315321
# - *use*: Whether to use constrained_layout. Default is False
316-
# - *w_pad*, *h_pad*: Padding around axes objects.
322+
# - *w_pad*, *h_pad*: Padding around Axes objects.
317323
# Float representing inches. Default is 3./72. inches (3 pts)
318324
# - *wspace*, *hspace*: Space between subplot groups.
319325
# Float representing a fraction of the subplot widths being separated.
@@ -376,7 +382,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
376382
# Note that in the above the left and right columns don't have the same
377383
# vertical extent. If we want the top and bottom of the two grids to line up
378384
# then they need to be in the same gridspec. We need to make this figure
379-
# larger as well in order for the axes not to collapse to zero height:
385+
# larger as well in order for the Axes not to collapse to zero height:
380386

381387
fig = plt.figure(figsize=(4, 6), layout="constrained")
382388

@@ -424,7 +430,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
424430

425431
# %%
426432
# Rather than using subgridspecs, Matplotlib now provides `~.Figure.subfigures`
427-
# which also work with ``constrained_layout``:
433+
# which also work with *constrained layout*:
428434

429435
fig = plt.figure(layout="constrained")
430436
sfigs = fig.subfigures(1, 2, width_ratios=[1, 2])
@@ -443,13 +449,13 @@ def example_plot(ax, fontsize=12, hide_labels=False):
443449
fig.suptitle('Nested plots using subfigures')
444450

445451
# %%
446-
# Manually setting axes positions
452+
# Manually setting Axes positions
447453
# ================================
448454
#
449455
# There can be good reasons to manually set an Axes position. A manual call
450-
# to `~.axes.Axes.set_position` will set the axes so constrained_layout has
451-
# no effect on it anymore. (Note that ``constrained_layout`` still leaves the
452-
# space for the axes that is moved).
456+
# to `~.axes.Axes.set_position` will set the Axes so constrained_layout has
457+
# no effect on it anymore. (Note that *constrained layout* still leaves the
458+
# space for the Axes that is moved).
453459

454460
fig, axs = plt.subplots(1, 2, layout="constrained")
455461
example_plot(axs[0], fontsize=12)
@@ -461,8 +467,8 @@ def example_plot(ax, fontsize=12, hide_labels=False):
461467
# Grids of fixed aspect-ratio Axes: "compressed" layout
462468
# =====================================================
463469
#
464-
# ``constrained_layout`` operates on the grid of "original" positions for
465-
# axes. However, when Axes have fixed aspect ratios, one side is usually made
470+
# *Constrained layout* operates on the grid of "original" positions for
471+
# Axes. However, when Axes have fixed aspect ratios, one side is usually made
466472
# shorter, and leaves large gaps in the shortened direction. In the following,
467473
# the Axes are square, but the figure quite wide so there is a horizontal gap:
468474

@@ -485,19 +491,19 @@ def example_plot(ax, fontsize=12, hide_labels=False):
485491

486492

487493
# %%
488-
# Manually turning off ``constrained_layout``
494+
# Manually turning off *constrained layout*
489495
# ===========================================
490496
#
491-
# ``constrained_layout`` usually adjusts the axes positions on each draw
497+
# *Constrained layout* usually adjusts the Axes positions on each draw
492498
# of the figure. If you want to get the spacing provided by
493-
# ``constrained_layout`` but not have it update, then do the initial
499+
# *Constrained layout* but not have it update, then do the initial
494500
# draw and then call ``fig.set_layout_engine('none')``.
495501
# This is potentially useful for animations where the tick labels may
496502
# change length.
497503
#
498-
# Note that ``constrained_layout`` is turned off for ``ZOOM`` and ``PAN``
504+
# Note that *Constrained layout* is turned off for ``ZOOM`` and ``PAN``
499505
# GUI events for the backends that use the toolbar. This prevents the
500-
# axes from changing position during zooming and panning.
506+
# Axes from changing position during zooming and panning.
501507
#
502508
#
503509
# Limitations
@@ -506,17 +512,17 @@ def example_plot(ax, fontsize=12, hide_labels=False):
506512
# Incompatible functions
507513
# ----------------------
508514
#
509-
# ``constrained_layout`` will work with `.pyplot.subplot`, but only if the
515+
# *Constrained layout* will work with `.pyplot.subplot`, but only if the
510516
# number of rows and columns is the same for each call.
511517
# The reason is that each call to `.pyplot.subplot` will create a new
512518
# `.GridSpec` instance if the geometry is not the same, and
513-
# ``constrained_layout``. So the following works fine:
519+
# *Constrained layout*. So the following works fine:
514520

515521
fig = plt.figure(layout="constrained")
516522

517523
ax1 = plt.subplot(2, 2, 1)
518524
ax2 = plt.subplot(2, 2, 3)
519-
# third axes that spans both rows in second column:
525+
# third Axes that spans both rows in second column:
520526
ax3 = plt.subplot(2, 2, (2, 4))
521527

522528
example_plot(ax1)
@@ -557,22 +563,22 @@ def example_plot(ax, fontsize=12, hide_labels=False):
557563
fig.suptitle('subplot2grid')
558564

559565
# %%
560-
# Other Caveats
566+
# Other caveats
561567
# -------------
562568
#
563-
# * ``constrained_layout`` only considers ticklabels, axis labels, titles, and
569+
# * *Constrained layout* only considers ticklabels, axis labels, titles, and
564570
# legends. Thus, other artists may be clipped and also may overlap.
565571
#
566572
# * It assumes that the extra space needed for ticklabels, axis labels,
567-
# and titles is independent of original location of axes. This is
573+
# and titles is independent of original location of Axes. This is
568574
# often true, but there are rare cases where it is not.
569575
#
570576
# * There are small differences in how the backends handle rendering fonts,
571577
# so the results will not be pixel-identical.
572578
#
573-
# * An artist using axes coordinates that extend beyond the axes
579+
# * An artist using Axes coordinates that extend beyond the Axes
574580
# boundary will result in unusual layouts when added to an
575-
# axes. This can be avoided by adding the artist directly to the
581+
# Axes. This can be avoided by adding the artist directly to the
576582
# :class:`~matplotlib.figure.Figure` using
577583
# :meth:`~matplotlib.figure.Figure.add_artist`. See
578584
# :class:`~matplotlib.patches.ConnectionPatch` for an example.
@@ -595,6 +601,8 @@ def example_plot(ax, fontsize=12, hide_labels=False):
595601
# not require outside data or dependencies (other than numpy).
596602

597603
# %%
604+
# .. _cl_notes_on_algorithm:
605+
#
598606
# Notes on the algorithm
599607
# ======================
600608
#
@@ -620,16 +628,16 @@ def example_plot(ax, fontsize=12, hide_labels=False):
620628
#
621629
# For a single Axes the layout is straight forward. There is one parent
622630
# layoutgrid for the figure consisting of one column and row, and
623-
# a child layoutgrid for the gridspec that contains the axes, again
631+
# a child layoutgrid for the gridspec that contains the Axes, again
624632
# consisting of one row and column. Space is made for the "decorations" on
625-
# each side of the axes. In the code, this is accomplished by the entries in
633+
# each side of the Axes. In the code, this is accomplished by the entries in
626634
# ``do_constrained_layout()`` like::
627635
#
628636
# gridspec._layoutgrid[0, 0].edit_margin_min('left',
629637
# -bbox.x0 + pos.x0 + w_pad)
630638
#
631-
# where ``bbox`` is the tight bounding box of the axes, and ``pos`` its
632-
# position. Note how the four margins encompass the axes decorations.
639+
# where ``bbox`` is the tight bounding box of the Axes, and ``pos`` its
640+
# position. Note how the four margins encompass the Axes decorations.
633641

634642
from matplotlib._layoutgrid import plot_children
635643

@@ -640,8 +648,8 @@ def example_plot(ax, fontsize=12, hide_labels=False):
640648
# %%
641649
# Simple case: two Axes
642650
# ---------------------
643-
# When there are multiple axes they have their layouts bound in
644-
# simple ways. In this example the left axes has much larger decorations
651+
# When there are multiple Axes they have their layouts bound in
652+
# simple ways. In this example the left Axes has much larger decorations
645653
# than the right, but they share a bottom margin, which is made large
646654
# enough to accommodate the larger xlabel. Same with the shared top
647655
# margin. The left and right margins are not shared, and hence are
@@ -682,16 +690,16 @@ def example_plot(ax, fontsize=12, hide_labels=False):
682690
# Uneven sized Axes
683691
# -----------------
684692
#
685-
# There are two ways to make axes have an uneven size in a
693+
# There are two ways to make Axes have an uneven size in a
686694
# Gridspec layout, either by specifying them to cross Gridspecs rows
687695
# or columns, or by specifying width and height ratios.
688696
#
689697
# The first method is used here. Note that the middle ``top`` and
690698
# ``bottom`` margins are not affected by the left-hand column. This
691699
# is a conscious decision of the algorithm, and leads to the case where
692-
# the two right-hand axes have the same height, but it is not 1/2 the height
693-
# of the left-hand axes. This is consistent with how ``gridspec`` works
694-
# without constrained layout.
700+
# the two right-hand Axes have the same height, but it is not 1/2 the height
701+
# of the left-hand Axes. This is consistent with how ``gridspec`` works
702+
# without *constrained layout*.
695703

696704
fig = plt.figure(layout="constrained")
697705
gs = gridspec.GridSpec(2, 2, figure=fig)
@@ -708,7 +716,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
708716
# constraining their width. In the case below, the right margin for column 0
709717
# and the left margin for column 3 have no margin artists to set their width,
710718
# so we take the maximum width of the margin widths that do have artists.
711-
# This makes all the axes have the same size:
719+
# This makes all the Axes have the same size:
712720

713721
fig = plt.figure(layout="constrained")
714722
gs = fig.add_gridspec(2, 4)

0 commit comments

Comments
 (0)