Note

This page was generated from gallery/cartopy_convert.ipynb.
Interactive online version: Binder badge

Plotting with CartoPy and GeoPandas#

Converting between GeoPandas and CartoPy for visualizing data.

CartoPy is a Python library that specializes in creating geospatial visualizations. It has a slightly different way of representing Coordinate Reference Systems (CRS) as well as constructing plots. This example steps through a round-trip transfer of data between GeoPandas and CartoPy.

First we’ll load in the data using GeoPandas.

[1]:
import matplotlib.pyplot as plt
import geopandas
from cartopy import crs as ccrs

path = geopandas.datasets.get_path('naturalearth_lowres')
df = geopandas.read_file(path)
# Add a column we'll use later
df['gdp_pp'] = df['gdp_md_est'] / df['pop_est']
ERROR 1: PROJ: proj_create_from_database: Open of /home/docs/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/share/proj failed

First we’ll visualize the map using GeoPandas

[2]:
df.plot()
[2]:
<AxesSubplot: >
../_images/gallery_cartopy_convert_3_1.png

Plotting with CartoPy#

Cartopy also handles Shapely objects well, but it uses a different system for CRS. To plot this data with CartoPy, we’ll first need to project it into a new CRS. We’ll use a CRS defined within CartoPy and use the GeoPandas to_crs method to make the transformation.

[3]:
# Define the CartoPy CRS object.
crs = ccrs.AzimuthalEquidistant()

# This can be converted into a `proj4` string/dict compatible with GeoPandas
crs_proj4 = crs.proj4_init
df_ae = df.to_crs(crs_proj4)

# Here's what the plot looks like in GeoPandas
df_ae.plot()
[3]:
<AxesSubplot: >
../_images/gallery_cartopy_convert_5_1.png

Now that our data is in a CRS based off of CartoPy, we can easily plot it.

[4]:
fig, ax = plt.subplots(subplot_kw={'projection': crs})
ax.add_geometries(df_ae['geometry'], crs=crs)
[4]:
<cartopy.mpl.feature_artist.FeatureArtist at 0x7fad73b5d720>
Error in callback <function _draw_all_if_interactive at 0x7fad85300d30> (for post_execute):
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/pyplot.py:119, in _draw_all_if_interactive()
    117 def _draw_all_if_interactive():
    118     if matplotlib.is_interactive():
--> 119         draw_all()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/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 ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backend_bases.py:2054, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   2052 if not self._is_idle_drawing:
   2053     with self._idle_draw_cntx():
-> 2054         self.draw(*args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backends/backend_agg.py:408, in FigureCanvasAgg.draw(self)
    404 # Acquire a lock on the shared font cache.
    405 with RendererAgg.lock, \
    406      (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
    407       else nullcontext()):
--> 408     self.figure.draw(self.renderer)
    409     # A GUI class may be need to update a window using this draw, so
    410     # don't forget to call the superclass.
    411     super().draw()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:74, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     72 @wraps(draw)
     73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74     result = draw(artist, renderer, *args, **kwargs)
     75     if renderer._rasterizing:
     76         renderer.stop_rasterizing()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/figure.py:3074, in Figure.draw(self, renderer)
   3071         # ValueError can occur when resizing a window.
   3073 self.patch.draw(renderer)
-> 3074 mimage._draw_list_compositing_images(
   3075     renderer, self, artists, self.suppressComposite)
   3077 for sfig in self.subfigs:
   3078     sfig.draw(renderer)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:543, in GeoAxes.draw(self, renderer, **kwargs)
    535 """
    536 Extend the standard behaviour of :func:`matplotlib.axes.Axes.draw`.
    537
   (...)
    540 been set.
    541 """
    542 # Shared processing steps
--> 543 self._draw_preprocess(renderer)
    545 # XXX This interface needs a tidy up:
    546 #       image drawing on pan/zoom;
    547 #       caching the resulting image;
    548 #       buffering the result by 10%...;
    549 if not self._done_img_factory:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:509, in GeoAxes._draw_preprocess(self, renderer)
    506 # If data has been added (i.e. autoscale hasn't been turned off)
    507 # then we should autoscale the view.
    508 if self.get_autoscale_on() and self.ignore_existing_data_limits:
--> 509     self.autoscale_view()
    511 # Adjust location of background patch so that new gridlines below are
    512 # clipped correctly.
    513 self.patch._adjust_location()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:946, in GeoAxes.autoscale_view(self, tight, scalex, scaley)
    943 matplotlib.axes.Axes.autoscale_view(self, tight=tight,
    944                                     scalex=scalex, scaley=scaley)
    945 # Limit the resulting bounds to valid area.
--> 946 if scalex and self._autoscaleXon:
    947     bounds = self.get_xbound()
    948     self.set_xbound(max(bounds[0], self.projection.x_limits[0]),
    949                     min(bounds[1], self.projection.x_limits[1]))

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/IPython/core/formatters.py:339, in BaseFormatter.__call__(self, obj)
    337     pass
    338 else:
--> 339     return printer(obj)
    340 # Finally look for special method names
    341 method = get_real_method(obj, self.print_method)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/IPython/core/pylabtools.py:151, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    148     from matplotlib.backend_bases import FigureCanvasBase
    149     FigureCanvasBase(fig)
--> 151 fig.canvas.print_figure(bytes_io, **kw)
    152 data = bytes_io.getvalue()
    153 if fmt == 'svg':

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backend_bases.py:2314, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2308     renderer = _get_renderer(
   2309         self.figure,
   2310         functools.partial(
   2311             print_method, orientation=orientation)
   2312     )
   2313     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2314         self.figure.draw(renderer)
   2316 if bbox_inches:
   2317     if bbox_inches == "tight":

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:74, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     72 @wraps(draw)
     73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74     result = draw(artist, renderer, *args, **kwargs)
     75     if renderer._rasterizing:
     76         renderer.stop_rasterizing()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/figure.py:3074, in Figure.draw(self, renderer)
   3071         # ValueError can occur when resizing a window.
   3073 self.patch.draw(renderer)
-> 3074 mimage._draw_list_compositing_images(
   3075     renderer, self, artists, self.suppressComposite)
   3077 for sfig in self.subfigs:
   3078     sfig.draw(renderer)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:543, in GeoAxes.draw(self, renderer, **kwargs)
    535 """
    536 Extend the standard behaviour of :func:`matplotlib.axes.Axes.draw`.
    537
   (...)
    540 been set.
    541 """
    542 # Shared processing steps
--> 543 self._draw_preprocess(renderer)
    545 # XXX This interface needs a tidy up:
    546 #       image drawing on pan/zoom;
    547 #       caching the resulting image;
    548 #       buffering the result by 10%...;
    549 if not self._done_img_factory:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:509, in GeoAxes._draw_preprocess(self, renderer)
    506 # If data has been added (i.e. autoscale hasn't been turned off)
    507 # then we should autoscale the view.
    508 if self.get_autoscale_on() and self.ignore_existing_data_limits:
--> 509     self.autoscale_view()
    511 # Adjust location of background patch so that new gridlines below are
    512 # clipped correctly.
    513 self.patch._adjust_location()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:946, in GeoAxes.autoscale_view(self, tight, scalex, scaley)
    943 matplotlib.axes.Axes.autoscale_view(self, tight=tight,
    944                                     scalex=scalex, scaley=scaley)
    945 # Limit the resulting bounds to valid area.
--> 946 if scalex and self._autoscaleXon:
    947     bounds = self.get_xbound()
    948     self.set_xbound(max(bounds[0], self.projection.x_limits[0]),
    949                     min(bounds[1], self.projection.x_limits[1]))

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
<Figure size 640x480 with 1 Axes>

Note that we could have easily done this with an EPSG code like so:

[5]:
crs_epsg = ccrs.epsg('3857')
df_epsg = df.to_crs(epsg='3857')

# Generate a figure with two axes, one for CartoPy, one for GeoPandas
fig, axs = plt.subplots(1, 2, subplot_kw={'projection': crs_epsg},
                        figsize=(10, 5))
# Make the CartoPy plot
axs[0].add_geometries(df_epsg['geometry'], crs=crs_epsg,
                      facecolor='white', edgecolor='black')
# Make the GeoPandas plot
df_epsg.plot(ax=axs[1], color='white', edgecolor='black')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In [5], line 11
      8 axs[0].add_geometries(df_epsg['geometry'], crs=crs_epsg,
      9                       facecolor='white', edgecolor='black')
     10 # Make the GeoPandas plot
---> 11 df_epsg.plot(ax=axs[1], color='white', edgecolor='black')

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/geopandas/plotting.py:968, in GeoplotAccessor.__call__(self, *args, **kwargs)
    966 kind = kwargs.pop("kind", "geo")
    967 if kind == "geo":
--> 968     return plot_dataframe(data, *args, **kwargs)
    969 if kind in self._pandas_kinds:
    970     # Access pandas plots
    971     return PlotAccessor(data)(kind=kind, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/geopandas/plotting.py:704, in plot_dataframe(df, column, cmap, color, ax, cax, categorical, legend, scheme, k, vmin, vmax, markersize, figsize, legend_kwds, categories, classification_kwds, missing_kwds, aspect, **style_kwds)
    701     markersize = df[markersize].values
    703 if column is None:
--> 704     return plot_series(
    705         df.geometry,
    706         cmap=cmap,
    707         color=color,
    708         ax=ax,
    709         figsize=figsize,
    710         markersize=markersize,
    711         aspect=aspect,
    712         **style_kwds,
    713     )
    715 # To accept pd.Series and np.arrays as column
    716 if isinstance(column, (np.ndarray, pd.Series)):

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/geopandas/plotting.py:458, in plot_series(s, cmap, color, ax, figsize, aspect, **style_kwds)
    455         facecolor = color_
    457     values_ = values[poly_idx] if cmap else None
--> 458     _plot_polygon_collection(
    459         ax, polys, values_, facecolor=facecolor, cmap=cmap, **style_kwds
    460     )
    462 # plot all LineStrings and MultiLineString components in same collection
    463 lines = expl_series[line_idx]

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/geopandas/plotting.py:185, in _plot_polygon_collection(ax, geoms, values, color, cmap, vmin, vmax, **kwargs)
    182         collection.set_clim(vmin, vmax)
    184 ax.add_collection(collection, autolim=True)
--> 185 ax.autoscale_view()
    186 return collection

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:946, in GeoAxes.autoscale_view(self, tight, scalex, scaley)
    943 matplotlib.axes.Axes.autoscale_view(self, tight=tight,
    944                                     scalex=scalex, scaley=scaley)
    945 # Limit the resulting bounds to valid area.
--> 946 if scalex and self._autoscaleXon:
    947     bounds = self.get_xbound()
    948     self.set_xbound(max(bounds[0], self.projection.x_limits[0]),
    949                     min(bounds[1], self.projection.x_limits[1]))

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
Error in callback <function _draw_all_if_interactive at 0x7fad85300d30> (for post_execute):
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/pyplot.py:119, in _draw_all_if_interactive()
    117 def _draw_all_if_interactive():
    118     if matplotlib.is_interactive():
--> 119         draw_all()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/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 ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backend_bases.py:2054, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   2052 if not self._is_idle_drawing:
   2053     with self._idle_draw_cntx():
-> 2054         self.draw(*args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backends/backend_agg.py:408, in FigureCanvasAgg.draw(self)
    404 # Acquire a lock on the shared font cache.
    405 with RendererAgg.lock, \
    406      (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
    407       else nullcontext()):
--> 408     self.figure.draw(self.renderer)
    409     # A GUI class may be need to update a window using this draw, so
    410     # don't forget to call the superclass.
    411     super().draw()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:74, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     72 @wraps(draw)
     73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74     result = draw(artist, renderer, *args, **kwargs)
     75     if renderer._rasterizing:
     76         renderer.stop_rasterizing()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/figure.py:3074, in Figure.draw(self, renderer)
   3071         # ValueError can occur when resizing a window.
   3073 self.patch.draw(renderer)
-> 3074 mimage._draw_list_compositing_images(
   3075     renderer, self, artists, self.suppressComposite)
   3077 for sfig in self.subfigs:
   3078     sfig.draw(renderer)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:543, in GeoAxes.draw(self, renderer, **kwargs)
    535 """
    536 Extend the standard behaviour of :func:`matplotlib.axes.Axes.draw`.
    537
   (...)
    540 been set.
    541 """
    542 # Shared processing steps
--> 543 self._draw_preprocess(renderer)
    545 # XXX This interface needs a tidy up:
    546 #       image drawing on pan/zoom;
    547 #       caching the resulting image;
    548 #       buffering the result by 10%...;
    549 if not self._done_img_factory:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:509, in GeoAxes._draw_preprocess(self, renderer)
    506 # If data has been added (i.e. autoscale hasn't been turned off)
    507 # then we should autoscale the view.
    508 if self.get_autoscale_on() and self.ignore_existing_data_limits:
--> 509     self.autoscale_view()
    511 # Adjust location of background patch so that new gridlines below are
    512 # clipped correctly.
    513 self.patch._adjust_location()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:946, in GeoAxes.autoscale_view(self, tight, scalex, scaley)
    943 matplotlib.axes.Axes.autoscale_view(self, tight=tight,
    944                                     scalex=scalex, scaley=scaley)
    945 # Limit the resulting bounds to valid area.
--> 946 if scalex and self._autoscaleXon:
    947     bounds = self.get_xbound()
    948     self.set_xbound(max(bounds[0], self.projection.x_limits[0]),
    949                     min(bounds[1], self.projection.x_limits[1]))

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/IPython/core/formatters.py:339, in BaseFormatter.__call__(self, obj)
    337     pass
    338 else:
--> 339     return printer(obj)
    340 # Finally look for special method names
    341 method = get_real_method(obj, self.print_method)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/IPython/core/pylabtools.py:151, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    148     from matplotlib.backend_bases import FigureCanvasBase
    149     FigureCanvasBase(fig)
--> 151 fig.canvas.print_figure(bytes_io, **kw)
    152 data = bytes_io.getvalue()
    153 if fmt == 'svg':

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backend_bases.py:2314, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2308     renderer = _get_renderer(
   2309         self.figure,
   2310         functools.partial(
   2311             print_method, orientation=orientation)
   2312     )
   2313     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2314         self.figure.draw(renderer)
   2316 if bbox_inches:
   2317     if bbox_inches == "tight":

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:74, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     72 @wraps(draw)
     73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74     result = draw(artist, renderer, *args, **kwargs)
     75     if renderer._rasterizing:
     76         renderer.stop_rasterizing()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/figure.py:3074, in Figure.draw(self, renderer)
   3071         # ValueError can occur when resizing a window.
   3073 self.patch.draw(renderer)
-> 3074 mimage._draw_list_compositing_images(
   3075     renderer, self, artists, self.suppressComposite)
   3077 for sfig in self.subfigs:
   3078     sfig.draw(renderer)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:543, in GeoAxes.draw(self, renderer, **kwargs)
    535 """
    536 Extend the standard behaviour of :func:`matplotlib.axes.Axes.draw`.
    537
   (...)
    540 been set.
    541 """
    542 # Shared processing steps
--> 543 self._draw_preprocess(renderer)
    545 # XXX This interface needs a tidy up:
    546 #       image drawing on pan/zoom;
    547 #       caching the resulting image;
    548 #       buffering the result by 10%...;
    549 if not self._done_img_factory:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:509, in GeoAxes._draw_preprocess(self, renderer)
    506 # If data has been added (i.e. autoscale hasn't been turned off)
    507 # then we should autoscale the view.
    508 if self.get_autoscale_on() and self.ignore_existing_data_limits:
--> 509     self.autoscale_view()
    511 # Adjust location of background patch so that new gridlines below are
    512 # clipped correctly.
    513 self.patch._adjust_location()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:946, in GeoAxes.autoscale_view(self, tight, scalex, scaley)
    943 matplotlib.axes.Axes.autoscale_view(self, tight=tight,
    944                                     scalex=scalex, scaley=scaley)
    945 # Limit the resulting bounds to valid area.
--> 946 if scalex and self._autoscaleXon:
    947     bounds = self.get_xbound()
    948     self.set_xbound(max(bounds[0], self.projection.x_limits[0]),
    949                     min(bounds[1], self.projection.x_limits[1]))

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
<Figure size 1000x500 with 2 Axes>

CartoPy to GeoPandas#

Next we’ll perform a CRS projection in CartoPy, and then convert it back into a GeoPandas object.

[6]:
crs_new = ccrs.AlbersEqualArea()
new_geometries = [crs_new.project_geometry(ii, src_crs=crs)
                  for ii in df_ae['geometry'].values]

fig, ax = plt.subplots(subplot_kw={'projection': crs_new})
ax.add_geometries(new_geometries, crs=crs_new)
[6]:
<cartopy.mpl.feature_artist.FeatureArtist at 0x7fad69e409d0>
Error in callback <function _draw_all_if_interactive at 0x7fad85300d30> (for post_execute):
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/pyplot.py:119, in _draw_all_if_interactive()
    117 def _draw_all_if_interactive():
    118     if matplotlib.is_interactive():
--> 119         draw_all()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/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 ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backend_bases.py:2054, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   2052 if not self._is_idle_drawing:
   2053     with self._idle_draw_cntx():
-> 2054         self.draw(*args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backends/backend_agg.py:408, in FigureCanvasAgg.draw(self)
    404 # Acquire a lock on the shared font cache.
    405 with RendererAgg.lock, \
    406      (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
    407       else nullcontext()):
--> 408     self.figure.draw(self.renderer)
    409     # A GUI class may be need to update a window using this draw, so
    410     # don't forget to call the superclass.
    411     super().draw()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:74, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     72 @wraps(draw)
     73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74     result = draw(artist, renderer, *args, **kwargs)
     75     if renderer._rasterizing:
     76         renderer.stop_rasterizing()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/figure.py:3074, in Figure.draw(self, renderer)
   3071         # ValueError can occur when resizing a window.
   3073 self.patch.draw(renderer)
-> 3074 mimage._draw_list_compositing_images(
   3075     renderer, self, artists, self.suppressComposite)
   3077 for sfig in self.subfigs:
   3078     sfig.draw(renderer)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:543, in GeoAxes.draw(self, renderer, **kwargs)
    535 """
    536 Extend the standard behaviour of :func:`matplotlib.axes.Axes.draw`.
    537
   (...)
    540 been set.
    541 """
    542 # Shared processing steps
--> 543 self._draw_preprocess(renderer)
    545 # XXX This interface needs a tidy up:
    546 #       image drawing on pan/zoom;
    547 #       caching the resulting image;
    548 #       buffering the result by 10%...;
    549 if not self._done_img_factory:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:509, in GeoAxes._draw_preprocess(self, renderer)
    506 # If data has been added (i.e. autoscale hasn't been turned off)
    507 # then we should autoscale the view.
    508 if self.get_autoscale_on() and self.ignore_existing_data_limits:
--> 509     self.autoscale_view()
    511 # Adjust location of background patch so that new gridlines below are
    512 # clipped correctly.
    513 self.patch._adjust_location()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:946, in GeoAxes.autoscale_view(self, tight, scalex, scaley)
    943 matplotlib.axes.Axes.autoscale_view(self, tight=tight,
    944                                     scalex=scalex, scaley=scaley)
    945 # Limit the resulting bounds to valid area.
--> 946 if scalex and self._autoscaleXon:
    947     bounds = self.get_xbound()
    948     self.set_xbound(max(bounds[0], self.projection.x_limits[0]),
    949                     min(bounds[1], self.projection.x_limits[1]))

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/IPython/core/formatters.py:339, in BaseFormatter.__call__(self, obj)
    337     pass
    338 else:
--> 339     return printer(obj)
    340 # Finally look for special method names
    341 method = get_real_method(obj, self.print_method)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/IPython/core/pylabtools.py:151, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    148     from matplotlib.backend_bases import FigureCanvasBase
    149     FigureCanvasBase(fig)
--> 151 fig.canvas.print_figure(bytes_io, **kw)
    152 data = bytes_io.getvalue()
    153 if fmt == 'svg':

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backend_bases.py:2314, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2308     renderer = _get_renderer(
   2309         self.figure,
   2310         functools.partial(
   2311             print_method, orientation=orientation)
   2312     )
   2313     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2314         self.figure.draw(renderer)
   2316 if bbox_inches:
   2317     if bbox_inches == "tight":

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:74, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     72 @wraps(draw)
     73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74     result = draw(artist, renderer, *args, **kwargs)
     75     if renderer._rasterizing:
     76         renderer.stop_rasterizing()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/figure.py:3074, in Figure.draw(self, renderer)
   3071         # ValueError can occur when resizing a window.
   3073 self.patch.draw(renderer)
-> 3074 mimage._draw_list_compositing_images(
   3075     renderer, self, artists, self.suppressComposite)
   3077 for sfig in self.subfigs:
   3078     sfig.draw(renderer)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:543, in GeoAxes.draw(self, renderer, **kwargs)
    535 """
    536 Extend the standard behaviour of :func:`matplotlib.axes.Axes.draw`.
    537
   (...)
    540 been set.
    541 """
    542 # Shared processing steps
--> 543 self._draw_preprocess(renderer)
    545 # XXX This interface needs a tidy up:
    546 #       image drawing on pan/zoom;
    547 #       caching the resulting image;
    548 #       buffering the result by 10%...;
    549 if not self._done_img_factory:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:509, in GeoAxes._draw_preprocess(self, renderer)
    506 # If data has been added (i.e. autoscale hasn't been turned off)
    507 # then we should autoscale the view.
    508 if self.get_autoscale_on() and self.ignore_existing_data_limits:
--> 509     self.autoscale_view()
    511 # Adjust location of background patch so that new gridlines below are
    512 # clipped correctly.
    513 self.patch._adjust_location()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:946, in GeoAxes.autoscale_view(self, tight, scalex, scaley)
    943 matplotlib.axes.Axes.autoscale_view(self, tight=tight,
    944                                     scalex=scalex, scaley=scaley)
    945 # Limit the resulting bounds to valid area.
--> 946 if scalex and self._autoscaleXon:
    947     bounds = self.get_xbound()
    948     self.set_xbound(max(bounds[0], self.projection.x_limits[0]),
    949                     min(bounds[1], self.projection.x_limits[1]))

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
<Figure size 640x480 with 1 Axes>

Now that we’ve created new Shapely objects with the CartoPy CRS, we can use this to create a GeoDataFrame.

[7]:
df_aea = geopandas.GeoDataFrame(df['gdp_pp'], geometry=new_geometries,
                                crs=crs_new.proj4_init)
df_aea.plot()
[7]:
<AxesSubplot: >
../_images/gallery_cartopy_convert_13_1.png

We can even combine these into the same figure. Here we’ll plot the shapes of the countries with CartoPy. We’ll then calculate the centroid of each with GeoPandas and plot it on top.

[8]:
# Generate a CartoPy figure and add the countries to it
fig, ax = plt.subplots(subplot_kw={'projection': crs_new})
ax.add_geometries(new_geometries, crs=crs_new)

# Calculate centroids and plot
df_aea_centroids = df_aea.geometry.centroid
# Need to provide "zorder" to ensure the points are plotted above the polygons
df_aea_centroids.plot(ax=ax, markersize=5, color='r', zorder=10)

plt.show()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In [8], line 8
      6 df_aea_centroids = df_aea.geometry.centroid
      7 # Need to provide "zorder" to ensure the points are plotted above the polygons
----> 8 df_aea_centroids.plot(ax=ax, markersize=5, color='r', zorder=10)
     10 plt.show()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/geopandas/geoseries.py:809, in GeoSeries.plot(self, *args, **kwargs)
    807 @doc(plot_series)
    808 def plot(self, *args, **kwargs):
--> 809     return plot_series(self, *args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/geopandas/plotting.py:478, in plot_series(s, cmap, color, ax, figsize, aspect, **style_kwds)
    475     values_ = values[point_idx] if cmap else None
    476     color_ = expl_color[point_idx] if color_given else color
--> 478     _plot_point_collection(
    479         ax, points, values_, color=color_, cmap=cmap, **style_kwds
    480     )
    482 plt.draw()
    483 return ax

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/geopandas/plotting.py:306, in _plot_point_collection(ax, geoms, values, color, cmap, vmin, vmax, marker, markersize, **kwargs)
    303 _expand_kwargs(kwargs, multiindex)
    305 if "norm" not in kwargs:
--> 306     collection = ax.scatter(x, y, vmin=vmin, vmax=vmax, cmap=cmap, **kwargs)
    307 else:
    308     collection = ax.scatter(x, y, cmap=cmap, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:318, in _add_transform.<locals>.wrapper(self, *args, **kwargs)
    313     raise ValueError(f'Invalid transform: Spherical {func.__name__} '
    314                      'is not supported - consider using '
    315                      'PlateCarree/RotatedPole.')
    317 kwargs['transform'] = transform
--> 318 return func(self, *args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:1753, in GeoAxes.scatter(self, *args, **kwargs)
   1747     raise ValueError('Cartopy cannot currently do spherical '
   1748                      'scatter. The source CRS cannot be a '
   1749                      'geodetic, consider using the cyllindrical form '
   1750                      '(PlateCarree or RotatedPole).')
   1752 result = matplotlib.axes.Axes.scatter(self, *args, **kwargs)
-> 1753 self.autoscale_view()
   1754 return result

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:943, in GeoAxes.autoscale_view(self, tight, scalex, scaley)
    936 def autoscale_view(self, tight=None, scalex=True, scaley=True):
    937     """
    938     Autoscale the view limits using the data limits, taking into
    939     account the projection of the geoaxes.
    940
    941     See :meth:`~matplotlib.axes.Axes.imshow()` for more details.
    942     """
--> 943     matplotlib.axes.Axes.autoscale_view(self, tight=tight,
    944                                         scalex=scalex, scaley=scaley)
    945     # Limit the resulting bounds to valid area.
    946     if scalex and self._autoscaleXon:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/axes/_base.py:2973, in _AxesBase.autoscale_view(self, tight, scalex, scaley)
   2970     set_bound(x0, x1)
   2971     # End of definition of internal function 'handle_single_axis'.
-> 2973 handle_single_axis(
   2974     scalex, self._shared_axes["x"], 'x', self.xaxis, self._xmargin,
   2975     x_stickies, self.set_xbound)
   2976 handle_single_axis(
   2977     scaley, self._shared_axes["y"], 'y', self.yaxis, self._ymargin,
   2978     y_stickies, self.set_ybound)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/axes/_base.py:2970, in _AxesBase.autoscale_view.<locals>.handle_single_axis(scale, shared_axes, name, axis, margin, stickies, set_bound)
   2968 if not self._tight:
   2969     x0, x1 = locator.view_limits(x0, x1)
-> 2970 set_bound(x0, x1)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/axes/_base.py:3567, in _AxesBase.set_xbound(self, lower, upper)
   3564 if upper is None and np.iterable(lower):
   3565     lower, upper = lower
-> 3567 old_lower, old_upper = self.get_xbound()
   3568 if lower is None:
   3569     lower = old_lower

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/axes/_base.py:3539, in _AxesBase.get_xbound(self)
   3529 def get_xbound(self):
   3530     """
   3531     Return the lower and upper x-axis bounds, in increasing order.
   3532
   (...)
   3537     invert_xaxis, xaxis_inverted
   3538     """
-> 3539     left, right = self.get_xlim()
   3540     if left < right:
   3541         return left, right

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/axes/_base.py:3597, in _AxesBase.get_xlim(self)
   3577 def get_xlim(self):
   3578     """
   3579     Return the x-axis view limits.
   3580
   (...)
   3595     be greater than the *right* value.
   3596     """
-> 3597     return tuple(self.viewLim.intervalx)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/axes/_base.py:815, in _AxesBase.viewLim(self)
    813 @property
    814 def viewLim(self):
--> 815     self._unstale_viewLim()
    816     return self._viewLim

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/axes/_base.py:810, in _AxesBase._unstale_viewLim(self)
    808     for ax in self._shared_axes[name].get_siblings(self):
    809         ax._stale_viewlims[name] = False
--> 810 self.autoscale_view(**{f"scale{name}": scale
    811                        for name, scale in need_scale.items()})

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:946, in GeoAxes.autoscale_view(self, tight, scalex, scaley)
    943 matplotlib.axes.Axes.autoscale_view(self, tight=tight,
    944                                     scalex=scalex, scaley=scaley)
    945 # Limit the resulting bounds to valid area.
--> 946 if scalex and self._autoscaleXon:
    947     bounds = self.get_xbound()
    948     self.set_xbound(max(bounds[0], self.projection.x_limits[0]),
    949                     min(bounds[1], self.projection.x_limits[1]))

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
Error in callback <function _draw_all_if_interactive at 0x7fad85300d30> (for post_execute):
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/pyplot.py:119, in _draw_all_if_interactive()
    117 def _draw_all_if_interactive():
    118     if matplotlib.is_interactive():
--> 119         draw_all()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/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 ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backend_bases.py:2054, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
   2052 if not self._is_idle_drawing:
   2053     with self._idle_draw_cntx():
-> 2054         self.draw(*args, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backends/backend_agg.py:408, in FigureCanvasAgg.draw(self)
    404 # Acquire a lock on the shared font cache.
    405 with RendererAgg.lock, \
    406      (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
    407       else nullcontext()):
--> 408     self.figure.draw(self.renderer)
    409     # A GUI class may be need to update a window using this draw, so
    410     # don't forget to call the superclass.
    411     super().draw()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:74, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     72 @wraps(draw)
     73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74     result = draw(artist, renderer, *args, **kwargs)
     75     if renderer._rasterizing:
     76         renderer.stop_rasterizing()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/figure.py:3074, in Figure.draw(self, renderer)
   3071         # ValueError can occur when resizing a window.
   3073 self.patch.draw(renderer)
-> 3074 mimage._draw_list_compositing_images(
   3075     renderer, self, artists, self.suppressComposite)
   3077 for sfig in self.subfigs:
   3078     sfig.draw(renderer)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:558, in GeoAxes.draw(self, renderer, **kwargs)
    553         self.imshow(img, extent=extent, origin=origin,
    554                     transform=factory.crs, *factory_args[1:],
    555                     **factory_kwargs)
    556 self._done_img_factory = True
--> 558 return matplotlib.axes.Axes.draw(self, renderer=renderer, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/axes/_base.py:3107, in _AxesBase.draw(self, renderer)
   3104         a.draw(renderer)
   3105     renderer.stop_rasterizing()
-> 3107 mimage._draw_list_compositing_images(
   3108     renderer, self, artists, self.figure.suppressComposite)
   3110 renderer.close_group('axes')
   3111 self.stale = False

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/feature_artist.py:147, in FeatureArtist.draw(self, renderer, *args, **kwargs)
    145 extent = None
    146 try:
--> 147     extent = ax.get_extent(feature_crs)
    148 except ValueError:
    149     warnings.warn('Unable to determine extent. Defaulting to global.')

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:814, in GeoAxes.get_extent(self, crs)
    805 def get_extent(self, crs=None):
    806     """
    807     Get the extent (x0, x1, y0, y1) of the map in the given coordinate
    808     system.
   (...)
    812
    813     """
--> 814     p = self._get_extent_geom(crs)
    815     r = p.bounds
    816     x1, y1, x2, y2 = r

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:821, in GeoAxes._get_extent_geom(self, crs)
    819 def _get_extent_geom(self, crs=None):
    820     # Perform the calculations for get_extent(), which just repackages it.
--> 821     with self.hold_limits():
    822         if self.get_autoscale_on():
    823             self.autoscale_view()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/contextlib.py:135, in _GeneratorContextManager.__enter__(self)
    133 del self.args, self.kwds, self.func
    134 try:
--> 135     return next(self.gen)
    136 except StopIteration:
    137     raise RuntimeError("generator didn't yield") from None

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:491, in GeoAxes.hold_limits(self, hold)
    488 data_lim = self.dataLim.frozen().get_points()
    489 view_lim = self.viewLim.frozen().get_points()
    490 other = (self.ignore_existing_data_limits,
--> 491          self._autoscaleXon, self._autoscaleYon)
    492 try:
    493     yield

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/IPython/core/formatters.py:339, in BaseFormatter.__call__(self, obj)
    337     pass
    338 else:
--> 339     return printer(obj)
    340 # Finally look for special method names
    341 method = get_real_method(obj, self.print_method)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/IPython/core/pylabtools.py:151, in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    148     from matplotlib.backend_bases import FigureCanvasBase
    149     FigureCanvasBase(fig)
--> 151 fig.canvas.print_figure(bytes_io, **kw)
    152 data = bytes_io.getvalue()
    153 if fmt == 'svg':

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/backend_bases.py:2314, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2308     renderer = _get_renderer(
   2309         self.figure,
   2310         functools.partial(
   2311             print_method, orientation=orientation)
   2312     )
   2313     with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2314         self.figure.draw(renderer)
   2316 if bbox_inches:
   2317     if bbox_inches == "tight":

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:74, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
     72 @wraps(draw)
     73 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 74     result = draw(artist, renderer, *args, **kwargs)
     75     if renderer._rasterizing:
     76         renderer.stop_rasterizing()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/figure.py:3074, in Figure.draw(self, renderer)
   3071         # ValueError can occur when resizing a window.
   3073 self.patch.draw(renderer)
-> 3074 mimage._draw_list_compositing_images(
   3075     renderer, self, artists, self.suppressComposite)
   3077 for sfig in self.subfigs:
   3078     sfig.draw(renderer)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:558, in GeoAxes.draw(self, renderer, **kwargs)
    553         self.imshow(img, extent=extent, origin=origin,
    554                     transform=factory.crs, *factory_args[1:],
    555                     **factory_kwargs)
    556 self._done_img_factory = True
--> 558 return matplotlib.axes.Axes.draw(self, renderer=renderer, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/axes/_base.py:3107, in _AxesBase.draw(self, renderer)
   3104         a.draw(renderer)
   3105     renderer.stop_rasterizing()
-> 3107 mimage._draw_list_compositing_images(
   3108     renderer, self, artists, self.figure.suppressComposite)
   3110 renderer.close_group('axes')
   3111 self.stale = False

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/image.py:131, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    129 if not_composite or not has_images:
    130     for a in artists:
--> 131         a.draw(renderer)
    132 else:
    133     # Composite any adjacent images together
    134     image_group = []

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/matplotlib/artist.py:51, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
     48     if artist.get_agg_filter() is not None:
     49         renderer.start_filter()
---> 51     return draw(artist, renderer)
     52 finally:
     53     if artist.get_agg_filter() is not None:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/feature_artist.py:147, in FeatureArtist.draw(self, renderer, *args, **kwargs)
    145 extent = None
    146 try:
--> 147     extent = ax.get_extent(feature_crs)
    148 except ValueError:
    149     warnings.warn('Unable to determine extent. Defaulting to global.')

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:814, in GeoAxes.get_extent(self, crs)
    805 def get_extent(self, crs=None):
    806     """
    807     Get the extent (x0, x1, y0, y1) of the map in the given coordinate
    808     system.
   (...)
    812
    813     """
--> 814     p = self._get_extent_geom(crs)
    815     r = p.bounds
    816     x1, y1, x2, y2 = r

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:821, in GeoAxes._get_extent_geom(self, crs)
    819 def _get_extent_geom(self, crs=None):
    820     # Perform the calculations for get_extent(), which just repackages it.
--> 821     with self.hold_limits():
    822         if self.get_autoscale_on():
    823             self.autoscale_view()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/contextlib.py:135, in _GeneratorContextManager.__enter__(self)
    133 del self.args, self.kwds, self.func
    134 try:
--> 135     return next(self.gen)
    136 except StopIteration:
    137     raise RuntimeError("generator didn't yield") from None

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.12.0/lib/python3.10/site-packages/cartopy/mpl/geoaxes.py:491, in GeoAxes.hold_limits(self, hold)
    488 data_lim = self.dataLim.frozen().get_points()
    489 view_lim = self.viewLim.frozen().get_points()
    490 other = (self.ignore_existing_data_limits,
--> 491          self._autoscaleXon, self._autoscaleYon)
    492 try:
    493     yield

AttributeError: 'GeoAxesSubplot' object has no attribute '_autoscaleXon'
<Figure size 640x480 with 1 Axes>