使用Networkx绘制图时为指定边添加方向箭头
为NetworkX无向图指定边添加箭头的实现方案
完全可以实现仅为Edges列表内特定边添加箭头的效果,不需要将整图转换为有向图,拆分边的绘制逻辑即可达成目标。
核心实现逻辑
nx.draw_networkx_edges方法原生支持箭头显示控制:
- 传入
arrows=True即可为当前批次绘制的边添加方向箭头 - 箭头方向由边元组的顺序决定:元组
(u, v)代表箭头从节点u指向节点v - 可通过
arrowsize、arrowstyle参数调整箭头大小、样式,和边宽、配色效果适配 - 将需要加箭头的边、不需要加箭头的边分两个批次调用绘制方法,即可实现仅部分边带箭头的效果
注意:无向图的边是无序存储的,如果边列表内的元组顺序和你定义的带箭头边元组顺序不一致(比如边存为(3,1),要添加的箭头方向为1→3),匹配时可以将边转为
frozenset做判断,避免漏绘。
修改后的可运行代码
import networkx as nx import numpy as np import matplotlib.pyplot as plt from matplotlib.cm import ScalarMappable N = 1 def pos(): x, y = 1, N + 3 - 1 for _ in range(2 * N * (N + 1)): yield (x, y) y -= (x + 2) // (N + 3) x = (x + 2) % (N + 3) G = nx.Graph() it_pos = pos() for u in range(2 * N * (N + 1)): G.add_node(u + 1, pos=next(it_pos)) if u % (2 * N + 1) < N: for v in (u - 2 * N - 1, u - N - 1, u - N): if G.has_node(v + 1): G.add_edge(u + 1, v + 1) elif u % (2 * N + 1) == N: G.add_edge(u + 1, u - N + 1) elif u % (2 * N + 1) < 2 * N: for v in (u - 1, u - N - 1, u - N): G.add_edge(u + 1, v + 1) else: for v in (u - 1, u - N - 1): G.add_edge(u + 1, v + 1) # 绘制基础图的节点、标签、默认样式边 pos = nx.get_node_attributes(G, 'pos') nx.draw(G, pos, with_labels=True, font_weight='bold') Edges=np.array([[1,2],[1,3],[1,4]]) Weights=np.array([[1.7],[2.9],[8.6]]) flat_weights = Weights.flatten() weights_normalized = [x / max(flat_weights) for x in flat_weights] edge_weight_map = dict(zip([tuple(e) for e in Edges.tolist()],weights_normalized)) my_cmap = plt.cm.get_cmap('Oranges') # 自定义配置:需要添加箭头的边,元组顺序即为箭头方向 arrow_edges = [(1,3), (1,4)] # 筛选出同批次着色但不需要加箭头的边 non_arrow_edges = [e for e in [tuple(x) for x in Edges.tolist()] if e not in arrow_edges] # 绘制不带箭头的着色边 non_arrow_colors = my_cmap([edge_weight_map[e] for e in non_arrow_edges]) nx.draw_networkx_edges(G, pos, edge_color=non_arrow_colors, edgelist=non_arrow_edges, width=5) # 绘制带箭头的着色边,调整箭头大小匹配边宽 arrow_colors = my_cmap([edge_weight_map[e] for e in arrow_edges]) nx.draw_networkx_edges(G, pos, edge_color=arrow_colors, edgelist=arrow_edges, width=5, arrows=True, arrowsize=20, arrowstyle='->') # 绘制色阶条 sm = ScalarMappable(cmap=my_cmap, norm=plt.Normalize(0,max(flat_weights))) plt.colorbar(sm) plt.show()
自定义调整说明
- 原有边的权重映射着色逻辑完全保留,不会影响颜色和权重的对应关系
- 仅需要修改
arrow_edges列表内容,即可自定义哪些边需要加箭头、箭头的指向 - 调整
arrowsize参数数值可以放大/缩小箭头,适配不同边宽下的视觉效果
效果参考
- 原代码运行输出效果:

- 预期实现效果:

内容的提问来源于stack exchange,提问作者Wiz123
相关产品推荐
相关产品推荐

