使用默认为节点名称的节点标签绘制 networkx 图

NetworkX 很强大,但我试图绘制一个图表,显示默认的节点标签,我很惊讶,这个看似简单的任务对于一个初到 NetworkX 的人来说是多么乏味。有一个示例演示如何向图中添加标签。

Https://networkx.github.io/documentation/latest/examples/drawing/labels_and_colors.html

这个示例的问题在于它使用了太多的步骤和方法,而我所要做的只是在绘制图形时显示与节点名相同的标签。

# Add nodes and edges
G.add_node("Node1")
G.add_node("Node2")
G.add_edge("Node1", "Node2")
nx.draw(G)    # Doesn't draw labels. How to make it show labels Node1, Node2 along?

有没有办法使 nx.draw(G)在图中内联显示默认标签(本例中为 Node1,Node2) ?

121648 次浏览

Tl/dr: 只需将 with_labels=True添加到 nx.draw调用中。

您正在查看的 呼叫有些复杂,因为它显示了如何设置许多不同的东西作为标签,如何为不同的节点提供不同的颜色,以及如何仔细地提供控制节点的位置。发生了很多事。

但是,您似乎只希望每个节点使用自己的名称,并且对默认颜色和默认位置感到满意。那么

import networkx as nx
import pylab as plt


G=nx.Graph()
# Add nodes and edges
G.add_edge("Node1", "Node2")
nx.draw(G, with_labels = True)
plt.savefig('labels.png')

enter image description here

如果您希望执行某些操作,以使节点标签不同,则可以将 dict 作为参数发送。比如说,

labeldict = {}
labeldict["Node1"] = "shopkeeper"
labeldict["Node2"] = "angry man with parrot"


nx.draw(G, labels=labeldict, with_labels = True)

enter image description here

我觉得更好的答案是不要用 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、 pygrapviz、 Graphviz 等)。我怀疑 pydot 和 pygrapviz 出于某种原因是最好的,因为 networkx 只支持这两个。Pygrapviz 中的文档似乎表明它有一个类似的 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 并没有真正的文档(这让我个人感到困扰。如果它在我的浏览器上看起来不好,或者它让我觉得项目没有得到开发人员的重视,我觉得有些东西就是感觉不对劲,即使它有一个更高的用户集 pydot 15k vs pygrapviz 4k)参考: https://github.com/pydot/pydot/pull/241

而且,pygrapviz 似乎比常规 Graphviz ref: Graphviz vs PyGraphViz具有更多的粒度控制。此外,我不知道如何将 networkx 直接转换成 Graphviz obj (因为 Graphviz 有最好的文档和最高的用户基数 ~ 19k,所以我更喜欢这个) ,所以我将使用 pygrapviz。Pygravix 也有文档,虽然小让我高兴(虽然不如 Graphviz 好,但我知道如何从 networkx 制作 Graphviz 图形)。做出这些决定很难,但我不能永远坚持下去,这似乎足够谨慎。另外,networkx 很不错,因为我也可以将 dgl 图转换为 networkx (重新标记很简单)。

考虑到这些原因,让我给你我写的示例代码,做你想要的使用 pygrapviz (但你可以做它与 pydot 如果你知道如何,转换到 pydot obj 是微不足道的使用 networkx 见我以前的链接) :

# 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 可视化的链接,因为它似乎非常有用: 使用 pydot 显示图形而不保存,并且可能为其他人提供了 pydot 的答案,如果他们需要的话。尽管如此,我还是希望看到支持 Pydot 的论点。


编辑1: 如果你想通过属性而不是标签来绘制图表,请看这个答案: NetworkX 节点属性绘制注意,我建议的重新标签方式并不总是有预期的语义(例如,它可能会连接两个不应该被连接的节点)。


编辑2: 如果您想要绘制属性,而不是偶然发生自循环,请参见以下答案: 使用 PyGraphviz 绘制关于图形节点的更多信息