17
17
]
18
18
19
19
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
+
20
33
def decode_geometries (encoded : xr .Dataset ) -> xr .Dataset :
21
34
"""
22
35
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
282
295
----------
283
296
Please refer to the CF conventions document: http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#geometries
284
297
"""
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
+
285
306
# Get all types to call the appropriate translation function.
286
307
types = {
287
308
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
300
321
301
322
ds [GEOMETRY_CONTAINER_NAME ].attrs .update (coordinates = "crd_x crd_y" )
302
323
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
+
303
336
# 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
306
339
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" )
309
350
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" )
312
351
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" )
316
356
317
357
return ds
318
358
0 commit comments