Skip to content

Polar errcaps #23592

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 2 commits into from
Oct 7, 2022
Merged

Polar errcaps #23592

merged 2 commits into from
Oct 7, 2022

Conversation

deep-jkl
Copy link
Contributor

@deep-jkl deep-jkl commented Aug 9, 2022

PR Summary

Trying to reopen #21006, including fix for theta error bars.

I had to squash original contribution from @dstansby to pass through PR cleanliness, if there is any other way to reopen the original PR I would gladly do it (however, I couldn't figure it out).
The changes are minor, just changing the order of resolving "polar" criterion.
The fix is based on fact that to achieve markers perpendicular to the error bar, we need to find the error bar "midpoint theta", this is done by averaging lower and upper theta limit.

I have checked that it works for uneven error bars, see images comments.

PR Checklist

Tests and Styling

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (install flake8-docstrings and run flake8 --docstring-convention=all).

Documentation

  • New features are documented, with examples if plot related.
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).

@deep-jkl
Copy link
Contributor Author

import matplotlib.pyplot as plt

import numpy as np
fig = plt.figure(figsize=(10,10))
ax = plt.subplot(111, projection='polar')
theta = np.arange(0, 2*np.pi, np.pi / 4)
r = theta / np.pi / 2 + 0.5
ax.errorbar(theta, r, xerr=[0.15], xuplims=True, capsize=7)

theta_errorbars_uplims

@deep-jkl
Copy link
Contributor Author

import matplotlib.pyplot as plt

import numpy as np
fig = plt.figure(figsize=(10,10))
ax = plt.subplot(111, projection='polar')
theta = np.arange(0, 2*np.pi, np.pi / 4)
r = theta / np.pi / 2 + 0.5
xerr= np.vstack([[0.05]*8, [0.15]*8])
ax.errorbar(theta, r, xerr=xerr, capsize=7)

theta_errorbars_uneven

@deep-jkl deep-jkl marked this pull request as ready for review August 10, 2022 20:32
@deep-jkl deep-jkl changed the title Draft: Polar errcaps Polar errcaps Aug 11, 2022
@jklymak
Copy link
Member

jklymak commented Aug 11, 2022

I guess I'm confused. Is this a theta error? If so, it should be drawn as a curve and kept at the same radius as the data point?

@oscargus
Copy link
Member

If so, it should be drawn as a curve and kept at the same radius as the data point?

That is probably the ideal solution, yes. Similar to the lines not directly connecting the points, but uses some sort of curve. However, considering the current output this PR is clearly a step in the right direction, actually making it possible to use error caps.

On the other hand, it shouldn't be impossible to use an Arc instead and orient the caps pointing to the center. But if noone is implementing that, I'd clearly go for this solution in the meantime.

(One can also think about if the caps for errorbars in the other direction should be rounded or not?)

@timhoffm
Copy link
Member

Yes, if we want to be exact, theta errors should be curved. However, personally, I would not be that pedantic. Errors should be reasonably small (or the visualization does not tell much anyway). And fore small errors, a straight theta-line is a reasonable approximation of the curve. So if somebody wants to implement curved theta bars, great. But I would live with straight that-bars, if that's all we can do with reasonable effort now.

That said, I can also see an argument for not supporting theta bars at all if they are not curved.

@jklymak
Copy link
Member

jklymak commented Aug 11, 2022

If you can see the tilt for uncentred bars, I assume you can also see that they are not curved?

@deep-jkl
Copy link
Contributor Author

The original (rejected) solution in PR #21006 looked like this:

fig = plt.figure()
ax = plt.subplot(111, projection='polar')
theta = np.arange(0, 2*np.pi, np.pi / 4)
r = theta / np.pi / 2 + 0.5
ax.errorbar(theta, r, xerr=0.15, yerr=0.1)
ax.set_rlim(0, 2)

image

On the other hand, under different settings I believe that curved theta error is must have, consider following plot:

import matplotlib.pyplot as plt

import numpy as np
fig = plt.figure(figsize=(10,10))
ax = plt.subplot(111, projection='polar')
theta = np.arange(0, 2*np.pi, np.pi / 4)
r = theta / np.pi / 2 + 0.5
ax.errorbar(theta, r, xerr=0.25, capsize=7, fmt="o")

theta_big_bars

@timhoffm
Copy link
Member

grafik
Um, this is indeed awkward. Whether curved or not, the theta-error line should hit the data point.

Probably not the final call on polar error bars. Nevertheless, this PR fixes the caps for yerr and makes it a little less bad for xerr. So I approve as an improvement.

(One can also think about if the caps for errorbars in the other direction should be rounded or not?)
IMHO this is not needed. Caps are essentially markers of the end point. They don't make a statement on the orthogonal axis. I.e. a y-cap does not say anything about theta. - Even if you disagress, from a practical point of view, caps are small enough so that the difference between rounded arc and straight line is small.

@timhoffm
Copy link
Member

Closes #441.

@QuLogic
Copy link
Member

QuLogic commented Aug 12, 2022

Closes #441.

This needs to go in the original description, a commit message, or you can link with the Description section in the right sidebar. Putting it here though, doesn't do anything. Unfortunately, #441 doesn't show up here to be linked, but if you go there, this PR shows up to be linked, which I've now done.

@QuLogic QuLogic linked an issue Aug 12, 2022 that may be closed by this pull request
@deep-jkl deep-jkl force-pushed the polar-errcaps branch 2 times, most recently from 715e544 to d712e61 Compare August 14, 2022 11:33
@deep-jkl
Copy link
Contributor Author

I have fixed the testing figure. Additionally I have fixed the issue with radial offset for large error bars, see below:

import matplotlib.pyplot as plt

import numpy as np
fig = plt.figure(figsize=(10,10))
ax = plt.subplot(111, projection='polar')
theta = np.arange(0, 2*np.pi, np.pi / 4)
r = theta / np.pi / 2 + 0.5
ax.errorbar(theta, r, xerr=0.25, capsize=7, fmt="o")

nice_errorbars

Additionally I have done some experiments with curved error bars:
curved_errorbars

You can see proof of principle with code changes here

@deep-jkl
Copy link
Contributor Author

And just to make decision even harder, here I show some bar graphs with error bars:

import matplotlib.pyplot as plt

import numpy as np
fig = plt.figure(figsize=(10,10))
ax = plt.subplot(111, projection='polar')
theta = np.arange(0, 2*np.pi, np.pi / 4)
r = theta / np.pi / 2 + 0.5
ax.errorbar(theta, r, xerr=0.25, yerr=0.1, capsize=7, fmt="o")
ax.bar(theta, r, width=0.4, bottom=0.0,  alpha=0.5)

Straight:
polar_bars_straight

And curved:
polar_bars_curved

@oscargus
Copy link
Member

Nice! I guess the best thing now is to discuss it at the dev-call on Thursday? Feel free to join if you want!

(Personally, I think that the curved error bars is the way to go.)

@timhoffm
Copy link
Member

I agree: The curved error bars is what we want.

@tacaswell tacaswell added this to the v3.7.0 milestone Aug 18, 2022
@tacaswell
Copy link
Member

This was discussed on the weekly call. The consensus was curved error bars and wait for it all to be ready for 3.7 rather than squeezing this in for 3.6 with straight lines.

We also discussed the interpolate step (private) feature of Path to simplify making the curved lines.

@deep-jkl deep-jkl force-pushed the polar-errcaps branch 2 times, most recently from 70c6382 to b9813ec Compare August 19, 2022 15:24
@deep-jkl deep-jkl force-pushed the polar-errcaps branch 2 times, most recently from cf7ca12 to fec9b60 Compare August 21, 2022 10:37
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.

This looks good to me. However, can it get an example for the gallery, and the what's-new link the example?

@deep-jkl
Copy link
Contributor Author

This looks good to me. However, can it get an example for the gallery, and the what's-new link the example?

I have added an gallery example (just a simple one), but I am not sure that the link in what's new is valid.

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.

Small nit that you take or leave...

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(10, 10))
ax = plt.subplot(111, projection='polar')
Copy link
Member

Choose a reason for hiding this comment

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

This would be more idiomatic, but not a big deal:

Suggested change
ax = plt.subplot(111, projection='polar')
ax = fig.add_subplot(projection='polar')

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 will fix it, I am taking some time to think of a more elaborate gallery example :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I could not think of something better. I have just added overlapping examples, including your suggestions.

Caps and error lines are now drawn with respect to polar coordinates,
when plotting errorbars on polar plots.

.. figure:: /gallery/pie_and_polar_charts/images/sphx_glr_polar_error_caps_001.png
Copy link
Member

Choose a reason for hiding this comment

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

If this works, great! (not sure it will, but my ignorance of sphinx is relatively vast)

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 just mimicked it from this what's new message, but it does not seem to work properly in the built documentation, so I am not sure it is worth the try.

 - uses _interpolation_steps
 - prefers transform MarkerStyle in init over _transform property
 - adjusted what's new
 - added more tests for overlapping, asymmetric and long errorbars
 - combine all tests to a single figure
 - remove overlappnig since it does not work same on all platforms
 - rework test figure, add overlapping, might work by avoiding grid
 - update what's new with image and link to example
@timhoffm timhoffm merged commit 2393866 into matplotlib:main Oct 7, 2022
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.

Polar plot error bars don't rotate with angle
8 participants