OSMnx 无向图和 (u, v, k) 顺序
Posted
技术标签:
【中文标题】OSMnx 无向图和 (u, v, k) 顺序【英文标题】:OSMnx undirected graphs and (u, v, k) order 【发布时间】:2021-12-22 17:38:28 【问题描述】:我想知道 OSMnx 网络的有向 (MultiGraph) 和无向 (MultiDiGraph) 表示(1)找到最近的边和(2)以可重现的方式将网络及其属性写入磁盘。
-
我调用 osmnx.simplification.consolidate_intersections,为某些边组合 OSM 方式 ID。
然后我将图形转换为 GeoDataFrames 并进行更多预处理。
然后我使用 osmnx.distance.nearest_edges 将观察结果定位到边缘(即街道);为此,我需要将地理数据框改回图表。
在整个分析过程中,我使用最近边的 (u, v, key) 来交叉参考观察和街道段几何。从地理数据帧到 networkx 图来回转换不会保留边缘索引的 (u, v, k) 顺序。
在 OSMnx 图通过 osmnx.simplification.consolidate_intersections 后,边是否有唯一且不变的标识符?
编辑:根据要求,下面是一个简短的示例,说明 [u, v, key] 设置在从 GeoDataFrames 读取和写入图形到磁盘时发生变化。从this github issue 和the networkx docs 我看到我的假设 [u, v, key] 不会改变不会成立。我已经通过使用网络的 networkx.MultiGraph 表示而不是 GeoDataFrame 表示进行更多的预处理来解决这个问题,并且只在管道结束时转换为 GeoDataFrame 并写入磁盘一次。
import osmnx as ox
import geopandas as gpd
TRANSVERSE_MERCATOR_NZ = 'EPSG:2193'
fname_gpkg = '/tmp/test.gpkg'
fname_graphml = '/tmp/test.graphml'
# 1) create an OSMnx graph for Auckland, New Zealand. Reproject,
# consolidate intersections, convert to undirected. Do some analyses:
# assigning the "road_class" variable serves here as a placeholder.
# Save to geopackage.
g = ox.graph_from_place(
['NZ-AUK'], network_type="drive", retain_all=True
)
# reproject, consolidate, undirect
gp = ox.projection.project_graph(g, TRANSVERSE_MERCATOR_NZ)
g_simplified = ox.simplification.consolidate_intersections(gp, tolerance=30)
g_simplified_undirected = ox.utils_graph.get_undirected(g_simplified)
# get geodataframes and add a column to edges
gdf_nodes_0, gdf_edges_0 = ox.utils_graph.graph_to_gdfs(g_simplified_undirected)
gdf_edges_0['road_class'] = 1 # placeholder for more complicated stuff
# convert back to graph and save to geopackage
g_from_frames = ox.utils_graph.graph_from_gdfs(gdf_nodes_0, gdf_edges_0)
g_for_output = ox.utils_graph.get_undirected(g_from_frames)
ox.io.save_graph_geopackage(g_for_output, fname_gpkg)
# 2) load the saved geopackage back to GeoDataFrames, demonstrate that
# the u, v, k values have changed.
gdf_nodes_1 = gpd.read_file(fname_gpkg,
layer='nodes').set_index('osmid')
gdf_edges_1 = gpd.read_file(fname_gpkg,
layer='edges').set_index(['u', 'v', 'key'])
# show that the network saved to the geopackage and the network loaded
# from the geopackage have edges with different u, v, w indices
assert gdf_nodes_1.index.is_unique and gdf_edges_1.index.is_unique
graph_attrs = 'crs': 'epsg:2193', 'simplified': True
idx_0 = gdf_edges_0.reset_index()[['u', 'v', 'key']]
idx_1 = gdf_edges_1.reset_index()[['u', 'v', 'key']]
only_0 = idx_0.merge(idx_1, how='outer', indicator=True).loc[lambda x: x['_merge'] == 'left_only']
only_1 = idx_0.merge(idx_1, how='outer', indicator=True).loc[lambda x: x['_merge'] == 'right_only']
# only_0 contains [u, v, key] sets that are in gdf_edges_0 but not gdf_edges_1.
# only_1 contains [u, v, key] sets that are in gdf_edges_1 but not gdf_edges_0.
【问题讨论】:
请提供一个可重现的最小示例:这种情况下的答案将取决于您的具体参数化。 按要求发布了一个小例子。我已经设法重新处理我的处理管道,以避免由于我对 [u, v, key] 集不变的错误假设而引起的问题。 感谢@gboeing 提供这个出色的工具。它非常有用。 【参考方案1】:在 OSMnx 图通过 osmnx.simplification.consolidate_intersections 后,边是否有唯一且不变的标识符?
合并时边会发生变化,因为节点会在合并时发生变化。边由它们的端点节点加上一个键唯一标识,作为元组(u, v, k)
。所以当节点改变时,边的唯一标识符也会改变。但是,您可以获取边的唯一标识符 (u, v, k)
,在合并图中查找相应的节点,并检查它们的 osmid_original
属性:
# download, project, consolidate graph
G = ox.graph_from_place('Piedmont, CA, USA', network_type='drive')
Gp = ox.project_graph(G)
Gc = ox.consolidate_intersections(Gp)
# select the first edge
u, v, k = list(Gc.edges)[0]
# inspect this edge's attributes
print(Gc.edges[(u, v, k)])
# what was the original OSM ID of this edge's u and v nodes?
u_original = Gc.nodes[u]['osmid_original']
v_original = Gc.nodes[v]['osmid_original']
# inspect the original edge's attributes
print(G.edges[(u_original, v_original, k)])
因此,边由其节点唯一标识,并且合并图中的节点具有将它们链接回其原始 OSM ID 的属性。但是,这并不总是有效,因为合并图中的某些单个节点(根据定义)包含原始图中的多个节点,因此无法进行查找。为了更好的理论对应,合并本质上会减少信息。
【讨论】:
以上是关于OSMnx 无向图和 (u, v, k) 顺序的主要内容,如果未能解决你的问题,请参考以下文章
POJ 3177 Redundant Paths 无向图边双联通基础题