diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 40766ed8b60..3d661b30c07 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -27,6 +27,8 @@ New Features - Add support for lshift and rshift binary operators (``<<``, ``>>``) on :py:class:`xr.DataArray` of type :py:class:`int` (:issue:`7727` , :pull:`7741`). By `Alan Brammer `_. +- Fix `as_compatible_data` for masked float arrays, now always creates a copy when mask is present (:issue:`2377`, :pull:`7788`). + By `Max Hollmann `_. Breaking changes diff --git a/xarray/core/variable.py b/xarray/core/variable.py index c19cb21cba2..b4026ed325e 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -274,8 +274,7 @@ def as_compatible_data(data, fastpath=False): mask = np.ma.getmaskarray(data) if mask.any(): dtype, fill_value = dtypes.maybe_promote(data.dtype) - data = np.asarray(data, dtype=dtype) - data[mask] = fill_value + data = duck_array_ops.where_method(data, ~mask, fill_value) else: data = np.asarray(data) diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index bef5efc15cc..a6dffb82660 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -2560,6 +2560,19 @@ def test_masked_array(self): assert_array_equal(expected, actual) assert np.dtype(float) == actual.dtype + original = np.ma.MaskedArray([1.0, 2.0], mask=[True, False]) + original.flags.writeable = False + expected = [np.nan, 2.0] + actual = as_compatible_data(original) + assert_array_equal(expected, actual) + assert np.dtype(float) == actual.dtype + + # GH2377 + actual = Variable(dims=tuple(), data=np.ma.masked) + expected = Variable(dims=tuple(), data=np.nan) + assert_array_equal(expected, actual) + assert actual.dtype == expected.dtype + @pytest.mark.filterwarnings("ignore:Converting non-nanosecond") def test_datetime(self): expected = np.datetime64("2000-01-01")