Skip to content

Commit c96578f

Browse files
committed
More support for missing_value.
Fixes pydata#2871
1 parent 4e778f0 commit c96578f

File tree

4 files changed

+36
-3
lines changed

4 files changed

+36
-3
lines changed

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ Bug fixes
4141
By `Deepak Cherian <https://github.com/dcherian`_.
4242
- A deep copy deep-copies the coords (:issue:`1463`)
4343
By `Martin Pletcher <https://github.com/pletchm>`_.
44+
- Increased support for `missing_value` (:issue:`2871`)
45+
By `Deepak Cherian <https://github.com/dcherian>`_.
4446

4547
.. _whats-new.0.12.1:
4648

xarray/coding/variables.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,24 @@ class CFMaskCoder(VariableCoder):
145145
def encode(self, variable, name=None):
146146
dims, data, attrs, encoding = unpack_for_encoding(variable)
147147

148-
if encoding.get('_FillValue') is not None:
148+
fv = encoding.get('_FillValue')
149+
mv = encoding.get('missing_value')
150+
151+
if (fv is not None) and (mv is not None) and (fv != mv):
152+
raise ValueError("Variable {!r} has multiple fill values {}. "
153+
"Cannot encode data. "
154+
.format(name, [fv, mv]))
155+
156+
if fv is not None:
149157
fill_value = pop_to(encoding, attrs, '_FillValue', name=name)
150158
if not pd.isnull(fill_value):
151159
data = duck_array_ops.fillna(data, fill_value)
152160

161+
if mv is not None:
162+
fill_value = pop_to(encoding, attrs, 'missing_value', name=name)
163+
if not pd.isnull(fill_value):
164+
data = duck_array_ops.fillna(data, fill_value)
165+
153166
return Variable(dims, data, attrs, encoding)
154167

155168
def decode(self, variable, name=None):

xarray/conventions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ def maybe_encode_nonstring_dtype(var, name=None):
8282
if dtype != var.dtype:
8383
if np.issubdtype(dtype, np.integer):
8484
if (np.issubdtype(var.dtype, np.floating) and
85-
'_FillValue' not in var.attrs):
85+
'_FillValue' not in var.attrs and
86+
'missing_value' not in var.attrs):
8687
warnings.warn('saving variable %s with floating '
8788
'point data as an integer dtype without '
8889
'any _FillValue to use for NaNs' % name,

xarray/tests/test_coding.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import xarray as xr
77
from xarray.coding import variables
88

9-
from . import assert_identical, requires_dask
9+
from . import assert_equal, assert_identical, requires_dask
1010

1111
with suppress(ImportError):
1212
import dask.array as da
@@ -20,6 +20,23 @@ def test_CFMaskCoder_decode():
2020
assert_identical(expected, encoded)
2121

2222

23+
def test_CFMaskCoder_missing_value():
24+
expected = xr.DataArray(np.array([[26915, 27755, -9999, 27705],
25+
[25595, -9999, 28315, -9999]]),
26+
dims=['npts', 'ntimes'],
27+
name='tmpk')
28+
expected.attrs['missing_value'] = -9999
29+
30+
decoded = xr.decode_cf(expected.to_dataset())
31+
encoded, _ = xr.conventions.cf_encoder(decoded, decoded.attrs)
32+
33+
assert_equal(encoded['tmpk'], expected.variable)
34+
35+
decoded.tmpk.encoding['_FillValue'] = -9940
36+
with pytest.raises(ValueError):
37+
encoded, _ = xr.conventions.cf_encoder(decoded, decoded.attrs)
38+
39+
2340
@requires_dask
2441
def test_CFMaskCoder_decode_dask():
2542
original = xr.Variable(('x',), [0, -1, 1], {'_FillValue': -1}).chunk()

0 commit comments

Comments
 (0)