3
3
Constrained Layout Guide
4
4
================================
5
5
6
- How to use constrained- layout to fit plots within your figure cleanly.
6
+ Use * constrained layout* to fit plots within your figure cleanly.
7
7
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.
11
11
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.
16
21
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
19
24
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.::
22
27
23
28
plt.subplots(layout="constrained")
24
29
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::
27
31
28
32
plt.rcParams['figure.constrained_layout.use'] = True
29
33
30
34
Those are described in detail throughout the following sections.
31
35
32
- Simple Example
36
+ .. warning::
37
+
38
+ Calling ``plt.tight_layout()`` will turn off *constrained layout*!
39
+
40
+ Simple example
33
41
==============
34
42
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
38
46
clipped.
39
47
"""
40
48
@@ -67,18 +75,18 @@ def example_plot(ax, fontsize=12, hide_labels=False):
67
75
example_plot (ax , fontsize = 24 )
68
76
69
77
# %%
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
71
79
# subplots, this can be done manually by adjusting the subplot parameters
72
80
# 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.
75
83
76
84
fig , ax = plt .subplots (layout = "constrained" )
77
85
example_plot (ax , fontsize = 24 )
78
86
79
87
# %%
80
88
# When you have multiple subplots, often you see labels of different
81
- # axes overlapping each other.
89
+ # Axes overlapping each other.
82
90
83
91
fig , axs = plt .subplots (2 , 2 , layout = None )
84
92
for ax in axs .flat :
@@ -93,21 +101,19 @@ def example_plot(ax, fontsize=12, hide_labels=False):
93
101
example_plot (ax )
94
102
95
103
# %%
104
+ #
96
105
# Colorbars
97
106
# =========
98
107
#
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``.
104
112
#
105
113
# .. note::
106
114
#
107
115
# 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.
111
117
112
118
arr = np .arange (100 ).reshape ((10 , 10 ))
113
119
norm = mcolors .Normalize (vmin = 0. , vmax = 100. )
@@ -118,17 +124,17 @@ def example_plot(ax, fontsize=12, hide_labels=False):
118
124
fig .colorbar (im , ax = ax , shrink = 0.6 )
119
125
120
126
# %%
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
122
128
# ``ax`` argument of ``colorbar``, constrained_layout will take space from
123
- # the specified axes .
129
+ # the specified Axes .
124
130
125
131
fig , axs = plt .subplots (2 , 2 , figsize = (4 , 4 ), layout = "constrained" )
126
132
for ax in axs .flat :
127
133
im = ax .pcolormesh (arr , ** pc_kwargs )
128
134
fig .colorbar (im , ax = axs , shrink = 0.6 )
129
135
130
136
# %%
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
132
138
# will steal space appropriately, and leave a gap, but all subplots will
133
139
# still be the same size.
134
140
@@ -142,7 +148,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
142
148
# Suptitle
143
149
# =========
144
150
#
145
- # ``constrained_layout`` can also make room for `~.Figure.suptitle`.
151
+ # *Constrained layout* can also make room for `~.Figure.suptitle`.
146
152
147
153
fig , axs = plt .subplots (2 , 2 , figsize = (4 , 4 ), layout = "constrained" )
148
154
for ax in axs .flat :
@@ -180,7 +186,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
180
186
# however, that the legend's ``get_in_layout`` status will have to be
181
187
# toggled again to make the saved file work, and we must manually
182
188
# trigger a draw if we want constrained_layout to adjust the size
183
- # of the axes before printing.
189
+ # of the Axes before printing.
184
190
185
191
fig , axs = plt .subplots (1 , 2 , figsize = (4 , 2 ), layout = "constrained" )
186
192
@@ -234,13 +240,13 @@ def example_plot(ax, fontsize=12, hide_labels=False):
234
240
#
235
241
236
242
# %%
237
- # Padding and Spacing
243
+ # Padding and spacing
238
244
# ===================
239
245
#
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
241
247
# *wspace*, and vertical by *h_pad* and *hspace*. These can be edited
242
248
# 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:
244
250
245
251
fig , axs = plt .subplots (2 , 2 , layout = "constrained" )
246
252
for ax in axs .flat :
@@ -274,7 +280,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
274
280
275
281
# %%
276
282
# 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* :
278
284
279
285
fig , axs = plt .subplots (2 , 2 , layout = "constrained" ,
280
286
gridspec_kw = {'wspace' : 0.3 , 'hspace' : 0.2 })
@@ -313,7 +319,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
313
319
# file. They all have the prefix ``figure.constrained_layout``:
314
320
#
315
321
# - *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.
317
323
# Float representing inches. Default is 3./72. inches (3 pts)
318
324
# - *wspace*, *hspace*: Space between subplot groups.
319
325
# Float representing a fraction of the subplot widths being separated.
@@ -376,7 +382,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
376
382
# Note that in the above the left and right columns don't have the same
377
383
# vertical extent. If we want the top and bottom of the two grids to line up
378
384
# 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:
380
386
381
387
fig = plt .figure (figsize = (4 , 6 ), layout = "constrained" )
382
388
@@ -424,7 +430,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
424
430
425
431
# %%
426
432
# Rather than using subgridspecs, Matplotlib now provides `~.Figure.subfigures`
427
- # which also work with ``constrained_layout`` :
433
+ # which also work with *constrained layout* :
428
434
429
435
fig = plt .figure (layout = "constrained" )
430
436
sfigs = fig .subfigures (1 , 2 , width_ratios = [1 , 2 ])
@@ -443,13 +449,13 @@ def example_plot(ax, fontsize=12, hide_labels=False):
443
449
fig .suptitle ('Nested plots using subfigures' )
444
450
445
451
# %%
446
- # Manually setting axes positions
452
+ # Manually setting Axes positions
447
453
# ================================
448
454
#
449
455
# 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).
453
459
454
460
fig , axs = plt .subplots (1 , 2 , layout = "constrained" )
455
461
example_plot (axs [0 ], fontsize = 12 )
@@ -461,8 +467,8 @@ def example_plot(ax, fontsize=12, hide_labels=False):
461
467
# Grids of fixed aspect-ratio Axes: "compressed" layout
462
468
# =====================================================
463
469
#
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
466
472
# shorter, and leaves large gaps in the shortened direction. In the following,
467
473
# the Axes are square, but the figure quite wide so there is a horizontal gap:
468
474
@@ -485,19 +491,19 @@ def example_plot(ax, fontsize=12, hide_labels=False):
485
491
486
492
487
493
# %%
488
- # Manually turning off ``constrained_layout``
494
+ # Manually turning off *constrained layout*
489
495
# ===========================================
490
496
#
491
- # ``constrained_layout`` usually adjusts the axes positions on each draw
497
+ # *Constrained layout* usually adjusts the Axes positions on each draw
492
498
# 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
494
500
# draw and then call ``fig.set_layout_engine('none')``.
495
501
# This is potentially useful for animations where the tick labels may
496
502
# change length.
497
503
#
498
- # Note that ``constrained_layout`` is turned off for ``ZOOM`` and ``PAN``
504
+ # Note that *Constrained layout* is turned off for ``ZOOM`` and ``PAN``
499
505
# 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.
501
507
#
502
508
#
503
509
# Limitations
@@ -506,17 +512,17 @@ def example_plot(ax, fontsize=12, hide_labels=False):
506
512
# Incompatible functions
507
513
# ----------------------
508
514
#
509
- # ``constrained_layout`` will work with `.pyplot.subplot`, but only if the
515
+ # *Constrained layout* will work with `.pyplot.subplot`, but only if the
510
516
# number of rows and columns is the same for each call.
511
517
# The reason is that each call to `.pyplot.subplot` will create a new
512
518
# `.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:
514
520
515
521
fig = plt .figure (layout = "constrained" )
516
522
517
523
ax1 = plt .subplot (2 , 2 , 1 )
518
524
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:
520
526
ax3 = plt .subplot (2 , 2 , (2 , 4 ))
521
527
522
528
example_plot (ax1 )
@@ -557,22 +563,22 @@ def example_plot(ax, fontsize=12, hide_labels=False):
557
563
fig .suptitle ('subplot2grid' )
558
564
559
565
# %%
560
- # Other Caveats
566
+ # Other caveats
561
567
# -------------
562
568
#
563
- # * ``constrained_layout`` only considers ticklabels, axis labels, titles, and
569
+ # * *Constrained layout* only considers ticklabels, axis labels, titles, and
564
570
# legends. Thus, other artists may be clipped and also may overlap.
565
571
#
566
572
# * 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
568
574
# often true, but there are rare cases where it is not.
569
575
#
570
576
# * There are small differences in how the backends handle rendering fonts,
571
577
# so the results will not be pixel-identical.
572
578
#
573
- # * An artist using axes coordinates that extend beyond the axes
579
+ # * An artist using Axes coordinates that extend beyond the Axes
574
580
# 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
576
582
# :class:`~matplotlib.figure.Figure` using
577
583
# :meth:`~matplotlib.figure.Figure.add_artist`. See
578
584
# :class:`~matplotlib.patches.ConnectionPatch` for an example.
@@ -595,6 +601,8 @@ def example_plot(ax, fontsize=12, hide_labels=False):
595
601
# not require outside data or dependencies (other than numpy).
596
602
597
603
# %%
604
+ # .. _cl_notes_on_algorithm:
605
+ #
598
606
# Notes on the algorithm
599
607
# ======================
600
608
#
@@ -620,16 +628,16 @@ def example_plot(ax, fontsize=12, hide_labels=False):
620
628
#
621
629
# For a single Axes the layout is straight forward. There is one parent
622
630
# 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
624
632
# 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
626
634
# ``do_constrained_layout()`` like::
627
635
#
628
636
# gridspec._layoutgrid[0, 0].edit_margin_min('left',
629
637
# -bbox.x0 + pos.x0 + w_pad)
630
638
#
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.
633
641
634
642
from matplotlib ._layoutgrid import plot_children
635
643
@@ -640,8 +648,8 @@ def example_plot(ax, fontsize=12, hide_labels=False):
640
648
# %%
641
649
# Simple case: two Axes
642
650
# ---------------------
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
645
653
# than the right, but they share a bottom margin, which is made large
646
654
# enough to accommodate the larger xlabel. Same with the shared top
647
655
# 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):
682
690
# Uneven sized Axes
683
691
# -----------------
684
692
#
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
686
694
# Gridspec layout, either by specifying them to cross Gridspecs rows
687
695
# or columns, or by specifying width and height ratios.
688
696
#
689
697
# The first method is used here. Note that the middle ``top`` and
690
698
# ``bottom`` margins are not affected by the left-hand column. This
691
699
# 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* .
695
703
696
704
fig = plt .figure (layout = "constrained" )
697
705
gs = gridspec .GridSpec (2 , 2 , figure = fig )
@@ -708,7 +716,7 @@ def example_plot(ax, fontsize=12, hide_labels=False):
708
716
# constraining their width. In the case below, the right margin for column 0
709
717
# and the left margin for column 3 have no margin artists to set their width,
710
718
# 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:
712
720
713
721
fig = plt .figure (layout = "constrained" )
714
722
gs = fig .add_gridspec (2 , 4 )
0 commit comments