@@ -338,27 +338,21 @@ def _get_measure_variable(
338
338
339
339
def _get_measure (obj : Union [DataArray , Dataset ], key : str ) -> List [str ]:
340
340
"""
341
- Translate from cell measures ("area" or "volume") to appropriate variable name.
341
+ Translate from cell measures to appropriate variable name.
342
342
This function interprets the ``cell_measures`` attribute on DataArrays.
343
343
344
344
Parameters
345
345
----------
346
346
obj: DataArray, Dataset
347
347
DataArray belonging to the coordinate to be checked
348
- key: str, ["area", "volume"]
348
+ key: str
349
349
key to check for.
350
350
351
351
Returns
352
352
-------
353
353
List[str], Variable name(s) in parent xarray object that matches axis or coordinate `key`
354
354
"""
355
355
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
-
362
356
if isinstance (obj , DataArray ):
363
357
obj = obj ._to_temp_dataset ()
364
358
@@ -438,7 +432,7 @@ def _build_docstring(func):
438
432
mapper_docstrings = {
439
433
_get_axis_coord : f"One or more of { (_AXIS_NAMES + _COORD_NAMES )!r} " ,
440
434
_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}",
442
436
}
443
437
444
438
sig = inspect .signature (func )
@@ -653,6 +647,18 @@ class CFAccessor:
653
647
654
648
def __init__ (self , da ):
655
649
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
656
662
657
663
def _process_signature (
658
664
self ,
@@ -833,7 +839,7 @@ def describe(self):
833
839
834
840
text += "\n Cell Measures:\n "
835
841
measures = self .cell_measures
836
- for key in _CELL_MEASURES :
842
+ for key in sorted ( self . _get_all_cell_measures ()) :
837
843
text += f"\t { key } : { measures [key ] if key in measures else []} \n "
838
844
839
845
text += "\n Standard Names:\n "
@@ -868,8 +874,7 @@ def keys(self) -> Set[str]:
868
874
"""
869
875
870
876
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 ))
873
878
varnames .extend (list (self .standard_names ))
874
879
875
880
return set (varnames )
@@ -930,15 +935,23 @@ def cell_measures(self) -> Dict[str, List[str]]:
930
935
Returns
931
936
-------
932
937
Dictionary of valid cell measure names that can be used with __getitem__ or .cf[key].
933
- Will be ("area", "volume") or a subset thereof.
934
938
"""
935
939
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 ]
940
953
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 }
942
955
943
956
def get_standard_names (self ) -> List [str ]:
944
957
@@ -1069,7 +1082,7 @@ def check_results(names, k):
1069
1082
check_results (names , k )
1070
1083
successful [k ] = bool (names )
1071
1084
coords .extend (names )
1072
- elif k in _CELL_MEASURES :
1085
+ elif k in self . _get_all_cell_measures () :
1073
1086
measure = _get_measure (self ._obj , k )
1074
1087
check_results (measure , k )
1075
1088
successful [k ] = bool (measure )
0 commit comments