在 Python 中使用 OSMnx 对街道网络进行图分析





5.00/5 (3投票s)
本教程将通过代码示例,介绍 GeoPandas GeoDataFrame、OSM 街道网络的快速简易可视化,以及使用 OSMnx 对生成地图进行额外自定义的辅助函数。
无论您是想找到从 A 地到 B 地的最佳路线,还是想分析社区超市的可达性以识别食品荒漠,将问题以网络的形式构建,并使用街道作为边,通常是解决问题的最简单、最便捷的方法。
然而,在开始构建街道网络之前,您需要数据。想到地理信息时,Google 地图可能是大多数人首先想到的选择,但其 API 不幸不是免费的。幸运的是,有一个免费的开源替代方案,拥有大部分相同的数据:OpenStreetMap (OSM) 项目。
尽管找到了数据源,但导航 OSM 的节点、路径和关系数据模型仍然可能很麻烦。熟悉多个 API(它有三个)以及下载方法及其相关的查询语言更是困难重重,而且非常耗时。幸好,南加州大学Geoff Boeing 教授的出色OSMnx 项目可以为您完成所有繁重的工作。
OSMnx 简介
OSMnx 是一个开源 Python 库,允许您通过简单的查询(例如地名或边界框)下载 OSM 数据。它不仅可以获取这些数据,更重要的是,它还对来自 OSM 的原始数据进行各种预处理,并将其格式化为易于转换为NetworkX MultiDiGraph 的形式。对于不熟悉它的人来说,NetworkX 是 Python 中首屈一指的图分析和可视化库。因此,它能够轻松处理许多任务,例如查找两点之间的最短路径等等。
此外,OSMnx 还对 NetworkX 图和 GeoPandas GeoDataFrame 之间的转换提供一流支持。GeoPandas GeoDataFrame 是我们都熟悉和喜爱的 Pandas DataFrame 的扩展,增加了对以表格格式处理地理空间数据的支持。通过这样做,OSMnx 还允许使用 GeoPandas 绘图工具对 OSM 街道网络进行快速简易的可视化,并提供额外的辅助函数以增加生成地图的自定义程度。
本教程的其余部分将通过代码示例,介绍使用 OSMnx 实现其中一些任务的示例。让我们从下载一些数据开始。
使用 OSMnx 下载街道网络
您可以通过 OSMnx 使用多种选项下载街道网络,例如地名、边界框、距某个经纬度点的距离或某个地址周围的半径。例如,让我们尝试获取旧金山和加利福尼亚州奥克兰的街道网络。
import osmnx as ox
cities = [
"San Francisco, California",
{
'city': 'Oakland',
'state': 'California',
'country': 'USA'
}
]
sf_oakland = ox.graph_from_place(cities, network_type='drive', simplify=True)
请注意,我们可以将地点指定为字符串(在旧金山的情况下)或指定区域更精确的字典(如我们对奥克兰所做)。如上例所示,我们也可以仅对单个地点或地点列表调用该函数。这就是我们刚刚下载的图的样子。
除了指定地点的字符串,我们还可以下载给定地址一定距离内所有街道的图。接下来,让我们尝试一下,拉取距离英国首相官邸唐宁街 10 号 2 公里内的所有道路。
downing = ox.graph_from_address("10 Downing Street, London, UK", dist=2000)
这就是这张图的样子
我们可以类似地使用多种类型的参数下载数据。有关所有可能选项的更多详细信息,请参阅osmnx.graph 模块的文档。
type(downing)
networkx.classes.multidigraph.MultiDiGraph
此外,请注意该图存储为 NetworkX MultiDiGraph,因此您在调用单个函数后,实际上可以直接进入项目的网络分析部分。这真是非常方便!
使用 OSMnx 绘制街道网络
到目前为止,我只向您展示了图的绘制,而没有解释它们是如何制作的。现在,让我们看看如何使用 OSMnx 绘制图。幸运的是,这就像调用一个函数一样简单
fig, ax = ox.plot_graph(downing, node_size=2, node_color='r', edge_color='w', edge_linewidth=0.2)
幸运的是,`ox.plot_graph` 函数的大多数参数都一目了然。让我们快速回顾一下它们
node_size
允许您指定图中节点的半径node_color
允许您指定图中节点的颜色edge_color
允许您指定图中边的颜色edge_linewidth
允许您指定图中表示边的线的宽度
这里有几点需要注意
- 上文中的“节点”指的是两条或多条街道的交叉点。
- 上文中的“边”指的是连接两个(或更多)交叉点的单一街道。
- OSMnx 在底层使用 GeoPandas 的绘图函数,而 GeoPandas 又基于 Matplotlib。因此,您可以对生成的图像使用许多您熟悉的 Matplotlib 操作。例如,fig.savefig("./my_network.png") 会将上述可视化保存为当前目录中的 PNG 文件。
- 由于我们使用的是 GeoPandas 的绘图工具,您可以看到边(道路)以其正确的地理空间形状表示,而不是如果我们使用 NetworkX 可视化图时会看到的直线。
转换为 GeoDataFrames
OSMnx 最好的优点之一是它能很好地融入现有的 Python GIS 生态系统,而无需重复造轮子。需要进行图分析?街道网络默认转换为 NetworkX 图,并可与该库一起使用。
需要以表格格式处理道路网络以进行更广泛的批量操作?GeoPandas 的 GeoDataFrame 来拯救您,并且在使用 OSMnx 时是一等公民。使用 OSMnx 将街道网络转换为表格格式就像一行代码一样简单,并将图分为两个数据帧,一个包含节点,一个包含边。
nodes, edges = ox.utils_graph.graph_to_gdfs(downing)
nodes.head()
是 | x | 街道数量 | 公路 | ref | 几何 | |
OSM ID | ||||||
101990 | 51.520573 | -0.147701 | 4 | NaN | NaN | 点 (-0.14770 51.52057) |
101992 | 51.521395 | -0.149695 | 4 | NaN | NaN | 点 (-0.14970 51.52139) |
101993 | 51.520316 | -0.149225 | 4 | NaN | NaN | 点 (-0.14923 51.52032) |
101995 | 51.519974 | -0.151786 | 3 | NaN | NaN | 点 (-0.15179 51.51997) |
101997 | 51.519093 | -0.148652 | 4 | NaN | NaN | 点 (-0.14865 51.51909) |
以表格格式处理这些数据对于大型数据清理操作来说非常方便。上面的节点数据帧包含节点的经度和纬度(x 和 y 列),而 geometry 列包含 Shapely 几何形状,其中包含所有相关的 GIS 映射信息。
edges.iloc[:, :4].head()
OSM ID | 单向 | 名称 | 公路 | |||
u | v | 键 | ||||
101990 | 330803151 | 0 | 17944925 | True | 威茅斯街 | 三级 |
101998 | 0 | 532636970 | True | 哈利街 | 三级 | |
101992 | 1667118178 | 0 | 615056689 | 假 | 德文郡街 | 未分类 |
101993 | 1685938630 | 0 | 17944925 | True | 威茅斯街 | 三级 |
101992 | 0 | 4254943 | True | 上温波尔街 | 三级 |
u 和 v 列分别表示边的源节点和目标节点。由于这是一个 MultiDiGraph,我们可以有具有相同 (u, v) 值的平行边,通过 key 进行消歧。其余列包含关于边的各种其他信息,例如街道名称、道路类型等。边数据帧也包含一个 geometry 列,其中包含关于边的相关 GIS 信息,但由于表格非常宽,此处已截断。
然后,您可以使用我们熟悉和喜爱的(有时也讨厌的)Pandas 语法进行选择的清理、过滤、分组和其他操作,然后再次用一行代码将网络转换回 MultiDiGraph。
downing = ox.utils_graph.graph_from_gdfs(nodes, edges)
现在我们已经可视化了街道网络并对网络进行了任意数量的数据操作,我们可以开始分析网络以解决我们最初的问题(例如路由或识别食物荒漠)。如前所述,OSMnx 是一个定位极佳的库,它不试图做其他包已经可以做的事情。
因此,鉴于对 NetworkX 图的本地支持,您很可能会将进一步的分析转移到 NetworkX 库及其为此目的专门设计的出色实用程序数组中。然而,OSMnx 确实带有一些用于分析网络的内置函数。让我们看一个使用 `basic_stats` 函数来检查此网络中连接到单个节点的平均街道数量的快速示例。
ox.basic_stats(downing)['streets_per_node_avg']
2.8493639608309693
结论
总而言之,OSMnx 可以通过下载、清理、可视化并将街道数据转换为可供分析的 NetworkX 图,从而显著简化街道网络分析问题的整个 ETL 过程。它只需几行代码即可完成此操作,从而为您节省潜在的数小时甚至数天的设置时间。它还与现有的 Python 生态系统完美契合,对 GeoPandas 提供出色的数据操作支持,对 NetworkX 提供网络分析支持,使 Python 中的街道网络分析尽可能地易于访问和顺畅。
本文最初作为客座投稿出现在ContentLab。