@@ -338,27 +338,21 @@ def _get_measure_variable(
338338
339339def _get_measure (obj : Union [DataArray , Dataset ], key : str ) -> List [str ]:
340340 """
341- Translate from cell measures ("area" or "volume") to appropriate variable name.
341+ Translate from cell measures to appropriate variable name.
342342 This function interprets the ``cell_measures`` attribute on DataArrays.
343343
344344 Parameters
345345 ----------
346346 obj: DataArray, Dataset
347347 DataArray belonging to the coordinate to be checked
348- key: str, ["area", "volume"]
348+ key: str
349349 key to check for.
350350
351351 Returns
352352 -------
353353 List[str], Variable name(s) in parent xarray object that matches axis or coordinate `key`
354354 """
355355
356- valid_keys = _CELL_MEASURES
357- if key not in valid_keys :
358- raise KeyError (
359- f"cf_xarray did not understand key { key !r} . Expected one of { valid_keys !r} "
360- )
361-
362356 if isinstance (obj , DataArray ):
363357 obj = obj ._to_temp_dataset ()
364358
@@ -438,7 +432,7 @@ def _build_docstring(func):
438432 mapper_docstrings = {
439433 _get_axis_coord : f"One or more of { (_AXIS_NAMES + _COORD_NAMES )!r} " ,
440434 _get_axis_coord_single : f"One of { (_AXIS_NAMES + _COORD_NAMES )!r} " ,
441- _get_measure_variable : f"One of { _CELL_MEASURES !r} " ,
435+ # _get_measure_variable: f"One of {_CELL_MEASURES!r}",
442436 }
443437
444438 sig = inspect .signature (func )
@@ -653,6 +647,18 @@ class CFAccessor:
653647
654648 def __init__ (self , da ):
655649 self ._obj = da
650+ self ._all_cell_measures = None
651+
652+ def _get_all_cell_measures (self ):
653+ """
654+ Get all cell measures defined in the object, adding CF pre-defined measures.
655+ """
656+
657+ # get all_cell_measures only once
658+ if not self ._all_cell_measures :
659+ self ._all_cell_measures = set (_CELL_MEASURES + tuple (self .cell_measures ))
660+
661+ return self ._all_cell_measures
656662
657663 def _process_signature (
658664 self ,
@@ -833,7 +839,7 @@ def describe(self):
833839
834840 text += "\n Cell Measures:\n "
835841 measures = self .cell_measures
836- for key in _CELL_MEASURES :
842+ for key in sorted ( self . _get_all_cell_measures ()) :
837843 text += f"\t { key } : { measures [key ] if key in measures else []} \n "
838844
839845 text += "\n Standard Names:\n "
@@ -868,8 +874,7 @@ def keys(self) -> Set[str]:
868874 """
869875
870876 varnames = list (self .axes ) + list (self .coordinates )
871- if not isinstance (self ._obj , Dataset ):
872- varnames .extend (list (self .cell_measures ))
877+ varnames .extend (list (self .cell_measures ))
873878 varnames .extend (list (self .standard_names ))
874879
875880 return set (varnames )
@@ -930,15 +935,23 @@ def cell_measures(self) -> Dict[str, List[str]]:
930935 Returns
931936 -------
932937 Dictionary of valid cell measure names that can be used with __getitem__ or .cf[key].
933- Will be ("area", "volume") or a subset thereof.
934938 """
935939
936- measures = {
937- key : apply_mapper (_get_measure , self ._obj , key , error = False )
938- for key in _CELL_MEASURES
939- }
940+ obj = self ._obj
941+ all_attrs = [da .attrs .get ("cell_measures" , "" ) for da in obj .coords .values ()]
942+ if isinstance (obj , DataArray ):
943+ all_attrs += [obj .attrs .get ("cell_measures" , "" )]
944+ elif isinstance (obj , Dataset ):
945+ all_attrs += [
946+ da .attrs .get ("cell_measures" , "" ) for da in obj .data_vars .values ()
947+ ]
948+
949+ measures : Dict [str , List [str ]] = dict ()
950+ for attr in all_attrs :
951+ for key , value in parse_cell_methods_attr (attr ).items ():
952+ measures [key ] = measures .setdefault (key , []) + [value ]
940953
941- return {k : sorted (v ) for k , v in measures .items () if v }
954+ return {k : sorted (set ( v ) ) for k , v in measures .items () if v }
942955
943956 def get_standard_names (self ) -> List [str ]:
944957
@@ -1069,7 +1082,7 @@ def check_results(names, k):
10691082 check_results (names , k )
10701083 successful [k ] = bool (names )
10711084 coords .extend (names )
1072- elif k in _CELL_MEASURES :
1085+ elif k in self . _get_all_cell_measures () :
10731086 measure = _get_measure (self ._obj , k )
10741087 check_results (measure , k )
10751088 successful [k ] = bool (measure )
0 commit comments