繁体   English   中英

使用 geopandas 计算多边形中所有线段的长度

[英]Calculate length of all segments in polygon using geopandas

我有一个我想解决的小问题,我到处寻找答案。 我找不到它似乎很奇怪,但它可能只是我。

所以,我有这个 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

我将其转换为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)

返回:

                                             
id                                        geometry                                 
A1  POLYGON ((65.42208 48.14785, 46.63571 51.16575...
A3  POLYGON ((46.63571 54.10819, 46.63571 51.84477...

我可以计算面积和周长:

df_geometry["area"] = df_geometry['geometry'].area
df_geometry["perimeter"] = df_geometry['geometry'].length

这使:

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

现在,我的问题的核心是:如果可以计算长度,那么肯定正在计算多边形的每一段的长度。 我怎样才能找回这个?

我知道对于非常复杂的多边形(例如国家地图,这可能是存储问题)。 有人有想法吗?

这是可运行的代码,显示了创建包含所需段长度的 dataframe 的所有步骤。

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)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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