Skip to content

Weird behavior with pint.Quantity + masked array #8908

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

Closed
dopplershift opened this issue Jul 18, 2017 · 3 comments
Closed

Weird behavior with pint.Quantity + masked array #8908

dopplershift opened this issue Jul 18, 2017 · 3 comments

Comments

@dopplershift
Copy link
Contributor

From my SciPy 2017 talk, the combination of pint.Quantity for unit support with masked arrays produces problems not seen with either individually:

%matplotlib inline

import matplotlib.pyplot as plt
import numpy as np
import pint

units = pint.UnitRegistry()

data = np.random.randn(30,)
data_units = data * units.meters
data_masked = np.ma.array(data, mask=data<0.)
data_masked_units = data_masked * units.meters

fig, axes = plt.subplots(1, 3, sharex=True, sharey=True, figsize=(8, 4))
axes[0].plot(data_units)
axes[1].plot(data_masked)
axes[2].plot(data_masked_units)

produces:

bug

@dopplershift dopplershift self-assigned this Jul 18, 2017
@dopplershift dopplershift added this to the 2.1 (next point release) milestone Jul 18, 2017
@dopplershift
Copy link
Contributor Author

It's possible the problem lies outside matplotlib, but need to track down what matplotlib is doing exactly to evoke this behavior.

@dopplershift
Copy link
Contributor Author

So the behavior in the leftmost panel is just reflecting the behavior of:

>>> np.asarray(data_masked_units)
array([  9.01813386e-02,   1.00000000e+00,   1.00000000e+00,
         1.00000000e+00,   7.39062957e-01,   1.00000000e+00,
         1.00000000e+00,   2.99023902e-01,   7.01311229e-04,
         1.05263214e+00,   1.88309697e+00,   1.75411405e-01,
         1.12874122e+00,   3.08208814e-01,   1.00000000e+00,
         1.00000000e+00,   1.00000000e+00,   7.67253492e-01,
         1.43523599e-01,   1.00000000e+00,   1.00000000e+00,
         1.00000000e+00,   1.00000000e+00,   1.00000000e+00,
         1.86541911e+00,   1.00000000e+00,   1.00000000e+00,
         1.00000000e+00,   1.08489593e+00,   1.00000000e+00])

The reason this line runs is because there's an isintance check, which fails with a Quantity that holds a masked array, here:

def recache(self, always=False):
if always or self._invalidx:
xconv = self.convert_xunits(self._xorig)
if isinstance(self._xorig, np.ma.MaskedArray):
x = np.ma.asarray(xconv, float).filled(np.nan)
else:
x = np.asarray(xconv, float)
x = x.ravel()

So, how would we feel about replacing the isinstance(self._xorig, np.ma.MaskedArray) with something more duck-type-y, like hasattr(self._xorig, 'mask')? Other suggestions?

@dopplershift
Copy link
Contributor Author

The more I stare at that, I wonder at the wisdom of using np.ma.asarray(xconv, float).filled(np.nan) rather than xconv.astype(float).filled(np.nan), since implicitly xconv has to already be some kind of masked array, since that's where the mask to be filled comes from. If we use the latter form, we could replace isinstance with a try...except AttributeError block.

dopplershift added a commit to dopplershift/matplotlib that referenced this issue Aug 17, 2017
Refactor many places that check for masked arrays, and fill the masked
values with nans, with a helper to accomplish that. In the helper,
replace the isinstance check with a attribute check for 'mask'. This
allows libraries, like pint, that wrap mask arrays to pass the check and
be converted appropriately.

Also fix one spot using atleast_1d with _check_1d.
dopplershift added a commit to dopplershift/matplotlib that referenced this issue Aug 17, 2017
Refactor many places that check for masked arrays, and fill the masked
values with nans, with a helper to accomplish that. In the helper,
replace the isinstance check with a attribute check for 'mask'. This
allows libraries, like pint, that wrap mask arrays to pass the check and
be converted appropriately.

Also fix one spot using atleast_1d with _check_1d.
dstansby added a commit that referenced this issue Aug 29, 2017
BUG: Fix weird behavior with mask and units (Fixes #8908)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant