我觉得更好的答案是不要使用networkx来绘制。他们明确警告您,图形可视化很难,networkx 主要用于图形分析(来自https://networkx.org/documentation/stable/reference/drawing.html#module-networkx.drawing.layout):
绘图
NetworkX 提供了可视化图形的基本功能,但其主要目标是启用图形分析而不是执行图形可视化。将来,图形可视化功能可能会从 NetworkX 中移除,或者仅作为附加包提供。
正确的图表可视化很难,我们强烈建议人们使用专用于该任务的工具来可视化他们的图表。 Cytoscape、Gephi、Graphviz 以及用于 LaTeX 排版的 PGF/TikZ 是专用且功能齐全的图形可视化工具的著名示例。要使用这些工具和其他此类工具,您应该将 NetworkX 图形导出为这些工具可以读取的格式。例如,Cytoscape 可以读取 GraphML 格式,因此 networkx.write_graphml(G, path) 可能是一个合适的选择。
因此我的建议是将图形转换为具有图形可视化专用软件的某种格式,然后进行绘制(例如 pydot、pygraphviz、graphviz 等)。我怀疑 pydot 和 pygraphviz 出于某种原因是最好的,因为 networkx 只支持这两个。从 pygraphviz 中的文档看来,它具有类似的 api,因此如果您已经想使用 networkx (https://pygraphviz.github.io/documentation/stable/tutorial.html),它可能是最容易使用的:
API 与 NetworkX 的 API 非常相似。 https://networkx.org/documentation/latest/tutorial.html 的大部分 NetworkX 教程都适用于 PyGraphviz。主要区别请参见http://pygraphviz.github.io/documentation/latest/reference/api_notes.html。
此外,到目前为止,pydot 并没有真正的文档(这让我个人感到困扰。如果它在我的浏览器上看起来不太好,或者它让我觉得项目没有被它的开发人员认真对待idk 有些东西感觉不对,即使它有更多的用户 pydot 15k vs pygraphviz 4k) 参考:https://github.com/pydot/pydot/pull/241。
此外,pygraphviz 似乎比常规 graphviz 具有更精细的控制 ref:Graphviz vs PyGraphViz。此外,我不知道如何将 networkx 直接转换为 graphviz obj(因为 graphviz 拥有最好的文档和最高的用户群约 19k,所以我确实更喜欢那个),所以出于这些原因,我将使用 pygraphviz。 Pygravix 也有文档,虽然很小,但让我很开心(虽然不如 graphviz,但我知道如何从 networkx 制作 graphviz 图表)。做出这些决定很困难,但我不能永远坚持下去,这似乎足够用心。此外,networkx 也很好,因为我也可以将 dgl 图转换为 networkx(并且重新标记很简单)。
考虑到这些原因,让我为您提供我编写的示例代码,该代码使用 pygraphviz 执行您想要的操作(但如果您知道如何使用 pydot 来实现,使用 networkx 转换为 pydot obj 是微不足道的,请参阅我以前的链接):
# https://stackoverflow.com/questions/28533111/plotting-networkx-graph-with-node-labels-defaulting-to-node-name
import dgl
import numpy as np
import torch
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from pathlib import Path
g = dgl.graph(([0, 0, 0, 0, 0], [1, 2, 3, 4, 5]), num_nodes=6)
print(f'{g=}')
print(f'{g.edges()=}')
# Since the actual graph is undirected, we convert it for visualization purpose.
g = g.to_networkx().to_undirected()
print(f'{g=}')
# relabel
int2label = {0: "app", 1: "cons", 2: "with", 3: "app3", 4: "app4", 5: "app5"}
g = nx.relabel_nodes(g, int2label)
# https://networkx.org/documentation/stable/reference/drawing.html#module-networkx.drawing.layout
g = nx.nx_agraph.to_agraph(g)
print(f'{g=}')
print(f'{g.string()=}')
# draw
g.layout()
g.draw("file.png")
# https://stackoverflow.com/questions/20597088/display-a-png-image-from-python-on-mint-15-linux
img = mpimg.imread('file.png')
plt.imshow(img)
plt.show()
# remove file https://stackoverflow.com/questions/6996603/how-to-delete-a-file-or-folder
Path('./file.png').expanduser().unlink()
# import os
# os.remove('./file.png')
输出:
g=Graph(num_nodes=6, num_edges=5,
ndata_schemes={}
edata_schemes={})
g.edges()=(tensor([0, 0, 0, 0, 0]), tensor([1, 2, 3, 4, 5]))
g=<networkx.classes.multigraph.MultiGraph object at 0x7f8443e94250>
g=<AGraph <Swig Object of type 'Agraph_t *' at 0x7f846117a930>>
g.string()='graph "" {\n\tapp -- cons [key=0,\n\tid=0];\napp -- with [key=0,\nid=1];\napp -- app3 [key=0,\nid=2];\napp -- app4 [key=0,\nid=3];\napp -- app5 [key=0,\nid=4];\n}\n'
虽然我想留下这个关于 pydot 可视化的链接,因为它通常看起来非常有用:Display graph without saving using pydot 并且如果他们需要它可能会为其他人提供 pydot 答案。不过,我希望看到支持 pydot 的论据。
Edit1:如果您想按属性而不是标签进行绘图,请参阅此答案:NetworkX node attribute drawing 请注意,按照我建议的方式重新标记并不总是具有预期的语义(例如,它可能会加入两个不打算加入)。
Edit2:如果您想绘制属性而不是意外发生自循环,请参阅此答案:Draw more information on graph\nodes using PyGraphviz