Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
Axes3D.plot_surface
: Allow masked arrays andNaN
values#20725
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'm slightly worried that we are throwing away data and not storing the original inputs in thePolyCollection
. Do we have precedent for that?
Nevertheless I'm tempted to accept the solution as it is much simpler and faster than any later data cleaning. Maybe we should add a note on the data cleaning in the docstring.
Uh oh!
There was an error while loading.Please reload this page.
I don't know, hopefully someone else does. The one thought I had was to see what is done in importmatplotlib.pyplotaspltimportnumpyasnpx,y=np.mgrid[-10:10.1:2,-10:10.1:2]z=np.ma.masked_less(x**2+y**2,50)fig,ax=plt.subplots(figsize=(6,6))contours=ax.contourf(x,y,z)segs=np.concatenate([np.concatenate(s)forsincontours.allsegsifs]).Tpaths=np.concatenate( [i.verticesforpathsincontours.collectionsforiinpaths.get_paths()]).Tax.plot(segs[0],segs[1],"rs")ax.plot(paths[0],paths[1],".b") |
The user threw the data away when they NaN-ed or masked it. I don't think we are going to offer a way to unmask it after the surface is made, so I don't think there is harm in removing it. But maybe I'm missing a subtlety in the data->polygon pipeline. I assume if the user changes x, y, Z in the data then the polygons are regenerated anyway? |
Sorry@jklymak I don't understand your question. What kind of changing of x, y and Z do you have in mind? |
via |
I'm not sure what the equivalent would be. You could get the paths with The original x, y and z don't get passed to the |
Sorry if I'm taking you off on a tangent - many of our methods save a representation of the original data. If this has no such representation, then there really is no harm done in throwing out masked data because the user can't modify it post-facto anyways. |
The |
@eric-wieser@WeatherGod@ianthomas23 do any of you have time to comment onthis solution to the masking problem? It seems reasonable tome but I don't know if I've ever used |
eric-wieser commentedJul 29, 2021 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Can you add a test showing how this behaves with striding? For instance, if a facet with stride=4 has all the
|
@eric-wieser Here is the example you request (for before and after this PR). It is a bit hard to show here but from the side angle (third plot) it doesn't look right, neither before and after this PR. Is this what you wanted to see? Example without PRExample with PRCode for plotsimportmatplotlib.pyplotaspltimportnumpyasnpx,y=np.mgrid[-2:2.1:1,-2:2.1:1]z=np.ma.masked_less(x*y,2)fig, (ax1,ax2,ax3)=plt.subplots(figsize=(9,3),ncols=3,subplot_kw={"projection":"3d"})ax1.plot_surface(x,y,z)ax1.set_title("Default strides")ax1.view_init(60,-45)surf=ax2.plot_surface(x,y,z,rstride=4,cstride=4)ax2.set_title("r/cstride = 4")ax2.view_init(60,-45)surf=ax3.plot_surface(x,y,z,rstride=4,cstride=4)ax3.set_title("r/cstride = 4")ax3.view_init(2,30) |
Thanks, that does show what I was expecting to see. I don't think the side view is interesting, but I think the middle plot might be worth adding a test for in case someone decides they want different behavior later. Using |
Yes, that looks like a good test case to include, thanks! My question (possibly for a future PR) would be whether it makes sense to split that middle polygon in two, into two triangles - but it's not immediately clear to me how such an approach would generalize. |
Yes I had the same thought after the first example (whether the polygon could be split into pieces to help the side view). I'm not sure how simple it is, so I think as you say it might be a question for a future PR. |
I'm not sure we should be worried about striding effects - if you decimate your data you should expect aliasing, and if you decimate a mask it is luck of the draw where on the mask your stride will fall. If you need more control, it really isn't hard to stride your own data. |
I'd dispute that the claim that it's easy to stride your own data - this isn't just simple striding that takes 1/n² of the elements, it's preserving full resolution along the gridlines and discarding data in the cells, taking (2n-1)/n² of the elements. That means there's no way to represent the striding in a numpy array. That's not to say you're wrong in saying that the weirdness in the plot above is unimportant - I think it's fine to merge with the current behavior, and was only pushing for a test to ensure we were aware of the quirk. |
probably off topic, but that is confusing. The docs say |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
There were a couple of CI failures, but I've rerun them and they now pass.
As my opinion was requested, I've taken a look at this PR and am happy with the output. But I am not a frequent user of mplot3d.
eric-wieser commentedAug 4, 2021 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I mean that rstride=cstride=3 samples the input data as
Not
(Where every character is an entry in the input data array, and every # is a point that gets plotted) |
So is the problem that the docs are wrong or my understanding of the term "stride" is wrong? |
The docs are using "stride" in a vague sense, so they're not wrong per se, but certainly easy to misread. The reading I have of them that is consistent with the implementation is "Split the surface into row and column gridlines spaced
I think the current behavior of the striding (ignoring this PR) is the right behavior, but the docs don't describe it well. |
It appears this is good to go, and the striding discussion is orthogonal, so I'm going to merge this. |
Extend the logic introduced bymatplotlib#20725 for NaN values to inf values,avoiding the introduction of infinite vertices in the mesh that wreakhavoc when performing the z-sorting.Sadly I don't have a minimal test case for this problem.
Extend the logic introduced bymatplotlib#20725 for NaN values to inf values,avoiding the introduction of infinite vertices in the mesh that wreakhavoc when performing the z-sorting.Sadly I don't have a minimal test case for this problem.
Uh oh!
There was an error while loading.Please reload this page.
PR Summary
This is my third attempt at solving the issues with using masked arrays in
Axes3D.plot_surface
, previous attempts are#18114 and#20646. Hopefully it is third time lucky.I got the impression that the feedback on#18114 was reasonably positive but this approach solves more issues and also behaves like
contour
withcorner_mask=True
which was a preference expressed by@ianthomas23.The suggestion from#20646 was that it would be better to deal with NaNs before we get to
Poly3DCollection.do_3d_projection
which is called every time we adjust an interactive figure.I've gone "all in" on this PR and removed the warning about not supporting NaNs and added masked array support, if you prefer to take this step-by-step e.g. removing the masked array part or keeping the NaN warning, then let me know, and I'll happily change.
There are no tests yet, once I've had some feedback on this I'll add some based on the issues that this closes.
Examples of the issues that this PR solves (along with the code to make them) are below. I didn't add the example from#8222 which loads a large dataset but the before and after are visually the same as the examples shown in#20646.
Examples before this PR
Examples after this PR
Code for examples
PR Checklist
pytest
passes).flake8
on changed files to check).flake8-docstrings
and runflake8 --docstring-convention=all
).doc/users/next_whats_new/
(follow instructions in README.rst there).doc/api/next_api_changes/
(follow instructions in README.rst there).