Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add errorbars to mplot3d #8031

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

Merged
merged 36 commits into from
Aug 14, 2020
Merged

Conversation

vlas-sokolov
Copy link
Contributor

Motivated by the 'new-contributor-friendly' and 'wishlist' tags in #568, and having once asked this question on SO, this PR mimics the errorbar functionality present in the standard lib into mplot3d.

For a demonstration, I have rewritten a short snippet from here into and put in on Gist. It generates the figures below:

z-axis_errors
x-axis_errors

The new function was rewritten from its 2D counterpart. I aimed to follow the old structure as close as possible, and I think that most of the optional keywords have been successfully ported.

One issue that I'd like to get input in is the use of markers in error bar caps and (especially) limit symbols. The markers tend to rotate along with the camera position, and a 180 degree rotation along one of the axes may flip the markers into a rather confusing plot. What should be done with this? Is there a framework for projecting the markers in mplot3d?

As I'm a new contributor and might have missed some subtleties in the implementation, any feedback is highly appreciated!

@afvincent afvincent added this to the 2.1 (next point release) milestone Feb 6, 2017
@WeatherGod
Copy link
Member

(sent this earlier, but it hasn't shown up yet, so I am posting this again)

Heads up. There is another PR that is adding a new feature to errorbar that might need to be considered here, too: #6280

This looks neat. The marker problem is difficult to handle correctly and there isn't any framework for dealing with it partly because mplot3d does not properly integrate into the overall transforms system. Markers are actually avoided in Axis3D for ticks partly because of the difficulty in orienting and sizing them correctly. Now, it isn't impossible to get them right. Depending on the marker, they are implemented as PolyCollection or PatchCollection, if I remember correctly. Both of these have 3D analogs as Poly3DCollection and Patch3DCollection. In art3d.py, there are patch_collection_2d_to_3d() and poly_collection_2d_to_3d that will convert the 2D instances into 3D instances in-place. That might work for you here.

@vlas-sokolov
Copy link
Contributor Author

@WeatherGod I implemented (read: copied over from #6280) the tuple offsets for errorevery. Seems to work, although the overlap of errorbars is mainly set by the viewing angle. Still, for ax.view_init(10, 90) and a setup from #6280 the 3d equivalent is as follows:

errorevery_3d

I briefly looked over the marker issue again, but I can't find a way to improve it with the 2d_to_3d functions in art3d.py. Is it worth keeping the markers? In principle, we can ditch them in favor of 3d lines. The limits, etc. won't look as pretty though.

@vlas-sokolov
Copy link
Contributor Author

Not sure why Travis fails, could someone give a tip on how to fix this? Seems unrelated to me.

@anntzer
Copy link
Contributor

anntzer commented Feb 10, 2017

@vlas-sokolov Let's figure out what to do with #6280 (review) before including the extended version of errorevery.

@vlas-sokolov
Copy link
Contributor Author

@anntzer all right then, standing by.

@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.2 (next next feature release) Aug 29, 2017
@tacaswell
Copy link
Member

I completely missed that this PR came in, cool work!

What is the current state of this?

@vlas-sokolov
Copy link
Contributor Author

@tacaswell all the basic functionality should be there already. There is, however, an issue with using the markers in limit symbols - I didn't figure out how to rotate them in 3d properly, so certain projections look wrong for the marker caps. Perhaps it is wiser to draw the caps / limits with lines instead.

Also, following @WeatherGod's suggestion to add errorevery argument - is it better to roll it back for now until #6280 is resolved?

@vlas-sokolov
Copy link
Contributor Author

I've finished addressing the remaining issues on the PR, and it's ready for the final review. Here's how the new feature looks at the moment:

fig = plt.figure() 
ax = fig.gca(projection="3d") 
 
d = [1,2,3,4,5] 
e = [.5]*5 
f = [[.5]*5, [.2, .1, 1.1, 0.5, .2]] 
ax.errorbar(x=d, y=d, z=d, xerr=f, yerr=e, zerr=e, capsize=3,
            zuplims=[False, True, False, True, True], 
            zlolims=[True, False, False, True, False], 
            yuplims=True, 
            arrow_length_ratio=0.6, 
            ecolor='purple', label='Error lines') 
ax.legend()                                                  

errorbars3d

@vlas-sokolov
Copy link
Contributor Author

Can someone let me know if I can do anything to make the coveted "Approved" check mark happen sooner?

@vlas-sokolov
Copy link
Contributor Author

I've fixed the merge conflict against the latest master branch.

@QuLogic
Copy link
Member

QuLogic commented Jun 17, 2020

The 2D errorbar was simplified somewhat by #15037; is there anything there that can/should be applied here for the 3D case?

@vlas-sokolov
Copy link
Contributor Author

The 2D errorbar was simplified somewhat by #15037; is there anything there that can/should be applied here for the 3D case?

@QuLogic I wasn't aware of it. Will try to adapt the 3d code accordingly for the relevant bits.

@vlas-sokolov
Copy link
Contributor Author

@QuLogic I've ported most of the changes over to the 3d version.

label=label)
self.containers.append(errorbar_container)

return errlines, caplines, limmarks
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason to return these instead of the ErrorbarContainer?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. The errorbar container here is used only to make the legends work properly. To make this container, I have to "pretend" the data is in 2d, so if we would return the ErrorbarContainer, then we'd lose all the information on the 3rd axis. As per my comment above, I simply could not get the 3D container to work and the containers aren't used in other places in axes3d.py, so I stick to returning a tuple of drawn elements.

minz, maxz = _digout_minmax(coorderrs, 'z')
self.auto_scale_xyz((minx, maxx), (miny, maxy), (minz, maxz), had_data)

# Adapting errorbar containers for 3d case, assuming z-axis points "up"
Copy link
Member

Choose a reason for hiding this comment

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

Would it maybe be better to create an Errorbar3DContainer instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have tried subclassing ErrorbarContainer but it resulted in quite a few errors that I failed to fix. I would suggest postponing that, given that no other axes3d methods rely on containers yet.

@QuLogic
Copy link
Member

QuLogic commented Jul 24, 2020

I would like that we figure out kwarg handling (#17930) before releasing this, but it doesn't have to block merging (I can rebase that and update 3D too.)

Co-authored-by: Elliott Sales de Andrade <[email protected]>
@vlas-sokolov
Copy link
Contributor Author

@QuLogic if it's all right with you, I would prefer the latter option (merge, rebase, update the 3d code), since you're more familiar with the changes in #17930.

@vlas-sokolov
Copy link
Contributor Author

I'm not sure if the latest commit did anything to cause the tests to break - I removed the tolerance from errorbar tests but it doesn't seem the failures came from there?

@jklymak
Copy link
Member

jklymak commented Jul 29, 2020

No there was a pandas incompatibility. Should be fixed if you rebase on master.

@jklymak
Copy link
Member

jklymak commented Jul 29, 2020

Ooops, no this isn't the pandas thing, but some other issue with CI, but not an issue w/ your PR....

@QuLogic
Copy link
Member

QuLogic commented Jul 31, 2020

I restarted them; it seems they're fine.

@jklymak jklymak removed the request for review from dstansby August 14, 2020 19:49
Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

I admit to only skimming this, but @QuLogic gave it a long review, and its had input from @eric-wieser If there are follow up fixes we have some time before 3.4

@jklymak jklymak merged commit 56adbda into matplotlib:master Aug 14, 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 this pull request may close these issues.

9 participants