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

Posted

技术标签:

【中文标题】使用默认为节点名称的节点标签绘制 networkx 图【英文标题】:Plotting networkx graph with node labels defaulting to node name 【发布时间】:2015-04-16 11:21:14 【问题描述】:

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)?

【问题讨论】:

我想要类似的东西,但既然提到 networkx 不是图形可视化工具,也许这是一个更好的工作流程:1)将 networkx 转换为具有标签 2)然后也使用您最喜欢的图形可视化(例如pydot、pygraphviz 或 graphviz)。你知道如何直接从 name2label 字典中更改 networkx obj 的标签吗? 顺便说一句,如果您想按属性绘制(按标签绘制不同),请参阅此答案:***.com/questions/3982819/… 不幸的是它使用 nx。 【参考方案1】:

我觉得更好的答案是不要使用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://***.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://***.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://***.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

【讨论】:

【参考方案2】:

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

您正在查看的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')

如果您想做一些事情以使节点标签不同,您可以发送一个 dict 作为参数。例如,

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

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

【讨论】:

完美,有效!在 nx.draw 的帮助中没有提到 with_labels 参数,即 >>> help(nx.draw) 但它有效。谢谢! 所以它在文档中,但不是直接的:**kwds : optional keywords See networkx.draw_networkx() for a description of optional keywords. 但是这些节点太小了……你如何将它们显示得更大或更好? 使用其他关键字。检查networkx.draw_networkx的关键字 我想要类似的东西,但由于提到 networkx 不是图形可视化工具,也许这是一个更好的工作流程:1)将 networkx 转换为具有标签 2)然后也使用您最喜欢的图形可视化(例如pydot、pygraphviz 或 graphviz)。你知道如何直接从 name2label 字典中更改 networkx obj 的标签吗?

以上是关于使用默认为节点名称的节点标签绘制 networkx 图的主要内容,如果未能解决你的问题,请参考以下文章

使用networkx在两个节点之间绘制多条边

networkx之图遍历和图绘制

networkx:绘制多方图时的节点间距

Python:获取所有节点的度数,然后在networkx中绘制箱线图

子图中的 networkx 正在绘制部分在轴框架之外的节点

根据节点值为networkx中的节点绘制不同的颜色