Skip to content

set_{x,y,z}bound 3d limits are not persistent upon interactive rotation #18112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
anntzer opened this issue Jul 29, 2020 · 4 comments · Fixed by #18127
Closed

set_{x,y,z}bound 3d limits are not persistent upon interactive rotation #18112

anntzer opened this issue Jul 29, 2020 · 4 comments · Fixed by #18127

Comments

@anntzer
Copy link
Contributor

anntzer commented Jul 29, 2020

Bug report

Bug summary

3D axes limits set using set_{x,y,z}bound are dropped when interactively rotating 3d axes.

Code for reproduction

import matplotlib.pyplot as plt

ax = plt.figure().add_subplot(projection="3d")
ax.plot([0, 1], [0, 1], [0, 1])
ax.set(xbound=[-1, 1], ybound=[-1, 1], zbound=[-1, 1])
# ax.set(xlim=[-1, 1], ylim=[-1, 1], zlim=[-1, 1])
plt.show()

then interactively rotate the axes with the mouse.

Actual outcome

The axes limits immediately snap back to [0, 1] (plus margins).

Expected outcome

Limits are respected (as with set_{x,y,z}lim).

Matplotlib version

  • Operating system: linux
  • Matplotlib version: master
  • Matplotlib backend (print(matplotlib.get_backend())): qt5agg
  • Python version: 38
  • Jupyter version (if applicable):
  • Other libraries:
@timhoffm
Copy link
Member

The reason is the following

set_x/y/zlim() deactivate autoscaling (auto=False). set_x/y/zbound() leave the autoscaling unchanged (calling set_xlim(auto=None)).

This can be verified via

ax.set(xbound=[-1, 1], ybound=[-1, 1], zbound=[-1, 1])
ax._autoscaleXon = False
ax._autoscaleYon = False
ax._autoscaleZon = False

fixing the issue.

Questions:

  • Is it reasonable that *bounds and *lim behave differently concerning auto-scaling? But even if so, it may be hard to change, because I expect that would break a lot of user code.
  • Is there a reason that 3D rotation tries to auto-scale?

@QuLogic
Copy link
Member

QuLogic commented Jul 30, 2020

It's not the mouse move that triggers it, it's the draw. If you insert fig.canvas.draw() before plt.show(), the limits are [0, 1]. I don't know why this change during draw is not reflected in the plot.

I think this may be because of the new lazy autoscaling. Nothing in mplot3d sets the new ax._stale_viewlim_x, so _unstale_viewLim rescales.

@QuLogic
Copy link
Member

QuLogic commented Jul 30, 2020

This is a regression from 3.1.2; I will test some newer versions, but if it's lazy autoscaling, then it's a 3.3 3.2 regression. I think I've written most of a fix.

QuLogic added a commit to QuLogic/matplotlib that referenced this issue Jul 30, 2020
Since `Axes3D` derives from 2D `Axes`, this lazy autoscale was partially
implemented. This might cause extraneous re-scaling since the 3D case
did not always turn it off. It might also cause re-scaling to be missed
since 2D `Axes` does not check z.

Fixes matplotlib#18112.
@QuLogic
Copy link
Member

QuLogic commented Jul 31, 2020

I don't know why this change during draw is not reflected in the plot.

And this is because Axes3D.draw first calculates the world projection, then calls super().draw(), and Axes.draw calls self._unstale_viewLim. Putting that at the beginning of Axes3D.draw makes things stabler. This is similar to #17422 for PolarAxes.

QuLogic added a commit to QuLogic/matplotlib that referenced this issue Jul 31, 2020
Since `Axes3D` derives from 2D `Axes`, this lazy autoscale was partially
implemented. This might cause extraneous re-scaling since the 3D case
did not always turn it off. It might also cause re-scaling to be missed
since 2D `Axes` does not check z.

Fixes matplotlib#18112.
QuLogic added a commit to QuLogic/matplotlib that referenced this issue Aug 29, 2020
Since `Axes3D` derives from 2D `Axes`, this lazy autoscale was partially
implemented. This might cause extraneous re-scaling since the 3D case
did not always turn it off. It might also cause re-scaling to be missed
since 2D `Axes` does not check z.

Fixes matplotlib#18112.
QuLogic added a commit to QuLogic/matplotlib that referenced this issue Dec 19, 2020
Since `Axes3D` derives from 2D `Axes`, this lazy autoscale was partially
implemented. This might cause extraneous re-scaling since the 3D case
did not always turn it off. It might also cause re-scaling to be missed
since 2D `Axes` does not check z.

Fixes matplotlib#18112.
@QuLogic QuLogic added this to the v3.4.0 milestone Dec 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants