11
11
layout. Axes manually placed via ``figure.add_axes()`` will not.
12
12
13
13
See 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.
14
48
"""
15
49
16
50
import logging
22
56
import matplotlib ._layoutgrid as mlayoutgrid
23
57
24
58
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
-
59
59
_log = logging .getLogger (__name__ )
60
60
61
61
@@ -71,6 +71,8 @@ def do_constrained_layout(fig, h_pad, w_pad,
71
71
fig : Figure
72
72
``Figure`` instance to do the layout in.
73
73
74
+ renderer : Renderer
75
+ Renderer to use.
74
76
75
77
h_pad, w_pad : float
76
78
Padding around the axes elements in figure-normalized units.
@@ -91,6 +93,7 @@ def do_constrained_layout(fig, h_pad, w_pad,
91
93
layoutgrid : private debugging structure
92
94
"""
93
95
96
+ renderer = fig ._get_renderer ()
94
97
# make layoutgrid tree...
95
98
layoutgrids = make_layoutgrids (fig ,None ,rect = rect )
96
99
if not layoutgrids ['hasgrids' ]:
@@ -107,9 +110,9 @@ def do_constrained_layout(fig, h_pad, w_pad,
107
110
108
111
# make margins for all the axes and subfigures in the
109
112
# 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 ,
111
114
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 ,
113
116
w_pad = w_pad )
114
117
115
118
# 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,
121
124
layoutgrids [fig ].update_variables ()
122
125
123
126
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 ,
125
128
w_pad = w_pad ,hspace = hspace ,wspace = wspace )
126
129
else :
127
130
_api .warn_external ('constrained_layout not applied because '
@@ -282,7 +285,7 @@ def get_margin_from_padding(obj, *, w_pad=0, h_pad=0,
282
285
return margin
283
286
284
287
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 ,
286
289
hspace = 0 ,wspace = 0 ):
287
290
"""
288
291
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,
293
296
"""
294
297
for sfig in fig .subfigs :# recursively make child panel margins
295
298
ss = sfig ._subplotspec
296
- make_layout_margins (layoutgrids ,sfig ,
299
+ make_layout_margins (layoutgrids ,sfig ,renderer ,
297
300
w_pad = w_pad ,h_pad = h_pad ,
298
301
hspace = hspace ,wspace = wspace )
299
302
@@ -313,7 +316,7 @@ def make_layout_margins(layoutgrids, fig, *, w_pad=0, h_pad=0,
313
316
314
317
margin = get_margin_from_padding (ax ,w_pad = w_pad ,h_pad = h_pad ,
315
318
hspace = hspace ,wspace = wspace )
316
- pos ,bbox = get_pos_and_bbox (ax )
319
+ pos ,bbox = get_pos_and_bbox (ax , renderer )
317
320
# the margin is the distance between the bounding box of the axes
318
321
# and its position (plus the padding from above)
319
322
margin ['left' ]+= pos .x0 - bbox .x0
@@ -330,7 +333,7 @@ def make_layout_margins(layoutgrids, fig, *, w_pad=0, h_pad=0,
330
333
# colorbars can be child of more than one subplot spec:
331
334
cbp_rspan ,cbp_cspan = get_cb_parent_spans (cbax )
332
335
loc = cbax ._colorbar_info ['location' ]
333
- cbpos ,cbbbox = get_pos_and_bbox (cbax )
336
+ cbpos ,cbbbox = get_pos_and_bbox (cbax , renderer )
334
337
if loc == 'right' :
335
338
if cbp_cspan .stop == ss .colspan .stop :
336
339
# 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,
366
369
layoutgrids [gs ].edit_outer_margin_mins (margin ,ss )
367
370
368
371
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 ):
370
373
# Figure out how large the suptitle is and make the
371
374
# top level figure margin larger.
372
375
@@ -379,29 +382,29 @@ def make_margin_suptitles(layoutgrids, fig, *, w_pad=0, h_pad=0):
379
382
w_pad_local = padbox .width
380
383
381
384
for sfig in fig .subfigs :
382
- make_margin_suptitles (layoutgrids ,sfig ,
385
+ make_margin_suptitles (layoutgrids ,sfig ,renderer ,
383
386
w_pad = w_pad ,h_pad = h_pad )
384
387
385
388
if fig ._suptitle is not None and fig ._suptitle .get_in_layout ():
386
389
p = fig ._suptitle .get_position ()
387
390
if getattr (fig ._suptitle ,'_autopos' ,False ):
388
391
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 ))
390
393
layoutgrids [fig ].edit_margin_min ('top' ,bbox .height + 2 * h_pad )
391
394
392
395
if fig ._supxlabel is not None and fig ._supxlabel .get_in_layout ():
393
396
p = fig ._supxlabel .get_position ()
394
397
if getattr (fig ._supxlabel ,'_autopos' ,False ):
395
398
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 ))
397
400
layoutgrids [fig ].edit_margin_min ('bottom' ,
398
401
bbox .height + 2 * h_pad )
399
402
400
403
if fig ._supylabel is not None and fig ._supylabel .get_in_layout ():
401
404
p = fig ._supylabel .get_position ()
402
405
if getattr (fig ._supylabel ,'_autopos' ,False ):
403
406
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 ))
405
408
layoutgrids [fig ].edit_margin_min ('left' ,bbox .width + 2 * w_pad )
406
409
407
410
@@ -522,14 +525,14 @@ def get_cb_parent_spans(cbax):
522
525
return rowspan ,colspan
523
526
524
527
525
- def get_pos_and_bbox (ax ):
528
+ def get_pos_and_bbox (ax , renderer ):
526
529
"""
527
530
Get the position and the bbox for the axes.
528
531
529
532
Parameters
530
533
----------
531
534
ax
532
-
535
+ renderer
533
536
534
537
Returns
535
538
-------
@@ -542,15 +545,15 @@ def get_pos_and_bbox(ax):
542
545
pos = ax .get_position (original = True )
543
546
# pos is in panel co-ords, but we need in figure for the layout
544
547
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 )
546
549
if tightbbox is None :
547
550
bbox = pos
548
551
else :
549
552
bbox = tightbbox .transformed (fig .transFigure .inverted ())
550
553
return pos ,bbox
551
554
552
555
553
- def reposition_axes (layoutgrids ,fig ,* ,
556
+ def reposition_axes (layoutgrids ,fig ,renderer , * ,
554
557
w_pad = 0 ,h_pad = 0 ,hspace = 0 ,wspace = 0 ):
555
558
"""
556
559
Reposition all the axes based on the new inner bounding box.
@@ -560,7 +563,7 @@ def reposition_axes(layoutgrids, fig, *,
560
563
bbox = layoutgrids [sfig ].get_outer_bbox ()
561
564
sfig ._redo_transform_rel_fig (
562
565
bbox = bbox .transformed (trans_fig_to_subfig ))
563
- reposition_axes (layoutgrids ,sfig ,
566
+ reposition_axes (layoutgrids ,sfig ,renderer ,
564
567
w_pad = w_pad ,h_pad = h_pad ,
565
568
wspace = wspace ,hspace = hspace )
566
569
@@ -588,11 +591,11 @@ def reposition_axes(layoutgrids, fig, *,
588
591
offset = {'left' :0 ,'right' :0 ,'bottom' :0 ,'top' :0 }
589
592
for nn ,cbax in enumerate (ax ._colorbars [::- 1 ]):
590
593
if ax == cbax ._colorbar_info ['parents' ][0 ]:
591
- reposition_colorbar (layoutgrids ,cbax ,
594
+ reposition_colorbar (layoutgrids ,cbax ,renderer ,
592
595
offset = offset )
593
596
594
597
595
- def reposition_colorbar (layoutgrids ,cbax ,* ,offset = None ):
598
+ def reposition_colorbar (layoutgrids ,cbax ,renderer , * ,offset = None ):
596
599
"""
597
600
Place the colorbar in its new place.
598
601
@@ -601,6 +604,7 @@ def reposition_colorbar(layoutgrids, cbax, *, offset=None):
601
604
cbax : Axes
602
605
Axes for the colorbar
603
606
607
+ renderer :
604
608
w_pad, h_pad : float
605
609
width and height padding (in fraction of figure)
606
610
hspace, wspace : float
@@ -627,7 +631,7 @@ def reposition_colorbar(layoutgrids, cbax, *, offset=None):
627
631
aspect = cbax ._colorbar_info ['aspect' ]
628
632
shrink = cbax ._colorbar_info ['shrink' ]
629
633
630
- cbpos ,cbbbox = get_pos_and_bbox (cbax )
634
+ cbpos ,cbbbox = get_pos_and_bbox (cbax , renderer )
631
635
632
636
# Colorbar gets put at extreme edge of outer bbox of the subplotspec
633
637
# It needs to be moved in by: 1) a pad 2) its "margin" 3) by