OSMnx 路径规划:下载城市路网与计算最短路径
使用 OSMnx 进行路径规划:下载城市路网与计算最短路径
什么是 OSMnx?
OSMnx 是一个 Python 库,用于从 OpenStreetMap 下载、建模、分析和可视化真实世界的街道网络。它把地理空间数据转化为可计算的有向图,让路径规划、网络分析变得异常简单。你只需要几行代码,就可以拿到任意城市的路网,并利用图算法(如 Dijkstra 或 A*)找到两点之间的最短路径。
本教程的目标:教你如何用 OSMnx 下载一个城市的步行、骑行或驾车路网,并在该网络中计算任意起点和终点的最短路径,最后将结果可视化。
前置准备与安装
开始之前,请确保你的 Python 环境中安装了 OSMnx。推荐使用 conda 来创建隔离环境,避免地理库的依赖冲突。
conda create -n oxenv python=3.10
conda activate oxenv
conda install -c conda-forge osmnx
主要依赖会自动安装,包括 NetworkX、GeoPandas、Matplotlib 等。安装完成后,在 Jupyter Notebook 或 Python 脚本中导入库:
import osmnx as ox
import networkx as nx
import matplotlib.pyplot as plt
第一步:下载城市路网
OSMnx 提供了多种方式去获取街道网络。最常用的是 graph_from_place 函数,它接受一个地名字符串(如 "北京, 中国")或者地理边界框(经纬度),返回一个 NetworkX 的有向多重图 MultiDiGraph。
下载一个城市的驾车路网(默认 network_type='drive'):
# 下载上海部分区域的路网(为了快速演示,使用行政区划的查询)
G = ox.graph_from_place('徐汇区, 上海, 中国', network_type='drive')
network_type 参数控制下载哪种类型的道路:
'drive'– 可以驾车的道路'walk'– 所有可以步行的路径(含步道)'bike'– 允许骑行的路网'all'– 所有可能通行的路径
如果你想下载整个城市,直接传入 '北京市, 中国' 即可,但注意数据量可能较大,建议先从区级边界开始。
按经纬度边界框下载 更加精确:
north, south, east, west = 31.23, 31.18, 121.50, 121.42
G = ox.graph_from_bbox(north, south, east, west, network_type='walk')
graph_from_bbox 接受四点坐标(北、南、东、西),返回该矩形区域内的步行网络。
第二步:将路网图投影到平面坐标
下载的路网默认使用 WGS84 经纬度坐标(单位为度),要计算准确的距离和最短路径,需要把图投影到合理的平面坐标系(单位为米)。使用 OSMnx 的自动投影功能:
G_proj = ox.project_graph(G)
这会根据图的中心位置自动选择一个合适的 UTM 投影带,将所有节点的坐标转换为米的单位。
第三步:获取起点和终点的最近节点
路径规划需要起点和终点的图节点。假设我们有两个地理坐标点,我们需要找到路网中离它们最近的节点:
# 起点(徐家汇地铁站附近)和终点(上海体育场附近)
orig_point = (31.1957, 121.4374) # (纬度, 经度)
dest_point = (31.1821, 121.4439)
# 找到投影路网中最近节点
orig_node = ox.nearest_nodes(G_proj, X=orig_point[1], Y=orig_point[0])
dest_node = ox.nearest_nodes(G_proj, X=dest_point[1], Y=dest_point[0])
nearest_nodes 接受投影后的 X、Y 坐标(经度在前)。函数内部使用 KDTree 高效搜索最近节点。
第四步:计算最短路径
NetworkX 提供了内置的最短路径算法,OSMnx 封装了路由方法 shortest_path,它会考虑边的长度(单位为米)作为权重。
# 计算最短路径(默认使用长度作为权重)
route = ox.shortest_path(G_proj, orig_node, dest_node, weight='length')
# 查看路径节点序列
print(route[:10]) # 打印前10个节点ID
如果需要避开某类道路或考虑实时交通,目前版本 OSMnx 本身不处理实时流量,但可以通过给边赋自定义权重曲线实现。对于基础教程,weight='length' 就能给出几何意义上的最短路径。
第五步:可视化路径与路网
得到路径节点后,OSMnx 提供了便捷的绘图函数,将路线叠加在地图上。
使用 Matplotlib 静态可视化:
fig, ax = ox.plot_graph_route(G_proj, route, node_size=0,
bgcolor='w', edge_color='#999999',
route_color='#e31a1c', route_linewidth=4,
edge_linewidth=0.5)
plt.show()
G_proj是投影路网route是节点序列- 将背景道路设成灰色
#999999,路径用红色高亮
交互式地图(使用 Folium):
# 注意:需要将 G 保留为未投影的经纬度图,或使用 G 原始图
G_wgs = ox.project_graph(G, to_crs='EPSG:4326') # 转回经纬度
route_map = ox.plot_route_folium(G_wgs, route, tiles='cartodbpositron')
route_map.save('route_map.html')
这会生成一个可交互的 HTML 地图,可以缩放查看路线细节。
进阶技巧:考虑速度与时间的最短路径
默认最短路径是几何距离最短,你也可以使用 travel_time 作为权重,这需要先为每条边估算行程时间。OSMnx 提供了添加速度和时间属性的功能:
# 为驾车网络添加默认速度限制并计算行程时间
G_time = ox.add_edge_speeds(G_proj)
G_time = ox.add_edge_travel_times(G_time)
route_by_time = ox.shortest_path(G_time, orig_node, dest_node, weight='travel_time')
之后可以对比两种路线的差异。
实战:完整示例脚本
以下是一个完整的可运行脚本,它下载徐汇区步行网络,计算两个地标间最短步行路径并显示。
import osmnx as ox
import matplotlib.pyplot as plt
# 1. 下载步行网络
G = ox.graph_from_place('徐汇区, 上海, 中国', network_type='walk')
# 2. 投影
G_proj = ox.project_graph(G)
# 3. 定义起终点坐标
orig_lat, orig_lon = 31.1957, 121.4374
dest_lat, dest_lon = 31.1821, 121.4439
# 4. 最近节点
orig_node = ox.nearest_nodes(G_proj, orig_lon, orig_lat)
dest_node = ox.nearest_nodes(G_proj, dest_lon, dest_lat)
# 5. 最短路径
route = ox.shortest_path(G_proj, orig_node, dest_node, weight='length')
# 6. 绘图
fig, ax = ox.plot_graph_route(G_proj, route, node_size=0,
bgcolor='w', edge_color='#aaaaaa',
route_color='#d73027', route_linewidth=5)
plt.show()
常见问题与故障排查
- 下载路网时报错
insufficient response:地区范围太大或者网络请求超时。尝试缩小查询范围,或用ox.geocode_to_gdf获取更小的行政边界来构建图。 - 找不到最近节点返回
ValueError:检查坐标顺序,nearest_nodes需要经度在前,纬度在后;并且确保坐标位于路网覆盖范围内。 - 投影后距离计算异常:确保在下载后对图进行投影,否则
length属性是以度数计算,毫无意义。
小结
你现在已经掌握了 OSMnx 路径规划的核心流程:下载指定城市的路网 → 投影坐标 → 定位最近节点 → 计算最短路径 → 可视化。这套流程适用于任意城市,并且只需更换 network_type 就可以切换驾车、步行或骑行模式。下一步可以尝试为多点路线、循环路线或者网络属性分析(如计算任意两点的可达性)扩展此基础模板。