furbaw
furbaw

Reputation: 109

Create Shapely Polygon around labelled coordinates

I have a pandas dataframe of buildings in a city. The buildings have a latitude and longitude column and are grouped into separate management locations.

I've managed to create a geopandas dataframe with a 'geometry' column of shapely Points for each building and plot those on a map with separate colour for each management location. However is there a way to group the geodataframe by management location and have the 'geometry' column as a shapely Polygon encompassing the points corresponding to each building within each management location?

I currently have:

geo_poly['geometry'] = geo_poly['geometry'].apply(lambda x: x.coords[0])
geo_poly = geo_poly.groupby('management location')['geometry'].apply(lambda x: Polygon(x.tolist())).reset_index()
geo_poly = gpd.GeoDataFrame(geo_poly, geometry = 'geometry')

But when I plot it:

geo_poly.plot(ax = ax)

It has obviously drawn a polygon by traversing each point in the geopandas dataframe.

plot of polygons

I would have thought geopandas would have (or there would exist somewhere) a better way to draw a polygon around the points at the edge of a defined cluster but I'm having difficulty finding one.

Any help would be gratefully received, Thanks

Upvotes: 2

Views: 1818

Answers (1)

Felipe D.
Felipe D.

Reputation: 1281

You can use the GeoDataFrame's dissolve function to "fuse" all the points in the groups and then use the convex_hull attribute to extract the polygon surrounding all the grouped/fused/dissolved points.

Here's a small reproducible example:

# Importing libraries used
import numpy as np
import geopandas as gpd
import shapely

# Setting the random seed
np.random.seed(6)

# Determining the number of points in the example
npoints = 15

# Generating the GeoDataFrame with random Points
mydf = gpd.GeoDataFrame({'id':range(npoints),
                         'geometry':(pd.Series(list(np.random.rand(npoints,2)))
                                     .apply(shapely.geometry.Point)),
                         'group':np.random.randint(1,3,npoints)})

# Plotting the GeoDataFrame according to the "group" column
mydf.plot(column='group', cmap='Set1')

# Fusing all of the Points based on the "group" column and 
# generating a Polygon that envelops all of the Points in
# each group
new_df = (mydf.dissolve(by='group')
          .convex_hull
          .reset_index()
          .rename({0:'geometry'},axis=1))

# Plotting the original Point and the newly-generated Polygons
ax = new_df.plot(column='group',cmap='tab20c', alpha=.7)
mydf.plot(ax = ax, column='group', cmap='Set1')

Here is the plot of the original points by group:

Points colored by group

And here is the plot of the polygons that enclose the point groups:

Polygons enclosing each group's points

So, for your specific example, you could do something like this:

from shapely.geometry import Point

# Creating a new column with Point geometries
geo_poly['geometry_pt'] = geo_poly['geometry'].apply(lambda x: Point(x.coords[0]))

# Transforming into a GeoDataFrame
geo_poly = gpd.GeoDataFrame(geo_poly, geometry = 'geometry_pt')

# Dissolving and extracting the new Polygons
new_geo_poly = (geo_poly.dissolve(by='management location')
                .convex_hull
                .reset_index()
                .rename({0:'geometry'},axis=1))

You might have to tweak that line regarding the creation of the new "geometry_pt" column. But once you get that fixed, the rest should work =)

Upvotes: 4

Related Questions