NetworkX与GIS结合:如何连通离散节点边计算跨片区最短路径
问题解答
两种方案均可实现跨不连通GIS片区的路径计算需求,可根据使用场景选择:
方案1:直接在NetworkX中新增边完成连通
适合临时测试、不需要复用数据的场景,操作逻辑如下:
- 先对网络中的节点按所属片区分组,分别提取黄色片区、紫色片区、绿色片区的所有节点集合
- 计算黄色片区与紫色片区节点对之间的最小地理距离,取距离最近的两个节点,新增一条无向边,边的
weight属性设为两点的大地距离(平面坐标可直接用欧氏距离) - 同理计算紫色片区与绿色片区的最近节点对,新增对应加权边
- 计算路径时需额外适配「经过紫色片区」的要求:不要直接计算黄色起点到绿色终点的最短路径,可分两段计算:先算黄色起点到紫色片区任意节点的最短路径,再算该紫色中转节点到绿色终点的最短路径,拼接后得到符合要求的完整路径
注意你提供的测试代码存在两处可优化点:
- 笔误:读取的图对象是
G,但调用nx.draw时传入的是未定义的doralGDF,会触发NameError- 不要用
nx.spring_layout生成节点位置,直接用节点自带的地理坐标作为绘图位置,避免空间位置错乱
方案2:GIS预处理阶段完成连通(更推荐长期复用场景)
如果该份GIS数据需要多次用于路径计算,优先在GIS工具(QGIS、ArcGIS等)中完成连通处理:在不连通的片区之间绘制对应连接线,补全长度等属性字段后重新导出shp文件,后续NetworkX读取的网络天生就是连通的,无需额外在代码中做适配,数据一致性更高。
修正后可运行的参考代码
import networkx as nx import matplotlib.pyplot as plt from geopy.distance import geodesic # 用于计算WGS84坐标的大地距离,平面坐标可替换为math.hypot # 读取shp文件 G = nx.read_shp('doral27thStreet.shp') # --------------需提前自定义三个片区的节点集合-------------- # yellow_nodes = [黄色片区所有节点的坐标元组] # purple_nodes = [紫色片区所有节点的坐标元组] # green_nodes = [绿色片区所有节点的坐标元组] # -------------------------------------------------------- # 计算两个节点集合的最近点对 def get_nearest_node_pair(nodes1, nodes2): min_dist = float('inf') nearest_pair = None for n1 in nodes1: for n2 in nodes2: # WGS84坐标为(lon, lat),geodesic入参要求为(lat, lon) dist = geodesic((n1[1], n1[0]), (n2[1], n2[0])).meters if dist < min_dist: min_dist = dist nearest_pair = (n1, n2) return nearest_pair, min_dist # 新增片区连接边 yp_pair, yp_dist = get_nearest_node_pair(yellow_nodes, purple_nodes) G.add_edge(yp_pair[0], yp_pair[1], weight=yp_dist) pg_pair, pg_dist = get_nearest_node_pair(purple_nodes, green_nodes) G.add_edge(pg_pair[0], pg_pair[1], weight=pg_dist) # 计算黄->紫->绿的完整路径 yellow_start = list(yellow_nodes)[22] # 找离黄色起点最近的紫色节点作为中转 purple_transfer = min(purple_nodes, key=lambda x: nx.shortest_path_length(G, yellow_start, x, weight='weight')) green_end = list(green_nodes)[1] # 拼接两段路径,去重中转节点 path_y2p = nx.shortest_path(G, yellow_start, purple_transfer, weight='weight') path_p2g = nx.shortest_path(G, purple_transfer, green_end, weight='weight') full_path = path_y2p + path_p2g[1:] # 绘图 pos = {node: node for node in G.nodes()} # 直接用地理坐标作为绘图位置 nx.draw(G, pos, node_color='k', node_size=10) nx.draw_networkx_nodes(G, pos, nodelist=full_path, node_color='r', node_size=20) plt.axis('equal') plt.show()
内容的提问来源于stack exchange,提问作者Derek_P
相关产品推荐
相关产品推荐

