I have a shapefile of points, defined by X and Y coordinates, ad the ID feature. I have at least 3 different points with the same ID number.
I would like to define, for each ID, the shapefile of a circle that circumscribes the points.
How can this be done in python environment?
Advertisement
Answer
- there is a library that does it: https://pypi.org/project/miniball/
- it’s pretty forward to integrate in standard pandas pattern https://pandas.pydata.org/pandas-docs/stable/user_guide/groupby.html
- solution really reduces to this:
def circle(points): p, r = miniball.get_bounding_ball(np.array([points.x, points.y]).T) return shapely.geometry.Point(p).buffer(math.sqrt(r)) col = "group" # generate circles around groups of points gdf_c = cities.groupby(col, as_index=False).agg(geometry=("geometry", circle))
- with sample example and visualisation, circles do become distorted due to epsg:4326 projection limitations
full working example
import geopandas as gpd import numpy as np import shapely import miniball import math import pandas as pd cities = gpd.read_file(gpd.datasets.get_path("naturalearth_cities")) world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres")) # a semi-synthetic grouping of cities world["size"] = world.groupby("continent")["pop_est"].apply( lambda d: pd.cut(d, 2, labels=list("ab"), duplicates="drop").astype(str) ) cities = cities.sjoin(world.loc[:, ["continent", "iso_a3", "size", "geometry"]]) cities["group"] = cities["continent"] + cities["size"] def circle(points): p, r = miniball.get_bounding_ball(np.array([points.x, points.y]).T) return shapely.geometry.Point(p).buffer(math.sqrt(r)) col = "group" # generate circles around groups of points gdf_c = cities.groupby(col, as_index=False).agg(geometry=("geometry", circle)) # visualize it m = cities.explore(column=col, height=300, width=600, legend=False) gdf_c.loc[~gdf_c["geometry"].is_empty].explore( m=m, column=col, marker_kwds={"radius": 20}, legend=False )