Skip to content

Fix restoring 'auto' aspect in 3D axes after switching from 'equal'#31304

Open
jayaprajapatii wants to merge 1 commit into
matplotlib:mainfrom
jayaprajapatii:fix-3dplot-aspect-back-to-auto
Open

Fix restoring 'auto' aspect in 3D axes after switching from 'equal'#31304
jayaprajapatii wants to merge 1 commit into
matplotlib:mainfrom
jayaprajapatii:fix-3dplot-aspect-back-to-auto

Conversation

@jayaprajapatii

Copy link
Copy Markdown
Contributor

Closes #31276

Switching the aspect of a 3D axis from "auto" to "equal" and then back to "auto" did not restore the original plot correctly. The logic for handling "auto" continued executing the equal-aspect adjustments, which modified the axis limits and box aspect.

This change ensures that when aspect == "auto", the box aspect is reset and the function exits early, preventing further equal-aspect logic from running.

The baseline image for test_aspects has been updated to reflect the corrected rendering.

@rcomer

rcomer commented Mar 14, 2026

Copy link
Copy Markdown
Member

I'm not too familiar with 3D plotting, but the test explicitly set the box aspect. If a user did similarly, shouldn't we respect it?

ax.set_box_aspect((3, 4, 5))
ax.set_aspect(aspects[i], adjustable='datalim')

@jayaprajapatii

Copy link
Copy Markdown
Contributor Author

Thanks @rcomer
My intention with the early return was to avoid the equal-aspect adjustment logic from running when aspect="auto", since it was continuing to modify the axis limits and box aspect.
You're right that the test explicitly sets a box aspect. In that case we should respect a user-defined set_box_aspect.

Would it make more sense to only reset the box aspect when it was implicitly modified by the equal-aspect logic, rather than when it was explicitly set by the user?

@QuLogic QuLogic requested a review from scottshambaugh March 17, 2026 21:33
@scottshambaugh

Copy link
Copy Markdown
Contributor

I think that overriding a previously set aspect with "auto" is the correct behavior. But we should have different behavior with setting "auto" on the "datalim" - the box shouldn't be modified in that case.

@scottshambaugh scottshambaugh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test image was changed in separate commits, so that needs to be git squashed or rebased to fix the "PR Cleanliness" failure.

Also, this new behavior needs to be tested.

Comment thread lib/mpl_toolkits/mplot3d/axes3d.py Outdated
Comment thread lib/mpl_toolkits/mplot3d/axes3d.py Outdated
Comment thread lib/mpl_toolkits/mplot3d/axes3d.py Outdated
@jayaprajapatii jayaprajapatii force-pushed the fix-3dplot-aspect-back-to-auto branch from e8db81d to a4d63fa Compare March 22, 2026 17:10

@scottshambaugh scottshambaugh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I think this is looking good for the adjustable='box' case. What's the current behavior for 'datalim'? That should be fixed at the same time as well.

Comment thread lib/mpl_toolkits/mplot3d/tests/test_axes3d.py
@jayaprajapatii

Copy link
Copy Markdown
Contributor Author

Hello @scottshambaugh

Updated set_aspect('auto') to respect adjustable. For adjustable='box', the box aspect is reset as expected.
For adjustable='datalim', the existing behavior is preserved.

I verified that in the datalim case, switching to 'equal' does not lead to a meaningful change in limits, so I did not add an assertion for limit differences.
Added a test to cover the adjustable='datalim' behavior.

@scottshambaugh

Copy link
Copy Markdown
Contributor

What is the current behavior for 'datalim'? Please share screenshots, and try to set up a case where this is exercised. I don't think the test added for the datalim case is meaningfully doing anything right now.

@jayaprajapatii

Copy link
Copy Markdown
Contributor Author

Hello,
I rechecked the datalim case with a minimal example.

Observed behavior:
Initial limits, after setting 'equal', and after switching back to 'auto' all remain the same. So in the 'datalim' case, aspect changes do not seem to affect limits.

Screenshot 2026-03-25 032213 Screenshot 2026-03-25 032247

Given this behavior, I’m trying to determine what the intended assertion should be for the datalim case. Could you clarify what aspect of the behavior we should validate here?

@scottshambaugh

scottshambaugh commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

The auto with datalim should give the same limits in both cases here (which should both match the default autoscaling):

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(1, 1, subplot_kw={'projection': '3d'})

ax.plot([0, 1], [0, 1], [0, 1])
print('default:', np.array(ax.get_w_lims()))
ax.set_aspect('auto', 'datalim')
print('auto:', np.array(ax.get_w_lims()))

ax.set_aspect('equal', 'datalim')
print('equal:', np.array(ax.get_w_lims()))
ax.set_aspect('auto', 'datalim')
print('auto:', np.array(ax.get_w_lims()))
default: [-0.07291667  1.07291667 -0.07291667  1.07291667 -0.02083333  1.02083333]
auto: [-0.07291667  1.07291667 -0.07291667  1.07291667 -0.02083333  1.02083333]
equal: [-0.19444444  1.19444444 -0.19444444  1.19444444 -0.02083333  1.02083333]
auto: [-0.19444444  1.19444444 -0.19444444  1.19444444 -0.02083333  1.02083333]

@scottshambaugh

Copy link
Copy Markdown
Contributor

Hi @jayaprajapatii are you still interested in working on this? I think you may need to rebase to main to get the tests working again

@jayaprajapatii

Copy link
Copy Markdown
Contributor Author

Thankyou @scottshambaugh
Yes, I’m still working on this. I’ll rebase onto main and update the PR shortly.

@scottshambaugh

Copy link
Copy Markdown
Contributor

Hi @jayaprajapatii are you still interested in working on this? The baseline image test failure is real.

@scottshambaugh

Copy link
Copy Markdown
Contributor

Ok almost there - you'll need to squash /rebase your commits so the aspects.png baseline image isn't modified in multiple of them. We do that to help limit the size of the git history.

@jayaprajapatii jayaprajapatii force-pushed the fix-3dplot-aspect-back-to-auto branch from 1b03c4c to cc7babe Compare May 24, 2026 06:50
@scottshambaugh

scottshambaugh commented May 24, 2026

Copy link
Copy Markdown
Contributor

I don't see any visual changes in the aspects.png baseline image now, and it passes locally with the new code. I don't think it needs to be updated unless CI complains - could you please remove that image change?

@jayaprajapatii jayaprajapatii force-pushed the fix-3dplot-aspect-back-to-auto branch from cc7babe to 672356e Compare May 25, 2026 06:11

@scottshambaugh scottshambaugh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good for me, thanks for putting it together!

Comment thread lib/mpl_toolkits/mplot3d/axes3d.py Outdated
self._aspect == "auto"
and aspect in ('equal', 'equalxy', 'equalxz', 'equalyz')
):
self._auto_aspect_restore_limits = self.get_w_lims()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an attribute? It only appears to be used in this method.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hii @QuLogic ,
I think the limits need to persist across separate set_aspect calls when switching back from "equal" to "auto", which is why I stored them on the instance.

@QuLogic QuLogic Jul 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understood that part between switching modes. What I don't understand is how it manages to work if you change w_lims (i.e., xlim, ylim, or zlim) between switching.

~That is, this does work now:~
ax2.set_aspect('auto', adjustable='datalim')
ax2.set_xlim([-50, 50])
fig2.savefig('3d-plot1.png')  # Correct
ax2.set_aspect('equal', adjustable='datalim')
ax2.set_xlim([-50, 50])
ax2.set_aspect('auto', adjustable='datalim')
fig2.savefig('3d-plot2.png')  # Previously wrong (inconsistent with 3d-plot1.png) but fixed in this PR.

but I'm missing where the persisted limits get refreshed.

@QuLogic QuLogic Jul 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No wait, I'm dumb; my example doesn't work. It's just that I set the xlim on the Axes before the first save, so of course it carried through to the second one. When doing it individually, this PR is still incorrect:

fig2 = plt.figure()
ax2 = fig2.add_subplot(projection='3d')
X, Y, Z = axes3d.get_test_data()
ax2.contourf(X, Y, Z, cmap="coolwarm")
ax2.set_aspect('auto', adjustable='datalim')
ax2.set_xlim([-50, 50])
fig2.savefig('3d-plot1.png')  # Correct

fig3 = plt.figure()
ax3 = fig3.add_subplot(projection='3d')
X, Y, Z = axes3d.get_test_data()
ax3.contourf(X, Y, Z, cmap="coolwarm")
ax3.set_aspect('equal', adjustable='datalim')
ax3.set_xlim([-50, 50])
ax3.set_aspect('auto', adjustable='datalim')
fig3.savefig('3d-plot2.png')  # Wrong (inconsistent with 3d-plot1.png)

@jayaprajapatii

Copy link
Copy Markdown
Contributor Author

Hello @QuLogic

Just a gentle ping, please have a look at this PR.

@scottshambaugh scottshambaugh added this to the v3.11.1 milestone Jun 30, 2026
@jayaprajapatii jayaprajapatii force-pushed the fix-3dplot-aspect-back-to-auto branch 2 times, most recently from d889829 to 1d08ff6 Compare July 10, 2026 18:06
@jayaprajapatii jayaprajapatii force-pushed the fix-3dplot-aspect-back-to-auto branch from 1d08ff6 to 7e7d7f8 Compare July 10, 2026 18:17
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]: Setting aspect back to auto cannot recover the original 3D plot

4 participants