SciTools / cartopy

Cartopy - a cartographic python library with matplotlib support
https://scitools.org.uk/cartopy/docs/latest
BSD 3-Clause "New" or "Revised" License
1.41k stars 359 forks source link

A GEOSException error occurred when calling contourf #2370

Open Clarmy opened 5 months ago

Clarmy commented 5 months ago

Description

I encountered a strange shapely.errors.GEOSException error when using cartopy to draw maps with contourf. The plotting works fine if I just use matplotlib without the cartopy projection transformation.

sample data: https://drive.google.com/file/d/1n1PkwgZez3Ukz-0klkll2YAJX46vOH-6/view?usp=sharing

Code to reproduce

The code runs normally if I execute the following.

import numpy as np
import matplotlib.pyplot as plt

data = np.load('./data.npy')
lons = np.load('./lons.npy')
lats = np.load('./lats.npy')

plt.contourf(lons, lats, data, levels=np.arange(0, 101, 5))
plt.savefig('./output.png')

However, if I execute the following code, it results in an error.

import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs

data = np.load('./data.npy')
lons = np.load('./lons.npy')
lats = np.load('./lats.npy')

fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(111, projection=ccrs.GOOGLE_MERCATOR)
ax.contourf(lons, lats, data, levels=np.arange(0, 101, 5), cmap=plt.cm.PiYG, transform=ccrs.PlateCarree())
ax.set_extent((50, 160, 0, 60))
ax.set_axis_off()
fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
fig.savefig('./output.png')

Traceback

GEOSException                             Traceback (most recent call last)
Cell In[7], line 11
      9 fig = plt.figure(figsize=(20, 10))
     10 ax = fig.add_subplot(111, projection=ccrs.GOOGLE_MERCATOR)
---> 11 ax.contourf(lons, lats, data, levels=np.arange(0, 101, 5), cmap=plt.cm.PiYG, transform=ccrs.PlateCarree())
     12 ax.set_extent((50, 160, 0, 60))
     13 ax.set_axis_off()

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/geoaxes.py:315, in _add_transform.<locals>.wrapper(self, *args, **kwargs)
    310     raise ValueError(f'Invalid transform: Spherical {func.__name__} '
    311                      'is not supported - consider using '
    312                      'PlateCarree/RotatedPole.')
    314 kwargs['transform'] = transform
--> 315 return func(self, *args, **kwargs)

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/geoaxes.py:359, in _add_transform_first.<locals>.wrapper(self, *args, **kwargs)
    357     # Use the new points as the input arguments
    358     args = (x, y, z) + args[3:]
--> 359 return func(self, *args, **kwargs)

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/geoaxes.py:1666, in GeoAxes.contourf(self, *args, **kwargs)
   1664         self.update_datalim(extent.get_points())
   1665 else:
-> 1666     self.update_datalim(result.get_datalim(self.transData))
   1668 self.autoscale_view()
   1670 # Re-cast the contour as a GeoContourSet.

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/collections.py:267, in Collection.get_datalim(self, transData)
    264     return transforms.Bbox.null()
    266 if not transform.is_affine:
--> 267     paths = [transform.transform_path_non_affine(p) for p in paths]
    268     # Don't convert transform to transform.get_affine() here because
    269     # we may have transform.contains_branch(transData) but not
    270     # transforms.get_affine().contains_branch(transData).  But later,
    271     # be careful to only apply the affine part that remains.
    273 offsets = self.get_offsets()

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/collections.py:267, in <listcomp>(.0)
    264     return transforms.Bbox.null()
    266 if not transform.is_affine:
--> 267     paths = [transform.transform_path_non_affine(p) for p in paths]
    268     # Don't convert transform to transform.get_affine() here because
    269     # we may have transform.contains_branch(transData) but not
    270     # transforms.get_affine().contains_branch(transData).  But later,
    271     # be careful to only apply the affine part that remains.
    273 offsets = self.get_offsets()

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/transforms.py:2426, in CompositeGenericTransform.transform_path_non_affine(self, path)
   2424     return path
   2425 elif not self._a.is_affine and self._b.is_affine:
-> 2426     return self._a.transform_path_non_affine(path)
   2427 else:
   2428     return self._b.transform_path_non_affine(
   2429                             self._a.transform_path(path))

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/geoaxes.py:182, in InterProjectionTransform.transform_path_non_affine(self, src_path)
    177 transformed_geoms = []
    178 # Check whether this transform has the "force_path_ccw" attribute set.
    179 # This is a cartopy extension to the Transform API to allow finer
    180 # control of Path orientation handling (Path ordering is not important
    181 # in matplotlib, but is in Cartopy).
--> 182 geoms = cpatch.path_to_geos(src_path,
    183                             getattr(self, 'force_path_ccw', False))
    185 for geom in geoms:
    186     proj_geom = self.target_projection.project_geometry(
    187         geom, self.source_projection)

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/patch.py:180, in path_to_geos(path, force_ccw)
    175 if geom.is_empty:
    176     pass
    177 elif (len(collection) > 0 and
    178         isinstance(collection[-1][0], sgeom.Polygon) and
    179         isinstance(geom, sgeom.Polygon) and
--> 180         collection[-1][0].contains(geom.exterior)):
    181     if any(internal.contains(geom) for internal in collection[-1][1]):
    182         collection.append((geom, []))

File ~/miniconda3/lib/python3.9/site-packages/shapely/geometry/base.py:675, in BaseGeometry.contains(self, other)
    673 def contains(self, other):
    674     """Returns True if the geometry contains the other, else False"""
--> 675     return _maybe_unpack(shapely.contains(self, other))

File ~/miniconda3/lib/python3.9/site-packages/shapely/decorators.py:77, in multithreading_enabled.<locals>.wrapped(*args, **kwargs)
     75     for arr in array_args:
     76         arr.flags.writeable = False
---> 77     return func(*args, **kwargs)
     78 finally:
     79     for arr, old_flag in zip(array_args, old_flags):

File ~/miniconda3/lib/python3.9/site-packages/shapely/predicates.py:526, in contains(a, b, **kwargs)
    472 @multithreading_enabled
    473 def contains(a, b, **kwargs):
    474     """Returns True if geometry B is completely inside geometry A.
    475 
    476     A contains B if no points of B lie in the exterior of A and at least one
   (...)
    524     False
    525     """
--> 526     return lib.contains(a, b, **kwargs)

GEOSException: TopologyException: side location conflict at 97 16.5. This can occur if the input geometry is invalid.

Error in callback <function _draw_all_if_interactive at 0x10f89e5e0> (for post_execute):
---------------------------------------------------------------------------
GEOSException                             Traceback (most recent call last)
File ~/miniconda3/lib/python3.9/site-packages/matplotlib/pyplot.py:197, in _draw_all_if_interactive()
    195 def _draw_all_if_interactive() -> None:
    196     if matplotlib.is_interactive():
--> 197         draw_all()

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/_pylab_helpers.py:132, in Gcf.draw_all(cls, force)
    130 for manager in cls.get_all_fig_managers():
    131     if force or manager.canvas.figure.stale:
--> 132         manager.canvas.draw_idle()

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/backend_bases.py:1893, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   1891 if not self._is_idle_drawing:
   1892     with self._idle_draw_cntx():
-> 1893         self.draw(*args, **kwargs)

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/backends/backend_agg.py:388, in FigureCanvasAgg.draw(self)
    385 # Acquire a lock on the shared font cache.
    386 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
    387       else nullcontext()):
--> 388     self.figure.draw(self.renderer)
    389     # A GUI class may be need to update a window using this draw, so
    390     # don't forget to call the superclass.
    391     super().draw()

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:95, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     93 @wraps(draw)
     94 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 95     result = draw(artist, renderer, *args, **kwargs)
     96     if renderer._rasterizing:
     97         renderer.stop_rasterizing()

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/figure.py:3154, in Figure.draw(self, renderer)
   3151         # ValueError can occur when resizing a window.
   3153 self.patch.draw(renderer)
-> 3154 mimage._draw_list_compositing_images(
   3155     renderer, self, artists, self.suppressComposite)
   3157 for sfig in self.subfigs:
   3158     sfig.draw(renderer)

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/image.py:132, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130 if not_composite or not has_images:
    131     for a in artists:
--> 132         a.draw(renderer)
    133 else:
    134     # Composite any adjacent images together
    135     image_group = []

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/geoaxes.py:535, in GeoAxes.draw(self, renderer, **kwargs)
    530         self.imshow(img, extent=extent, origin=origin,
    531                     transform=factory.crs, *factory_args[1:],
    532                     **factory_kwargs)
    533 self._done_img_factory = True
--> 535 return super().draw(renderer=renderer, **kwargs)

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/axes/_base.py:3070, in _AxesBase.draw(self, renderer)
   3067 if artists_rasterized:
   3068     _draw_rasterized(self.figure, artists_rasterized, renderer)
-> 3070 mimage._draw_list_compositing_images(
   3071     renderer, self, artists, self.figure.suppressComposite)
   3073 renderer.close_group('axes')
   3074 self.stale = False

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/image.py:132, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130 if not_composite or not has_images:
    131     for a in artists:
--> 132         a.draw(renderer)
    133 else:
    134     # Composite any adjacent images together
    135     image_group = []

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:39, in _prevent_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     36     renderer.stop_rasterizing()
     37     renderer._rasterizing = False
---> 39 return draw(artist, renderer, *args, **kwargs)

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/contour.py:1478, in ContourSet.draw(self, renderer)
   1476 n_paths = len(paths)
   1477 if not self.filled or all(hatch is None for hatch in self.hatches):
-> 1478     super().draw(renderer)
   1479     return
   1480 # In presence of hatching, draw contours one at a time.

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/collections.py:354, in Collection.draw(self, renderer)
    350 renderer.open_group(self.__class__.__name__, self.get_gid())
    352 self.update_scalarmappable()
--> 354 transform, offset_trf, offsets, paths = self._prepare_points()
    356 gc = renderer.new_gc()
    357 self._set_gc_clip(gc)

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/collections.py:331, in Collection._prepare_points(self)
    328     offsets = np.ma.column_stack([xs, ys])
    330 if not transform.is_affine:
--> 331     paths = [transform.transform_path_non_affine(path)
    332              for path in paths]
    333     transform = transform.get_affine()
    334 if not offset_trf.is_affine:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/collections.py:331, in <listcomp>(.0)
    328     offsets = np.ma.column_stack([xs, ys])
    330 if not transform.is_affine:
--> 331     paths = [transform.transform_path_non_affine(path)
    332              for path in paths]
    333     transform = transform.get_affine()
    334 if not offset_trf.is_affine:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/transforms.py:2426, in CompositeGenericTransform.transform_path_non_affine(self, path)
   2424     return path
   2425 elif not self._a.is_affine and self._b.is_affine:
-> 2426     return self._a.transform_path_non_affine(path)
   2427 else:
   2428     return self._b.transform_path_non_affine(
   2429                             self._a.transform_path(path))

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/geoaxes.py:182, in InterProjectionTransform.transform_path_non_affine(self, src_path)
    177 transformed_geoms = []
    178 # Check whether this transform has the "force_path_ccw" attribute set.
    179 # This is a cartopy extension to the Transform API to allow finer
    180 # control of Path orientation handling (Path ordering is not important
    181 # in matplotlib, but is in Cartopy).
--> 182 geoms = cpatch.path_to_geos(src_path,
    183                             getattr(self, 'force_path_ccw', False))
    185 for geom in geoms:
    186     proj_geom = self.target_projection.project_geometry(
    187         geom, self.source_projection)

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/patch.py:180, in path_to_geos(path, force_ccw)
    175 if geom.is_empty:
    176     pass
    177 elif (len(collection) > 0 and
    178         isinstance(collection[-1][0], sgeom.Polygon) and
    179         isinstance(geom, sgeom.Polygon) and
--> 180         collection[-1][0].contains(geom.exterior)):
    181     if any(internal.contains(geom) for internal in collection[-1][1]):
    182         collection.append((geom, []))

File ~/miniconda3/lib/python3.9/site-packages/shapely/geometry/base.py:675, in BaseGeometry.contains(self, other)
    673 def contains(self, other):
    674     """Returns True if the geometry contains the other, else False"""
--> 675     return _maybe_unpack(shapely.contains(self, other))

File ~/miniconda3/lib/python3.9/site-packages/shapely/decorators.py:77, in multithreading_enabled.<locals>.wrapped(*args, **kwargs)
     75     for arr in array_args:
     76         arr.flags.writeable = False
---> 77     return func(*args, **kwargs)
     78 finally:
     79     for arr, old_flag in zip(array_args, old_flags):

File ~/miniconda3/lib/python3.9/site-packages/shapely/predicates.py:526, in contains(a, b, **kwargs)
    472 @multithreading_enabled
    473 def contains(a, b, **kwargs):
    474     """Returns True if geometry B is completely inside geometry A.
    475 
    476     A contains B if no points of B lie in the exterior of A and at least one
   (...)
    524     False
    525     """
--> 526     return lib.contains(a, b, **kwargs)

GEOSException: TopologyException: side location conflict at 97 16.5. This can occur if the input geometry is invalid.

---------------------------------------------------------------------------
GEOSException                             Traceback (most recent call last)
File ~/miniconda3/lib/python3.9/site-packages/IPython/core/formatters.py:340, in BaseFormatter.__call__(self, obj)
    338     pass
    339 else:
--> 340     return printer(obj)
    341 # Finally look for special method names
    342 method = get_real_method(obj, self.print_method)

File ~/miniconda3/lib/python3.9/site-packages/IPython/core/pylabtools.py:152, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    149     from matplotlib.backend_bases import FigureCanvasBase
    150     FigureCanvasBase(fig)
--> 152 fig.canvas.print_figure(bytes_io, **kw)
    153 data = bytes_io.getvalue()
    154 if fmt == 'svg':

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/backend_bases.py:2158, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2155     # we do this instead of `self.figure.draw_without_rendering`
   2156     # so that we can inject the orientation
   2157     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2158         self.figure.draw(renderer)
   2159 if bbox_inches:
   2160     if bbox_inches == "tight":

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:95, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     93 @wraps(draw)
     94 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 95     result = draw(artist, renderer, *args, **kwargs)
     96     if renderer._rasterizing:
     97         renderer.stop_rasterizing()

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/figure.py:3154, in Figure.draw(self, renderer)
   3151         # ValueError can occur when resizing a window.
   3153 self.patch.draw(renderer)
-> 3154 mimage._draw_list_compositing_images(
   3155     renderer, self, artists, self.suppressComposite)
   3157 for sfig in self.subfigs:
   3158     sfig.draw(renderer)

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/image.py:132, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130 if not_composite or not has_images:
    131     for a in artists:
--> 132         a.draw(renderer)
    133 else:
    134     # Composite any adjacent images together
    135     image_group = []

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/geoaxes.py:535, in GeoAxes.draw(self, renderer, **kwargs)
    530         self.imshow(img, extent=extent, origin=origin,
    531                     transform=factory.crs, *factory_args[1:],
    532                     **factory_kwargs)
    533 self._done_img_factory = True
--> 535 return super().draw(renderer=renderer, **kwargs)

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/axes/_base.py:3070, in _AxesBase.draw(self, renderer)
   3067 if artists_rasterized:
   3068     _draw_rasterized(self.figure, artists_rasterized, renderer)
-> 3070 mimage._draw_list_compositing_images(
   3071     renderer, self, artists, self.figure.suppressComposite)
   3073 renderer.close_group('axes')
   3074 self.stale = False

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/image.py:132, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130 if not_composite or not has_images:
    131     for a in artists:
--> 132         a.draw(renderer)
    133 else:
    134     # Composite any adjacent images together
    135     image_group = []

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:39, in _prevent_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     36     renderer.stop_rasterizing()
     37     renderer._rasterizing = False
---> 39 return draw(artist, renderer, *args, **kwargs)

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/contour.py:1478, in ContourSet.draw(self, renderer)
   1476 n_paths = len(paths)
   1477 if not self.filled or all(hatch is None for hatch in self.hatches):
-> 1478     super().draw(renderer)
   1479     return
   1480 # In presence of hatching, draw contours one at a time.

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/artist.py:72, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     69     if artist.get_agg_filter() is not None:
     70         renderer.start_filter()
---> 72     return draw(artist, renderer)
     73 finally:
     74     if artist.get_agg_filter() is not None:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/collections.py:354, in Collection.draw(self, renderer)
    350 renderer.open_group(self.__class__.__name__, self.get_gid())
    352 self.update_scalarmappable()
--> 354 transform, offset_trf, offsets, paths = self._prepare_points()
    356 gc = renderer.new_gc()
    357 self._set_gc_clip(gc)

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/collections.py:331, in Collection._prepare_points(self)
    328     offsets = np.ma.column_stack([xs, ys])
    330 if not transform.is_affine:
--> 331     paths = [transform.transform_path_non_affine(path)
    332              for path in paths]
    333     transform = transform.get_affine()
    334 if not offset_trf.is_affine:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/collections.py:331, in <listcomp>(.0)
    328     offsets = np.ma.column_stack([xs, ys])
    330 if not transform.is_affine:
--> 331     paths = [transform.transform_path_non_affine(path)
    332              for path in paths]
    333     transform = transform.get_affine()
    334 if not offset_trf.is_affine:

File ~/miniconda3/lib/python3.9/site-packages/matplotlib/transforms.py:2426, in CompositeGenericTransform.transform_path_non_affine(self, path)
   2424     return path
   2425 elif not self._a.is_affine and self._b.is_affine:
-> 2426     return self._a.transform_path_non_affine(path)
   2427 else:
   2428     return self._b.transform_path_non_affine(
   2429                             self._a.transform_path(path))

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/geoaxes.py:182, in InterProjectionTransform.transform_path_non_affine(self, src_path)
    177 transformed_geoms = []
    178 # Check whether this transform has the "force_path_ccw" attribute set.
    179 # This is a cartopy extension to the Transform API to allow finer
    180 # control of Path orientation handling (Path ordering is not important
    181 # in matplotlib, but is in Cartopy).
--> 182 geoms = cpatch.path_to_geos(src_path,
    183                             getattr(self, 'force_path_ccw', False))
    185 for geom in geoms:
    186     proj_geom = self.target_projection.project_geometry(
    187         geom, self.source_projection)

File ~/miniconda3/lib/python3.9/site-packages/cartopy/mpl/patch.py:180, in path_to_geos(path, force_ccw)
    175 if geom.is_empty:
    176     pass
    177 elif (len(collection) > 0 and
    178         isinstance(collection[-1][0], sgeom.Polygon) and
    179         isinstance(geom, sgeom.Polygon) and
--> 180         collection[-1][0].contains(geom.exterior)):
    181     if any(internal.contains(geom) for internal in collection[-1][1]):
    182         collection.append((geom, []))

File ~/miniconda3/lib/python3.9/site-packages/shapely/geometry/base.py:675, in BaseGeometry.contains(self, other)
    673 def contains(self, other):
    674     """Returns True if the geometry contains the other, else False"""
--> 675     return _maybe_unpack(shapely.contains(self, other))

File ~/miniconda3/lib/python3.9/site-packages/shapely/decorators.py:77, in multithreading_enabled.<locals>.wrapped(*args, **kwargs)
     75     for arr in array_args:
     76         arr.flags.writeable = False
---> 77     return func(*args, **kwargs)
     78 finally:
     79     for arr, old_flag in zip(array_args, old_flags):

File ~/miniconda3/lib/python3.9/site-packages/shapely/predicates.py:526, in contains(a, b, **kwargs)
    472 @multithreading_enabled
    473 def contains(a, b, **kwargs):
    474     """Returns True if geometry B is completely inside geometry A.
    475 
    476     A contains B if no points of B lie in the exterior of A and at least one
   (...)
    524     False
    525     """
--> 526     return lib.contains(a, b, **kwargs)

GEOSException: TopologyException: side location conflict at 97 16.5. This can occur if the input geometry is invalid.

<Figure size 1440x720 with 1 Axes>
Full environment definition ### Operating system MacOS ### Cartopy version 0.22.0 ### conda list ``` # packages in environment at /Users/clarmylee/miniconda3: # # Name Version Build Channel affine 2.4.0 pypi_0 pypi aiohttp 3.9.3 pypi_0 pypi aiosignal 1.3.1 pypi_0 pypi aliyun-python-sdk-core 2.14.0 pypi_0 pypi aliyun-python-sdk-kms 2.16.2 pypi_0 pypi annotated-types 0.6.0 pypi_0 pypi antlr4-python3-runtime 4.9.3 pypi_0 pypi anyio 3.7.1 pypi_0 pypi appnope 0.1.3 pyhd8ed1ab_0 conda-forge apscheduler 3.10.4 pypi_0 pypi archspec 0.2.1 pyhd8ed1ab_1 conda-forge argon2-cffi 23.1.0 pypi_0 pypi argon2-cffi-bindings 21.2.0 pypi_0 pypi arrow 1.3.0 pypi_0 pypi asttokens 2.4.0 pypi_0 pypi async-lru 2.0.4 pypi_0 pypi async-timeout 4.0.3 pypi_0 pypi attrs 23.1.0 pyh71513ae_1 conda-forge babel 2.13.0 pypi_0 pypi backcall 0.2.0 pyh9f0ad1d_0 conda-forge backports 1.0 pyhd8ed1ab_3 conda-forge backports.functools_lru_cache 1.6.5 pyhd8ed1ab_0 conda-forge beautifulsoup4 4.12.2 pyha770c72_0 conda-forge black 23.10.1 pypi_0 pypi blas 1.0 openblas bleach 6.1.0 pyhd8ed1ab_0 conda-forge blosc 1.21.3 h313beb8_0 boltons 23.0.0 pyhd8ed1ab_0 conda-forge boost-cpp 1.78.0 hf1d6563_2 conda-forge branca 0.7.0 pypi_0 pypi brotlipy 0.7.0 py39h1a28f6b_1002 bzip2 1.0.8 h620ffc9_4 c-ares 1.19.1 h80987f9_0 c-blosc2 2.8.0 h313beb8_0 ca-certificates 2024.2.2 hf0a4a13_0 conda-forge cairo 1.16.0 h73a0509_1014 conda-forge cartopy 0.22.0 pypi_0 pypi cattrs 23.2.3 pypi_0 pypi cdsapi 0.6.1 pypi_0 pypi certifi 2024.2.2 pyhd8ed1ab_0 conda-forge cf-units 3.2.0 py39h373d45f_4 conda-forge cfchecker 4.1.0 pyhd8ed1ab_0 conda-forge cffi 1.15.0 py39h22df2f2_1 cfitsio 4.2.0 h2f961c4_0 conda-forge cftime 1.6.3 py39h373d45f_0 conda-forge cfunits 3.3.6 pyhd8ed1ab_0 conda-forge charset-normalizer 2.0.4 pyhd3eb1b0_0 click 8.1.7 pypi_0 pypi click-plugins 1.1.1 pypi_0 pypi cligj 0.7.2 pypi_0 pypi cnmaps 1.1.7 pypi_0 pypi colorama 0.4.4 pyhd3eb1b0_0 comm 0.1.4 pypi_0 pypi compliance-checker 5.1.0 pyhd8ed1ab_0 conda-forge conda 23.7.4 py39h2804cbe_0 conda-forge conda-content-trust 0.1.1 pyhd3eb1b0_0 conda-package-handling 2.2.0 pyh38be061_0 conda-forge conda-package-streaming 0.9.0 pyhd8ed1ab_0 conda-forge confluent-kafka 2.3.0 pypi_0 pypi contourpy 1.1.1 pypi_0 pypi crcmod 1.7 pypi_0 pypi cryptography 40.0.2 py39he2a39a8_0 conda-forge curl 8.4.0 h02f6b3c_0 cycler 0.12.1 pypi_0 pypi cyeva 0.1.0b11 pypi_0 pypi dashscope 1.14.1 pypi_0 pypi dataclasses 0.8 pyhc8e2a94_3 conda-forge debugpy 1.8.0 pypi_0 pypi decorator 5.1.1 pyhd8ed1ab_0 conda-forge defusedxml 0.7.1 pyhd8ed1ab_0 conda-forge eccodes 2.29.0 h4f94b83_1 conda-forge entrypoints 0.4 pyhd8ed1ab_0 conda-forge exceptiongroup 1.1.3 pyhd8ed1ab_0 conda-forge executing 2.0.0 pypi_0 pypi expat 2.5.0 hb7217d7_1 conda-forge fastapi 0.104.1 pypi_0 pypi fiona 1.9.5 pypi_0 pypi fire 0.5.0 pypi_0 pypi flatbuffers 23.5.26 pypi_0 pypi fmt 10.1.1 h1995070_0 conda-forge folium 0.15.0 pypi_0 pypi font-ttf-dejavu-sans-mono 2.37 hab24e00_0 conda-forge font-ttf-inconsolata 3.000 h77eed37_0 conda-forge font-ttf-source-code-pro 2.038 h77eed37_0 conda-forge font-ttf-ubuntu 0.83 hab24e00_0 conda-forge fontconfig 2.14.2 h82840c6_0 conda-forge fonts-conda-ecosystem 1 0 conda-forge fonts-conda-forge 1 0 conda-forge fonttools 4.43.1 pypi_0 pypi fqdn 1.5.1 pypi_0 pypi freetype 2.12.1 hadb7bae_2 conda-forge freexl 1.0.6 h1a8c8d9_1 conda-forge frozenlist 1.4.1 pypi_0 pypi future 0.18.3 pyhd8ed1ab_0 conda-forge gdal 3.6.2 py39h766d3fc_9 conda-forge geojson 3.1.0 pypi_0 pypi geopandas 0.14.0 pypi_0 pypi geos 3.11.1 hb7217d7_0 conda-forge geotiff 1.7.1 hdcdc974_6 conda-forge gettext 0.21.1 h0186832_0 conda-forge giflib 5.2.1 h1a8c8d9_3 conda-forge h11 0.14.0 pypi_0 pypi hdf4 4.2.15 h1a38d6a_5 conda-forge hdf5 1.12.2 nompi_ha7af310_101 conda-forge howhigh 0.0.1 dev_0 icu 70.1 h6b3803e_0 conda-forge idna 3.3 pyhd3eb1b0_0 imageio 2.32.0 pypi_0 pypi importlib-metadata 6.8.0 pyha770c72_0 conda-forge importlib_resources 6.1.0 pyhd8ed1ab_0 conda-forge iniconfig 2.0.0 pypi_0 pypi ipdb 0.13.13 pypi_0 pypi ipykernel 6.25.2 pypi_0 pypi ipython 8.16.1 pyh31c8845_0 conda-forge ipython-genutils 0.2.0 pypi_0 pypi ipython_genutils 0.2.0 py_1 conda-forge ipywidgets 8.1.1 pypi_0 pypi isodate 0.6.1 pyhd8ed1ab_0 conda-forge isoduration 20.11.0 pypi_0 pypi isort 5.13.2 pypi_0 pypi jasper 4.0.0 hc3cd1e9_0 conda-forge jedi 0.19.1 pyhd8ed1ab_0 conda-forge jinja2 3.1.2 pyhd8ed1ab_1 conda-forge jmespath 0.10.0 pypi_0 pypi jpeg 9e h1a8c8d9_3 conda-forge json-c 0.16 hc449e50_0 conda-forge json5 0.9.14 pypi_0 pypi jsonpatch 1.33 pyhd8ed1ab_0 conda-forge jsonpointer 2.4 pypi_0 pypi jsonschema 4.19.1 pypi_0 pypi jsonschema-specifications 2023.7.1 pypi_0 pypi jupyter 1.0.0 pypi_0 pypi jupyter-client 7.4.9 pypi_0 pypi jupyter-console 6.6.3 pypi_0 pypi jupyter-contrib-core 0.4.2 pypi_0 pypi jupyter-core 5.4.0 pypi_0 pypi jupyter-events 0.8.0 pypi_0 pypi jupyter-lsp 2.2.0 pypi_0 pypi jupyter-nbextensions-configurator 0.6.3 pypi_0 pypi jupyter-server 2.8.0 pypi_0 pypi jupyter-server-terminals 0.4.4 pypi_0 pypi jupyter_client 7.3.4 pyhd8ed1ab_0 conda-forge jupyter_contrib_core 0.4.0 pyhd8ed1ab_0 conda-forge jupyter_contrib_nbextensions 0.7.0 pyhd8ed1ab_0 conda-forge jupyter_core 5.3.0 py39hca03da5_0 jupyter_highlight_selected_word 0.2.0 pyhd8ed1ab_1006 conda-forge jupyter_latex_envs 1.4.6 pyhd8ed1ab_1002 conda-forge jupyter_nbextensions_configurator 0.6.1 pyhd8ed1ab_0 conda-forge jupyterlab 4.0.7 pypi_0 pypi jupyterlab-server 2.25.0 pypi_0 pypi jupyterlab-widgets 3.0.9 pypi_0 pypi jupyterlab_pygments 0.2.2 pyhd8ed1ab_0 conda-forge kealib 1.5.0 hfd766a6_0 conda-forge kiwisolver 1.4.5 pypi_0 pypi krb5 1.20.1 h69eda48_0 conda-forge lazy-loader 0.3 pypi_0 pypi lcms2 2.15 h481adae_0 conda-forge lerc 4.0.0 h9a09cb3_0 conda-forge libaec 1.0.6 hb7217d7_1 conda-forge libarchive 3.6.2 h83f22c9_0 conda-forge libcurl 8.4.0 h3e2b118_0 libcxx 16.0.6 h4653b0c_0 conda-forge libdeflate 1.17 h1a8c8d9_0 conda-forge libedit 3.1.20221030 h80987f9_0 libev 4.33 h1a28f6b_1 libexpat 2.5.0 hb7217d7_1 conda-forge libffi 3.4.2 hc377ac9_2 libgdal 3.6.2 h8d4b95d_9 conda-forge libgfortran 5.0.0 12_2_0_hd922786_32 conda-forge libgfortran5 12.2.0 h0eea778_32 conda-forge libglib 2.78.1 hd9b11f9_0 conda-forge libiconv 1.17 he4db4b2_0 conda-forge libkml 1.3.0 h4f02115_1016 conda-forge libmamba 1.5.1 h6089622_0 conda-forge libmambapy 1.5.1 py39hc4dfcfb_0 conda-forge libnetcdf 4.9.1 nompi_h232cb48_101 conda-forge libnghttp2 1.57.0 h62f6fdd_0 libopenblas 0.3.21 h269037a_0 libpng 1.6.39 h76d750c_0 conda-forge libpq 15.2 h1a28acd_0 conda-forge librttopo 1.1.0 h844f84d_12 conda-forge libsodium 1.0.18 h27ca646_1 conda-forge libsolv 0.7.25 ha614eb4_0 conda-forge libspatialite 5.0.1 h14115fc_23 conda-forge libsqlite 3.43.2 h091b4b1_0 conda-forge libssh2 1.11.0 h7a5bd25_0 conda-forge libtiff 4.5.0 h5dffbdd_2 conda-forge libudunits2 2.2.28 h5f3f34b_3 conda-forge libwebp-base 1.3.2 hb547adb_0 conda-forge libxml2 2.10.3 h67585b2_4 conda-forge libxslt 1.1.37 h1bd8bc4_0 conda-forge libzip 1.10.1 ha0bc3c6_3 conda-forge libzlib 1.2.13 h53f4e23_5 conda-forge llvm-openmp 14.0.6 hc6e5704_0 llvmlite 0.41.1 pypi_0 pypi loguru 0.7.2 pypi_0 pypi lxml 4.9.2 py39h0520ce3_0 conda-forge lz4 4.3.2 pypi_0 pypi lz4-c 1.9.4 h313beb8_0 lzo 2.10 h1a28f6b_2 mamba 1.5.1 py39ha55b623_0 conda-forge markupsafe 2.1.3 pypi_0 pypi matplotlib 3.8.0 pypi_0 pypi matplotlib-inline 0.1.6 pyhd8ed1ab_0 conda-forge mercantile 1.2.1 pypi_0 pypi mistune 3.0.2 pypi_0 pypi multidict 6.0.5 pypi_0 pypi mypy-extensions 1.0.0 pypi_0 pypi nbclassic 1.0.0 pypi_0 pypi nbclient 0.8.0 pyhd8ed1ab_0 conda-forge nbconvert 7.9.2 pyhd8ed1ab_0 conda-forge nbconvert-core 7.9.2 pyhd8ed1ab_0 conda-forge nbconvert-pandoc 7.9.2 pyhd8ed1ab_0 conda-forge nbformat 5.9.2 pyhd8ed1ab_0 conda-forge ncurses 6.4 h7ea286d_0 conda-forge nest-asyncio 1.5.8 pyhd8ed1ab_0 conda-forge netcdf4 1.6.5 pypi_0 pypi networkx 3.2.1 pypi_0 pypi notebook 7.0.6 pypi_0 pypi notebook-shim 0.2.3 pypi_0 pypi nspr 4.35 hb7217d7_0 conda-forge nss 3.94 hc6b9969_0 conda-forge numba 0.58.1 pypi_0 pypi numexpr 2.8.7 py39hecc3335_0 numpy 1.26.1 pypi_0 pypi numpy-base 1.26.0 py39ha9811e2_0 omegaconf 2.3.0 pypi_0 pypi opencv-python 4.9.0.80 pypi_0 pypi openjpeg 2.5.0 hbc2ba62_2 conda-forge openmeteo-requests 1.1.0 pypi_0 pypi openmeteo-sdk 1.7.2 pypi_0 pypi openssl 3.2.1 h0d3ecfb_1 conda-forge orjson 3.9.10 pypi_0 pypi oss2 2.18.2 pypi_0 pypi overrides 7.4.0 pypi_0 pypi owslib 0.29.2 pyhd8ed1ab_0 conda-forge packaging 23.2 pypi_0 pypi pandas 2.1.1 pypi_0 pypi pandoc 3.1.3 hce30654_0 conda-forge pandocfilters 1.5.0 pyhd8ed1ab_0 conda-forge parso 0.8.3 pyhd8ed1ab_0 conda-forge pathspec 0.11.2 pypi_0 pypi pcre2 10.40 hb34f9b4_0 conda-forge pendulum 2.1.2 py39h0f82c59_6 conda-forge pexpect 4.8.0 pyh1a96a4e_2 conda-forge pickleshare 0.7.5 py_1003 conda-forge pillow 10.0.1 pypi_0 pypi pint 0.18 pypi_0 pypi pip 21.2.4 py39hca03da5_0 pixman 0.42.2 h13dd4ca_0 conda-forge pkgutil-resolve-name 1.3.10 pyhd8ed1ab_1 conda-forge platformdirs 3.11.0 pyhd8ed1ab_0 conda-forge pluggy 1.3.0 pyhd8ed1ab_0 conda-forge poppler 23.03.0 h9564b9f_0 conda-forge poppler-data 0.4.12 hd8ed1ab_0 conda-forge postgresql 15.2 h45c140d_0 conda-forge proj 9.1.1 h13f728c_2 conda-forge prometheus_client 0.17.1 pyhd8ed1ab_0 conda-forge prompt-toolkit 3.0.39 pyha770c72_0 conda-forge prompt_toolkit 3.0.39 hd8ed1ab_0 conda-forge psutil 5.9.6 pypi_0 pypi ptyprocess 0.7.0 pyhd3deb0d_0 conda-forge pure_eval 0.2.2 pyhd8ed1ab_0 conda-forge py-cpuinfo 9.0.0 py39hca03da5_0 pyapollos 0.1.5 pypi_0 pypi pybind11-abi 4 hd8ed1ab_3 conda-forge pycosat 0.6.3 py39h1a28f6b_0 pycparser 2.21 pyhd3eb1b0_0 pycryptodome 3.19.0 pypi_0 pypi pydantic 2.5.1 pypi_0 pypi pydantic-core 2.14.3 pypi_0 pypi pygeohash 1.2.0 pypi_0 pypi pygeoif 1.1.1 pyhd8ed1ab_0 conda-forge pygments 2.16.1 pyhd8ed1ab_0 conda-forge pygrib 2.1.4 py39h914d841_8 conda-forge pymetaf 0.1.3 pypi_0 pypi pyopenssl 23.2.0 pyhd8ed1ab_1 conda-forge pyparsing 3.1.1 pypi_0 pypi pyproj 3.6.1 pypi_0 pypi pyrsistent 0.18.0 py39h1a28f6b_0 pyshp 2.3.1 pypi_0 pypi pysocks 1.7.1 py39hca03da5_0 pytables 3.7.0 py39h8abd629_3 conda-forge pyterrain 0.0.2 pypi_0 pypi pytest 7.4.4 pypi_0 pypi python 3.9.18 hfa1ae8a_0_cpython conda-forge python-dateutil 2.8.2 pyhd8ed1ab_0 conda-forge python-fastjsonschema 2.18.1 pyhd8ed1ab_0 conda-forge python-json-logger 2.0.7 pypi_0 pypi python.app 3 py39h1a28f6b_0 python_abi 3.9 2_cp39 conda-forge pytz 2023.3.post1 pyhd8ed1ab_0 conda-forge pytzdata 2020.1 pyh9f0ad1d_0 conda-forge pyyaml 6.0.1 pypi_0 pypi pyzmq 24.0.1 pypi_0 pypi qtconsole 5.4.4 pypi_0 pypi qtpy 2.4.0 pypi_0 pypi rasterio 1.3.9 pypi_0 pypi readline 8.2 h92ec313_1 conda-forge redis 5.0.3 pypi_0 pypi referencing 0.30.2 pypi_0 pypi regex 2023.10.3 py39h0f82c59_0 conda-forge reproc 14.2.4.post0 h93a5062_1 conda-forge reproc-cpp 14.2.4.post0 h965bd2d_1 conda-forge requests 2.31.0 pypi_0 pypi requests-cache 1.1.1 pypi_0 pypi retry-requests 2.0.0 pypi_0 pypi retrying 1.3.4 pypi_0 pypi rfc3339-validator 0.1.4 pypi_0 pypi rfc3986-validator 0.1.1 pypi_0 pypi rpds-py 0.10.6 pypi_0 pypi ruamel.yaml 0.17.16 py39h5161555_0 conda-forge ruamel.yaml.clib 0.2.2 py39h46acfd9_2 conda-forge ruamel_yaml 0.15.100 py39h1a28f6b_0 scikit-image 0.22.0 pypi_0 pypi scipy 1.11.3 pypi_0 pypi send2trash 1.8.2 pypi_0 pypi setuptools 68.2.2 pyhd8ed1ab_0 conda-forge shapely 2.0.3 pypi_0 pypi six 1.16.0 pyhd3eb1b0_1 sniffio 1.3.0 pypi_0 pypi snuggs 1.4.7 pypi_0 pypi soupsieve 2.5 pyhd8ed1ab_1 conda-forge sqlite 3.38.2 h1058600_0 stack-data 0.6.3 pypi_0 pypi stack_data 0.6.2 pyhd8ed1ab_0 conda-forge starlette 0.27.0 pypi_0 pypi termcolor 2.3.0 pypi_0 pypi terminado 0.17.1 pyhd1c38e8_0 conda-forge tifffile 2024.2.12 pypi_0 pypi tiledb 2.13.2 h9bd36d0_0 conda-forge timeout-decorator 0.5.0 pypi_0 pypi tinycss2 1.2.1 pyhd8ed1ab_0 conda-forge tk 8.6.13 hb31c410_0 conda-forge tokei 12.1.1 h6ee1f66_0 conda-forge toml 0.10.2 pypi_0 pypi tomli 2.0.1 pypi_0 pypi toolz 0.12.0 pyhd8ed1ab_0 conda-forge tornado 6.3.3 pypi_0 pypi tqdm 4.66.1 pypi_0 pypi traitlets 5.11.2 pypi_0 pypi types-python-dateutil 2.8.19.14 pypi_0 pypi typing-extensions 4.8.0 hd8ed1ab_0 conda-forge typing_extensions 4.8.0 pyha770c72_0 conda-forge tzcode 2023c h1a8c8d9_0 conda-forge tzdata 2023.3 pypi_0 pypi tzlocal 5.2 pypi_0 pypi udunits2 2.2.28 h5f3f34b_3 conda-forge uri-template 1.3.0 pypi_0 pypi uriparser 0.9.7 hb7217d7_1 conda-forge url-normalize 1.4.3 pypi_0 pypi urllib3 1.26.8 pyhd3eb1b0_0 uvicorn 0.24.0.post1 pypi_0 pypi validators 0.22.0 pyhd8ed1ab_0 conda-forge wcwidth 0.2.8 pyhd8ed1ab_0 conda-forge webcolors 1.13 pypi_0 pypi webencodings 0.5.1 pyhd8ed1ab_2 conda-forge websocket-client 1.6.4 pypi_0 pypi wget 3.2 pypi_0 pypi wheel 0.37.1 pyhd3eb1b0_0 widgetsnbextension 4.0.9 pypi_0 pypi xarray 2023.10.1 pypi_0 pypi xerces-c 3.2.4 h627aa08_1 conda-forge xz 5.4.2 h80987f9_0 yaml 0.2.5 h1a28f6b_0 yaml-cpp 0.7.0 h13dd4ca_3 conda-forge yarl 1.9.4 pypi_0 pypi zeromq 4.3.4 hc377ac9_0 zipp 3.17.0 pyhd8ed1ab_0 conda-forge zlib 1.2.13 h53f4e23_5 conda-forge zlib-ng 2.0.7 h80987f9_0 zstandard 0.21.0 py39haf70649_1 conda-forge zstd 1.5.5 hd90d995_0 ``` ### pip list ``` Package Version Location --------------------------------- ------------ ----------------------------------- affine 2.4.0 aiohttp 3.9.3 aiosignal 1.3.1 aliyun-python-sdk-core 2.14.0 aliyun-python-sdk-kms 2.16.2 annotated-types 0.6.0 antlr4-python3-runtime 4.9.3 anyio 3.7.1 appnope 0.1.3 APScheduler 3.10.4 archspec 0.2.1 argon2-cffi 23.1.0 argon2-cffi-bindings 21.2.0 arrow 1.3.0 asttokens 2.4.1 async-lru 2.0.4 async-timeout 4.0.3 attrs 23.1.0 Babel 2.13.0 backcall 0.2.0 backports.functools-lru-cache 1.6.5 beautifulsoup4 4.12.2 black 23.10.1 bleach 6.1.0 boltons 23.0.0 branca 0.7.0 brotlipy 0.7.0 Cartopy 0.22.0 cattrs 23.2.3 cdsapi 0.6.1 certifi 2024.2.2 cf-units 3.2.0 cfchecker 4.1.0 cffi 1.15.0 cftime 1.6.3 cfunits 3.3.6 charset-normalizer 2.0.4 click 8.1.7 click-plugins 1.1.1 cligj 0.7.2 cnmaps 1.1.7 colorama 0.4.4 comm 0.1.4 compliance-checker 5.1.0 conda 23.7.4 conda-content-trust 0+unknown conda-package-handling 2.2.0 conda_package_streaming 0.9.0 confluent-kafka 2.3.0 contourpy 1.1.1 crcmod 1.7 cryptography 40.0.2 cycler 0.12.1 cyeva 0.1.0b11 dashscope 1.14.1 dataclasses 0.8 debugpy 1.8.0 decorator 5.1.1 defusedxml 0.7.1 entrypoints 0.4 exceptiongroup 1.1.3 executing 2.0.1 fastapi 0.104.1 fastjsonschema 2.18.1 fiona 1.9.5 fire 0.5.0 flatbuffers 23.5.26 folium 0.15.0 fonttools 4.43.1 fqdn 1.5.1 frozenlist 1.4.1 future 0.18.3 GDAL 3.6.2 geojson 3.1.0 geopandas 0.14.0 h11 0.14.0 howhigh 0.0.1 /Users/clarmylee/github/howhighisit idna 3.3 imageio 2.32.0 importlib-metadata 6.8.0 importlib-resources 6.1.0 iniconfig 2.0.0 ipdb 0.13.13 ipykernel 6.25.2 ipython 8.16.1 ipython-genutils 0.2.0 ipywidgets 8.1.1 isodate 0.6.1 isoduration 20.11.0 isort 5.13.2 jedi 0.19.1 Jinja2 3.1.2 jmespath 0.10.0 json5 0.9.14 jsonpatch 1.33 jsonpointer 2.4 jsonschema 4.19.1 jsonschema-specifications 2023.7.1 jupyter 1.0.0 jupyter_client 7.4.9 jupyter-console 6.6.3 jupyter-contrib-core 0.4.2 jupyter-contrib-nbextensions 0.7.0 jupyter_core 5.4.0 jupyter-events 0.8.0 jupyter-highlight-selected-word 0.2.0 jupyter-latex-envs 1.4.6 jupyter-lsp 2.2.0 jupyter-nbextensions-configurator 0.6.3 jupyter_server 2.8.0 jupyter_server_terminals 0.4.4 jupyterlab 4.0.7 jupyterlab-pygments 0.2.2 jupyterlab_server 2.25.0 jupyterlab-widgets 3.0.9 kiwisolver 1.4.5 lazy_loader 0.3 libmambapy 1.5.1 llvmlite 0.41.1 loguru 0.7.2 lxml 4.9.2 lz4 4.3.2 mamba 1.5.1 MarkupSafe 2.1.3 matplotlib 3.8.0 matplotlib-inline 0.1.6 mercantile 1.2.1 mistune 3.0.2 multidict 6.0.5 mypy-extensions 1.0.0 nbclassic 1.0.0 nbclient 0.8.0 nbconvert 7.9.2 nbformat 5.9.2 nest-asyncio 1.5.8 netCDF4 1.6.5 networkx 3.2.1 notebook 7.0.6 notebook_shim 0.2.3 numba 0.58.1 numexpr 2.8.7 numpy 1.26.1 omegaconf 2.3.0 opencv-python 4.9.0.80 openmeteo_requests 1.1.0 openmeteo_sdk 1.7.2 orjson 3.9.10 oss2 2.18.2 overrides 7.4.0 OWSLib 0.29.2 packaging 23.2 pandas 2.1.1 pandocfilters 1.5.0 parso 0.8.3 pathspec 0.11.2 pendulum 2.1.2 pexpect 4.8.0 pickleshare 0.7.5 Pillow 10.0.1 Pint 0.18 pip 21.2.4 pkgutil_resolve_name 1.3.10 platformdirs 3.11.0 pluggy 1.3.0 powerline-status 2.7 prometheus-client 0.17.1 prompt-toolkit 3.0.39 psutil 5.9.6 ptyprocess 0.7.0 pure-eval 0.2.2 py-cpuinfo 9.0.0 pyapollos 0.1.5 pycosat 0.6.3 pycparser 2.21 pycryptodome 3.19.0 pydantic 2.5.1 pydantic_core 2.14.3 pygeohash 1.2.0 pygeoif 1.1.1 Pygments 2.16.1 pygrib 2.1.4 pymetaf 0.1.3 pyOpenSSL 23.2.0 pyparsing 3.1.1 pyproj 3.6.1 pyrsistent 0.18.0 pyshp 2.3.1 PySocks 1.7.1 pyterrain 0.0.2 pytest 7.4.4 python-dateutil 2.8.2 python-json-logger 2.0.7 pytz 2023.3.post1 pytzdata 2020.1 PyYAML 6.0.1 pyzmq 25.1.0 qtconsole 5.4.4 QtPy 2.4.0 rasterio 1.3.9 redis 5.0.3 referencing 0.30.2 regex 2023.10.3 requests 2.31.0 requests-cache 1.1.1 retry-requests 2.0.0 retrying 1.3.4 rfc3339-validator 0.1.4 rfc3986-validator 0.1.1 rpds-py 0.10.6 ruamel.yaml 0.17.16 ruamel.yaml.clib 0.2.2 ruamel-yaml-conda 0.15.100 scikit-image 0.22.0 scipy 1.11.3 Send2Trash 1.8.2 setuptools 68.2.2 shapely 2.0.3 six 1.16.0 sniffio 1.3.0 snuggs 1.4.7 soupsieve 2.5 stack-data 0.6.3 starlette 0.27.0 tables 3.7.0 termcolor 2.3.0 terminado 0.17.1 tifffile 2024.2.12 timeout-decorator 0.5.0 tinycss2 1.2.1 toml 0.10.2 tomli 2.0.1 toolz 0.12.0 tornado 6.3.3 tqdm 4.66.1 traitlets 5.11.2 types-python-dateutil 2.8.19.14 typing_extensions 4.8.0 tzdata 2023.3 tzlocal 5.2 uri-template 1.3.0 url-normalize 1.4.3 urllib3 1.26.8 uvicorn 0.24.0.post1 validators 0.22.0 wcwidth 0.2.8 webcolors 1.13 webencodings 0.5.1 websocket-client 1.6.4 wget 3.2 wheel 0.37.1 widgetsnbextension 4.0.9 xarray 2023.10.1 yarl 1.9.4 zipp 3.17.0 zstandard 0.21.0 ```
rcomer commented 5 months ago

Thanks for the report @Clarmy. This looks like it could be the same problem as #2260. Please could you try again with the newly released Cartopy 0.23?

Clarmy commented 5 months ago

@rcomer Thank you for your reply. I just tried upgrading cartopy to version 0.23, and then reran the previous code, but it still produced the same error as before. It seems that my issue is not the same as issue #2260.

Clarmy commented 4 months ago

@rcomer Hello, I have found the root cause of the issue. When using the contourf function to create contour line path data, the polygon object may encounter topological errors. This error might be caused by the presence of overlapping points in the polygon, which could be introduced by matplotlib during the plotting process. Cartopy does not perform the corresponding checks in this case. After debugging, I have found a solution and have submitted a PR: #2373. Please take some time to review and approve it.