如何为OSMnx道路网络绘图中的Edges设置自定义z-order层级?
OSMnx道路网络图z-order层级自定义解决方案
问题背景
我用OSMnx绘制带颜色数据的道路网络图,示例通过颜色展示介数中心性,但遇到问题:z-order层级设置导致浅色边在节点密集的路口被其他边覆盖。
OSMnx的plot_graph方法会调用GeoPandas的gdf.plot,后者基于Pandas的PlotAccessor实现。查阅OSMnx文档后未找到传递z-order参数的方式,想请教能否通过GeoPandas、Pandas或Matplotlib直接绘图,为道路网络的Edges指定自定义z-order层级?
原代码示例:
import networkx as nx import osmnx as ox place = 'Hornsea' G = ox.graph_from_place(place, network_type="drive") # Digraph removes parallel edges # Line graph swaps nodes and edges line_graph = nx.line_graph(ox.get_digraph(G)) betweenness_centrality = nx.betweenness_centrality(line_graph, weight='travel_time') for edge in G.edges: if edge not in betweenness_centrality: nx.set_edge_attributes(G, {edge: 0}, 'betweenness_centrality') betweenness_centrality = {(k[0], k[1], 0): v for k, v in betweenness_centrality.items()} nx.set_edge_attributes(G, betweenness_centrality, "betweenness_centrality") ec = ox.plot.get_edge_colors_by_attr(G, 'betweenness_centrality', cmap='plasma') # "RdYlGn_r" ew = [G.get_edge_data(*edge).get('betweenness_centrality', 0) * 10 + 0.25 for edge in G.edges] fig, ax = ox.plot_graph(G, edge_color=ec, edge_linewidth=ew, node_size=0) fig.savefig(f"images/{place}_betweenness_centrality.png", facecolor="w", dpi=1000, bbox_inches="tight")
原效果示例:
解决方案
完全可以绕过OSMnx的plot_graph,直接用GeoPandas+Matplotlib手动绘图,实现自定义边的z-order层级。核心逻辑是将图的边转换为GeoDataFrame,为每条边设置z-order值(让优先级高的边绘制在顶层),再分层渲染。
实现步骤
- 将OSMnx图转换为边的GeoDataFrame,提取所有边数据
- 为边添加
zorder列,按介数中心性降序分配层级(值越大,绘制层级越高) - 用Matplotlib创建画布,调用GeoDataFrame的
plot方法,指定zorder参数
修改后的完整代码:
import networkx as nx import osmnx as ox import matplotlib.pyplot as plt place = 'Hornsea' G = ox.graph_from_place(place, network_type="drive") # 保留原介数中心性计算逻辑 line_graph = nx.line_graph(ox.get_digraph(G)) betweenness_centrality = nx.betweenness_centrality(line_graph, weight='travel_time') for edge in G.edges: if edge not in betweenness_centrality: nx.set_edge_attributes(G, {edge: 0}, 'betweenness_centrality') betweenness_centrality = {(k[0], k[1], 0): v for k, v in betweenness_centrality.items()} nx.set_edge_attributes(G, betweenness_centrality, "betweenness_centrality") # 转换为边的GeoDataFrame gdf_edges = ox.utils_graph.graph_to_gdfs(G, nodes=False, edges=True) # 按介数中心性降序设置z-order:值越高的边,zorder越大,绘制在最上层 gdf_edges['zorder'] = gdf_edges['betweenness_centrality'].rank(ascending=False) # 生成颜色和线宽数据 gdf_edges['edge_color'] = ox.plot.get_edge_colors_by_attr(G, 'betweenness_centrality', cmap='plasma') gdf_edges['edge_width'] = gdf_edges['betweenness_centrality'] * 10 + 0.25 # 手动绘图控制层级 fig, ax = plt.subplots(figsize=(10, 10)) # 绘制边时指定zorder参数 gdf_edges.plot( ax=ax, color=gdf_edges['edge_color'], linewidth=gdf_edges['edge_width'], zorder=gdf_edges['zorder'] ) # 隐藏坐标轴 ax.set_axis_off() # 保存图片 fig.savefig(f"images/{place}_betweenness_centrality.png", facecolor="w", dpi=1000, bbox_inches="tight") plt.close()
关键说明
- 直接使用GeoDataFrame绘图时,
zorder参数可直接传入plot方法,完全控制图层顺序 - 示例中用
rank(ascending=False)让介数中心性最高的边获得最大z-order,确保重要的深色/宽边不会被浅色边覆盖 - 若需按其他规则设置层级(如道路等级),只需修改
zorder列的计算逻辑即可,比如用gdf_edges['highway'].map({'motorway':5, 'primary':4, 'secondary':3})来定义层级
内容的提问来源于stack exchange,提问作者George Willcox
相关产品推荐
相关产品推荐

