Skip to content

Commit 6f47339

Browse files
authored
Drop missing variables (#267)
1 parent 31ceff2 commit 6f47339

File tree

2 files changed

+48
-8
lines changed

2 files changed

+48
-8
lines changed

cf_xarray/accessor.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,10 @@ def isin(self, test_elements):
10291029
mapped_test_elements.append(flag_dict[elem])
10301030
return self._obj.isin(mapped_test_elements)
10311031

1032+
def _drop_missing_variables(self, variables: List[str]) -> List[str]:
1033+
1034+
return [var for var in variables if var in self._obj or var in self._obj.coords]
1035+
10321036
def _get_all_cell_measures(self):
10331037
"""
10341038
Get all cell measures defined in the object, adding CF pre-defined measures.
@@ -1383,7 +1387,9 @@ def cell_measures(self) -> Dict[str, List[str]]:
13831387
keys = {}
13841388
for attr in all_attrs:
13851389
keys.update(parse_cell_methods_attr(attr))
1386-
measures = {key: _get_all(self._obj, key) for key in keys}
1390+
measures = {
1391+
key: self._drop_missing_variables(_get_all(self._obj, key)) for key in keys
1392+
}
13871393

13881394
return {k: sorted(set(v)) for k, v in measures.items() if v}
13891395

@@ -1877,9 +1883,15 @@ def formula_terms(self) -> Dict[str, Dict[str, str]]:
18771883
Property that returns a dictionary
18781884
{parametric_coord_name: {standard_term_name: variable_name}}
18791885
"""
1880-
return {
1881-
dim: self._obj[dim].cf.formula_terms for dim in _get_dims(self._obj, "Z")
1882-
}
1886+
results = {}
1887+
for dim in _get_dims(self._obj, "Z"):
1888+
terms = self._obj[dim].cf.formula_terms
1889+
variables = self._drop_missing_variables(list(terms.values()))
1890+
terms = {key: val for key, val in terms.items() if val in variables}
1891+
if terms:
1892+
results[dim] = terms
1893+
1894+
return results
18831895

18841896
@property
18851897
def bounds(self) -> Dict[str, List[str]]:
@@ -1896,12 +1908,15 @@ def bounds(self) -> Dict[str, List[str]]:
18961908
keys = self.keys() | set(obj.variables)
18971909

18981910
vardict = {
1899-
key: apply_mapper(_get_bounds, obj, key, error=False) for key in keys
1911+
key: self._drop_missing_variables(
1912+
apply_mapper(_get_bounds, obj, key, error=False)
1913+
)
1914+
for key in keys
19001915
}
19011916

19021917
return {k: sorted(v) for k, v in vardict.items() if v}
19031918

1904-
def get_bounds(self, key: str) -> DataArray:
1919+
def get_bounds(self, key: str) -> Union[DataArray, Dataset]:
19051920
"""
19061921
Get bounds variable corresponding to key.
19071922
@@ -1915,7 +1930,11 @@ def get_bounds(self, key: str) -> DataArray:
19151930
DataArray
19161931
"""
19171932

1918-
return apply_mapper(_variables(_single(_get_bounds)), self._obj, key)[0]
1933+
results = self.bounds.get(key, [])
1934+
if not results:
1935+
raise KeyError(f"No results found for {key!r}.")
1936+
1937+
return self._obj[results[0] if len(results) == 1 else results]
19191938

19201939
def get_bounds_dim_name(self, key: str) -> str:
19211940
"""

cf_xarray/tests/test_accessor.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def test_cell_measures():
177177
ds["air"].attrs["cell_measures"] += " volume: foo"
178178
ds["foo"].attrs["cell_measures"] = ds["air"].attrs["cell_measures"]
179179
expected = dict(area=["cell_area"], foo_measure=["foo"], volume=["foo"])
180-
actual_air = ds["air"].cf.cell_measures
180+
actual_air = ds.cf["air"].cf.cell_measures
181181
actual_foo = ds.cf["foo_measure"].cf.cell_measures
182182
assert actual_air == actual_foo == expected
183183

@@ -1451,3 +1451,24 @@ def test_flag_errors():
14511451

14521452
with pytest.raises(ValueError):
14531453
basin.cf == "pacific_ocean"
1454+
1455+
1456+
def test_missing_variables():
1457+
1458+
# Bounds
1459+
ds = mollwds.copy(deep=True)
1460+
ds = ds.drop("lon_bounds")
1461+
assert ds.cf.bounds == {"lat": ["lat_bounds"], "latitude": ["lat_bounds"]}
1462+
1463+
with pytest.raises(KeyError, match=r"No results found for 'longitude'."):
1464+
ds.cf.get_bounds("longitude")
1465+
1466+
# Cell measures
1467+
ds = airds.copy(deep=True)
1468+
ds = ds.drop("cell_area")
1469+
assert ds.cf.cell_measures == {}
1470+
1471+
# Formula terms
1472+
ds = vert.copy(deep=True)
1473+
ds = ds.drop("ap")
1474+
assert ds.cf.formula_terms == {"lev": {"b": "b", "ps": "ps"}}

0 commit comments

Comments
 (0)