Skip to content

Commit f61fb66

Browse files
authored
Support Dataset.cf.cell_measures (#117)
* Support Dataset.cf.cell_measures * Cleanup * fix docstring
1 parent b99b6b9 commit f61fb66

File tree

3 files changed

+22
-26
lines changed

3 files changed

+22
-26
lines changed

cf_xarray/accessor.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -336,45 +336,44 @@ def _get_measure_variable(
336336
return [da[varnames[0]]]
337337

338338

339-
def _get_measure(da: Union[DataArray, Dataset], key: str) -> List[str]:
339+
def _get_measure(obj: Union[DataArray, Dataset], key: str) -> List[str]:
340340
"""
341341
Translate from cell measures ("area" or "volume") to appropriate variable name.
342342
This function interprets the ``cell_measures`` attribute on DataArrays.
343343
344344
Parameters
345345
----------
346-
da: DataArray
346+
obj: DataArray, Dataset
347347
DataArray belonging to the coordinate to be checked
348348
key: str, ["area", "volume"]
349349
key to check for.
350-
error: bool
351-
raise errors when key is not found or interpretable. Use False and provide default
352-
to replicate dict.get(k, None).
353-
default: Any
354-
default value to return when error is False.
355350
356351
Returns
357352
-------
358353
List[str], Variable name(s) in parent xarray object that matches axis or coordinate `key`
359354
"""
360-
if not isinstance(da, DataArray):
361-
raise NotImplementedError("Measures not implemented for Datasets yet.")
362-
363-
if "cell_measures" not in da.attrs:
364-
raise KeyError("'cell_measures' not present in 'attrs'.")
365355

366356
valid_keys = _CELL_MEASURES
367357
if key not in valid_keys:
368358
raise KeyError(
369359
f"cf_xarray did not understand key {key!r}. Expected one of {valid_keys!r}"
370360
)
371361

372-
attr = da.attrs["cell_measures"]
373-
measures = parse_cell_methods_attr(attr)
374-
results: Union[str, List] = measures.get(key, [])
362+
if isinstance(obj, DataArray):
363+
obj = obj._to_temp_dataset()
364+
365+
results = set()
366+
for var in obj.variables:
367+
da = obj[var]
368+
if "cell_measures" in da.attrs:
369+
attr = da.attrs["cell_measures"]
370+
measures = parse_cell_methods_attr(attr)
371+
if key in measures:
372+
results.update([measures[key]])
373+
375374
if isinstance(results, str):
376375
return [results]
377-
return results
376+
return list(results)
378377

379378

380379
#: Default mappers for common keys.
@@ -833,10 +832,7 @@ def describe(self):
833832
text += f"\t{key}: {coords[key] if key in coords else []}\n"
834833

835834
text += "\nCell Measures:\n"
836-
if isinstance(self._obj, Dataset):
837-
measures = {key: "unsupported" for key in _CELL_MEASURES}
838-
else:
839-
measures = self.cell_measures
835+
measures = self.cell_measures
840836
for key in _CELL_MEASURES:
841837
text += f"\t{key}: {measures[key] if key in measures else []}\n"
842838

@@ -930,14 +926,12 @@ def cell_measures(self) -> Dict[str, List[str]]:
930926
931927
This is useful for checking whether a key is valid for indexing, i.e.
932928
that the attributes necessary to allow indexing by that key exist.
933-
However, it will only return the cell measure names.
934929
935930
Returns
936931
-------
937932
Dictionary of valid cell measure names that can be used with __getitem__ or .cf[key].
938933
Will be ("area", "volume") or a subset thereof.
939934
"""
940-
assert isinstance(self._obj, DataArray), "this only works with DataArrays"
941935

942936
measures = {
943937
key: apply_mapper(_get_measure, self._obj, key, error=False)

cf_xarray/tests/test_accessor.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def test_describe(capsys):
2626
"Axes:\n\tX: ['lon']\n\tY: ['lat']\n\tZ: []\n\tT: ['time']\n"
2727
"\nCoordinates:\n\tlongitude: ['lon']\n\tlatitude: ['lat']"
2828
"\n\tvertical: []\n\ttime: ['time']\n"
29-
"\nCell Measures:\n\tarea: unsupported\n\tvolume: unsupported\n"
29+
"\nCell Measures:\n\tarea: ['cell_area']\n\tvolume: []\n"
3030
"\nStandard Names:\n\tair_temperature: ['air']\n\n"
3131
)
3232
assert actual == expected
@@ -58,12 +58,13 @@ def test_cell_measures():
5858
ds["air"].attrs["cell_measures"] += " foo_measure: foo"
5959
assert "foo_std_name" in ds.cf["air_temperature"].cf
6060

61-
expected = dict(area=["cell_area"])
61+
ds["air"].attrs["cell_measures"] += " volume: foo"
62+
expected = dict(area=["cell_area"], volume=["foo"])
6263
actual = ds["air"].cf.cell_measures
6364
assert actual == expected
6465

65-
with pytest.raises(AssertionError, match=r"this only works with DataArrays"):
66-
popds.cf.cell_measures
66+
actual = ds.cf.cell_measures
67+
assert actual == expected
6768

6869

6970
def test_standard_names():

doc/whats-new.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ What's New
44

55
v0.4.0 (unreleased)
66
===================
7+
- Support ``Dataset.cf.cell_measures``. By `Deepak Cherian`_.
78
- Added ``.axes`` to return a dictionary mapping available Axis standard names to variable names of an xarray object, ``.coordinates`` for Coordinates,
89
``.cell_measures`` for Cell Measures, and ``.standard_names`` for all variables. `Kristen Thyng`_ and `Mattia Almansi`_.
910
- Changed ``get_valid_keys()`` to ``.keys()``. `Kristen Thyng`_.

0 commit comments

Comments
 (0)