用Python玩转城市路网:OSMnx一键下载北京/上海街道数据并可视化分析(附完整代码)

用Python玩转城市路网:OSMnx一键下载北京/上海街道数据并可视化分析(附完整代码) 用Python玩转城市路网OSMnx一键下载北京/上海街道数据并可视化分析附完整代码当你在深夜打开导航软件看着那些闪烁的路线和拥堵提示是否好奇这些数据背后的秘密城市路网就像人体的血管系统承载着整个城市的活力与脉搏。而今天我们将用Python这把手术刀解剖北京、上海这样超级城市的道路网络揭示那些隐藏在数据中的城市密码。对于城市规划师、交通工程师或是数据科学爱好者来说获取和分析城市路网数据曾是一项耗时费力的工作。但有了OSMnx这个Python神器我们只需几行代码就能下载完整的街道数据并进行专业的网络分析和可视化。本文将带你从零开始掌握这套高效的工作流无论是学术研究还是商业分析都能游刃有余。1. 环境准备与OSMnx基础在开始我们的城市探险之前需要确保工具包准备就绪。OSMnx建立在几个强大的Python库之上包括NetworkX用于网络分析GeoPandas处理地理数据以及Matplotlib进行可视化。安装依赖库推荐使用conda环境conda create -n street_analysis python3.9 conda activate street_analysis conda install -c conda-forge osmnx geopandas matplotlib foliumOSMnx的核心优势在于它简化了从OpenStreetMap获取数据的流程。不同于传统GIS软件需要手动下载和处理数据OSMnx提供了直观的Python接口。例如获取北京市中心区域的路网只需一行代码import osmnx as ox beijing_graph ox.graph_from_place(北京市, 中国, network_typedrive)提示network_type参数支持drive(机动车)、walk(步行)、bike(骑行)三种模式对应不同的路网筛选条件。OSMnx下载的数据会自动转换为NetworkX的图结构同时保留完整的几何信息和属性表。我们可以用以下方法快速查看数据摘要ox.basic_stats(beijing_graph)典型输出结果可能包括指标数值说明节点数12,345交叉口或道路端点边数23,456道路段数量平均度3.8每个节点连接的道路数街道总长1,234 km路网总长度2. 高级数据获取与预处理实际分析中我们往往需要更精确地控制下载区域和数据类型。OSMnx提供了多种灵活的数据获取方式2.1 按行政区划获取# 获取上海市黄浦区路网 huangpu ox.graph_from_place(黄浦区, 上海市, 中国, network_typewalk)2.2 按地理边界框获取# 北京五环范围(近似) north, south, east, west 40.02, 39.87, 116.47, 116.25 wuhuan ox.graph_from_bbox(north, south, east, west, network_typedrive)2.3 按点半径范围获取# 以上海人民广场为中心3公里半径 renmin_square ox.graph_from_point((31.2304, 121.4737), dist3000)获取原始数据后通常需要进行清洗和处理# 清理孤立节点和重复边 cleaned_graph ox.consolidate_intersections( wuhuan, tolerance15, # 合并15米内的交叉口 rebuild_graphTrue ) # 计算街道长度并添加为边属性 wuhuan ox.add_edge_lengths(wuhuan)对于大型城市下载和处理可能耗时较长建议将处理好的数据保存# 保存为GraphML格式保留所有属性 ox.save_graphml(wuhuan, beijing_wuhuan.graphml) # 也可导出为GIS标准格式 ox.io.save_graph_shapefile(wuhuan, filepath./beijing_roads)3. 路网分析与指标计算有了干净的路网数据我们就可以进行各种专业分析了。NetworkX提供了丰富的图论算法实现结合OSMnx的扩展功能能计算出许多有实际意义的城市指标。3.1 连通性分析import networkx as nx # 检查是否为连通图 is_connected nx.is_strongly_connected(wuhuan) print(f路网是否强连通: {is_connected}) # 如果不连通获取最大连通子图 largest_cc max(nx.strongly_connected_components(wuhuan), keylen) main_graph wuhuan.subgraph(largest_cc)3.2 中心性指标计算中心性指标能识别路网中的关键节点对交通规划尤为重要# 计算接近中心性 closeness nx.closeness_centrality(main_graph, distancelength) # 计算介数中心性 betweenness nx.betweenness_centrality(main_graph, weightlength) # 将结果添加到节点属性 nx.set_node_attributes(main_graph, closeness, closeness) nx.set_node_attributes(main_graph, betweenness, betweenness)3.3 街道方向分析城市街道的走向往往反映了规划的特点# 计算所有街道的方位角 bearings ox.bearing.calculate_bearing( ox.utils_graph.graph_to_gdfs(main_graph, nodesFalse) ) # 生成极坐标直方图 fig, ax ox.bearing.plot_orientation( main_graph, title北京市五环内街道方向分布, color#003366, showFalse ) ax.set_theta_zero_location(N) # 北方为0度 ax.set_theta_direction(-1) # 顺时针方向典型城市可能呈现以下方向模式网格状规划城市如纽约在0°、90°方向有明显峰值有机生长城市如伦敦分布相对均匀混合型城市如北京主方向明显但分布较广4. 高级可视化技巧静态图表难以展现复杂的地理数据我们需要更丰富的可视化手段。4.1 带热力图的静态可视化# 创建Figure和Axes对象 fig, ax ox.plot_graph( main_graph, node_size0, # 不显示节点 edge_linewidth0.5, showFalse, closeFalse ) # 提取节点位置和中心性值 nodes ox.utils_graph.graph_to_gdfs(main_graph, edgesFalse) sc ax.scatter( nodes.x, nodes.y, cnodes[betweenness], s5, cmapplasma, alpha0.7, zorder3 ) # 添加颜色条 cbar fig.colorbar(sc, axax, shrink0.5) cbar.set_label(介数中心性)4.2 交互式地图使用Folium创建可缩放的交互地图import folium # 计算图的地理中心 center ox.utils_geo.graph_to_gdfs(main_graph, edgesFalse).unary_union.centroid m folium.Map(location[center.y, center.x], zoom_start13) # 添加路网 ox.folium.plot_graph_folium(main_graph, graph_mapm, colorgray, weight1) # 添加中心性热力图 points ox.utils_geo.graph_to_gdfs(main_graph, edgesFalse) for _, row in points.iterrows(): folium.CircleMarker( location(row.y, row.x), radius2, colorNone, fillTrue, fill_colorred, fill_opacityrow[betweenness]*10, popupf介数中心性: {row[betweenness]:.4f} ).add_to(m) # 保存为HTML m.save(beijing_road_analysis.html)4.3 3D可视化使用PyVista创建三维效果import pyvista as pv from pyvista import examples # 将路网转换为3D线条 edges ox.utils_graph.graph_to_gdfs(main_graph, nodesFalse) plotter pv.Plotter() for _, edge in edges.iterrows(): line pv.Line( pointa(edge.geometry.coords[0][0], edge.geometry.coords[0][1], 0), pointb(edge.geometry.coords[-1][0], edge.geometry.coords[-1][1], 0) ) plotter.add_mesh(line, colorwhite, line_width0.3) # 添加地形背景示例 dem examples.download_crater_topo() plotter.add_mesh(dem, cmapgist_earth) plotter.show()5. 实际应用案例北京vs上海路网对比让我们通过一个完整案例对比两个超级城市的路网特征。5.1 数据获取与清洗# 下载数据 shanghai ox.graph_from_place(上海市中心, 上海市, 中国, network_typedrive) beijing ox.graph_from_place(北京市中心, 北京市, 中国, network_typedrive) # 标准化处理 def standardize_graph(G): G ox.add_edge_lengths(G) G ox.add_edge_speeds(G) # 添加默认速度 G ox.add_edge_travel_times(G) # 计算行程时间 return ox.consolidate_intersections(G, tolerance20) shanghai standardize_graph(shanghai) beijing standardize_graph(beijing)5.2 基础指标对比# 计算统计指标 sh_stats ox.basic_stats(shanghai) bj_stats ox.basic_stats(beijing) # 创建对比表格 comparison { 指标: [节点数, 边数, 平均节点度, 街道总长(km), 平均街道长度(m)], 上海: [ sh_stats[n], sh_stats[m], round(sh_stats[average_degree], 2), round(sh_stats[street_length_total]/1000, 1), round(sh_stats[street_length_avg], 1) ], 北京: [ bj_stats[n], bj_stats[m], round(bj_stats[average_degree], 2), round(bj_stats[street_length_total]/1000, 1), round(bj_stats[street_length_avg], 1) ] } # 使用Pandas显示美观表格 import pandas as pd pd.DataFrame(comparison).set_index(指标)5.3 拓扑结构差异绘制两个城市的街道方向分布import matplotlib.pyplot as plt fig, (ax1, ax2) plt.subplots(1, 2, figsize(12, 5), subplot_kw{polar: True}) # 上海 ox.bearing.plot_orientation( shanghai, axax1, title上海市中心街道方向, color#e63946, showFalse ) # 北京 ox.bearing.plot_orientation( beijing, axax2, title北京市中心街道方向, color#457b9d, showFalse ) plt.tight_layout()从方向分布图中我们通常可以发现上海由于历史原因中心城区呈现更有机的放射状模式北京受传统城市规划影响东西-南北走向更为明显5.4 可达性分析计算从中心点到周边区域的行程时间# 选择中心点上海人民广场和北京天安门 sh_center ox.distance.nearest_nodes(shanghai, 121.4737, 31.2304) bj_center ox.distance.nearest_nodes(beijing, 116.3974, 39.9087) # 计算等时圈 def calculate_isochrones(G, center, trip_times[5,10,15]): isochrones [] for time in sorted(trip_times, reverseTrue): subgraph nx.ego_graph( G, center, radiustime*60, # 转换为秒 distancetravel_time ) isochrones.append(subgraph) return isochrones sh_isochrones calculate_isochrones(shanghai, sh_center) bj_isochrones calculate_isochrones(beijing, bj_center)可视化等时圈# 创建底图 sh_map ox.plot_graph(shanghai, showFalse, closeFalse, node_size0) bj_map ox.plot_graph(beijing, showFalse, closeFalse, node_size0) # 绘制等时圈 colors [#ff0000, #ff9900, #ffff00] for i, (sh_subg, bj_subg) in enumerate(zip(sh_isochrones, bj_isochrones)): # 上海 sh_nodes ox.utils_graph.graph_to_gdfs(sh_subg, edgesFalse) sh_map.scatter( sh_nodes.x, sh_nodes.y, colorcolors[i], s3, labelf{5*(i1)}分钟可达 ) # 北京 bj_nodes ox.utils_graph.graph_to_gdfs(bj_subg, edgesFalse) bj_map.scatter( bj_nodes.x, bj_nodes.y, colorcolors[i], s3, labelf{5*(i1)}分钟可达 ) sh_map.legend() bj_map.legend()这种分析可以直观展示不同城市的交通效率为商业选址、公共服务设施规划等提供参考。