Skip to content

Fix Axes3D.get_tightbbox to include axis labels when not for_layout_only#31571

Open
Scolliq wants to merge 1 commit intomatplotlib:mainfrom
Scolliq:fix/axes3d-tightbbox-labels
Open

Fix Axes3D.get_tightbbox to include axis labels when not for_layout_only#31571
Scolliq wants to merge 1 commit intomatplotlib:mainfrom
Scolliq:fix/axes3d-tightbbox-labels

Conversation

@Scolliq
Copy link
Copy Markdown

@Scolliq Scolliq commented Apr 25, 2026

Problem

When saving a 3D figure with fig.savefig("out.png", bbox_inches='tight'),
axis labels (zlabel, xlabel, ylabel) are clipped because
Axes3D.get_tightbbox unconditionally calls
_get_tightbbox_for_layout_only for each 3D axis, which always passes
for_layout_only=True and therefore explicitly excludes labels from
the bounding box.

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.set_xlabel('X axis')
ax.set_zlabel('Z axis')
ax.scatter([1], [1], [1])
fig.savefig('out.png', bbox_inches='tight')  # labels get clipped

Fixes #28117.

Fix

In Axes3D.get_tightbbox, differentiate between the two call paths:

  • for_layout_only=True (layout engine): continue using
    _get_tightbbox_for_layout_only so layout calculations are unaffected
  • for_layout_only=False (savefig tight path): call
    axis.get_tightbbox(renderer, for_layout_only=False) directly so that
    labels are included in the bounding box

Tests

Added test_axes3d_tightbbox_includes_axis_labels which:

  • Verifies the full bbox is at least as large as the layout-only bbox
    (labels expand the bbox)
  • Confirms savefig(bbox_inches='tight') completes without error

When savefig(bbox_inches='tight') is used on a figure with 3D axes,
axis labels (zlabel, xlabel, ylabel) were being clipped because
Axes3D.get_tightbbox unconditionally called
_get_tightbbox_for_layout_only for each axis, which always passes
for_layout_only=True and therefore excludes labels from the bbox.

Fix: when the outer call has for_layout_only=False (the savefig path),
call axis.get_tightbbox(renderer, for_layout_only=False) directly so
that labels are included in the bounding box calculation.

The for_layout_only=True path (layout engine) continues to use the
existing helper to avoid affecting constrained/tight layout behaviour.

Fixes matplotlib#28117
@rcomer
Copy link
Copy Markdown
Member

rcomer commented Apr 25, 2026

Hello @Scolliq, I see you opened two PRs at the same time. We ask that new contributors not open a second PR until the first is closed
https://matplotlib.org/devdocs/devel/contribute.html#first-contributions

Please could you decide which of your PRs you would like to move forward with and close the other for now.

@rcomer
Copy link
Copy Markdown
Member

rcomer commented Apr 25, 2026

Since your PRs look AI driven, please also familiarise yourself with our policy on that
https://matplotlib.org/devdocs/devel/contribute.html#use-of-generative-ai

@Scolliq
Copy link
Copy Markdown
Author

Scolliq commented Apr 25, 2026

Apologies did not know about the one per person for the initial. The other has been closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: The zlabel on 3D axes will be cut when using '%matplotlib inline' in Jupyter

2 participants