如何用NetworkX绘制带权双向多重图?解决边双向性与不显示问题
问题解决步骤
1. 替换图类型以支持多边
NetworkX的普通DiGraph/Graph不支持平行边(同一节点对的多条边),会自动覆盖重复边,所以必须改用MultiDiGraph(支持有向多边)或MultiGraph(支持无向多边),才能保存并显示多条边。
2. 满足节点边数要求
按照需求给节点1与2、1与3添加至少3条边:
- 无向图:直接给节点对
(1,2)、(1,3)各加3条边 - 双向有向图:给
(1,2)和(2,1)、(1,3)和(3,1)各加3条边
3. 调整绘制逻辑避免多边重叠
给同节点对的每条边分配不同弧度,让它们分散显示,不会重叠在一起。
完整修正代码
方案一:无向多边图(MultiGraph)
import networkx as nx import matplotlib.pyplot as plt # 使用支持多边的无向图结构 G = nx.MultiGraph() # 给1-2、1-3各添加3条带权重的边 edge_list = [ (1, 2, {'w': 'A1'}), (1, 2, {'w': 'A2'}), (1, 2, {'w': 'A3'}), (1, 3, {'w': 'B1'}), (1, 3, {'w': 'B2'}), (1, 3, {'w': 'B3'}) ] G.add_edges_from(edge_list) # 固定布局种子保证节点位置一致 pos = nx.spring_layout(G, seed=5) fig, ax = plt.subplots() # 绘制节点和标签 nx.draw_networkx_nodes(G, pos, ax=ax) nx.draw_networkx_labels(G, pos, ax=ax) # 分组处理同节点对的多边,分配不同弧度 edge_groups = {} for u, v, key in G.edges(keys=True): # 无向图中(u,v)和(v,u)是同一组 group_key = tuple(sorted((u, v))) if group_key not in edge_groups: edge_groups[group_key] = [] edge_groups[group_key].append((u, v, key)) for group, edges in edge_groups.items(): num_edges = len(edges) # 给每条边分配从-0.3到0.3的分散弧度 rads = [i * 0.6 / (num_edges - 1) - 0.3 for i in range(num_edges)] for i, (u_e, v_e, key) in enumerate(edges): nx.draw_networkx_edges( G, pos, ax=ax, edgelist=[(u_e, v_e)], connectionstyle=f'arc3, rad={rads[i]}' ) # 绘制边权重标签 nx.draw_networkx_edge_labels(G, pos, edge_labels={(u, v, key): d['w'] for u, v, key, d in G.edges(data=True, keys=True)}) plt.show()
方案二:双向有向多边图(MultiDiGraph)
import networkx as nx import matplotlib.pyplot as plt # 使用支持多边的有向图结构 G = nx.MultiDiGraph() # 给1→2、2→1、1→3、3→1各添加3条带权重的边 edge_list = [ (1, 2, {'w': 'A1'}), (1, 2, {'w': 'A2'}), (1, 2, {'w': 'A3'}), (2, 1, {'w': 'A4'}), (2, 1, {'w': 'A5'}), (2, 1, {'w': 'A6'}), (1, 3, {'w': 'B1'}), (1, 3, {'w': 'B2'}), (1, 3, {'w': 'B3'}), (3, 1, {'w': 'B4'}), (3, 1, {'w': 'B5'}), (3, 1, {'w': 'B6'}) ] G.add_edges_from(edge_list) pos = nx.spring_layout(G, seed=5) fig, ax = plt.subplots() # 绘制节点和标签 nx.draw_networkx_nodes(G, pos, ax=ax) nx.draw_networkx_labels(G, pos, ax=ax) # 处理同方向多边的弧度,反向边用负弧度避免重叠 edge_pairs = {} for u, v, key in G.edges(keys=True): if (u, v) not in edge_pairs: edge_pairs[(u, v)] = [] edge_pairs[(u, v)].append((u, v, key)) for (u, v), edges in edge_pairs.items(): num_edges = len(edges) rads = [i * 0.2 for i in range(num_edges)] # 反向边用负弧度,和正向边区分开 if (v, u) in edge_pairs: rads = [-r for r in rads] for i, (u_e, v_e, key) in enumerate(edges): nx.draw_networkx_edges( G, pos, ax=ax, edgelist=[(u_e, v_e)], connectionstyle=f'arc3, rad={rads[i]}', arrowstyle='->' ) # 绘制边权重标签 nx.draw_networkx_edge_labels(G, pos, edge_labels={(u, v, key): d['w'] for u, v, key, d in G.edges(data=True, keys=True)}) plt.show()
关键问题说明
- 多边不显示的根源:原代码使用的
DiGraph不支持平行边,重复添加的边会被覆盖,改用MultiDiGraph/MultiGraph才能存储多条边。 - 双向/无向实现:无向图直接用
MultiGraph,所有边默认双向;如果需要明确的双向有向边,用MultiDiGraph并给每个方向都添加足够数量的边。 - 多边可视化:通过给每条同节点对的边分配不同弧度,避免重叠,确保所有边都能被看到。
内容的提问来源于stack exchange,提问作者Curious
相关产品推荐
相关产品推荐

