)
用PythonNetworkX打造专业级地铁网络可视化从数据处理到交互式图表地铁网络可视化是城市交通数据分析中的重要环节。想象一下当你面对一份包含81个地铁站点连接关系的CSV文件时如何快速理解这个复杂的网络结构本文将带你用Python的NetworkX库从零开始构建一个专业级的地铁网络可视化方案。1. 环境准备与数据加载在开始之前确保你的Python环境已经安装了必要的库。推荐使用conda或pip安装以下依赖pip install pandas networkx matplotlib numpy假设我们有一个名为Metro_roadMap.csv的文件其内容是一个81×81的邻接矩阵表示地铁站点之间的连接关系。让我们先加载这个数据import pandas as pd # 读取CSV文件注意编码问题 file_path Metro_roadMap.csv df pd.read_csv(file_path, index_col0, encodinggb2312) # 查看前5行和前5列 print(df.iloc[:5, :5])这个邻接矩阵的特点是行和列都代表地铁站ID值为1表示两个站点直接相连值为0表示不相连2. 构建网络图结构有了邻接矩阵我们可以使用NetworkX来构建图结构。NetworkX提供了多种图类型这里我们选择无向图Graph因为地铁连接是双向的。import networkx as nx # 创建空的无向图 G nx.Graph() # 添加节点 nodes list(df.index) G.add_nodes_from(nodes) # 添加边 for i, node_i in enumerate(nodes): for j, node_j in enumerate(nodes): if df.iloc[i, j] 1 and i j: # 避免重复添加边 G.add_edge(node_i, node_j) # 检查图的基本信息 print(f节点数: {G.number_of_nodes()}) print(f边数: {G.number_of_edges()})3. 基础可视化让我们先用matplotlib做一个基础的可视化import matplotlib.pyplot as plt plt.figure(figsize(12, 12)) pos nx.spring_layout(G) # 使用弹簧布局 nx.draw(G, pos, with_labelsTrue, node_size300, font_size8) plt.title(Basic Metro Network Visualization) plt.show()这个基础版本虽然能显示网络结构但存在几个问题节点标签重叠严重不同线路没有区分布局不够美观4. 高级可视化技巧4.1 线路分类与着色假设我们有3条地铁线路每条线路包含特定的站点ID范围# 定义线路分类 line_1 set(range(0, 34)) # 假设线路1包含站点0-33 line_2 set(range(34, 67)) # 线路2包含站点34-66 line_3 set(range(67, 81)) # 线路3包含站点67-80 # 分类节点 nodes_1 [node for node in nodes if node in line_1] nodes_2 [node for node in nodes if node in line_2] nodes_3 [node for node in nodes if node in line_3]4.2 优化布局与可视化plt.figure(figsize(15, 15)) # 使用Kamada-Kawai布局更适合地铁网络 pos nx.kamada_kawai_layout(G) # 绘制不同线路的节点 nx.draw_networkx_nodes(G, pos, nodelistnodes_1, node_size400, node_color#1f77b4, labelLine 1) nx.draw_networkx_nodes(G, pos, nodelistnodes_2, node_size400, node_color#ff7f0e, labelLine 2) nx.draw_networkx_nodes(G, pos, nodelistnodes_3, node_size400, node_color#2ca02c, labelLine 3) # 绘制边 nx.draw_networkx_edges(G, pos, width1.5, edge_colorgray, alpha0.7) # 绘制标签 - 只显示主要站点避免拥挤 important_nodes [0, 20, 40, 60, 80] # 示例重要节点 labels {node: fS{node} for node in important_nodes} nx.draw_networkx_labels(G, pos, labels, font_size10, font_weightbold) # 添加图例和标题 plt.legend(scatterpoints1, fontsize12) plt.title(Metro Network Visualization with Line Classification, fontsize14) plt.axis(off) plt.tight_layout() plt.show()4.3 可视化优化技巧布局算法选择spring_layout: 默认布局适合小型网络kamada_kawai_layout: 更适合地铁网络这种有明确物理意义的图spectral_layout: 基于图拉普拉斯矩阵适合社区结构明显的网络节点大小与颜色可以根据站点客流量设置节点大小使用颜色区分不同线路或功能区标签显示策略只显示重要节点标签调整字体大小和位置避免重叠5. 交互式可视化静态图像有时难以全面展示复杂网络。我们可以使用pyvis库创建交互式可视化from pyvis.network import Network # 创建pyvis网络 net Network(notebookTrue, height750px, width100%) # 添加节点和边 for node in G.nodes(): if node in line_1: color #1f77b4 elif node in line_2: color #ff7f0e else: color #2ca02c net.add_node(node, labelfS{node}, colorcolor, size15) for edge in G.edges(): net.add_edge(edge[0], edge[1], width1) # 设置物理布局 net.set_options( { physics: { barnesHut: { gravitationalConstant: -80000, centralGravity: 0.3, springLength: 200, springConstant: 0.04, damping: 0.09, avoidOverlap: 0.1 }, minVelocity: 0.75 } } ) # 保存为HTML文件 net.show(metro_network.html)这个交互式可视化允许用户拖动节点调整布局点击节点查看详细信息缩放和平移视图动态调整物理模拟参数6. 进阶应用网络分析可视化只是第一步我们还可以对地铁网络进行各种分析6.1 计算网络中心性指标# 度中心性 degree_centrality nx.degree_centrality(G) # 接近中心性 closeness_centrality nx.closeness_centrality(G) # 中介中心性 betweenness_centrality nx.betweenness_centrality(G) # 创建DataFrame展示结果 centrality_df pd.DataFrame({ Degree: degree_centrality, Closeness: closeness_centrality, Betweenness: betweenness_centrality }).sort_values(Betweenness, ascendingFalse) print(centrality_df.head(10))6.2 识别关键枢纽站点# 找出中介中心性最高的5个站点 top_hubs centrality_df.nlargest(5, Betweenness).index.tolist() # 在可视化中突出显示这些枢纽 plt.figure(figsize(15, 15)) pos nx.kamada_kawai_layout(G) # 绘制节点 (省略部分代码...) # 突出显示枢纽节点 nx.draw_networkx_nodes(G, pos, nodelisttop_hubs, node_size800, node_colorgold, edgecolorsblack, linewidths2) plt.title(Metro Network with Key Hubs Highlighted, fontsize14) plt.show()6.3 社区检测from networkx.algorithms import community # 使用Louvain算法检测社区 communities community.louvain_communities(G, resolution1.0) # 为每个节点分配社区ID community_dict {} for i, comm in enumerate(communities): for node in comm: community_dict[node] i # 可视化社区结构 plt.figure(figsize(15, 15)) pos nx.kamada_kawai_layout(G) # 为每个社区使用不同颜色 colors plt.cm.tab20(range(len(communities))) for i, comm in enumerate(communities): nx.draw_networkx_nodes(G, pos, nodelistlist(comm), node_size400, node_color[colors[i]], labelfCommunity {i1}) nx.draw_networkx_edges(G, pos, width1.5, edge_colorgray, alpha0.5) plt.legend(scatterpoints1) plt.title(Metro Network Community Detection, fontsize14) plt.show()7. 性能优化与大规模网络处理当地铁网络规模很大时如超过1000个节点可视化可能会变得缓慢。以下是一些优化技巧使用更高效的布局算法# 多线程布局计算 pos nx.multipartite_layout(G) # 对于分层网络特别有效简化可视化元素减少显示的节点标签数量使用更简单的节点形状降低边的透明度采样和过滤# 只显示度大于2的节点至少连接两个其他站点 important_nodes [n for n in G.nodes() if G.degree(n) 2] H G.subgraph(important_nodes)使用专业可视化工具GephiCytoscapeGraph-tool8. 完整代码示例以下是整合了所有功能的完整代码示例import pandas as pd import networkx as nx import matplotlib.pyplot as plt from pyvis.network import Network from networkx.algorithms import community # 1. 数据加载 df pd.read_csv(Metro_roadMap.csv, index_col0, encodinggb2312) # 2. 构建图结构 G nx.Graph() nodes list(df.index) G.add_nodes_from(nodes) for i, node_i in enumerate(nodes): for j, node_j in enumerate(nodes): if df.iloc[i, j] 1 and i j: G.add_edge(node_i, node_j) # 3. 线路分类 line_1 set(range(0, 34)) line_2 set(range(34, 67)) line_3 set(range(67, 81)) nodes_1 [node for node in nodes if node in line_1] nodes_2 [node for node in nodes if node in line_2] nodes_3 [node for node in nodes if node in line_3] # 4. 静态可视化 plt.figure(figsize(15, 15)) pos nx.kamada_kawai_layout(G) nx.draw_networkx_nodes(G, pos, nodelistnodes_1, node_size400, node_color#1f77b4, labelLine 1) nx.draw_networkx_nodes(G, pos, nodelistnodes_2, node_size400, node_color#ff7f0e, labelLine 2) nx.draw_networkx_nodes(G, pos, nodelistnodes_3, node_size400, node_color#2ca02c, labelLine 3) nx.draw_networkx_edges(G, pos, width1.5, edge_colorgray, alpha0.7) important_nodes [0, 20, 40, 60, 80] labels {node: fS{node} for node in important_nodes} nx.draw_networkx_labels(G, pos, labels, font_size10, font_weightbold) plt.legend(scatterpoints1, fontsize12) plt.title(Professional Metro Network Visualization, fontsize14) plt.axis(off) plt.tight_layout() plt.savefig(metro_network.png, dpi300) plt.show() # 5. 交互式可视化 net Network(notebookTrue, height750px, width100%) for node in G.nodes(): if node in line_1: color #1f77b4 elif node in line_2: color #ff7f0e else: color #2ca02c net.add_node(node, labelfS{node}, colorcolor, size15) for edge in G.edges(): net.add_edge(edge[0], edge[1], width1) net.set_options( { physics: { barnesHut: { gravitationalConstant: -80000, centralGravity: 0.3, springLength: 200, springConstant: 0.04, damping: 0.09, avoidOverlap: 0.1 }, minVelocity: 0.75 } } ) net.show(metro_network_interactive.html) # 6. 网络分析 # 中心性分析 degree_centrality nx.degree_centrality(G) closeness_centrality nx.closeness_centrality(G) betweenness_centrality nx.betweenness_centrality(G) centrality_df pd.DataFrame({ Degree: degree_centrality, Closeness: closeness_centrality, Betweenness: betweenness_centrality }).sort_values(Betweenness, ascendingFalse) # 社区检测 communities community.louvain_communities(G, resolution1.0) community_dict {node: i for i, comm in enumerate(communities) for node in comm} # 保存分析结果 centrality_df.to_csv(metro_centrality_analysis.csv) pd.Series(community_dict).to_csv(metro_communities.csv)