简体   繁体   English

两个LineStrings Geopandas的交叉点

[英]Intersection of Two LineStrings Geopandas

Let's say I have the following to GeoDataFrames of linestrings, one of which represents roads and one of which represents contour lines. 假设我有以下字符串的GeoDataFrames,其中一个代表道路,其中一个代表等高线。

>>> import geopandas as gpd
>>> import geopandas.tools
>>> import shapely
>>> from shapely.geometry import *
>>> 
>>> r1=LineString([(-1,2),(3,2.5)])
>>> r2=LineString([(-1,4),(3,0)])
>>> Roads=gpd.GeoDataFrame(['Main St','Spruce St'],geometry=[r1,r2], columns=['Name'])
>>> Roads
        Name                  geometry
0    Main St  LINESTRING (-1 2, 3 2.5)
1  Spruce St    LINESTRING (-1 4, 3 0)
>>> 

>>> c1=LineString(Point(1,2).buffer(.5).exterior)
>>> c2=LineString(Point(1,2).buffer(.75).exterior)
>>> c3=LineString(Point(1,2).buffer(.9).exterior)
>>> Contours=gpd.GeoDataFrame([100,90,80],geometry=[c1,c2,c3], columns=['Elevation'])
>>> Contours
   Elevation                                           geometry
0        100  LINESTRING (1.5 2, 1.497592363336099 1.9509914...
1         90  LINESTRING (1.75 2, 1.746388545004148 1.926487...
2         80  LINESTRING (1.9 2, 1.895666254004977 1.9117845...
>>> 

If I plot these, they look like this: 如果我绘制这些,它们看起来像这样:

在此输入图像描述

There are 3 contour line and 2 roads. 有3条轮廓线和2条道路。 I want to find the elevation at each point along each road. 我想在每条道路的每个点找到高程。 Basically I want to intersect roads and contours (which should give me 12 points) and preserve the attributes from both geodataframes (road name and elevation). 基本上我想要交叉道路和轮廓(这应该给我12分)并保留两个地理位置(道路名称和高程)的属性。

I can generate the 12 points as such by using an intersection of the unions of the two geodataframes: 我可以通过使用两个地理数据框的联合的交集来生成12个点:

>>> Intersection=gpd.GeoDataFrame(geometry=list(Roads.unary_union.intersection(Contours.unary_union)))
>>> Intersection
                                        geometry
0    POINT (0.1118644118110415 2.13898305147638)
1   POINT (0.2674451642029509 2.158430645525369)
2   POINT (0.3636038969321072 2.636396103067893)
3   POINT (0.4696699141100895 2.530330085889911)
4   POINT (0.5385205980649126 2.192315074758114)
5   POINT (0.6464466094067262 2.353553390593274)
6    POINT (1.353553390593274 1.646446609406726)
7    POINT (1.399321982208571 2.299915247776072)
8     POINT (1.530330085889911 1.46966991411009)
9    POINT (1.636396103067893 1.363603896932107)
10   POINT (1.670759586114587 2.333844948264324)
11   POINT (1.827239686607525 2.353404960825941)
>>> 

However, how do I now get the road name and elevation for each of those 12 points? 但是,我现在如何获得这12个点中的每个点的道路名称和高程? A spatial join does not behave as I would expect and only returns 4 points (all 12 should intersect with the line files since they were created that way by definition). 空间连接的行为与我的预期不同,只返回4个点(所有12个应该与行文件相交,因为它们是按照定义创建的)。

>>> gpd.tools.sjoin(Intersection, Roads)
                                       geometry  index_right       Name
2  POINT (0.3636038969321072 2.636396103067893)            1  Spruce St
3  POINT (0.4696699141100895 2.530330085889911)            1  Spruce St
5  POINT (0.6464466094067262 2.353553390593274)            1  Spruce St
6   POINT (1.353553390593274 1.646446609406726)            1  Spruce St
>>> 

Any suggestions as to how I can do this? 有关如何做到这一点的任何建议?

EDIT: It appears that the issue has to do with how the intersection points are created. 编辑:问题似乎与交叉点的创建方式有关。 If I buffer the roads and contours by a very small amount, the intersection works as expected. 如果我以非常小的量缓冲道路和轮廓,则交叉点按预期工作。 See below: 见下文:

>>> RoadsBuff=gpd.GeoDataFrame(Roads, geometry=Roads.buffer(.000005))
>>> ContoursBuff=gpd.GeoDataFrame(Contours, geometry=Contours.buffer(.000005))
>>> 
>>> Join1=gpd.tools.sjoin(Intersection, RoadsBuff).drop('index_right',1).sort_index()
>>> Join2=gpd.tools.sjoin(Join1, ContoursBuff).drop('index_right',1).sort_index()
>>> 
>>> Join2
                                             geometry       Name  Elevation
0   POLYGON ((1.636395933642091 1.363596995290097,...  Spruce St         80
1   POLYGON ((1.530329916464109 1.469663012468079,...  Spruce St         90
2   POLYGON ((1.353553221167472 1.646439707764716,...  Spruce St        100
3   POLYGON ((0.5385239436706243 2.192310454047735...    Main St        100
4   POLYGON ((0.2674491823047923 2.158426108877007...    Main St         90
5   POLYGON ((0.1118688004427904 2.138978561144256...    Main St         80
6   POLYGON ((0.6464467873602107 2.353546141571978...  Spruce St        100
7   POLYGON ((0.4696700920635739 2.530322836868614...  Spruce St         90
8   POLYGON ((0.3636040748855915 2.636388854046597...  Spruce St         80
9   POLYGON ((1.399312865255344 2.299919147068011,...    Main St        100
10  POLYGON ((1.670752113626148 2.333849053114361,...    Main St         90
11  POLYGON ((1.827232214119086 2.353409065675979,...    Main St         80
>>> 

The above is the desired output although I'm not sure as to why I have to buffer the lines to get them to intersect the points that were created from the intersection of the lines. 上面是所需的输出,虽然我不确定为什么我必须缓冲线以使它们与从线的交叉点创建的点相交。

Notice that operations unary_union and intersection are made over the geometries inside the GeoDataFrame , so you lose the data stored in the rest of the columns. 请注意,操作unary_unionintersection是在GeoDataFrame内部的几何上进行的,因此您将丢失存储在其余列中的数据。 I think in this case you have to do it by hand by accessing each geometry in the data frames. 我认为在这种情况下,您必须通过访问数据框中的每个几何图形来手动完成。 The following code: 以下代码:

import geopandas as gpd
from shapely.geometry import LineString, Point

r1=LineString([(-1,2),(3,2.5)])
r2=LineString([(-1,4),(3,0)])
roads=gpd.GeoDataFrame(['Main St','Spruce St'],geometry=[r1,r2], columns=['Name'])

c1=LineString(Point(1,2).buffer(.5).exterior)
c2=LineString(Point(1,2).buffer(.75).exterior)
c3=LineString(Point(1,2).buffer(.9).exterior)
contours=gpd.GeoDataFrame([100,90,80],geometry=[c1,c2,c3], columns=['Elevation'])

columns_data = []
geoms = []
for _, n, r in roads.itertuples():
    for _, el, c in contours.itertuples():
        intersect = r.intersection(c)
        columns_data.append( (n,el) )
        geoms.append(intersect)

all_intersection = gpd.GeoDataFrame(columns_data, geometry=geoms, 
                    columns=['Name', 'Elevation'])

print all_intersection 

produces: 生产:

        Name  Elevation                                           geometry
0    Main St        100  (POINT (0.5385205980649125 2.192315074758114),...
1    Main St         90  (POINT (0.2674451642029509 2.158430645525369),...
2    Main St         80  (POINT (0.1118644118110415 2.13898305147638), ...
3  Spruce St        100  (POINT (0.6464466094067262 2.353553390593274),...
4  Spruce St         90  (POINT (0.4696699141100893 2.53033008588991), ...
5  Spruce St         80  (POINT (0.363603896932107 2.636396103067893), ...

Notice each geometry has two points, that you can access later if you want point by point information, or you can create a row for each point introducing a for loop that iterates over the points, something like: 请注意,每个几何体都有两个点,如果您想要逐点信息,可以稍后访问这些点,或者您可以为每个点创建一个行,引入迭代点的for循环,如:

for p in intersect:
    columns_data.append( (n,el) )
    geoms.append(p)

But in this case you depend on knowing that each intersection produces a multi-geometry. 但在这种情况下,你依赖于知道每个交叉点产生一个多几何。

About your other approach using the sjoin function, I couldn't test it because the version of geopandas I'm using does not provide the tools module. 关于使用sjoin函数的其他方法,我无法测试它,因为我正在使用的geopandas版本不提供tools模块。 Try to put buffer(0.0) to see what happens. 尝试放入buffer(0.0)以查看会发生什么。

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

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