33Constrained 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
3034Those 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
3846clipped.
3947"""
4048
@@ -67,18 +75,18 @@ def example_plot(ax, fontsize=12, hide_labels=False):
6775example_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
7684fig , ax = plt .subplots (layout = "constrained" )
7785example_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
8391fig , axs = plt .subplots (2 , 2 , layout = None )
8492for 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
112118arr = np .arange (100 ).reshape ((10 , 10 ))
113119norm = mcolors .Normalize (vmin = 0. , vmax = 100. )
@@ -118,17 +124,17 @@ def example_plot(ax, fontsize=12, hide_labels=False):
118124fig .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
125131fig , axs = plt .subplots (2 , 2 , figsize = (4 , 4 ), layout = "constrained" )
126132for ax in axs .flat :
127133 im = ax .pcolormesh (arr , ** pc_kwargs )
128134fig .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
147153fig , axs = plt .subplots (2 , 2 , figsize = (4 , 4 ), layout = "constrained" )
148154for 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
185191fig , 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
245251fig , axs = plt .subplots (2 , 2 , layout = "constrained" )
246252for 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
279285fig , 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
381387fig = 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
429435fig = plt .figure (layout = "constrained" )
430436sfigs = fig .subfigures (1 , 2 , width_ratios = [1 , 2 ])
@@ -443,13 +449,13 @@ def example_plot(ax, fontsize=12, hide_labels=False):
443449fig .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
454460fig , axs = plt .subplots (1 , 2 , layout = "constrained" )
455461example_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
515521fig = plt .figure (layout = "constrained" )
516522
517523ax1 = plt .subplot (2 , 2 , 1 )
518524ax2 = 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:
520526ax3 = plt .subplot (2 , 2 , (2 , 4 ))
521527
522528example_plot (ax1 )
@@ -557,22 +563,22 @@ def example_plot(ax, fontsize=12, hide_labels=False):
557563fig .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
634642from 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
696704fig = plt .figure (layout = "constrained" )
697705gs = 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
713721fig = plt .figure (layout = "constrained" )
714722gs = fig .add_gridspec (2 , 4 )
0 commit comments