简体   繁体   中英

Calculate length of all segments in polygon using geopandas

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM