I have this little issue I am trying to solve and I have looked everywhere for an answer. It seems odd that I cannot find it, but it might just be me.
So, I have this dataframe
df=
id x_zone y_zone
0 A1 65.422080 48.147850
1 A1 46.635708 51.165745
2 A1 46.597984 47.657444
3 A1 68.477700 44.073700
4 A3 46.635708 54.108190
5 A3 46.635708 51.844770
6 A3 63.309560 48.826878
7 A3 62.215572 54.108190
that I convert into a geopandas
dataframe:
df_geometry = gpd.GeoDataFrame(geometry=df.groupby('id').apply(
lambda g: Polygon(gpd.points_from_xy(g['x_zone'], g['y_zone']))))
df_geometry = df_geometry.reset_index()
print(df_geometry)
which returns:
id geometry
A1 POLYGON ((65.42208 48.14785, 46.63571 51.16575...
A3 POLYGON ((46.63571 54.10819, 46.63571 51.84477...
and for which I can compute the area and the perimeter:
df_geometry["area"] = df_geometry['geometry'].area
df_geometry["perimeter"] = df_geometry['geometry'].length
which gives:
id geometry area perimeter
0 A1 POLYGON ((65.42208 48.14785, 46.63571 51.16575... 72.106390 49.799695
1 A3 POLYGON ((46.63571 54.10819, 46.63571 51.84477... 60.011026 40.181476
Now, to the core of my problem: IF one can calculate the length, surely the length of each segment of the polygons is being calculated. How can I retrieve this?
I understand that for very complicated polygons (eg country maps, this might be problematics to store). Anyone with an idea?
Here is the runnable code that shows all the steps to create a dataframe that contains required segment lengths.
from io import StringIO
import geopandas as gpd
import pandas as pd
from shapely.geometry import Point, Polygon
import numpy as np
dats_str = """index id x_zone y_zone
0 A1 65.422080 48.147850
1 A1 46.635708 51.165745
2 A1 46.597984 47.657444
3 A1 68.477700 44.073700
4 A3 46.635708 54.108190
5 A3 46.635708 51.844770
6 A3 63.309560 48.826878
7 A3 62.215572 54.108190"""
# read the string, convert to dataframe
df1 = pd.read_csv(StringIO(dats_str), sep='\s+', index_col='index') #good for space/s separation
gdf = gpd.GeoDataFrame(geometry=df1.groupby('id')
.apply(lambda g: Polygon(gpd.points_from_xy(g['x_zone'], g['y_zone']))))
gdf = gdf.reset_index() #bring `id` to `column` status
# Facts about polygon outer vertices
# - first vertex is the same as the last
# - to get segments, ignore zero-th point (use it as from_point in next row)
# create basic lists for creation of new dataframe
indx = [] # for A1, A3
sequ = [] # for seg order
pxy0 = [] # from-point
pxy1 = [] # to-point
for ix,geom in zip(gdf.id, gdf.geometry):
num_pts = len(geom.exterior.xy[0])
#print(ix, "Num points:", num_pts)
old_xy = []
for inx, (x,y) in enumerate(zip(geom.exterior.xy[0],geom.exterior.xy[1])):
if (inx==0):
# first vertex is the same as the last
pass
else:
indx.append(ix)
sequ.append(inx)
pxy0.append(Point(old_xy))
pxy1.append(Point(x,y))
old_xy = (x,y)
# Create new geodataframe
pgon_segs = gpd.GeoDataFrame({"poly_id": indx,
"vertex_id": sequ,
"fr_point": pxy0,
"to_point": pxy1}, geometry="to_point")
# Compute segment lengths
# Note: seg length is Euclidean distance, ***not geographic***
pgon_segs["seg_length"] = pgon_segs.apply(lambda row: row.fr_point.distance(row.to_point), axis=1)
The content of pgon_segs
:
poly_id vertex_id fr_point to_point seg_length
0 A1 1 POINT (65.42207999999999 48.14785) POINT (46.63571 51.16575) 19.027230
1 A1 2 POINT (46.635708 51.165745) POINT (46.59798 47.65744) 3.508504
2 A1 3 POINT (46.597984 47.657444) POINT (68.47770 44.07370) 22.171270
3 A1 4 POINT (68.4777 44.0737) POINT (65.42208 48.14785) 5.092692
4 A3 1 POINT (46.635708 54.10819) POINT (46.63571 51.84477) 2.263420
5 A3 2 POINT (46.635708 51.84477) POINT (63.30956 48.82688) 16.944764
6 A3 3 POINT (63.30956 48.826878) POINT (62.21557 54.10819) 5.393428
7 A3 4 POINT (62.215572 54.10819) POINT (46.63571 54.10819) 15.579864
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.