Skip to content

Commit 81d28d7

Browse files
committed
Add basic crs accessors
1 parent 195fc2e commit 81d28d7

File tree

1 file changed

+50
-13
lines changed

1 file changed

+50
-13
lines changed

cf_xarray/accessor.py

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@
4848
)
4949

5050

51+
try:
52+
import pyproj
53+
import cartopy.crs
54+
except ImportError:
55+
pyproj = None
56+
57+
5158
from . import parametric, sgrid
5259
from .criteria import (
5360
_DSG_ROLES,
@@ -2745,6 +2752,20 @@ def grid_mapping_names(self) -> dict[str, list[str]]:
27452752
results[v].append(k)
27462753
return results
27472754

2755+
@property
2756+
def crs(self):
2757+
"""Cartopy CRS of the dataset's grid mapping."""
2758+
if pyproj is None:
2759+
raise ImportError('`crs` accessor requires optional packages `pyproj` and `cartopy`.')
2760+
gmaps = list(itertools.chain(*self.grid_mapping_names.values()))
2761+
if len(gmaps) > 1:
2762+
raise ValueError("Multiple grid mappings found.")
2763+
if len(gmaps) == 0:
2764+
if 'longitude' in self:
2765+
return cartopy.crs.PlateCarree()
2766+
raise ValueError('No grid mapping nor longitude found in dataset.')
2767+
return cartopy.crs.Projection(pyproj.CRS.from_cf(self._obj[gmaps[0]].attrs))
2768+
27482769
def decode_vertical_coords(
27492770
self, *, outnames: dict[str, str] | None = None, prefix: str | None = None
27502771
) -> None:
@@ -2899,6 +2920,21 @@ def formula_terms(self) -> dict[str, str]: # numpydoc ignore=SS06
28992920
terms[key] = value
29002921
return terms
29012922

2923+
def _get_grid_mapping(self, ignore_missing=False) -> DataArray:
2924+
da = self._obj
2925+
2926+
attrs_or_encoding = ChainMap(da.attrs, da.encoding)
2927+
grid_mapping = attrs_or_encoding.get("grid_mapping", None)
2928+
if not grid_mapping:
2929+
if ignore_missing:
2930+
return None
2931+
raise ValueError("No 'grid_mapping' attribute present.")
2932+
2933+
if grid_mapping not in da._coords:
2934+
raise ValueError(f"Grid Mapping variable {grid_mapping} not present.")
2935+
2936+
return da[grid_mapping]
2937+
29022938
@property
29032939
def grid_mapping_name(self) -> str:
29042940
"""
@@ -2919,21 +2955,22 @@ def grid_mapping_name(self) -> str:
29192955
>>> rotds.cf["temp"].cf.grid_mapping_name
29202956
'rotated_latitude_longitude'
29212957
"""
2922-
2923-
da = self._obj
2924-
2925-
attrs_or_encoding = ChainMap(da.attrs, da.encoding)
2926-
grid_mapping = attrs_or_encoding.get("grid_mapping", None)
2927-
if not grid_mapping:
2928-
raise ValueError("No 'grid_mapping' attribute present.")
2929-
2930-
if grid_mapping not in da._coords:
2931-
raise ValueError(f"Grid Mapping variable {grid_mapping} not present.")
2932-
2933-
grid_mapping_var = da[grid_mapping]
2934-
2958+
grid_mapping_var = self._get_grid_mapping()
29352959
return grid_mapping_var.attrs["grid_mapping_name"]
29362960

2961+
@property
2962+
def crs(self):
2963+
"""Cartopy CRS of the dataset's grid mapping."""
2964+
if pyproj is None:
2965+
raise ImportError('`crs` accessor requires optional packages `pyproj` and `cartopy`.')
2966+
2967+
grid_mapping_var = self._get_grid_mapping(ignore_missing=True)
2968+
if grid_mapping_var is None:
2969+
if 'longitude' in self:
2970+
return cartopy.crs.PlateCarree()
2971+
raise ValueError('No grid mapping nor longitude found.')
2972+
return cartopy.crs.Projection(pyproj.CRS.from_cf(grid_mapping_var.attrs))
2973+
29372974
def __getitem__(self, key: Hashable | Iterable[Hashable]) -> DataArray:
29382975
"""
29392976
Index into a DataArray making use of CF attributes.

0 commit comments

Comments
 (0)