如何在NetworkX中根据边的出现频次设置边的厚度
解决NetworkX边厚度随出现频次调整的问题
问题背景
现有如下Pandas数据框:
student_id 0 1 2 3 4 5 6 7 8 9 10 11 12 0 131X1319 1 14 6 16 1 10 8 15 15 17 15 18 16 1 13212YX3 1 1 4 8 11 9 14 7 0 3 0 17 13 2 13216131 1 1 13 9 15 17 0 9 3 15 11 8 10 3 132921W6 1 14 10 4 18 7 8 15 15 17 15 18 16
需要用NetworkX构建有向图,要求边的厚度随该边在数据框中的出现频次增加(比如路径15->15->17->15->18->16出现两次,对应边厚度设为2)。当前已实现基础图绘制,但无法设置边厚度,代码如下:
columns=list(pattern_df.columns.values) pattern_g = nx.empty_graph(0, nx.DiGraph()) for i in range(len(columns)-1): pattern_g.add_edges_from(zip(pattern_df[columns[i]], pattern_df[columns[i+1]])) sum_val=pattern_df.sum(numeric_only=True, axis=0) values = [sum_val.get(node, 0.25) for node in pattern_g.nodes()] nx.draw(pattern_g, with_labels=True, font_color='black') plt.show()
解决方案
核心逻辑是先统计每条边的出现频次,再将频次映射为边的宽度参数传入绘图函数。
1. 统计边的出现频次
遍历数据框的每一行,提取连续列的节点对(即边),用collections.Counter统计每条边的出现次数:
from collections import Counter edge_counts = Counter() # 遍历每一行,提取连续节点对 for idx, row in pattern_df.iterrows(): # 跳过student_id列,提取数值节点序列 nodes = row.iloc[1:].tolist() # 生成连续边对 edges = list(zip(nodes[:-1], nodes[1:])) edge_counts.update(edges)
2. 构建带权重的有向图
基于统计结果构建图,给每条边添加weight属性存储频次:
pattern_g = nx.DiGraph() for edge, count in edge_counts.items(): pattern_g.add_edge(edge[0], edge[1], weight=count)
3. 绘制带厚度的图
使用nx.draw_networkx_edges单独绘制边,通过width参数传入边的频次(可乘以系数调整厚度比例),同时保留节点和标签的绘制逻辑:
# 节点大小沿用原有逻辑,乘以系数放大显示 sum_val = pattern_df.sum(numeric_only=True, axis=0) node_sizes = [sum_val.get(node, 0.25)*100 for node in pattern_g.nodes()] # 固定布局让图结构稳定 pos = nx.spring_layout(pattern_g, seed=42) # 绘制节点 nx.draw_networkx_nodes(pattern_g, pos, node_size=node_sizes, node_color='lightblue') # 绘制节点标签 nx.draw_networkx_labels(pattern_g, pos, font_color='black', font_weight='bold') # 绘制边,宽度设为频次的0.5倍(可按需调整) edge_widths = [pattern_g[u][v]['weight'] * 0.5 for u, v in pattern_g.edges()] nx.draw_networkx_edges(pattern_g, pos, width=edge_widths, arrowstyle='->', arrowsize=15) plt.axis('off') plt.show()
完整整合代码
from collections import Counter import pandas as pd import networkx as nx import matplotlib.pyplot as plt # 构造示例数据框 data = { 'student_id': ['131X1319', '13212YX3', '13216131', '132921W6'], 0: [1,1,1,1], 1: [14,1,1,14], 2: [6,4,13,10], 3: [16,8,9,4], 4: [1,11,15,18], 5: [10,9,17,7], 6: [8,14,0,8], 7: [15,7,9,15], 8: [15,0,3,15], 9: [17,3,15,17], 10: [15,0,11,15], 11: [18,17,8,18], 12: [16,13,10,16] } pattern_df = pd.DataFrame(data) # 统计边频次 edge_counts = Counter() for idx, row in pattern_df.iterrows(): nodes = row.iloc[1:].tolist() edges = list(zip(nodes[:-1], nodes[1:])) edge_counts.update(edges) # 构建带权重的图 pattern_g = nx.DiGraph() for edge, count in edge_counts.items(): pattern_g.add_edge(edge[0], edge[1], weight=count) # 计算节点大小 sum_val = pattern_df.sum(numeric_only=True, axis=0) node_sizes = [sum_val.get(node, 0.25)*100 for node in pattern_g.nodes()] # 绘图 pos = nx.spring_layout(pattern_g, seed=42) nx.draw_networkx_nodes(pattern_g, pos, node_size=node_sizes, node_color='lightblue') nx.draw_networkx_labels(pattern_g, pos, font_color='black', font_weight='bold') edge_widths = [pattern_g[u][v]['weight'] * 0.5 for u, v in pattern_g.edges()] nx.draw_networkx_edges(pattern_g, pos, width=edge_widths, arrowstyle='->', arrowsize=15) plt.axis('off') plt.show()
内容的提问来源于stack exchange,提问作者black street boy
相关产品推荐
相关产品推荐

