@@ -295,7 +295,7 @@ def cf_to_points(ds: xr.Dataset):
295295 return xr .DataArray (geoms , dims = node_count .dims , coords = node_count .coords )
296296
297297
298- def grid_bounds_to_polygons (ds : xr .Dataset ) -> xr .DataArray :
298+ def grid_to_polygons (ds : xr .Dataset ) -> xr .DataArray :
299299 """
300300 Converts a regular 2D lat/lon grid to a 2D array of shapely polygons.
301301
@@ -313,7 +313,7 @@ def grid_bounds_to_polygons(ds: xr.Dataset) -> xr.DataArray:
313313 DataArray
314314 DataArray with shapely polygon per grid cell.
315315 """
316- from shapely import Polygon
316+ import shapely
317317
318318 grid = ds .cf [["latitude" , "longitude" ]].load ().reset_coords ()
319319 bounds = ds .cf .bounds
@@ -327,30 +327,24 @@ def grid_bounds_to_polygons(ds: xr.Dataset) -> xr.DataArray:
327327
328328 bounds_dim = grid .cf .get_bounds_dim_name ("latitude" )
329329 points = points .transpose (..., bounds_dim )
330- assert points .sizes [bounds_dim ] == 2
331-
332330 lonbnd = points [lon_bounds ].data
333331 latbnd = points [lat_bounds ].data
334332
335- # geopandas needs this
336- expanded_lon = lonbnd [..., [0 , 0 , 1 , 1 ]]
337- mask = expanded_lon [..., 0 ] >= 180
338- expanded_lon [mask , :] = expanded_lon [mask , :] - 360
339-
340- # these magic numbers are OK :
341- # - 4 corners to a polygon, and
342- # - 2 from stacking lat, lon along the last axis
343- # flatten here to make iteration easier. It would be nice to avoid that.
344- # potentially with just np.vectorize. The polygon creation is the real slow bit.
345- # Shapely's MultiPolygon also iterates over a list in Python...
346- blocked = np .stack ([expanded_lon , latbnd [..., [0 , 1 , 1 , 0 ]]], axis = - 1 ).reshape (
347- - 1 , 4 , 2
348- )
349- polyarray = np .array (
350- [Polygon (blocked [i , ...]) for i in range (blocked .shape [0 ])], dtype = "O"
351- )
352- newshape = latbnd .shape [:- 1 ]
353- polyarray = polyarray .reshape (newshape )
333+ if points .sizes [bounds_dim ] == 2 :
334+ # geopandas needs this
335+ lonbnd = lonbnd [..., [0 , 0 , 1 , 1 ]]
336+ mask = lonbnd [..., 0 ] >= 180
337+ lonbnd [mask , :] = lonbnd [mask , :] - 360
338+ latbnd = latbnd [..., [0 , 1 , 1 , 0 ]]
339+
340+ elif points .sizes [bounds_dim ] == 4 :
341+ raise NotImplementedError
342+ else :
343+ raise ValueError (
344+ f"The size of the detected bounds or vertex dimension { bounds_dim } is not 2 or 4."
345+ )
346+
347+ polyarray = shapely .polygons (shapely .linearrings (lonbnd , latbnd ))
354348 boxes = points [lon_bounds ][..., 0 ].copy (data = polyarray )
355349
356350 return boxes
0 commit comments