-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
[Bug]: Issue with setting axis limits on 3D plots #25804
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
Comments
I think that the axes not "truncating" the plotted surfaces is the intended behavior, though an option to crop data to the box inside the axis planes would be useful. Right now Somewhat related to #23450, where the issue is reversed - there we want to be clipping based on the 3d box, not the 2d one. |
A workaround in your case might be to edit your data so that points higher than 10 / 3000 on the respective axes are set to |
Thanks. I really don't understand why this is the intended behavior because it sure doesn't make sense and I wasted a lot of time trying to change the behavior. I just want to be able to set the axis limit without modifying the data. Any chance this could be fixed? |
Hi @nbfazel thank you for raising the issue! I'll try to take a look at this, but fair warning that it might not be soon and matplotlib only releases a new version every 6-12 months or so. I see two ways to implement this:
I think (2) is definitely much easier and covers most of the desired use cases here, and could always be a special case of (1) if that ever gets implemented. |
Thank you @scottshambaugh. I appreciate that. I will look for a interim solution while this is being implemented. |
I did some digging into this and think it will end up being rather complicated for surfaces plots like your example. The problem is that matplotlib's 3D renderer does not use a ray-tracing algorithm, so you cannot easily threshold drawing only part of a face for a polygon between specific bounds. Take (A) as your initial set of points. It would be fairly easy to threshold your points / vertices based on bounds, and I think that would work well for scatter plots. In the case of surfaces however, this will likely mean jagged sawtooth edges since you would not be drawing the polygons which have a vertex right outside your bounds, as in (B). Perhaps that's okay as a first step implementation. The way to get around this would be to fill in the gaps with new polygons created on the fly to edge match with the bounds, as in (C). That however could get very complicated especially in 3D near the corners/edges of the bounds from multiple axes, or in cases where your bounds are tighter than the extent of a single polygon. |
Thanks for the update. I wonder how this is done Matlab or Mathematica. |
In this example (scroll down to the answer), limits are set for all axes, without running into the issues I described above. I thought maybe it was because it also set axes to off. I tried that and it didn't make a difference. I'm not sure why setting axis limits works in the example. (I ran the example and produce the same image.) |
Just checking to see if we know why in the example provided above (on May 21), they don't run into the problem after setting axis limit in 3D. Thanks! |
Thank you so much. So do you think I should just go with the advice you gave on May 2? ("edit your data so that points higher than 10 / 3000 on the respective axes are set to np.nan") |
If you need to make these plots any time soon, then yes. With matplotlib as a 99%-volunteer effort it can take quite a long time to implement feature requests, and the number of people familiar with the 3D code is a smaller fraction than the 2D plotting. If you want to take a shot at adding this though, I think that an option to clip 3D data to the axis limits would be a welcome feature. :) |
Thanks! Recently I tried to fix an issue with SciPy (that I had reported) and even though the fix wasn't complicated, I spent a lot of time trying to set up my development environment and ultimately gave up. This is more challenging since I would first need to familiarize myself with 3D rendering and then again try to set up my development environment. |
LIke the suggestion by @scottshambaugh what if matplotlib chose the make the plots using the copy of the original numpy array with data points set to np.nan based on the choice of limits? Would that be easy to implement within matplotlib itself? |
Draft PR is up to add this functionality, I'll be fleshing it out over the next week. That PR will implement option (B) from my comment above, with jagged edges at the boundary. I'm going to say that getting straight/smooth edges rather than jagged edges is a "won't do" feature for now, as it would require some pretty drastic changes to how the renderer works, so (C) won't happen and I'll close this issue once the PR is merged. For further tracking of the smooth edges question, that bit can be considered a duplicate of this question: #8902 |
OK, thank you. I'll give it a try when it becomes available. |
#27349 to implement dynamic clipping in 3D plots is now ready for review if you'd like to play with it! |
Thanks! What do I need to do to sync up and pull the version of the code with the fix? |
@nbfazel you can find the branch that is getting merged here: https://github.com/scottshambaugh/matplotlib/tree/3d_dynamic_masking And this stackoverflow answer has good directions on the commands to do that: https://stackoverflow.com/questions/14383212/git-pulling-a-branch-from-another-repository But hopefully that issue has enough info to evaluate the behavior without having to download and test locally. |
Bug summary
I have created 3D surface plots using matplotlib as described [here]. Everything works except when I set the axis limits. Then the plots look very strange. It appears that commands such as Axes.set_xlim() (whether or not Axes.set_xbound()is used) limit the axis but not the data. The data is plotted and appears to continue beyond the axis limits.
Code for reproduction
Actual outcome
Surface plot after using
Axes.set_xlim(left=0, right=10)
:Surface plot after using using
Axes.set_xlim(left=0, right=10)
andaxes[0].set_zlim(0, 3000)
:Expected outcome
The image should look like the following but with the E axis ending at 10 keV and the vertical axis ending at 3000:
Additional information
I'm running the code that imports matplotlib in Spyder. I can share upon request the full code and input files needed to reproduce the error.
I tried all the suggestions in this post and also this one and none worked. For example, I tried:
Also
and
and
Operating system
OS/X Ventura 13.3.1
Matplotlib Version
3.5.2
Matplotlib Backend
Qt5Agg
Python version
3.9.13
Jupyter version
No response
Installation
None
The text was updated successfully, but these errors were encountered: