Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create polygons from points with GeoPandas

I have a geopandas dataframe containing a list of shapely POINT geometries. There is another column with a list of ID's that specifies which unique polygon each point belongs to. Simplified input code is:

import pandas as pd
from shapely.geometry import Point, LineString, Polygon
from geopandas import GeoDataFrame

data = [[1,10,10],[1,15,20],[1,20,10],[2,30,30],[2,35,40],[2,40,30]] 
df_poly = pd.DataFrame(data, columns = ['poly_ID','lon', 'lat']) 
geometry = [Point(xy) for xy in zip(df_poly.lon, df_poly.lat)]
geodf_poly = GeoDataFrame(df_poly, geometry=geometry)
geodf_poly.head()

I would like to groupby the poly_ID in order to convert the geometry from POINT to POLYGON. This output would essentially look like:

poly_ID   geometry
1         POLYGON ((10 10, 15 20, 20 10))
2         POLYGON ((30 30, 35 40, 40 30))

I imagine this is quite simple, but I'm having trouble getting it to work. I found the following code that allowed me to convert it to open ended polylines, but have not been able to figure it out for polygons. Can anyone suggest how to adapt this?

geodf_poly = geodf_poly.groupby(['poly_ID'])['geometry'].apply(lambda x: LineString(x.tolist()))

Simply replacing LineString with Polygon results in TypeError: object of type 'Point' has no len()

like image 559
EllRob Avatar asked Nov 07 '22 09:11

EllRob


1 Answers

Your request is a bit tricky to accomplish in Pandas because, in your output you want the text 'POLYGON' but numbers inside the brackets.

See the below options work for you

from itertools import chain
df_poly.groupby('poly_ID').agg(list).apply(lambda x: tuple(chain.from_iterable(zip(x['lon'], x['lat']))), axis=1).reset_index(name='geometry')

output

poly_ID     geometry
0   1   (10, 10, 15, 20, 20, 10)
1   2   (30, 30, 35, 40, 40, 30)

or

from itertools import chain

df_new =df_poly.groupby('poly_ID').agg(list).apply(lambda x: tuple(chain.from_iterable(zip(x['lon'], x['lat']))), axis=1).reset_index(name='geometry')
df_new['geometry']=df_new.apply(lambda x: 'POLYGON ('+str(x['geometry'])+')',axis=1 )
df_new

Output

poly_ID     geometry
0   1   POLYGON ((10, 10, 15, 20, 20, 10))
1   2   POLYGON ((30, 30, 35, 40, 40, 30))

Note: Column geometry is a string & I am not sure you can feed this directly into Shapely

like image 111
moys Avatar answered Nov 16 '22 10:11

moys