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

Skip to content

Apply unit conversion early in errorbar(). #19526

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 1 commit into from
Apr 5, 2021

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Feb 16, 2021

This allow using normal numpy constructs rather than manually looping
and broadcasting.

_process_unit_info was already special-handling data is None in a few
places; the change here only handle the (theoretical) extra case where a
custom unit converter would fail to properly pass None through.

PR Summary

PR Checklist

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (run flake8 on changed files to check).
  • New features are documented, with examples if plot related.
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • Conforms to Matplotlib style conventions (install flake8-docstrings and run flake8 --docstring-convention=all).
  • 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).

@QuLogic
Copy link
Member

QuLogic commented Feb 17, 2021

Probably these changes should be repeated in errorbar3d, but likely after #18436 since it's currently even more divergent. Though I'm also thinking maybe we should refactor some of these two together.

@anntzer
Copy link
Contributor Author

anntzer commented Feb 17, 2021

Let's merge the two PRs as separate improvements and figure out how to reuse the logic in both cases later? I actually already have a followup patch for the 2D case that factors together the x and y handling, probably I can make it handle z too.

jklymak
jklymak previously approved these changes Feb 17, 2021
Comment on lines 3284 to 3285
x, y, xerr, yerr = self._process_unit_info(
[("x", x), ("y", y), ("x", xerr), ("y", yerr)], kwargs)
Copy link
Member

Choose a reason for hiding this comment

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

So now convert=True, but I seem to be missing where the old conversion was that would be removed by this change?

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 think we just used to propagate unitful data to Line2D and rely on Line2D being (the only artist) able to handle them.

@QuLogic
Copy link
Member

QuLogic commented Feb 18, 2021

This breaks mixed unit error bars like:

x = np.arange(10)
y = [datetime(2020, 5, i * 2 + 1) for i in x]
plt.errorbar(x, y, timedelta(days=0.5))

@jklymak
Copy link
Member

jklymak commented Feb 18, 2021

This breaks mixed unit error bars like:

Ooops, good catch!

@jklymak jklymak dismissed their stale review February 18, 2021 01:23

obsolete

This allow using normal numpy constructs rather than manually looping
and broadcasting.

_process_unit_info was already special-handling `data is None` in a few
places; the change here only handle the (theoretical) extra case where a
custom unit converter would fail to properly pass None through.
@anntzer anntzer force-pushed the errorbar-early-units branch from cc2517c to 8cd22b4 Compare February 18, 2021 13:15
@anntzer
Copy link
Contributor Author

anntzer commented Feb 18, 2021

Good catch, now fixed by using object arrays whenever the inputs are not already arrays (test included).

@dstansby dstansby merged commit dca4a97 into matplotlib:master Apr 5, 2021
@anntzer anntzer deleted the errorbar-early-units branch April 5, 2021 11:00
@pllim
Copy link

pllim commented Apr 5, 2021

I think this has broken astropy (astropy/astropy#11479). Any advise would be greatly appreciated. Thanks!

@anntzer
Copy link
Contributor Author

anntzer commented Apr 5, 2021

I'll have a look.

@anntzer
Copy link
Contributor Author

anntzer commented Apr 5, 2021

Looks like the following fixes the problem:

diff --git i/lib/matplotlib/axes/_axes.py w/lib/matplotlib/axes/_axes.py
index e906dba6c8..e9e8c3ef25 100644
--- i/lib/matplotlib/axes/_axes.py
+++ w/lib/matplotlib/axes/_axes.py
@@ -3427,13 +3427,17 @@ class Axes(_AxesBase):
                 the note in the main docstring about this parameter's name.
             """
             try:
-                low, high = np.broadcast_to(err, (2, len(data)))
+                np.broadcast_to(err, (2, len(data)))
             except ValueError:
                 raise ValueError(
                     f"'{name}err' (shape: {np.shape(err)}) must be a scalar "
                     f"or a 1D or (2, n) array-like whose shape matches "
                     f"'{name}' (shape: {np.shape(data)})") from None
-            return data - low * ~lolims, data + high * ~uplims  # low, high
+            # This is like
+            #     low, high = np.broadcast_to(...)
+            #     return data - low * ~lolims, data + high * ~uplims
+            # except that broadcast_to would strip units.
+            return data + np.row_stack([-(1 - lolims), 1 - uplims]) * err
 
         if xerr is not None:
             left, right = extract_err('x', xerr, x, xlolims, xuplims)

but if you can help with writing a minimal test case to check that, that would be great :-)

@pllim
Copy link

pllim commented Apr 5, 2021

Here is a minimal test case from the broken astropy test, though I am not sure how to do it in a way that does not introduce astropy dependency in matplotlib if you are thinking about adding it as a unit test here...

import matplotlib.pyplot as plt

from astropy import units as u
from astropy.visualization.units import quantity_support

with quantity_support():
    x = [1, 2, 3] * u.s
    y = [1, 2, 3] * u.m
    yerr = [3, 2, 1] * u.cm

    fig, ax = plt.subplots()
    ax.errorbar(x, y, yerr=yerr)

    assert ax.xaxis.get_units() == u.s
    assert ax.yaxis.get_units() == u.m

    plt.show()  # Only if you want to see it, not for CI

Screenshot 2021-04-05 131311

@pllim
Copy link

pllim commented Apr 5, 2021

p.s. Here is the actual implementation of quantity_support -- https://github.com/astropy/astropy/blob/master/astropy/visualization/units.py

@anntzer anntzer added this to the v3.5.0 milestone Apr 5, 2021
@tacaswell
Copy link
Member

@pllim I'm loving that astropy is testing against our default branch :)

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.

6 participants