Repository: geopandas/geopandas
Pull request #2827 (2023-03-08 15:01:37)

ENH: add minimum_bounding_radius as GeoSeries method


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f755ca98..91fc182b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ New features and improvements:
   the distance along the Hilbert curve (#2070).
 - Added ``minimum_bounding_circle()`` method from shapely to GeoSeries/GeoDataframe (#2621).
 - Support specifying ``min_zoom`` and ``max_zoom`` inside the ``map_kwds`` argument for ``.explore()`` (#2599).
+- Added `minimum_bounding_radius()` as GeoSeries method (#2827).
 
 Deprecations and compatibility notes:
 
diff --git a/benchmarks/sindex.py b/benchmarks/sindex.py
index 0510f035..0767bb1f 100644
--- a/benchmarks/sindex.py
+++ b/benchmarks/sindex.py
@@ -27,7 +27,7 @@ def generate_test_df():
     }
     # ensure index is pre-generated
     for data_type in data.keys():
-        data[data_type].sindex.query(data[data_type].geometry.values.data[0])
+        data[data_type].sindex.query(data[data_type].geometry.values[0])
     return data
 
 
@@ -75,7 +75,7 @@ class BenchIndexCreation:
         tree = self.data[tree_geom_type].sindex
         # also do a single query to ensure the index is actually
         # generated and used
-        tree.query(self.data[tree_geom_type].geometry.values.data[0])
+        tree.query(self.data[tree_geom_type].geometry.values[0])
 
 
 class BenchQuery:
@@ -91,11 +91,11 @@ class BenchQuery:
 
     def time_query_bulk(self, predicate, input_geom_type, tree_geom_type):
         self.data[tree_geom_type].sindex.query_bulk(
-            self.data[input_geom_type].geometry.values.data,
+            self.data[input_geom_type].geometry.values,
             predicate=predicate,
         )
 
     def time_query(self, predicate, input_geom_type, tree_geom_type):
         tree = self.data[tree_geom_type].sindex
-        for geom in self.data[input_geom_type].geometry.values.data:
+        for geom in self.data[input_geom_type].geometry.values:
             tree.query(geom, predicate=predicate)
diff --git a/doc/source/docs/reference/geoseries.rst b/doc/source/docs/reference/geoseries.rst
index 465c040e..253aa810 100644
--- a/doc/source/docs/reference/geoseries.rst
+++ b/doc/source/docs/reference/geoseries.rst
@@ -26,6 +26,7 @@ General methods and attributes
    GeoSeries.representative_point
    GeoSeries.exterior
    GeoSeries.interiors
+   GeoSeries.minimum_bounding_radius
    GeoSeries.x
    GeoSeries.y
    GeoSeries.z
diff --git a/doc/source/gallery/cartopy_convert.ipynb b/doc/source/gallery/cartopy_convert.ipynb
index c749933a..bb9c415a 100644
--- a/doc/source/gallery/cartopy_convert.ipynb
+++ b/doc/source/gallery/cartopy_convert.ipynb
@@ -28,11 +28,10 @@
     "import matplotlib.pyplot as plt\n",
     "import geopandas\n",
     "from cartopy import crs as ccrs\n",
+    "from geodatasets import get_path\n",
     "\n",
-    "path = geopandas.datasets.get_path(\"naturalearth_lowres\")\n",
-    "df = geopandas.read_file(path)\n",
-    "# Add a column we'll use later\n",
-    "df[\"gdp_pp\"] = df[\"gdp_md_est\"] / df[\"pop_est\"]"
+    "path = get_path(\"naturalearth.land\")\n",
+    "df = geopandas.read_file(path)"
    ]
   },
   {
@@ -172,7 +171,7 @@
    "outputs": [],
    "source": [
     "df_aea = geopandas.GeoDataFrame(\n",
-    "    df[\"gdp_pp\"], geometry=new_geometries, crs=crs_new.proj4_init\n",
+    "    df.drop(columns=\"geometry\"), geometry=new_geometries, crs=crs_new.proj4_init\n",
     ")\n",
     "df_aea.plot()"
    ]
@@ -226,7 +225,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.1"
+   "version": "3.11.0"
   }
  },
  "nbformat": 4,
diff --git a/doc/source/gallery/create_geopandas_from_pandas.ipynb b/doc/source/gallery/create_geopandas_from_pandas.ipynb
index e1320cc4..4907e276 100644
--- a/doc/source/gallery/create_geopandas_from_pandas.ipynb
+++ b/doc/source/gallery/create_geopandas_from_pandas.ipynb
@@ -22,7 +22,8 @@
    "source": [
     "import pandas as pd\n",
     "import geopandas\n",
-    "import matplotlib.pyplot as plt"
+    "import matplotlib.pyplot as plt\n",
+    "from geodatasets import get_path"
    ]
   },
   {
@@ -111,10 +112,10 @@
    },
    "outputs": [],
    "source": [
-    "world = geopandas.read_file(geopandas.datasets.get_path(\"naturalearth_lowres\"))\n",
+    "world = geopandas.read_file(get_path(\"naturalearth.land\"))\n",
     "\n",
     "# We restrict to South America.\n",
-    "ax = world[world.continent == \"South America\"].plot(color=\"white\", edgecolor=\"black\")\n",
+    "ax = world.clip([-90, -55, -25, 15]).plot(color=\"white\", edgecolor=\"black\")\n",
     "\n",
     "# We can now plot our ``GeoDataFrame``.\n",
     "gdf.plot(ax=ax, color=\"red\")\n",
@@ -205,7 +206,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "ax = world[world.continent == \"South America\"].plot(color=\"white\", edgecolor=\"black\")\n",
+    "ax = world.clip([-90, -55, -25, 15]).plot(color=\"white\", edgecolor=\"black\")\n",
     "\n",
     "gdf.plot(ax=ax, color=\"red\")\n",
     "\n",
@@ -229,7 +230,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.1"
+   "version": "3.11.0"
   }
  },
  "nbformat": 4,
diff --git a/doc/source/gallery/matplotlib_scalebar.ipynb b/doc/source/gallery/matplotlib_scalebar.ipynb
index f193f3c5..ee37fce5 100644
--- a/doc/source/gallery/matplotlib_scalebar.ipynb
+++ b/doc/source/gallery/matplotlib_scalebar.ipynb
@@ -15,7 +15,8 @@
    "outputs": [],
    "source": [
     "import geopandas as gpd\n",
-    "from matplotlib_scalebar.scalebar import ScaleBar"
+    "from matplotlib_scalebar.scalebar import ScaleBar\n",
+    "from geodatasets import get_path"
    ]
   },
   {
@@ -39,7 +40,7 @@
    },
    "outputs": [],
    "source": [
-    "nybb = gpd.read_file(gpd.datasets.get_path(\"nybb\"))\n",
+    "nybb = gpd.read_file(get_path(\"nybb\"))\n",
     "nybb = nybb.to_crs(32619)  # Convert the dataset to a coordinate\n",
     "# system which uses meters\n",
     "\n",
@@ -220,7 +221,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.2"
+   "version": "3.11.0"
   }
  },
  "nbformat": 4,
diff --git a/doc/source/gallery/overlays.ipynb b/doc/source/gallery/overlays.ipynb
index b4d41a2d..d0791d1b 100644
--- a/doc/source/gallery/overlays.ipynb
+++ b/doc/source/gallery/overlays.ipynb
@@ -2,6 +2,7 @@
  "cells": [
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "# Overlays\n",
     "\n",
@@ -15,27 +16,29 @@
     "not on individual geometries, and the properties from both are retained\n",
     "\n",
     "![illustration](http://docs.qgis.org/testing/en/_images/overlay_operations.png)"
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "Now we can load up two GeoDataFrames containing (multi)polygon geometries..."
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "%matplotlib inline\n",
     "from shapely.geometry import Point\n",
-    "from geopandas import datasets, GeoDataFrame, read_file\n",
+    "from geopandas import GeoDataFrame, read_file\n",
     "from geopandas.tools import overlay\n",
+    "from geodatasets import get_path\n",
     "\n",
     "# NYC Boros\n",
-    "zippath = datasets.get_path(\"nybb\")\n",
+    "zippath = get_path(\"nybb\")\n",
     "polydf = read_file(zippath)\n",
     "\n",
     "# Generate some circles\n",
@@ -50,44 +53,43 @@
     "        )\n",
     "    ]\n",
     ")"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "The first dataframe contains multipolygons of the NYC boros"
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "polydf.plot()"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "And the second GeoDataFrame is a sequentially generated set of circles in the same geographic space. We'll plot these with a [different color palette](https://matplotlib.org/examples/color/colormaps_reference.html)."
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "polydf2.plot(cmap=\"tab20b\")"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "The `geopandas.tools.overlay` function takes three arguments:\n",
     "\n",
@@ -104,103 +106,102 @@
     "    'difference']\n",
     "\n",
     "So let's identify the areas (and attributes) where both dataframes intersect using the `overlay` method. "
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "newdf = polydf.overlay(polydf2, how=\"intersection\")\n",
     "newdf.plot(cmap=\"tab20b\")"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "And take a look at the attributes; we see that the attributes from both of the original GeoDataFrames are retained. "
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "polydf.head()"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "polydf2.head()"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "newdf.head()"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "Now let's look at the other `how` operations:"
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "newdf = polydf.overlay(polydf2, how=\"union\")\n",
     "newdf.plot(cmap=\"tab20b\")"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "newdf = polydf.overlay(polydf2, how=\"identity\")\n",
     "newdf.plot(cmap=\"tab20b\")"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "source": [
-    "newdf = polydf.overlay(polydf2, how=\"symmetric_difference\")\n",
-    "newdf.plot(cmap=\"tab20b\")"
-   ],
-   "outputs": [],
    "metadata": {
     "tags": [
      "nbsphinx-thumbnail"
     ]
-   }
+   },
+   "outputs": [],
+   "source": [
+    "newdf = polydf.overlay(polydf2, how=\"symmetric_difference\")\n",
+    "newdf.plot(cmap=\"tab20b\")"
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "newdf = polydf.overlay(polydf2, how=\"difference\")\n",
     "newdf.plot(cmap=\"tab20b\")"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   }
  ],
  "metadata": {
@@ -219,9 +220,9 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.2"
+   "version": "3.11.0"
   }
  },
  "nbformat": 4,
  "nbformat_minor": 4
-}
\ No newline at end of file
+}
diff --git a/doc/source/gallery/plot_clip.ipynb b/doc/source/gallery/plot_clip.ipynb
index e8a0047b..6940d428 100644
--- a/doc/source/gallery/plot_clip.ipynb
+++ b/doc/source/gallery/plot_clip.ipynb
@@ -2,25 +2,27 @@
  "cells": [
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "# Clip Vector Data with GeoPandas\n",
     "\n",
     "\n",
     "Learn how to clip geometries to the boundary of a polygon geometry\n",
     "using GeoPandas."
-   ],
-   "metadata": {}
+   ]
   },
   {
+   "attachments": {},
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "The example below shows you how to clip a set of vector geometries\n",
     "to the spatial extent / shape of another vector object. Both sets of geometries\n",
     "must be opened with GeoPandas as GeoDataFrames and be in the same Coordinate\n",
     "Reference System (CRS) for the `clip` function in GeoPandas to work.\n",
     "\n",
-    "This example uses GeoPandas example data ``'naturalearth_cities'`` and\n",
-    "``'naturalearth_lowres'``, alongside a custom rectangle geometry made with\n",
+    "This example uses example data from ``geodatasets`` ``'geoda.chicago-health'`` and\n",
+    "``'geoda.groceries'``, alongside a custom rectangle geometry made with\n",
     "shapely and then turned into a GeoDataFrame.\n",
     "\n",
     "<div class=\"alert alert-info\">\n",
@@ -32,90 +34,92 @@
     "be clipped to the total boundary of all polygons in clip object.\n",
     "</div>\n",
     "\n"
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "Import Packages\n",
     "---------------\n",
     "\n",
     "To begin, import the needed packages.\n",
     "\n"
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "import matplotlib.pyplot as plt\n",
     "import geopandas\n",
-    "from shapely.geometry import Polygon"
-   ],
-   "outputs": [],
-   "metadata": {}
+    "from shapely.geometry import box\n",
+    "import geodatasets"
+   ]
   },
   {
+   "attachments": {},
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "Get or Create Example Data\n",
     "--------------------------\n",
     "\n",
     "Below, the example GeoPandas data is imported and opened as a GeoDataFrame.\n",
     "Additionally, a polygon is created with shapely and then converted into a\n",
-    "GeoDataFrame with the same CRS as the GeoPandas world dataset.\n",
+    "GeoDataFrame with the same CRS as the GeoPandas chicago dataset.\n",
     "\n"
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
-    "capitals = geopandas.read_file(geopandas.datasets.get_path(\"naturalearth_cities\"))\n",
-    "world = geopandas.read_file(geopandas.datasets.get_path(\"naturalearth_lowres\"))\n",
+    "chicago = geopandas.read_file(geodatasets.get_path(\"geoda.chicago-health\"))\n",
+    "groceries = geopandas.read_file(geodatasets.get_path(\"geoda.groceries\")).to_crs(chicago.crs)\n",
     "\n",
-    "# Create a subset of the world data that is just the South American continent\n",
-    "south_america = world[world[\"continent\"] == \"South America\"]\n",
+    "# Create a subset of the chicago data that is just the South American continent\n",
+    "near_west_side = chicago[chicago[\"community\"] == \"NEAR WEST SIDE\"]\n",
     "\n",
     "# Create a custom polygon\n",
-    "polygon = Polygon([(0, 0), (0, 90), (180, 90), (180, 0), (0, 0)])\n",
-    "poly_gdf = geopandas.GeoDataFrame([1], geometry=[polygon], crs=world.crs)"
-   ],
-   "outputs": [],
-   "metadata": {}
+    "polygon = box(-87.8, 41.90, -87.5, 42)\n",
+    "poly_gdf = geopandas.GeoDataFrame([1], geometry=[polygon], crs=chicago.crs)"
+   ]
   },
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "Plot the Unclipped Data\n",
     "-----------------------\n",
     "\n"
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
     "fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))\n",
-    "world.plot(ax=ax1)\n",
+    "chicago.plot(ax=ax1)\n",
     "poly_gdf.boundary.plot(ax=ax1, color=\"red\")\n",
-    "south_america.boundary.plot(ax=ax2, color=\"green\")\n",
-    "capitals.plot(ax=ax2, color=\"purple\")\n",
-    "ax1.set_title(\"All Unclipped World Data\", fontsize=20)\n",
-    "ax2.set_title(\"All Unclipped Capital Data\", fontsize=20)\n",
+    "near_west_side.boundary.plot(ax=ax2, color=\"green\")\n",
+    "groceries.plot(ax=ax2, color=\"purple\")\n",
+    "ax1.set_title(\"All Unclipped Chicago Communities\", fontsize=20)\n",
+    "ax2.set_title(\"All Unclipped Groceries\", fontsize=20)\n",
     "ax1.set_axis_off()\n",
     "ax2.set_axis_off()\n",
     "plt.show()"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "Clip the Data\n",
     "--------------\n",
@@ -135,44 +139,46 @@
     "are in the same CRS.\n",
     "</div>\n",
     "\n"
-   ],
-   "metadata": {}
+   ]
   },
   {
+   "attachments": {},
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
-    "Clip the World Data\n",
+    "Clip the chicago Data\n",
     "--------------------\n",
     "\n"
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {
+    "tags": [
+     "nbsphinx-thumbnail"
+    ]
+   },
+   "outputs": [],
    "source": [
-    "world_clipped = world.clip(polygon)\n",
+    "chicago_clipped = chicago.clip(polygon)\n",
     "\n",
     "# Plot the clipped data\n",
-    "# The plot below shows the results of the clip function applied to the world\n",
+    "# The plot below shows the results of the clip function applied to the chicago\n",
     "# sphinx_gallery_thumbnail_number = 2\n",
     "fig, ax = plt.subplots(figsize=(12, 8))\n",
-    "world_clipped.plot(ax=ax, color=\"purple\")\n",
-    "world.boundary.plot(ax=ax)\n",
+    "chicago_clipped.plot(ax=ax, color=\"purple\")\n",
+    "chicago.boundary.plot(ax=ax)\n",
     "poly_gdf.boundary.plot(ax=ax, color=\"red\")\n",
-    "ax.set_title(\"World Clipped\", fontsize=20)\n",
+    "ax.set_title(\"Chicago Clipped\", fontsize=20)\n",
     "ax.set_axis_off()\n",
     "plt.show()"
-   ],
-   "outputs": [],
-   "metadata": {
-    "tags": [
-     "nbsphinx-thumbnail"
-    ]
-   }
+   ]
   },
   {
+   "attachments": {},
    "cell_type": "markdown",
+   "metadata": {},
    "source": [
     "<div class=\"alert alert-info\">\n",
     "    \n",
@@ -182,29 +188,28 @@
     "It is recommended to use the method as the function may be deprecated in the future.\n",
     "</div>\n",
     "\n",
-    "Clip the Capitals Data\n",
+    "Clip the groceries Data\n",
     "----------------------\n",
     "\n"
-   ],
-   "metadata": {}
+   ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
+   "metadata": {},
+   "outputs": [],
    "source": [
-    "capitals_clipped = capitals.clip(south_america)\n",
+    "groceries_clipped = groceries.clip(near_west_side)\n",
     "\n",
     "# Plot the clipped data\n",
     "# The plot below shows the results of the clip function applied to the capital cities\n",
     "fig, ax = plt.subplots(figsize=(12, 8))\n",
-    "capitals_clipped.plot(ax=ax, color=\"purple\")\n",
-    "south_america.boundary.plot(ax=ax, color=\"green\")\n",
-    "ax.set_title(\"Capitals Clipped\", fontsize=20)\n",
+    "groceries_clipped.plot(ax=ax, color=\"purple\")\n",
+    "near_west_side.boundary.plot(ax=ax, color=\"green\")\n",
+    "ax.set_title(\"Groceries Clipped\", fontsize=20)\n",
     "ax.set_axis_off()\n",
     "plt.show()"
-   ],
-   "outputs": [],
-   "metadata": {}
+   ]
   }
  ],
  "metadata": {
@@ -223,9 +228,9 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.1"
+   "version": "3.10.8"
   }
  },
  "nbformat": 4,
  "nbformat_minor": 4
-}
\ No newline at end of file
+}
diff --git a/doc/source/gallery/plotting_basemap_background.ipynb b/doc/source/gallery/plotting_basemap_background.ipynb
index 1fd48b5b..6ecfa8c0 100644
--- a/doc/source/gallery/plotting_basemap_background.ipynb
+++ b/doc/source/gallery/plotting_basemap_background.ipynb
@@ -23,6 +23,7 @@
    "outputs": [],
    "source": [
     "import geopandas\n",
+    "import geodatasets\n",
     "import contextily as cx"
    ]
   },
@@ -41,7 +42,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "df = geopandas.read_file(geopandas.datasets.get_path(\"nybb\"))\n",
+    "df = geopandas.read_file(geodatasets.get_path(\"nybb\"))\n",
     "ax = df.plot(figsize=(10, 10), alpha=0.5, edgecolor=\"k\")"
    ]
   },
diff --git a/doc/source/gallery/plotting_with_folium.ipynb b/doc/source/gallery/plotting_with_folium.ipynb
index d4009dd1..ff2eca9e 100644
--- a/doc/source/gallery/plotting_with_folium.ipynb
+++ b/doc/source/gallery/plotting_with_folium.ipynb
@@ -31,6 +31,7 @@
     "import pandas as pd\n",
     "import geopandas\n",
     "import folium\n",
+    "import geodatasets\n",
     "import matplotlib.pyplot as plt"
    ]
   },
@@ -68,7 +69,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "world = geopandas.read_file(geopandas.datasets.get_path(\"naturalearth_lowres\"))\n",
+    "world = geopandas.read_file(geodatasets.get_path(\"naturalearth.land\"))\n",
     "df.Type.unique()"
    ]
   },
@@ -258,7 +259,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.9.1"
+   "version": "3.11.0"
   }
  },
  "nbformat": 4,
diff --git a/doc/source/gallery/plotting_with_geoplot.ipynb b/doc/source/gallery/plotting_with_geoplot.ipynb
index 022bbd1c..441fd741 100644
--- a/doc/source/gallery/plotting_with_geoplot.ipynb
+++ b/doc/source/gallery/plotting_with_geoplot.ipynb
@@ -26,9 +26,10 @@
    "outputs": [],
    "source": [
     "import geopandas\n",
+    "import geodatasets\n",
     "import geoplot\n",
     "\n",
-    "world = geopandas.read_file(geopandas.datasets.get_path(\"naturalearth_lowres\"))\n",
+    "world = geopandas.read_file(\"https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip\")\n",
     "boroughs = geopandas.read_file(geoplot.datasets.get_path(\"nyc_boroughs\"))\n",
     "collisions = geopandas.read_file(geoplot.datasets.get_path(\"nyc_injurious_collisions\"))"
    ]
@@ -183,9 +184,9 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.7.6"
+   "version": "3.11.0"
   }
  },
  "nbformat": 4,
  "nbformat_minor": 4
-}
\ No newline at end of file
+}
diff --git a/doc/source/gallery/polygon_plotting_with_folium.ipynb b/doc/source/gallery/polygon_plotting_with_folium.ipynb
index 2bfe1227..3a71ffb1 100644
--- a/doc/source/gallery/polygon_plotting_with_folium.ipynb
+++ b/doc/source/gallery/polygon_plotting_with_folium.ipynb
@@ -15,6 +15,7 @@
    "outputs": [],
    "source": [
     "import geopandas as gpd\n",
+    "import geodatasets\n",
     "import folium\n",
     "import matplotlib.pyplot as plt"
    ]
@@ -33,7 +34,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "path = gpd.datasets.get_path(\"nybb\")\n",
+    "path = geodatasets.get_path(\"nybb\")\n",
     "df = gpd.read_file(path)\n",
     "df.head()"
    ]
diff --git a/doc/source/gallery/spatial_joins.ipynb b/doc/source/gallery/spatial_joins.ipynb
index 52c68a47..a7e452fd 100644
--- a/doc/source/gallery/spatial_joins.ipynb
+++ b/doc/source/gallery/spatial_joins.ipynb
@@ -104,10 +104,11 @@
    "source": [
     "%matplotlib inline\n",
     "from shapely.geometry import Point\n",
-    "from geopandas import datasets, GeoDataFrame, read_file\n",
+    "from geopandas import GeoDataFrame, read_file\n",
+    "import geodatasets\n",
     "\n",
     "# NYC Boros\n",
-    "zippath = datasets.get_path(\"nybb\")\n",
+    "zippath = geodatasets.get_path(\"nybb\")\n",
     "polydf = read_file(zippath)\n",
     "\n",
     "# Generate some points\n",
@@ -254,7 +255,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.7.6"
+   "version": "3.11.0"
   }
  },
  "nbformat": 4,
diff --git a/geopandas/_compat.py b/geopandas/_compat.py
index 8bbc5a91..eb9a2354 100644
--- a/geopandas/_compat.py
+++ b/geopandas/_compat.py
@@ -137,16 +137,21 @@ def set_use_pygeos(val=None):
     if USE_PYGEOS and env_use_pygeos is None and SHAPELY_GE_20:
         warnings.warn(
             "Shapely 2.0 is installed, but because PyGEOS is also installed, "
-            "GeoPandas will still use PyGEOS by default for now. To force to use and "
-            "test Shapely 2.0, you have to set the environment variable USE_PYGEOS=0. "
+            "GeoPandas still uses PyGEOS by default. However, starting with "
+            "version 0.14, the default will switch to Shapely. To force to "
+            "use Shapely 2.0 now, you can either uninstall PyGEOS or set the "
+            "environment variable USE_PYGEOS=0. "
             "You can do this before starting the Python process, or in your code "
             "before importing geopandas:"
             "\n\nimport os\nos.environ['USE_PYGEOS'] = '0'\nimport geopandas\n\n"
-            "In a future release, GeoPandas will switch to using Shapely by default. "
-            "If you are using PyGEOS directly (calling PyGEOS functions on geometries "
+            "In the next release, GeoPandas will switch to using Shapely by default, "
+            "even if PyGEOS is installed. If you only have PyGEOS installed to "
+            "get speed-ups, this switch should be smooth. However, if you are "
+            "using PyGEOS directly (calling PyGEOS functions on geometries "
             "from GeoPandas), this will then stop working and you are encouraged to "
             "migrate from PyGEOS to Shapely 2.0 "
             "(https://shapely.readthedocs.io/en/latest/migration_pygeos.html).",
+            DeprecationWarning,
             stacklevel=6,
         )
 
diff --git a/geopandas/_vectorized.py b/geopandas/_vectorized.py
index 19e51fa4..97534d52 100644
--- a/geopandas/_vectorized.py
+++ b/geopandas/_vectorized.py
@@ -688,6 +688,18 @@ def minimum_bounding_circle(data):
         )
 
 
+def minimum_bounding_radius(data):
+    if compat.USE_SHAPELY_20:
+        return shapely.minimum_bounding_radius(data)
+    elif compat.USE_PYGEOS:
+        return pygeos.minimum_bounding_radius(data)
+    else:
+        raise NotImplementedError(
+            f"shapely >= 2.0 or PyGEOS is required, "
+            f"version {shapely.__version__} is installed"
+        )
+
+
 #
 # Binary predicates
 #
diff --git a/geopandas/array.py b/geopandas/array.py
index 41f75f7a..1474ddf6 100644
--- a/geopandas/array.py
+++ b/geopandas/array.py
@@ -295,6 +295,18 @@ class GeometryArray(ExtensionArray):
 
     @property
     def data(self):
+        warnings.warn(
+            "Accessing the underlying geometries through the `.data` attribute is "
+            "deprecated and will be removed in GeoPandas 1.0. You can use "
+            "`np.asarray(..)` or the `to_numpy()` method instead.\n"
+            "Note that if you are using PyGEOS and using this attribute to get an "
+            "array of PyGEOS geometries, those other methods will always return an "
+            "array of Shapely geometries. Accessing the underlying PyGEOS geometries "
+            "directly is deprecated, and you should migrate to use Shapely >= 2.0 "
+            "instead.",
+            DeprecationWarning,
+            stacklevel=2,
+        )
         return self._data
 
     @property
@@ -526,6 +538,9 @@ class GeometryArray(ExtensionArray):
             vectorized.minimum_bounding_circle(self._data), crs=self.crs
         )
 
+    def minimum_bounding_radius(self):
+        return vectorized.minimum_bounding_radius(self._data)
+
     def normalize(self):
         return GeometryArray(vectorized.normalize(self._data), crs=self.crs)
 
diff --git a/geopandas/base.py b/geopandas/base.py
index abe3c857..c2ecf361 100644
--- a/geopandas/base.py
+++ b/geopandas/base.py
@@ -393,7 +393,7 @@ GeometryCollection
         features that have a z-component.
 
         Notes
-        ------
+        -----
         Every operation in GeoPandas is planar, i.e. the potential third
         dimension is not taken into account.
 
@@ -627,7 +627,7 @@ GeometryCollection
         Applies to GeoSeries containing only Polygons.
 
         Returns
-        ----------
+        -------
         inner_rings: Series of List
             Inner rings of each polygon in the GeoSeries.
 
@@ -726,6 +726,38 @@ GeometryCollection
         """
         return _delegate_geo_method("minimum_bounding_circle", self)
 
+    def minimum_bounding_radius(self):
+        """Returns a `Series` of the radii of the minimum bounding circles
+        that enclose each geometry.
+
+        Examples
+        --------
+        >>> from shapely.geometry import Point, LineString, Polygon
+        >>> s = geopandas.GeoSeries(
+        ...     [
+        ...         Polygon([(0, 0), (1, 1), (0, 1), (0, 0)]),
+        ...         LineString([(0, 0), (1, 1), (1, 0)]),
+        ...         Point(0,0),
+        ...     ]
+        ... )
+        >>> s
+        0    POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
+        1    LINESTRING (0.00000 0.00000, 1.00000 1.00000, ...
+        2                              POINT (0.00000 0.00000)
+        dtype: geometry
+        >>> s.minimum_bounding_radius()
+        0    0.707107
+        1    0.707107
+        2    0.000000
+        dtype: float64
+
+        See also
+        --------
+        GeoSeries.minumum_bounding_circle : minimum bounding circle (geometry)
+
+        """
+        return Series(self.geometry.values.minimum_bounding_radius(), index=self.index)
+
     def normalize(self):
         """Returns a ``GeoSeries`` of normalized
         geometries to normal form (or canonical form).
@@ -2979,7 +3011,7 @@ GeometryCollection
             If False, the order of elements is preserved.
 
         Returns
-        ----------
+        -------
         spatial_relations: Series of strings
             The DE-9IM intersection matrices which describe
             the spatial relations of the other geometry.
diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py
index 2e543885..9b816974 100644
--- a/geopandas/geodataframe.py
+++ b/geopandas/geodataframe.py
@@ -1203,6 +1203,14 @@ individually so that features may have different properties
         With selected drivers you can also append to a file with `mode="a"`:
 
         >>> gdf.to_file('dataframe.shp', mode="a")  # doctest: +SKIP
+
+        Using the engine-specific keyword arguments it is possible to e.g. create a
+        spatialite file with a custom layer name:
+
+        >>> gdf.to_file(
+        ...     'dataframe.sqlite', driver='SQLite', spatialite=True, layer='test'
+        ... )  # doctest: +SKIP
+
         """
         from geopandas.io.file import _to_file
 
@@ -1466,12 +1474,9 @@ individually so that features may have different properties
         -----
         The extra arguments ``*args`` and keyword arguments ``**kwargs`` are
         passed to DataFrame.merge.
-
-        Reference
-        ---------
-        https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas\
-        .DataFrame.merge.html
-
+        See https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas\
+.DataFrame.merge.html
+        for more details.
         """
         result = DataFrame.merge(self, *args, **kwargs)
         geo_col = self._geometry_column_name
@@ -1902,6 +1907,10 @@ individually so that features may have different properties
         This method requires SQLAlchemy and GeoAlchemy2, and a PostgreSQL
         Python driver (e.g. psycopg2) to be installed.
 
+        It is also possible to use :meth:`~GeoDataFrame.to_file` to write to a database.
+        Especially for file geodatabases like GeoPackage or SpatiaLite this can be
+        easier.
+
         Parameters
         ----------
         name : str
@@ -2066,7 +2075,7 @@ individually so that features may have different properties
     Europe    Austria    AUT    416600.0
 
         Notes
-        ------
+        -----
         Every operation in GeoPandas is planar, i.e. the potential third
         dimension is not taken into account.
 
@@ -2333,7 +2342,7 @@ countries_w_city_data[countries_w_city_data["name_left"] == "Italy"]
         overlay : equivalent top-level function
 
         Notes
-        ------
+        -----
         Every operation in GeoPandas is planar, i.e. the potential third
         dimension is not taken into account.
         """
diff --git a/geopandas/io/sql.py b/geopandas/io/sql.py
index 40f8daa4..bbbc6222 100644
--- a/geopandas/io/sql.py
+++ b/geopandas/io/sql.py
@@ -112,6 +112,9 @@ def _read_postgis(
     Returns a GeoDataFrame corresponding to the result of the query
     string, which must contain a geometry column in WKB representation.
 
+    It is also possible to use :meth:`~GeoDataFrame.read_file` to read from a database.
+    Especially for file geodatabases like GeoPackage or SpatiaLite this can be easier.
+
     Parameters
     ----------
     sql : string
@@ -149,7 +152,7 @@ def _read_postgis(
 
     SpatiaLite
 
-    >>> sql = "SELECT ST_Binary(geom) AS geom, highway FROM roads"
+    >>> sql = "SELECT ST_AsBinary(geom) AS geom, highway FROM roads"
     >>> df = geopandas.read_postgis(sql, con)  # doctest: +SKIP
     """
 
diff --git a/geopandas/plotting.py b/geopandas/plotting.py
index bd2fcb32..961999a4 100644
--- a/geopandas/plotting.py
+++ b/geopandas/plotting.py
@@ -527,20 +527,20 @@ def plot_dataframe(
         dataframe. Values are used to color the plot. Ignored if `color` is
         also set.
     kind: str
-        The kind of plots to produce:
-         - 'geo': Map (default)
-         Pandas Kinds
-         - 'line' : line plot
-         - 'bar' : vertical bar plot
-         - 'barh' : horizontal bar plot
-         - 'hist' : histogram
-         - 'box' : BoxPlot
-         - 'kde' : Kernel Density Estimation plot
-         - 'density' : same as 'kde'
-         - 'area' : area plot
-         - 'pie' : pie plot
-         - 'scatter' : scatter plot
-         - 'hexbin' : hexbin plot.
+        The kind of plots to produce. The default is to create a map ("geo").
+        Other supported kinds of plots from pandas:
+
+        - 'line' : line plot
+        - 'bar' : vertical bar plot
+        - 'barh' : horizontal bar plot
+        - 'hist' : histogram
+        - 'box' : BoxPlot
+        - 'kde' : Kernel Density Estimation plot
+        - 'density' : same as 'kde'
+        - 'area' : area plot
+        - 'pie' : pie plot
+        - 'scatter' : scatter plot
+        - 'hexbin' : hexbin plot.
     cmap : str (default None)
         The name of a colormap recognized by matplotlib.
     color : str, np.array, pd.Series (default None)
diff --git a/geopandas/sindex.py b/geopandas/sindex.py
index f3097f90..6f055416 100644
--- a/geopandas/sindex.py
+++ b/geopandas/sindex.py
@@ -716,7 +716,7 @@ if compat.SHAPELY_GE_20 or compat.HAS_PYGEOS:
                 A numpy array of pygeos geometries.
             """
             if isinstance(geometry, np.ndarray):
-                return geometry
+                return array.from_shapely(geometry)._data
             elif isinstance(geometry, geoseries.GeoSeries):
                 return geometry.values._data
             elif isinstance(geometry, array.GeometryArray):
diff --git a/geopandas/tools/hilbert_curve.py b/geopandas/tools/hilbert_curve.py
index 69c6c423..4568dea5 100644
--- a/geopandas/tools/hilbert_curve.py
+++ b/geopandas/tools/hilbert_curve.py
@@ -18,7 +18,7 @@ def _hilbert_distance(geoms, total_bounds=None, level=16):
         have coordinates in the range [0, 2^level - 1]).
 
     Returns
-    ---------
+    -------
     np.ndarray
         Array containing distances along the Hilbert curve
 
@@ -54,7 +54,7 @@ def _continuous_to_discrete_coords(bounds, level, total_bounds):
     total_bounds : Total bounds of geometries - array
 
     Returns
-    ---------
+    -------
     Discrete two-dimensional numpy array
     Two-dimensional array Array of hilbert distances for each geom
 
@@ -98,7 +98,7 @@ def _continuous_to_discrete(vals, val_range, n):
     n : Number of discrete values
 
     Returns
-    ---------
+    -------
     One-dimensional array of discrete ints
 
     """
diff --git a/geopandas/tools/overlay.py b/geopandas/tools/overlay.py
index ead7d812..674072b8 100644
--- a/geopandas/tools/overlay.py
+++ b/geopandas/tools/overlay.py
@@ -227,7 +227,7 @@ def overlay(df1, df2, how="intersection", keep_geom_type=None, make_valid=True):
     GeoDataFrame.overlay : equivalent method
 
     Notes
-    ------
+    -----
     Every operation in GeoPandas is planar, i.e. the potential third
     dimension is not taken into account.
     """
diff --git a/geopandas/tools/sjoin.py b/geopandas/tools/sjoin.py
index fae64432..fcb679a1 100644
--- a/geopandas/tools/sjoin.py
+++ b/geopandas/tools/sjoin.py
@@ -91,7 +91,7 @@ stria    AUT    416600.0
     GeoDataFrame.sjoin : equivalent method
 
     Notes
-    ------
+    -----
     Every operation in GeoPandas is planar, i.e. the potential third
     dimension is not taken into account.
     """


Test patch:
diff --git a/geopandas/io/tests/test_file_geom_types_drivers.py b/geopandas/io/tests/test_file_geom_types_drivers.py
index 457e2056..fc873dab 100644
--- a/geopandas/io/tests/test_file_geom_types_drivers.py
+++ b/geopandas/io/tests/test_file_geom_types_drivers.py
@@ -244,7 +244,7 @@ def geodataframe(request):
     return request.param
 
 
-@pytest.fixture(params=["GeoJSON", "ESRI Shapefile", "GPKG"])
+@pytest.fixture(params=["GeoJSON", "ESRI Shapefile", "GPKG", "SQLite"])
 def ogr_driver(request):
     return request.param
 
@@ -261,15 +261,42 @@ def engine(request):
 
 def test_to_file_roundtrip(tmpdir, geodataframe, ogr_driver, engine):
     output_file = os.path.join(str(tmpdir), "output_file")
+    write_kwargs = {}
+    if ogr_driver == "SQLite":
+        write_kwargs["spatialite"] = True
+
+        # This if statement can be removed once minimal fiona version >= 1.8.20
+        if engine == "fiona":
+            import fiona
+            from packaging.version import Version
+
+            if Version(fiona.__version__) < Version("1.8.20"):
+                pytest.skip("SQLite driver only available from version 1.8.20")
+
+        # If only 3D Points, geometry_type needs to be specified for spatialite at the
+        # moment. This if can be removed once the following PR is released:
+        # https://github.com/geopandas/pyogrio/pull/223
+        if (
+            engine == "pyogrio"
+            and len(geodataframe == 2)
+            and geodataframe.geometry[0] is None
+            and geodataframe.geometry[1] is not None
+            and geodataframe.geometry[1].has_z
+        ):
+            write_kwargs["geometry_type"] = "Point Z"
 
     expected_error = _expected_error_on(geodataframe, ogr_driver)
     if expected_error:
         with pytest.raises(
             RuntimeError, match="Failed to write record|Could not add feature to layer"
         ):
-            geodataframe.to_file(output_file, driver=ogr_driver, engine=engine)
+            geodataframe.to_file(
+                output_file, driver=ogr_driver, engine=engine, **write_kwargs
+            )
     else:
-        geodataframe.to_file(output_file, driver=ogr_driver, engine=engine)
+        geodataframe.to_file(
+            output_file, driver=ogr_driver, engine=engine, **write_kwargs
+        )
 
         reloaded = geopandas.read_file(output_file, engine=engine)
 
diff --git a/geopandas/tests/test_array.py b/geopandas/tests/test_array.py
index b26e3ba3..b62e3f0c 100644
--- a/geopandas/tests/test_array.py
+++ b/geopandas/tests/test_array.py
@@ -8,7 +8,7 @@ from pyproj import CRS
 import shapely
 import shapely.affinity
 import shapely.geometry
-from shapely.geometry.base import CAP_STYLE, JOIN_STYLE
+from shapely.geometry.base import CAP_STYLE, JOIN_STYLE, BaseGeometry
 import shapely.wkb
 import shapely.wkt
 
@@ -250,7 +250,18 @@ def test_to_wkt():
 
 def test_data():
     arr = from_shapely(points_no_missing)
-    assert isinstance(arr.data, np.ndarray)
+    with pytest.warns(DeprecationWarning):
+        np_arr = arr.data
+
+    assert isinstance(np_arr, np.ndarray)
+    if compat.USE_PYGEOS:
+        np_arr2 = arr.to_numpy()
+        assert isinstance(np_arr2[0], BaseGeometry)
+        np_arr3 = np.asarray(arr)
+        assert isinstance(np_arr3[0], BaseGeometry)
+    else:
+        assert arr.to_numpy() is np_arr
+        assert np.asarray(arr) is np_arr
 
 
 def test_as_array():
diff --git a/geopandas/tests/test_geom_methods.py b/geopandas/tests/test_geom_methods.py
index bacc908d..7bebc84b 100644
--- a/geopandas/tests/test_geom_methods.py
+++ b/geopandas/tests/test_geom_methods.py
@@ -1466,3 +1466,32 @@ class TestGeomMethods:
             NotImplementedError, match="shapely >= 2.0 or PyGEOS are required"
         ):
             self.g11.get_coordinates()
+
+    @pytest.mark.skipif(
+        not (compat.USE_PYGEOS or compat.USE_SHAPELY_20),
+        reason="minimum_bounding_radius not implemented for shapely<2",
+    )
+    def test_minimum_bounding_radius(self):
+        mbr_geoms = self.g1.minimum_bounding_radius()
+
+        assert_series_equal(
+            mbr_geoms,
+            Series([0.707106, 0.707106]),
+        )
+
+        mbr_lines = self.g5.minimum_bounding_radius()
+
+        assert_series_equal(
+            mbr_lines,
+            Series([0.707106, 0.707106]),
+        )
+
+    @pytest.mark.skipif(
+        (compat.USE_PYGEOS or compat.USE_SHAPELY_20),
+        reason="minimum_bounding_radius not implemented for shapely<2",
+    )
+    def test_minimium_bounding_radius_not(self):
+        with pytest.raises(
+            NotImplementedError, match="shapely >= 2.0 or PyGEOS is required"
+        ):
+            self.g1.minimum_bounding_radius()
diff --git a/geopandas/tests/test_sindex.py b/geopandas/tests/test_sindex.py
index e9d2e8ed..0cc2e42b 100644
--- a/geopandas/tests/test_sindex.py
+++ b/geopandas/tests/test_sindex.py
@@ -444,7 +444,7 @@ class TestPygeosInterface:
         tree_df = geopandas.GeoDataFrame(geometry=tree_polys)
         test_df = geopandas.GeoDataFrame(geometry=test_polys)
 
-        test_geo = test_df.geometry.values.data[0]
+        test_geo = test_df.geometry.values[0]
         res = tree_df.sindex.query(test_geo, sort=sort)
 
         # asserting the same elements
@@ -649,11 +649,11 @@ class TestPygeosInterface:
 
         # test numpy array
         res = self.df.sindex.query_bulk(
-            test_geom.geometry.values.data, predicate=predicate
+            test_geom.geometry.values.to_numpy(), predicate=predicate
         )
         assert_array_equal(res, expected)
         res = self.df.sindex.query_bulk(
-            test_geom.geometry.values.data, predicate=predicate
+            test_geom.geometry.values.to_numpy(), predicate=predicate
         )
         assert_array_equal(res, expected)