如何从OSMnx图中筛选指定边并构建子图?
问题:如何用OSMnx筛选目标边并生成子图?
问题背景
- 下载OSM地图为shapefile格式,筛选出目标路线的节点与特定街道边,导出为CSV后导入Python Notebook
- 通过
G.subgraph(nodes)成功生成仅包含目标节点的子图,但无法筛选目标边 - 尝试使用
G.edge_subgraph(edges),分别传入OSM ID列表[osmid_0,...,osmid_i]和节点对列表[(u_0,v_0),...(u_i,v_i)],执行G_mh.edge_subgraph(roads['osmid'])时触发以下错误:
Output exceeds the size limit. Open the full output data in a text editor--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[230], line 1 ----> 1 G_mh.edge_subgraph(roads['osmid']) File ~/Library/Python/3.9/lib/python/site-packages/networkx/classes/graph.py:1865, in Graph.edge_subgraph(self, edges) 1827 def edge_subgraph(self, edges): 1828 """Returns the subgraph induced by the specified edges. 1829 1830 The induced subgraph contains each edge in `edges` and each (...) 1863 1864 """ -> 1865 return nx.edge_subgraph(self, edges) File ~/Library/Python/3.9/lib/python/site-packages/networkx/classes/function.py:445, in edge_subgraph(G, edges) 443 if G.is_multigraph(): 444 if G.is_directed(): -> 445 induced_edges = nxf.show_multidiedges(edges) 446 else: 447 induced_edges = nxf.show_multiedges(edges) File ~/Library/Python/3.9/lib/python/site-packages/networkx/classes/filters.py:69, in show_multidiedges(edges) 68 def show_multidiedges(edges): ---> 69 edges = {(u, v, k) for u, v, k in edges} ... 68 def show_multidiedges(edges): ---> 69 edges = {(u, v, k) for u, v, k in edges} 70 return lambda u, v, k: (u, v, k) in edges ValueError: too many values to unpack (expected 3)
解决方案
错误原因
OSMnx默认生成的是MultiDiGraph(多有向图),edge_subgraph对这类图要求传入**(u, v, key)**三元组作为边的唯一标识符,而不是单独的osmid或(u,v)二元组。另外,osmid是边的属性字段,不是图的边标识符,直接传入osmid列表会触发解包错误。
具体实现步骤
通过osmid筛选边并生成子图
从CSV中提取目标osmid,遍历原图匹配对应边的三元组:import osmnx as ox import pandas as pd # 假设roads是导入的CSV数据框,包含目标边的osmid列 target_osmids = set(roads['osmid']) # 遍历原图的所有边,收集符合条件的(u, v, key)三元组 selected_edges = [] for u, v, key, edge_data in G_mh.edges(data=True, keys=True): # 注意部分边的osmid可能是列表(如合并的路段),需特殊处理 edge_osmid = edge_data.get('osmid') if isinstance(edge_osmid, list): if any(oid in target_osmids for oid in edge_osmid): selected_edges.append((u, v, key)) else: if edge_osmid in target_osmids: selected_edges.append((u, v, key)) # 生成边诱导子图 G_sub = G_mh.edge_subgraph(selected_edges)结合节点ID与osmid精准匹配
如果CSV中包含图的节点ID(u和v列),可以更精准地定位边:selected_edges = [] for _, row in roads.iterrows(): u, v, target_oid = row['u'], row['v'], row['osmid'] # 遍历该(u,v)对应的所有key(多图特性) if u in G_mh and v in G_mh[u]: for key in G_mh[u][v]: edge_data = G_mh[u][v][key] edge_osmid = edge_data.get('osmid') # 处理osmid为列表的情况 match = False if isinstance(edge_osmid, list): match = target_oid in edge_osmid else: match = (edge_osmid == target_oid) if match: selected_edges.append((u, v, key)) break # 找到匹配项后退出循环 G_sub = G_mh.edge_subgraph(selected_edges)保存子图
生成子图后,可通过以下方式保存:# 保存为GraphML格式(保留所有属性,推荐) ox.save_graphml(G_sub, filepath='target_subgraph.graphml') # 保存为shapefile(适合GIS工具处理) ox.save_graph_shapefile(G_sub, filepath='target_subgraph')
内容的提问来源于stack exchange,提问作者sdb
相关产品推荐
相关产品推荐

