Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c159c26

Browse files
committed
Include figure-level texts and legends in constrained layout
1 parent 54d3856 commit c159c26

2 files changed

Lines changed: 64 additions & 16 deletions

File tree

lib/matplotlib/_constrained_layout.py

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -440,22 +440,59 @@ def make_layout_margins(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0,
440440

441441
# make margins for figure-level legends:
442442
for leg in fig.legends:
443-
inv_trans_fig = None
444-
if leg._outside_loc and leg._bbox_to_anchor is None:
445-
if inv_trans_fig is None:
446-
inv_trans_fig = fig.transFigure.inverted().transform_bbox
447-
bbox = inv_trans_fig(leg.get_tightbbox(renderer))
448-
w = bbox.width + 2 * w_pad
449-
h = bbox.height + 2 * h_pad
450-
legendloc = leg._outside_loc
451-
if legendloc == 'lower':
452-
layoutgrids[fig].edit_margin_min('bottom', h)
453-
elif legendloc == 'upper':
454-
layoutgrids[fig].edit_margin_min('top', h)
455-
if legendloc == 'right':
456-
layoutgrids[fig].edit_margin_min('right', w)
457-
elif legendloc == 'left':
458-
layoutgrids[fig].edit_margin_min('left', w)
443+
# === NEW: handle figure-level texts ===
444+
inv_trans_fig = fig.transFigure.inverted().transform_bbox
445+
446+
for text in fig.texts:
447+
if not text.get_visible() or not text.get_in_layout():
448+
continue
449+
450+
try:
451+
bbox = inv_trans_fig(text.get_tightbbox(renderer))
452+
except Exception:
453+
continue
454+
455+
if bbox is None:
456+
continue
457+
458+
w = bbox.width + 2 * w_pad
459+
h = bbox.height + 2 * h_pad
460+
461+
# Expand margins conservatively
462+
if bbox.y1 > 1: # top overflow
463+
layoutgrids[fig].edit_margin_min('top', h)
464+
if bbox.y0 < 0: # bottom overflow
465+
layoutgrids[fig].edit_margin_min('bottom', h)
466+
if bbox.x0 < 0: # left overflow
467+
layoutgrids[fig].edit_margin_min('left', w)
468+
if bbox.x1 > 1: # right overflow
469+
layoutgrids[fig].edit_margin_min('right', w)
470+
471+
472+
# === NEW: handle general figure legends (not just _outside_loc) ===
473+
for leg in fig.legends:
474+
if not leg.get_visible() or not leg.get_in_layout():
475+
continue
476+
477+
try:
478+
bbox = inv_trans_fig(leg.get_tightbbox(renderer))
479+
except Exception:
480+
continue
481+
482+
if bbox is None:
483+
continue
484+
485+
w = bbox.width + 2 * w_pad
486+
h = bbox.height + 2 * h_pad
487+
488+
if bbox.y1 > 1:
489+
layoutgrids[fig].edit_margin_min('top', h)
490+
if bbox.y0 < 0:
491+
layoutgrids[fig].edit_margin_min('bottom', h)
492+
if bbox.x0 < 0:
493+
layoutgrids[fig].edit_margin_min('left', w)
494+
if bbox.x1 > 1:
495+
layoutgrids[fig].edit_margin_min('right', w)
459496

460497

461498
def make_margin_suptitles(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0):

lib/matplotlib/tests/test_constrainedlayout.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,18 @@
1414
pytestmark = [
1515
pytest.mark.usefixtures('text_placeholders')
1616
]
17+
def test_constrainedlayout_fig_text():
18+
import matplotlib.pyplot as plt
1719

20+
fig, ax = plt.subplots(layout="constrained")
21+
fig.text(0.5, 0.98, "Title", ha="center")
22+
23+
fig.draw_without_rendering()
24+
25+
ax_bbox = ax.get_position()
26+
27+
# Axes should not touch the top
28+
assert ax_bbox.y1 < 0.98
1829

1930
def example_plot(ax, fontsize=12, nodec=False):
2031
ax.plot([1, 2])

0 commit comments

Comments
 (0)