1717]
1818
1919
20+ # Useful convention language:
21+ # 1. Whether linked to normal CF space-time coordinates with a nodes attribute or not, inclusion of such coordinates is
22+ # recommended to maintain backward compatibility with software that has not implemented geometry capabilities.
23+ # 2. The geometry node coordinate variables must each have an axis attribute whose allowable values are X, Y, and Z.
24+ # 3. If a coordinates attribute is carried by the geometry container variable or its parent data variable, then those coordinate variables
25+ # that have a meaningful correspondence with node coordinates are indicated as such by a nodes attribute that names the corresponding node
26+ # coordinates, but only if the grid_mapping associated the geometry node variables is the same as that of the coordinate variables.
27+ # If a different grid mapping is used, then the provided coordinates must not have the nodes attribute.
28+ #
29+ # Interpretation:
30+ # 1. node coordinates are exact; the 'normal' coordinates are a reasonable value to use, if you do not know how to interpret the nodes.
31+
32+
2033def decode_geometries (encoded : xr .Dataset ) -> xr .Dataset :
2134 """
2235 Decode CF encoded geometries to a numpy object array containing shapely geometries.
@@ -282,6 +295,14 @@ def shapely_to_cf(geometries: xr.DataArray | Sequence, grid_mapping: str | None
282295 ----------
283296 Please refer to the CF conventions document: http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#geometries
284297 """
298+
299+ if isinstance (geometries , xr .DataArray ) and grid_mapping is not None :
300+ raise DeprecationWarning (
301+ "Explicitly passing `grid_mapping` with DataArray of geometries is deprecated. "
302+ "Please set a `grid_mapping` attribute on `geometries`, " ,
303+ "and set the grid mapping variable as a coordinate" ,
304+ )
305+
285306 # Get all types to call the appropriate translation function.
286307 types = {
287308 geom .item ().geom_type if isinstance (geom , xr .DataArray ) else geom .geom_type
@@ -300,19 +321,38 @@ def shapely_to_cf(geometries: xr.DataArray | Sequence, grid_mapping: str | None
300321
301322 ds [GEOMETRY_CONTAINER_NAME ].attrs .update (coordinates = "crd_x crd_y" )
302323
324+ if (
325+ grid_mapping is None
326+ and isinstance (geometries , xr .DataArray )
327+ and (grid_mapping_varname := geometries .attrs .get ("grid_mapping" ))
328+ ):
329+ if grid_mapping_varname in geometries .coords :
330+ grid_mapping = geometries .coords [grid_mapping_varname ].attrs [
331+ "grid_mapping_name"
332+ ]
333+ for name_ in ["x" , "y" , "crd_x" , "crd_y" ]:
334+ ds [name_ ].attrs ["grid_mapping" ] = grid_mapping_varname
335+
303336 # Special treatment of selected grid mappings
304- if grid_mapping == "longitude_latitude" :
305- # Special case for longitude_latitude grid mapping
337+ if grid_mapping in [ "latitude_longitude" , "rotated_latitude_longitude" ] :
338+ # Special case for longitude_latitude type grid mappings
306339 ds = ds .rename (crd_x = "lon" , crd_y = "lat" )
307- ds .lon .attrs .update (units = "degrees_east" , standard_name = "longitude" )
308- ds .lat .attrs .update (units = "degrees_north" , standard_name = "latitude" )
340+ if grid_mapping == "latitude_longitude" :
341+ ds .lon .attrs .update (units = "degrees_east" , standard_name = "longitude" )
342+ ds .x .attrs .update (units = "degrees_east" , standard_name = "longitude" )
343+ ds .lat .attrs .update (units = "degrees_north" , standard_name = "latitude" )
344+ ds .y .attrs .update (units = "degrees_north" , standard_name = "latitude" )
345+ elif grid_mapping == "rotated_latitude_longitude" :
346+ ds .lon .attrs .update (units = "degrees" , standard_name = "grid_longitude" )
347+ ds .x .attrs .update (units = "degrees" , standard_name = "grid_longitude" )
348+ ds .lat .attrs .update (units = "degrees" , standard_name = "grid_latitude" )
349+ ds .y .attrs .update (units = "degrees" , standard_name = "grid_latitude" )
309350 ds [GEOMETRY_CONTAINER_NAME ].attrs .update (coordinates = "lon lat" )
310- ds .x .attrs .update (units = "degrees_east" , standard_name = "longitude" )
311- ds .y .attrs .update (units = "degrees_north" , standard_name = "latitude" )
312351 elif grid_mapping is not None :
313- raise NotImplementedError (
314- f"Only grid mapping longitude_latitude is implemented. Got { grid_mapping } ."
315- )
352+ ds .crd_x .attrs .update (standard_name = "projection_x_coordinate" )
353+ ds .x .attrs .update (standard_name = "projection_x_coordinate" )
354+ ds .crd_y .attrs .update (standard_name = "projection_y_coordinate" )
355+ ds .y .attrs .update (standard_name = "projection_y_coordinate" )
316356
317357 return ds
318358
0 commit comments