ENH: add minimum_bounding_circle as GeoSeries method (#2621)

* ENH: add minimum_bounding_circle as GeoSeries method

* skipif

* changelog

* fix docs build
This commit is contained in:
Martin Fleischmann
2023-01-03 22:09:17 +01:00
committed by GitHub
parent 037c428305
commit 03e79e9ee3
6 changed files with 70 additions and 0 deletions
+4
View File
@@ -2,6 +2,10 @@
## Development version
New features and improvements:
- Added ``minimum_bounding_circle()`` method from shapely to GeoSeries/GeoDataframe (#2621).
Deprecations and compatibility notes:
- Added warning that ``unary_union`` will return ``'GEOMETRYCOLLECTION EMPTY'`` instead
+1
View File
@@ -86,6 +86,7 @@ Constructive methods and attributes
GeoSeries.centroid
GeoSeries.convex_hull
GeoSeries.envelope
GeoSeries.minimum_bounding_circle
GeoSeries.simplify
GeoSeries.normalize
+12
View File
@@ -677,6 +677,18 @@ def representative_point(data):
return out
def minimum_bounding_circle(data):
if compat.USE_SHAPELY_20:
return shapely.minimum_bounding_circle(data)
elif compat.USE_PYGEOS:
return pygeos.minimum_bounding_circle(data)
else:
raise NotImplementedError(
f"shapely >= 2.0 or PyGEOS is required, "
f"version {shapely.__version__} is installed"
)
#
# Binary predicates
#
+5
View File
@@ -511,6 +511,11 @@ class GeometryArray(ExtensionArray):
def representative_point(self):
return GeometryArray(vectorized.representative_point(self.data), crs=self.crs)
def minimum_bounding_circle(self):
return GeometryArray(
vectorized.minimum_bounding_circle(self.data), crs=self.crs
)
def normalize(self):
return GeometryArray(vectorized.normalize(self.data), crs=self.crs)
+33
View File
@@ -692,6 +692,39 @@ GeometryCollection
"""
return _delegate_geo_method("representative_point", self)
def minimum_bounding_circle(self):
"""Returns a ``GeoSeries`` of geometries representing the minimum bounding
circle that encloses each geometry.
Examples
--------
>>> from shapely.geometry import Polygon, LineString, Point
>>> 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_circle()
0 POLYGON ((1.20711 0.50000, 1.19352 0.36205, 1....
1 POLYGON ((1.20711 0.50000, 1.19352 0.36205, 1....
2 POINT (0.00000 0.00000)
dtype: geometry
See also
--------
GeoSeries.convex_hull : convex hull geometry
"""
return _delegate_geo_method("minimum_bounding_circle", self)
def normalize(self):
"""Returns a ``GeoSeries`` of normalized
geometries to normal form (or canonical form).
+15
View File
@@ -928,6 +928,21 @@ class TestGeomMethods:
assert isinstance(e, GeoSeries)
assert self.g3.crs == e.crs
@pytest.mark.skipif(
not (compat.USE_PYGEOS or compat.USE_SHAPELY_20),
reason="minimum_bounding_circle is only implemented for pygeos, not shapely",
)
def test_minimum_bounding_circle(self):
mbc = self.g1.minimum_bounding_circle()
centers = GeoSeries([Point(0.5, 0.5)] * 2)
assert np.all(mbc.centroid.geom_equals_exact(centers, 0.001))
assert_series_equal(
mbc.area,
Series([1.560723, 1.560723]),
)
assert isinstance(mbc, GeoSeries)
assert self.g1.crs == mbc.crs
def test_total_bounds(self):
bbox = self.sol.x, self.sol.y, self.esb.x, self.esb.y
assert isinstance(self.landmarks.total_bounds, np.ndarray)