绘制带有节点标签的networkx图,默认为节点名称

89

NetworkX非常强大,但是我想绘制一个默认显示节点标签的图形,对于新手来说,这个看似简单的任务却很繁琐。有一个示例可以展示如何向图形添加标签。

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

这个例子的问题在于使用了太多步骤和方法,而我只想在绘制图表时显示与节点名称相同的标签。请注意保留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)?

我想要类似的东西,但由于提到networkx不是一个图形可视化工具,也许这是更好的工作流程:1)将networkx转换为带有标签的形式;2)然后使用您喜欢的图形可视化工具(例如pydot、pygraphviz或graphviz)。您知道如何直接从name2label字典更改networkx对象的标签吗? - Charlie Parker
顺便提一下,如果你想通过属性绘制(与通过标签绘制不同),请参阅此答案:https://dev59.com/pW865IYBdhLWcg3wHKte 不幸的是,它使用了nx。 - Charlie Parker
2个回答

186

简而言之:只需在nx.draw调用中添加with_labels=True

您正在查看的page页面有些复杂,因为它显示了如何将许多不同的内容设置为标签,如何给不同的节点设置不同的颜色,并如何精确控制节点位置。所以有很多事情要做。

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

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

如果您想让节点标签不同,可以发送一个字典作为参数。例如,
labeldict = {}
labeldict["Node1"] = "shopkeeper"
labeldict["Node2"] = "angry man with parrot"

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

enter image description here


3
太好了,可以这样做!with_labels 参数没有在 nx.draw 的帮助文档中提到,即 >>> help(nx.draw),但它可以正常工作。谢谢! - Pranjal Mittal
3
在文档中,但不是直接的:**kwds : 可选关键字参数,请参阅 networkx.draw_networkx() 以了解可选关键字参数的描述。 - Joel
2
但是这些节点非常小,你如何将它们显示得更大或更好? - Charlie Parker
使用networkx.draw_networkx函数检查其他关键字。 - Joel
我想要类似的东西,但由于提到networkx不是一个图形可视化工具,也许这是更好的工作流程:1)将networkx转换为带有标签的形式;2)然后使用您喜欢的图形可视化工具(例如pydot、pygraphviz或graphviz)。您知道如何直接从name2label字典更改networkx对象的标签吗? - Charlie Parker
请注意,字典中不能有键不在图中的元素。当networkx尝试查找未绘制的节点n的位置pos[n]时,这将导致KeyError错误。 - Jack Valmadre

2
我认为更好的解决方案是不使用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非常相似。 NetworkX教程的大部分内容在https://networkx.org/documentation/latest/tutorial.html上也适用于PyGraphviz。请参见http://pygraphviz.github.io/documentation/latest/reference/api_notes.html了解主要差异。”
此外,目前pydot实际上没有文档(这让我个人感到困扰。我不知道是因为它在我的浏览器上看起来不好还是因为它让我感到该项目的开发者并未认真对待,无论它的用户数量高还是低,pydot 15k vs pygraphviz 4k)参考:https://github.com/pydot/pydot/pull/241
此外,似乎pygraphviz比常规graphviz具有更细粒度的控制能力,参考:Graphviz vs PyGraphViz。此外,我不知道如何将networkx直接转换为graphviz对象(因为graphviz拥有最好的文档和最高的用户基数约19k,所以我更喜欢它),因此我会选择pygraphviz。尽管Pygravix的文档虽小但让我感到满意(虽然不如graphviz好,但我不知道如何从networkx制作graphviz图形)。做出这些决定很难,但我不能永远停留在这里,而且这看起来足够周到。此外,networkx很好,因为我也可以将dgl图形转换为networkx(重新标记也很简单)。
考虑到这些原因,让我给您展示使用pygraphviz编写的示例代码,该代码可以实现您想要的功能(但如果您找到了方法,使用pydot也可以实现,使用networkx将其转换为pydot对象非常容易,请参见我之前的链接)。
# https://dev59.com/814b5IYBdhLWcg3w7FYv

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://dev59.com/7HrZa4cB1Zd3GeqP0Ub4
img = mpimg.imread('file.png')
plt.imshow(img)
plt.show()

# remove file https://dev59.com/kGw05IYBdhLWcg3w11Qk
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在图形节点上绘制更多信息

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接