You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python的NetworkX库中正确绘制有向非对称图的双向边(含不同权重)

如何在Python的NetworkX库中正确绘制有向非对称图的双向边(含不同权重)

我完全懂你的困扰——你明明已经把双向边的正确数据存进有向图里了,但可视化的时候两条边重叠成一条,只能看到一个权重,这确实挺闹心的。其实核心原因是NetworkX默认的绘图逻辑会把双向边画在同一条直线上,所以看起来就像只有一条边,但你的数据其实完全没问题(从你打印G[4][3]和G[3][4]的结果就能确认这一点)。

下面给你一个简单有效的解决方案,通过给双向边添加弯曲效果来分开它们,这样就能同时显示两条边的不同权重了:

修改后的完整代码

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt

# 用你提供的前10个城市数据作为示例矩阵
distance_matrix = np.array([
    [0, np.inf, 1033.836, 2954.445, np.inf, 570.7902, np.inf, 5201.642, 927.6648, np.inf],
    [np.inf, 0, 846.4284, 2988.993, 1739.0, 586.6539, 556.8027, 4718.087, 992.3883, np.inf],
    [1065.751, np.inf, 0, 3713.848, 2328.803, 1293.154, 922.5469, 5968.72, 1660.567, 917.3977],
    [3093.118, 2721.323, 3738.992, 0, 1386.044, 2593.299, 2926.249, 2167.597, 2188.789, 2756.88],
    [1547.838, 1609.13, 2530.782, 1509.116, 0, 1071.186, np.inf, 3437.752, 624.6915, 1348.369],
    [541.9545, 603.5713, 1270.946, 2354.782, 1026.145, 0, 204.1122, 4501.91, 436.0267, 401.6861],
    [459.8273, 581.1262, 1058.695, 2634.319, 1264.167, np.inf, 0, np.inf, 717.3868, 300.6823],
    [4815.335, 5330.784, 5322.427, 2153.888, 3612.119, 4600.471, 5372.185, 0, 3998.066, 5173.963],
    [789.3162, 901.9897, 1795.072, 2139.049, 635.1849, 434.8522, 738.8418, 4598.177, 0, 775.1959],
    [794.9219, 244.2613, np.inf, 2964.827, 1463.854, 388.5041, 297.126, 5215.893, 845.9431, 0]
])

G = nx.DiGraph(directed=True)
num_nodes = 10

# 保留你原来的加边逻辑,数据是对的
for i in range(num_nodes):
    for j in range(num_nodes): 
        if (distance_matrix[i][j] != 0) and (distance_matrix[i][j] != np.inf):
            G.add_edge(i, j, weight=distance_matrix[i][j])

# 保留你用的随机布局(带seed保证一致性),也可以换成spring_layout试试
pos = nx.random_layout(G, seed=6)
edge_labels = {key: round(value, 3) for key, value in nx.get_edge_attributes(G, "weight").items()}

base_options = {
    'node_color': 'lightblue',
    'node_size': 100,
    'width': 1,
    'arrowstyle': '->',
    'arrowsize': 12,
}

plt.figure(figsize=(10, 10))

# 拆分绘图步骤,精准控制每部分样式
# 1. 先画节点和节点标签
nx.draw_networkx_nodes(G, pos, node_color=base_options['node_color'], node_size=base_options['node_size'])
nx.draw_networkx_labels(G, pos, font_size=8)

# 2. 区分单向边和双向边,避免重复处理
bidirectional_edges = [(u, v) for u, v in G.edges() if u < v and (v, u) in G.edges()]
unidirectional_edges = [edge for edge in G.edges() if not ((edge[0], edge[1]) in bidirectional_edges or (edge[1], edge[0]) in bidirectional_edges)]

# 3. 画单向边(默认直线)
nx.draw_networkx_edges(G, pos, edgelist=unidirectional_edges, width=base_options['width'], arrowstyle=base_options['arrowstyle'], arrowsize=base_options['arrowsize'])

# 4. 画双向边,给两个方向设置相反的弯曲度,避免重叠
for u, v in bidirectional_edges:
    # u→v的边向右弯曲
    nx.draw_networkx_edges(G, pos, edgelist=[(u, v)], width=base_options['width'], arrowstyle=base_options['arrowstyle'], arrowsize=base_options['arrowsize'], connectionstyle="arc3,rad=0.1")
    # v→u的边向左弯曲
    nx.draw_networkx_edges(G, pos, edgelist=[(v, u)], width=base_options['width'], arrowstyle=base_options['arrowstyle'], arrowsize=base_options['arrowsize'], connectionstyle="arc3,rad=-0.1")

# 5. 最后画边标签
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=5)

plt.title("Distance Matrix Visualized as Graph (With Bidirectional Edges)")
plt.show()

关键修改点说明

  1. 拆分绘图流程:不再用nx.draw_networkx一次性画完所有元素,而是拆分节点、单向边、双向边分别绘制,这样能精准控制双向边的样式。
  2. 弯曲的双向边:通过connectionstyle="arc3,rad=±0.1"让双向边向相反方向弯曲,rad的值可以根据你的图的大小调整,数值越大弯曲程度越明显,正负号控制弯曲方向。
  3. 区分单向/双向边:提前筛选出双向边,避免重复处理,确保每条双向边的两个方向都能被单独设置样式。

这样修改后,你就能看到3→4和4→3的两条边分别带着自己的权重显示出来了,不会再重叠在一起~

备注:内容来源于stack exchange,提问作者Himanshu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 13:35:27