1111layout. Axes manually placed via ``figure.add_axes()`` will not.
1212
1313See Tutorial: :doc:`/tutorials/intermediate/constrainedlayout_guide`
14+
15+ General idea:
16+ -------------
17+
18+ First, a figure has a gridspec that divides the figure into nrows and ncols,
19+ with heights and widths set by ``height_ratios`` and ``width_ratios``,
20+ often just set to 1 for an equal grid.
21+
22+ Subplotspecs that are derived from this gridspec can contain either a
23+ ``SubPanel``, a ``GridSpecFromSubplotSpec``, or an ``Axes``. The ``SubPanel``
24+ and ``GridSpecFromSubplotSpec`` are dealt with recursively and each contain an
25+ analogous layout.
26+
27+ Each ``GridSpec`` has a ``_layoutgrid`` attached to it. The ``_layoutgrid``
28+ has the same logical layout as the ``GridSpec``. Each row of the grid spec
29+ has a top and bottom "margin" and each column has a left and right "margin".
30+ The "inner" height of each row is constrained to be the same (or as modified
31+ by ``height_ratio``), and the "inner" width of each column is
32+ constrained to be the same (as modified by ``width_ratio``), where "inner"
33+ is the width or height of each column/row minus the size of the margins.
34+
35+ Then the size of the margins for each row and column are determined as the
36+ max width of the decorators on each axes that has decorators in that margin.
37+ For instance, a normal axes would have a left margin that includes the
38+ left ticklabels, and the ylabel if it exists. The right margin may include a
39+ colorbar, the bottom margin the xaxis decorations, and the top margin the
40+ title.
41+
42+ With these constraints, the solver then finds appropriate bounds for the
43+ columns and rows. It's possible that the margins take up the whole figure,
44+ in which case the algorithm is not applied and a warning is raised.
45+
46+ See the tutorial doc:`/tutorials/intermediate/constrainedlayout_guide`
47+ for more discussion of the algorithm with examples.
1448"""
1549
1650import logging
2256import matplotlib ._layoutgrid as mlayoutgrid
2357
2458
25- # General idea:
26- # -------------
27- #
28- # First, a figure has a gridspec that divides the figure into nrows and ncols,
29- # with heights and widths set by ``height_ratios`` and ``width_ratios``,
30- # often just set to 1 for an equal grid.
31- #
32- # Subplotspecs that are derived from this gridspec can contain either a
33- # ``SubPanel``, a ``GridSpecFromSubplotSpec``, or an ``Axes``. The
34- # ``SubPanel`` and ``GridSpecFromSubplotSpec`` are dealt with recursively and
35- # each contain an analogous layout.
36- #
37- # Each ``GridSpec`` has a ``_layoutgrid`` attached to it. The ``_layoutgrid``
38- # has the same logical layout as the ``GridSpec``. Each row of the grid spec
39- # has a top and bottom "margin" and each column has a left and right "margin".
40- # The "inner" height of each row is constrained to be the same (or as modified
41- # by ``height_ratio``), and the "inner" width of each column is
42- # constrained to be the same (as modified by ``width_ratio``), where "inner"
43- # is the width or height of each column/row minus the size of the margins.
44- #
45- # Then the size of the margins for each row and column are determined as the
46- # max width of the decorators on each axes that has decorators in that margin.
47- # For instance, a normal axes would have a left margin that includes the
48- # left ticklabels, and the ylabel if it exists. The right margin may include a
49- # colorbar, the bottom margin the xaxis decorations, and the top margin the
50- # title.
51- #
52- # With these constraints, the solver then finds appropriate bounds for the
53- # columns and rows. It's possible that the margins take up the whole figure,
54- # in which case the algorithm is not applied and a warning is raised.
55- #
56- # See the tutorial doc:`/tutorials/intermediate/constrainedlayout_guide`
57- # for more discussion of the algorithm with examples.
58-
5959_log = logging .getLogger (__name__ )
6060
6161
@@ -71,6 +71,8 @@ def do_constrained_layout(fig, h_pad, w_pad,
7171 fig : Figure
7272 ``Figure`` instance to do the layout in.
7373
74+ renderer : Renderer
75+ Renderer to use.
7476
7577 h_pad, w_pad : float
7678 Padding around the axes elements in figure-normalized units.
@@ -91,6 +93,7 @@ def do_constrained_layout(fig, h_pad, w_pad,
9193 layoutgrid : private debugging structure
9294 """
9395
96+ renderer = fig ._get_renderer ()
9497 # make layoutgrid tree...
9598 layoutgrids = make_layoutgrids (fig , None , rect = rect )
9699 if not layoutgrids ['hasgrids' ]:
@@ -107,9 +110,9 @@ def do_constrained_layout(fig, h_pad, w_pad,
107110
108111 # make margins for all the axes and subfigures in the
109112 # figure. Add margins for colorbars...
110- make_layout_margins (layoutgrids , fig , h_pad = h_pad ,
113+ make_layout_margins (layoutgrids , fig , renderer , h_pad = h_pad ,
111114 w_pad = w_pad , hspace = hspace , wspace = wspace )
112- make_margin_suptitles (layoutgrids , fig , h_pad = h_pad ,
115+ make_margin_suptitles (layoutgrids , fig , renderer , h_pad = h_pad ,
113116 w_pad = w_pad )
114117
115118 # if a layout is such that a columns (or rows) margin has no
@@ -121,7 +124,7 @@ def do_constrained_layout(fig, h_pad, w_pad,
121124 layoutgrids [fig ].update_variables ()
122125
123126 if check_no_collapsed_axes (layoutgrids , fig ):
124- reposition_axes (layoutgrids , fig , h_pad = h_pad ,
127+ reposition_axes (layoutgrids , fig , renderer , h_pad = h_pad ,
125128 w_pad = w_pad , hspace = hspace , wspace = wspace )
126129 else :
127130 _api .warn_external ('constrained_layout not applied because '
@@ -282,7 +285,7 @@ def get_margin_from_padding(obj, *, w_pad=0, h_pad=0,
282285 return margin
283286
284287
285- def make_layout_margins (layoutgrids , fig , * , w_pad = 0 , h_pad = 0 ,
288+ def make_layout_margins (layoutgrids , fig , renderer , * , w_pad = 0 , h_pad = 0 ,
286289 hspace = 0 , wspace = 0 ):
287290 """
288291 For each axes, make a margin between the *pos* layoutbox and the
@@ -293,7 +296,7 @@ def make_layout_margins(layoutgrids, fig, *, w_pad=0, h_pad=0,
293296 """
294297 for sfig in fig .subfigs : # recursively make child panel margins
295298 ss = sfig ._subplotspec
296- make_layout_margins (layoutgrids , sfig ,
299+ make_layout_margins (layoutgrids , sfig , renderer ,
297300 w_pad = w_pad , h_pad = h_pad ,
298301 hspace = hspace , wspace = wspace )
299302
@@ -313,7 +316,7 @@ def make_layout_margins(layoutgrids, fig, *, w_pad=0, h_pad=0,
313316
314317 margin = get_margin_from_padding (ax , w_pad = w_pad , h_pad = h_pad ,
315318 hspace = hspace , wspace = wspace )
316- pos , bbox = get_pos_and_bbox (ax )
319+ pos , bbox = get_pos_and_bbox (ax , renderer )
317320 # the margin is the distance between the bounding box of the axes
318321 # and its position (plus the padding from above)
319322 margin ['left' ] += pos .x0 - bbox .x0
@@ -330,7 +333,7 @@ def make_layout_margins(layoutgrids, fig, *, w_pad=0, h_pad=0,
330333 # colorbars can be child of more than one subplot spec:
331334 cbp_rspan , cbp_cspan = get_cb_parent_spans (cbax )
332335 loc = cbax ._colorbar_info ['location' ]
333- cbpos , cbbbox = get_pos_and_bbox (cbax )
336+ cbpos , cbbbox = get_pos_and_bbox (cbax , renderer )
334337 if loc == 'right' :
335338 if cbp_cspan .stop == ss .colspan .stop :
336339 # only increase if the colorbar is on the right edge
@@ -366,7 +369,7 @@ def make_layout_margins(layoutgrids, fig, *, w_pad=0, h_pad=0,
366369 layoutgrids [gs ].edit_outer_margin_mins (margin , ss )
367370
368371
369- def make_margin_suptitles (layoutgrids , fig , * , w_pad = 0 , h_pad = 0 ):
372+ def make_margin_suptitles (layoutgrids , fig , renderer , * , w_pad = 0 , h_pad = 0 ):
370373 # Figure out how large the suptitle is and make the
371374 # top level figure margin larger.
372375
@@ -379,29 +382,29 @@ def make_margin_suptitles(layoutgrids, fig, *, w_pad=0, h_pad=0):
379382 w_pad_local = padbox .width
380383
381384 for sfig in fig .subfigs :
382- make_margin_suptitles (layoutgrids , sfig ,
385+ make_margin_suptitles (layoutgrids , sfig , renderer ,
383386 w_pad = w_pad , h_pad = h_pad )
384387
385388 if fig ._suptitle is not None and fig ._suptitle .get_in_layout ():
386389 p = fig ._suptitle .get_position ()
387390 if getattr (fig ._suptitle , '_autopos' , False ):
388391 fig ._suptitle .set_position ((p [0 ], 1 - h_pad_local ))
389- bbox = inv_trans_fig (fig ._suptitle .get_tightbbox ())
392+ bbox = inv_trans_fig (fig ._suptitle .get_tightbbox (renderer ))
390393 layoutgrids [fig ].edit_margin_min ('top' , bbox .height + 2 * h_pad )
391394
392395 if fig ._supxlabel is not None and fig ._supxlabel .get_in_layout ():
393396 p = fig ._supxlabel .get_position ()
394397 if getattr (fig ._supxlabel , '_autopos' , False ):
395398 fig ._supxlabel .set_position ((p [0 ], h_pad_local ))
396- bbox = inv_trans_fig (fig ._supxlabel .get_tightbbox ())
399+ bbox = inv_trans_fig (fig ._supxlabel .get_tightbbox (renderer ))
397400 layoutgrids [fig ].edit_margin_min ('bottom' ,
398401 bbox .height + 2 * h_pad )
399402
400403 if fig ._supylabel is not None and fig ._supylabel .get_in_layout ():
401404 p = fig ._supylabel .get_position ()
402405 if getattr (fig ._supylabel , '_autopos' , False ):
403406 fig ._supylabel .set_position ((w_pad_local , p [1 ]))
404- bbox = inv_trans_fig (fig ._supylabel .get_tightbbox ())
407+ bbox = inv_trans_fig (fig ._supylabel .get_tightbbox (renderer ))
405408 layoutgrids [fig ].edit_margin_min ('left' , bbox .width + 2 * w_pad )
406409
407410
@@ -522,14 +525,14 @@ def get_cb_parent_spans(cbax):
522525 return rowspan , colspan
523526
524527
525- def get_pos_and_bbox (ax ):
528+ def get_pos_and_bbox (ax , renderer ):
526529 """
527530 Get the position and the bbox for the axes.
528531
529532 Parameters
530533 ----------
531534 ax
532-
535+ renderer
533536
534537 Returns
535538 -------
@@ -542,15 +545,15 @@ def get_pos_and_bbox(ax):
542545 pos = ax .get_position (original = True )
543546 # pos is in panel co-ords, but we need in figure for the layout
544547 pos = pos .transformed (fig .transSubfigure - fig .transFigure )
545- tightbbox = martist ._get_tightbbox_for_layout_only (ax )
548+ tightbbox = martist ._get_tightbbox_for_layout_only (ax , renderer )
546549 if tightbbox is None :
547550 bbox = pos
548551 else :
549552 bbox = tightbbox .transformed (fig .transFigure .inverted ())
550553 return pos , bbox
551554
552555
553- def reposition_axes (layoutgrids , fig , * ,
556+ def reposition_axes (layoutgrids , fig , renderer , * ,
554557 w_pad = 0 , h_pad = 0 , hspace = 0 , wspace = 0 ):
555558 """
556559 Reposition all the axes based on the new inner bounding box.
@@ -560,7 +563,7 @@ def reposition_axes(layoutgrids, fig, *,
560563 bbox = layoutgrids [sfig ].get_outer_bbox ()
561564 sfig ._redo_transform_rel_fig (
562565 bbox = bbox .transformed (trans_fig_to_subfig ))
563- reposition_axes (layoutgrids , sfig ,
566+ reposition_axes (layoutgrids , sfig , renderer ,
564567 w_pad = w_pad , h_pad = h_pad ,
565568 wspace = wspace , hspace = hspace )
566569
@@ -588,11 +591,11 @@ def reposition_axes(layoutgrids, fig, *,
588591 offset = {'left' : 0 , 'right' : 0 , 'bottom' : 0 , 'top' : 0 }
589592 for nn , cbax in enumerate (ax ._colorbars [::- 1 ]):
590593 if ax == cbax ._colorbar_info ['parents' ][0 ]:
591- reposition_colorbar (layoutgrids , cbax ,
594+ reposition_colorbar (layoutgrids , cbax , renderer ,
592595 offset = offset )
593596
594597
595- def reposition_colorbar (layoutgrids , cbax , * , offset = None ):
598+ def reposition_colorbar (layoutgrids , cbax , renderer , * , offset = None ):
596599 """
597600 Place the colorbar in its new place.
598601
@@ -601,6 +604,7 @@ def reposition_colorbar(layoutgrids, cbax, *, offset=None):
601604 cbax : Axes
602605 Axes for the colorbar
603606
607+ renderer :
604608 w_pad, h_pad : float
605609 width and height padding (in fraction of figure)
606610 hspace, wspace : float
@@ -627,7 +631,7 @@ def reposition_colorbar(layoutgrids, cbax, *, offset=None):
627631 aspect = cbax ._colorbar_info ['aspect' ]
628632 shrink = cbax ._colorbar_info ['shrink' ]
629633
630- cbpos , cbbbox = get_pos_and_bbox (cbax )
634+ cbpos , cbbbox = get_pos_and_bbox (cbax , renderer )
631635
632636 # Colorbar gets put at extreme edge of outer bbox of the subplotspec
633637 # It needs to be moved in by: 1) a pad 2) its "margin" 3) by
0 commit comments