Python (GIS):如何使用 Networkx 将几何线(以 LineString 的形式)转换为完整图网络

问题描述 投票:0回答:1

TL;DR 如何使用 NetworkX 将 LineStrings 地理数据框转换为完整图?

我有一个由线串集合组成的地理数据框,这些线串在地理上代表道路网络(紫色)。我有 2 个点(红色和蓝色)代表 A 和 B。我想找到 A 和 B 之间沿道路网行驶的最短路线。 enter image description here

我已经使用momepy库将地理数据框转换为网络:

road = gpd.read_file(input_road.shp)

#need to explode roads, as is multiline
exploded = road.explode(index_parts=True)

G = momepy.gdf_to_nx(exploded, approach="primal",length='mm_len',multigraph=True)

这成功地将我的道路网络转换为 networkx 多重图,同时保留点之间的距离 (mm_len)。

然后,我通过获取道路网络上距离这些点最近的节点,将点 A 和 B 添加到网络中:

my_points = gpd.read_file(my_points)

#Firstly, need to convert the coordinates to a tuple of x,y coordinates
for my_point in my_points .geometry.values:
    coords_values = re.findall('[0-9.]+ [0-9.]+', str(my_point ))
    
    #convert list of strings separated by spaces, to a list of coords as list. 
    coords = [sub.split(' ') for sub in coords_values ][0]
    coords_tuple= tuple(map(float, coords ))
    coords_list.append(coords_tuple)

#add this coord tuple as a column in the dataframe
my_points["coords_syntax"] = coords_list

#this dictionary will be used to select the network nodes. The key is the coordinate tuple, and the attribute will be the 'Name' of the point
dict_df_mypoints = home.set_index('coords_syntax')['Name'].to_dict()   

#select the nearest node points on the road network to these coordinate tuples
A = list(G.nodes())

#iterate through dict of coords: my_points
for point in dict_df_mypoints :
    
    
    #get closest node (using KDTree) between point and the array of cords A generated above
    closest_node = A[scipy.spatial.KDTree(A).query(point)[1]]
    
    #make these above closest nodes have attribute my_point, with other attributes (dict_df[point])
    G.nodes[closest_node]['my_point'] = dict_df[point]

所以现在在我的道路网络的所有节点中,我有 2 个分别代表点 A 和 B。它们的节点键是坐标对。

但是,当我在 A 和 B 之间运行最短路径算法时,出现此错误:

nx.shortest_path(G,source = (455529.02164326626, 206374.9504608615),target = (454340.3426543578, 207204.53480888018))


>>NetworkXNoPath: No path between (455529.02164326626, 206374.9504608615) and (454340.3426543578, 207204.53480888018)

当我检查这些节点的边缘时,它们只连接到它们的 2 个邻居,而没有其他节点:

nx.single_source_shortest_path_length(G,source = (455529.02164326626, 206374.9504608615))

 >>{(455529.02164326626, 206374.9504608615): 0,
 >>(455582.6204962559, 206424.4603359318): 1,
 >>(455596.5948359391, 206455.62556823122): 2}

因此,对于我的道路网络,我认为我需要将所有节点通过边缘相互连接(而不仅仅是与其邻居),否则最短路径将不起作用。我需要使我的网络成为一个完整的图。然而,我不知道该怎么做——Momepy 无法做到这一点。然而,我不确定如何从头开始创建 NetworkX Graph,同时保留道路网络节点之间的地理距离 - 这就是吸引我首先使用 Momepy 的原因。意见将不胜感激,谢谢:)

python charts gis networkx shortest-path
1个回答
0
投票

我会使用

sjoin_nearest
idxmin
来获取相关节点,然后在请求两点(A 和 B
)之间的 
shortest_path 时指定权重:

from shapely import Point

points = gpd.GeoDataFrame(
    {"point": [*"AB"]},
    geometry=gpd.points_from_xy(*zip(*[A, B])),
    crs=road.crs,
)
nodes = gpd.GeoDataFrame(
    {"node": G.nodes},
    geometry=list(map(Point, G.nodes)),
    crs=road.crs,
)

dis = nodes.sjoin_nearest(points, distance_col="dis")
njoin = dis.loc[dis.groupby("point")["dis"].idxmin()]
matches = njoin.set_index("point")["node"].to_dict()

a_to_b = nx.shortest_path(
    G,
    source=matches["A"],
    target=matches["B"],
    weight="mm_len",
)

NB:我使用了“bubenec”道路/数据集(由momepy提供)来进行绘图。

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.