---------------------------------------------------------------------------
GEOSException Traceback (most recent call last)
Cell In[113], line 1
----> 1 plot_obj = arr.plot(projection=ccrs.Robinson(central_longitude=100))
File ~/Code/uxarray/uxarray/plot/accessor.py:385, in UxDataArrayPlotAccessor.__call__(self, **kwargs)
382 def __call__(self, **kwargs) -> Any:
383 if self._uxda._face_centered():
384 # polygons for face-centered data
--> 385 return self.polygons(**kwargs)
386 else:
387 # points for node and edge centered data
388 return self.points(**kwargs)
File ~/Code/uxarray/uxarray/plot/accessor.py:473, in UxDataArrayPlotAccessor.polygons(self, periodic_elements, backend, engine, rasterize, dynamic, projection, xlabel, ylabel, *args, **kwargs)
470 if "clabel" not in kwargs and self._uxda.name is not None:
471 kwargs["clabel"] = self._uxda.name
--> 473 gdf = self._uxda.to_geodataframe(
474 periodic_elements=periodic_elements,
475 projection=kwargs.get("projection"),
476 engine=engine,
477 project=False,
478 )
480 # import datashader # no need to import explicitly, but gets used below when rasterize=True.
481 # (commented here for future reference, since datashader appears in uxarray dependency list,
482 # but it isn't imported explicitly anywhere in uxarray. For more details see PR #1548.)
483 return gdf.hvplot.polygons(
484 c=self._uxda.name if self._uxda.name is not None else "var",
485 rasterize=rasterize,
(...) 490 **kwargs,
491 )
File ~/Code/uxarray/uxarray/core/dataarray.py:277, in UxDataArray.to_geodataframe(self, periodic_elements, projection, cache, override, engine, exclude_antimeridian, **kwargs)
271 raise DimensionError(
272 f"Data Variable must be 1-dimensional, with shape {self.uxgrid.n_face} "
273 f"for face-centered data."
274 )
276 if self._face_centered():
--> 277 gdf, non_nan_polygon_indices = self.uxgrid.to_geodataframe(
278 periodic_elements=periodic_elements,
279 projection=projection,
280 project=kwargs.get("project", True),
281 cache=cache,
282 override=override,
283 exclude_antimeridian=exclude_antimeridian,
284 return_non_nan_polygon_indices=True,
285 engine=engine,
286 )
288 if exclude_antimeridian is not None:
289 if exclude_antimeridian:
File ~/Code/uxarray/uxarray/grid/grid.py:2608, in Grid.to_geodataframe(self, periodic_elements, projection, cache, override, engine, exclude_antimeridian, return_non_nan_polygon_indices, exclude_nan_polygons, **kwargs)
2605 return self._gdf_cached_parameters["gdf"]
2607 # construct a GeoDataFrame with the faces stored as polygons as the geometry
-> 2608 gdf, non_nan_polygon_indices = _grid_to_polygon_geodataframe(
2609 self, periodic_elements, projection, project, engine
2610 )
2612 if exclude_nan_polygons and non_nan_polygon_indices is not None:
2613 # exclude any polygons that contain NaN values
2614 gdf = GeoDataFrame({"geometry": gdf["geometry"][non_nan_polygon_indices]})
File ~/Code/uxarray/uxarray/grid/geometry.py:244, in _grid_to_polygon_geodataframe(grid, periodic_elements, projection, project, engine)
241 grid._gdf_cached_parameters["antimeridian_face_indices"] = antimeridian_face_indices
243 if periodic_elements == "split":
--> 244 gdf = _build_geodataframe_with_antimeridian(
245 polygon_shells,
246 projected_polygon_shells,
247 antimeridian_face_indices,
248 engine=engine,
249 )
250 elif periodic_elements == "ignore":
251 if engine == "geopandas":
252 # create a geopandas.GeoDataFrame
File ~/Code/uxarray/uxarray/grid/geometry.py:325, in _build_geodataframe_with_antimeridian(polygon_shells, projected_polygon_shells, antimeridian_face_indices, engine)
322 import spatialpandas
323 from spatialpandas.geometry import MultiPolygonArray
--> 325 polygons = _build_corrected_shapely_polygons(
326 polygon_shells, projected_polygon_shells, antimeridian_face_indices
327 )
328 if engine == "geopandas":
329 # Create a geopandas.GeoDataFrame
330 gdf = geopandas.GeoDataFrame({"geometry": polygons})
File ~/Code/uxarray/uxarray/grid/geometry.py:354, in _build_corrected_shapely_polygons(polygon_shells, projected_polygon_shells, antimeridian_face_indices)
351 shells = polygon_shells
353 # list of shapely Polygons representing each face in our grid
--> 354 polygons = Polygons(shells)
356 # construct antimeridian polygons
357 antimeridian_polygons = Polygons(polygon_shells[antimeridian_face_indices])
File ~/Code/venvs/py314/lib/python3.14/site-packages/shapely/decorators.py:173, in deprecate_positional.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
171 @wraps(func)
172 def wrapper(*args, **kwargs):
--> 173 result = func(*args, **kwargs)
175 n = len(args)
176 if n > warn_from:
File ~/Code/venvs/py314/lib/python3.14/site-packages/shapely/decorators.py:88, in multithreading_enabled.<locals>.wrapped(*args, **kwargs)
86 for arr in array_args:
87 arr.flags.writeable = False
---> 88 return func(*args, **kwargs)
89 finally:
90 for arr, old_flag in zip(array_args, old_flags):
File ~/Code/venvs/py314/lib/python3.14/site-packages/shapely/creation.py:417, in polygons(geometries, holes, indices, out, **kwargs)
413 geometries = np.asarray(geometries)
414 if not isinstance(geometries, Geometry) and np.issubdtype(
415 geometries.dtype, np.number
416 ):
--> 417 geometries = linearrings(geometries)
419 if indices is not None:
420 if holes is not None:
File ~/Code/venvs/py314/lib/python3.14/site-packages/shapely/decorators.py:173, in deprecate_positional.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
171 @wraps(func)
172 def wrapper(*args, **kwargs):
--> 173 result = func(*args, **kwargs)
175 n = len(args)
176 if n > warn_from:
File ~/Code/venvs/py314/lib/python3.14/site-packages/shapely/decorators.py:88, in multithreading_enabled.<locals>.wrapped(*args, **kwargs)
86 for arr in array_args:
87 arr.flags.writeable = False
---> 88 return func(*args, **kwargs)
89 finally:
90 for arr, old_flag in zip(array_args, old_flags):
File ~/Code/venvs/py314/lib/python3.14/site-packages/shapely/creation.py:316, in linearrings(coords, y, z, indices, handle_nan, out, **kwargs)
314 handle_nan = HandleNaN.get_value(handle_nan)
315 if indices is None:
--> 316 return lib.linearrings(coords, np.intc(handle_nan), out=out, **kwargs)
317 else:
318 return simple_geometries_1d(
319 coords, indices, GeometryType.LINEARRING, handle_nan=handle_nan, out=out
320 )
GEOSException: IllegalArgumentException: Points of LinearRing do not form a closed linestring
Version
v2026.09.1
How did you install UXarray?
Source
What happened?
Using almost any cartopy projection with a nonzero
central_longitudecausesuxarr.plot(..., projection=that_projection)to crash with GEOSException.(note: this is the same bug which @erogluorhan encountered during the recent usclivar meeting.)
The exception seems to be occurring inside uxarray's to_geodataframe, so it is likely something that should be fixed within uxarray, not an upstream issue. The full traceback looks like this:
click to show full traceback
I checked all other projections from cartopy (except the "local" projections
'EuroPP', 'LambertZoneII', 'OSGB', 'OSNI'which focus on only one particular region) and found that, with the exception of ObliqueMercator, all of them have this error. Here's a copy-pastable block with the full list of projections I checked:What did you expect to happen?
I expected this to work just fine! It works fine when using structured grids.
Can you provide a MCVE to repoduce the bug?