Python Networkx graphviz : Plot right position of nodes

标签 python graphviz networkx

我想使用 Graphvize 绘制下图:

xx = nx.DiGraph()

xx.add_node("P")
xx.add_node("C0")
xx.add_node("C1")
xx.add_node("I2")
xx.add_node("C3")
xx.add_node("C4")
xx.add_node("I5")
xx.add_node("C6")
xx.add_node("C7")

xx.node["C1"]['pos'] = (2,3)
xx.node["I2"]['pos'] = (4,5)
xx.node["C3"]['pos'] = (6,7)
xx.node["C4"]['pos'] = (6,5)
xx.node["I5"]['pos'] = (4,1)
xx.node["C6"]['pos'] = (6,2)
xx.node["C7"]['pos'] = (6,0)
xx.node["P"]['pos'] = (-2,3)
xx.node["C0"]['pos'] = (0,3)

xx.add_edge("P", "C0")
xx.add_edge("C0", "C1")
xx.add_edge("C1", "I2")
xx.add_edge("I2", "C3")
xx.add_edge("I2", "C4")
xx.add_edge("C1", "I5")
xx.add_edge("I5", "C6")
xx.add_edge("I5", "C7")

layout = dict((n, xx.node[n]["pos"]) for n in xx.nodes_iter())
nx.draw(xx,pos=layout,node_color='white')

nx.write_dot(xx,'66666.dot')

使用 matplotlitb 我得到所有节点的正确位置:

enter image description here

使用 Graphviz 没有位置的图形。

enter image description here

我的问题:是否有可能在 Graphviz 中添加正确的位置?是否可以直接在 python 中打开文件“66666.dot”?

非常感谢您的帮助!

最佳答案

由于NetworkX库来不及更新和打破向后兼容性,问题中描述的问题仍然存在于新版本的库中,我将尝试更新NetworkX 2.8.7变体的示例代码并提供一个解决方案。

更新 NetworkX 2.8.7 的示例代码

  • 错误:NameError:未定义名称“nx”
    如何修复:这不是版本问题,而是一个 Minimal, Reproducible Example问题,所以只需安装 NetworkX 库(pip install networkx)并在代码开头包含该库:
    import networkx as nx
    
  • 错误:AttributeError:“有向图”对象没有属性“节点”
    如何修复:使用 xx.nodes["C1"]['pos'] 而不是 xx.node["C1"]['pos']。引用:NetworkX Migration guide from 1.X to 2.0
  • 错误:AttributeError:“DiGraph”对象没有属性“nodes_iter”
    如何修复:使用 xx.nodes() 而不是 xx.nodes_iter()Reference .
  • 错误:AttributeError:模块 networkx 没有属性 write_dot
    如何修复:使用 nx.drawing.nx_agraph.write_dot(xx,'66666.dot') 而不是 nx.write_dot(xx,'66666.dot')。引用:AttributeError: 'module' object has no attribute 'write_dot' for networkx library

Note: If you do not already have graphviz and pygraphviz installed, you may need to install it. pygraphviz library for Windows can be installed as a precompiled binary downloaded from Unofficial Windows Binaries for Python Extension Packages with command pip install nameOfDownloadedPackage.whl.

示例代码现在如下所示:

# Listing 1
import networkx as nx

xx = nx.DiGraph()

xx.add_node("P")
xx.add_node("C0")
xx.add_node("C1")
xx.add_node("I2")
xx.add_node("C3")
xx.add_node("C4")
xx.add_node("I5")
xx.add_node("C6")
xx.add_node("C7")

xx.nodes["C1"]['pos'] = (2,3)
xx.nodes["I2"]['pos'] = (4,5)
xx.nodes["C3"]['pos'] = (6,7)
xx.nodes["C4"]['pos'] = (6,5)
xx.nodes["I5"]['pos'] = (4,1)
xx.nodes["C6"]['pos'] = (6,2)
xx.nodes["C7"]['pos'] = (6,0)
xx.nodes["P"]['pos'] = (-2,3)
xx.nodes["C0"]['pos'] = (0,3)

xx.add_edge("P", "C0")
xx.add_edge("C0", "C1")
xx.add_edge("C1", "I2")
xx.add_edge("I2", "C3")
xx.add_edge("I2", "C4")
xx.add_edge("C1", "I5")
xx.add_edge("I5", "C6")
xx.add_edge("I5", "C7")

layout = dict((n, xx.nodes[n]["pos"]) for n in xx.nodes())
nx.draw(xx,pos=layout,node_color='white')

nx.drawing.nx_agraph.write_dot(xx,'66666.dot')

正确输出图像的解决方案

TLDR:使用格式 pos="x,y!"记录文件中节点的位置,而不是 pos=("x,y")
现在我们有了一个可行的示例,我们可以继续讨论如何绘制节点的正确位置。
创建的文件 66666.dot 包含 dot language 中的文本:

strict digraph "" {
    P   [pos="(-2, 3)"];
    C0  [pos="(0, 3)"];
    P -> C0;
    C1  [pos="(2, 3)"];
    C0 -> C1;
    I2  [pos="(4, 5)"];
    C1 -> I2;
    I5  [pos="(4, 1)"];
    C1 -> I5;
    C3  [pos="(6, 7)"];
    I2 -> C3;
    C4  [pos="(6, 5)"];
    I2 -> C4;
    C6  [pos="(6, 2)"];
    I5 -> C6;
    C7  [pos="(6, 0)"];
    I5 -> C7;
}

如果你有graphviz安装后,您可以在终端中运行命令:

dot -Tpng 66666.dot -o output.png

并检查将在文件 output.png 中绘制的内容:
graph was drawn as PNG image using graphviz

问题是在 graphviz 库中有不同的 layout engines , 负责绘制节点的位置和 dot layout engine不理解属性 pos="(4, 1)" , 所以我们将使用 neato layout engine了解此属性(如其文档中所述)。我们在终端中得到输出:

Error: node P, position (-2, 3), expected two doubles
Error: node C0, position (0, 3), expected two doubles
Error: node C1, position (2, 3), expected two doubles
Error: node I2, position (4, 5), expected two doubles
Error: node I5, position (4, 1), expected two doubles
Error: node C3, position (6, 7), expected two doubles
Error: node C4, position (6, 5), expected two doubles
Error: node C6, position (6, 2), expected two doubles
Error: node C7, position (6, 0), expected two doubles

和文件output.png:
graph was drawn as PNG image using graphviz neato layout engine

我们看到坐标不影响绘图位置,并且写入有关输入数据格式不正确的错误。如此处所述(converting network graph to graphviz),此错误是由于坐标值输入不正确造成的。 graphviz 理解的格式是 pos="x,y" ,而不是 pos="(x,y)"

Note: Full value format looks like this %f,%f('!')? (e.g. pos="42,24!"). The optional ! indicates the node position should not change.

让我们在将图形对象写入文件之前更改其位置格式:

# Listing 2
# See the previous part of the code in Listing 1

for node in xx:
    xx.nodes[node]['pos'] = "{},{}!".format(
        xx.nodes[node]['pos'][0], xx.nodes[node]['pos'][1])

nx.drawing.nx_agraph.write_dot(xx,'66666.dot')

现在文件 66666.dot 中的结果:

strict digraph "" {
    P   [pos="-2,3!"];
    C0  [pos="0,3!"];
    P -> C0;
    C1  [pos="2,3!"];
    C0 -> C1;
    I2  [pos="4,5!"];
    C1 -> I2;
    I5  [pos="4,1!"];
    C1 -> I5;
    C3  [pos="6,7!"];
    I2 -> C3;
    C4  [pos="6,5!"];
    I2 -> C4;
    C6  [pos="6,2!"];
    I5 -> C6;
    C7  [pos="6,0!"];
    I5 -> C7;
}

output.png中的结果:
graph was drawn as PNG image using graphviz neato layout engine
看起来挺好的。为了使其看起来像 matplotlib 的结果,您需要添加更多属性 label , shape到节点和arrowhead到边缘:

# Listing 3
# See the previous part of the code in Listing 1

for node in xx:
    xx.nodes[node]['pos'] = "{},{}!".format(
        xx.nodes[node]['pos'][0], xx.nodes[node]['pos'][1])
    xx.nodes[node]['label'] = ""
    xx.nodes[node]['shape'] = "circle"
for edge in xx.edges:
    xx.edges[edge]['arrowhead'] = 'box'

nx.drawing.nx_agraph.write_dot(xx,'66666.dot')

output.png中的结果:
graph was drawn as PNG image using graphviz neato layout engine

Note (optional): To show the result of the matplotlib, add at the beginning of the file import matplotlib.pyplot as plt and at the end plt.show().

直接用Python打开.dot文件

  • 您可以使用 standard Python library 的函数读取文件.
  • 要在 Python 中直接打开文件 filename.dot 并获取图形对象,可以使用函数 networkx.drawing.nx_agraph.read_dot .
  • 如果你需要在 GUI 中嵌入图形,这取决于框架,SO 和互联网上有很多关于如何在 wxPython、PyQt5、Tkinter 中使用 Matplotlib 嵌入图形的答案。

关于Python Networkx graphviz : Plot right position of nodes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35730535/

相关文章:

python - pytest 模拟函数但验证参数

python - 使用pseudoTTY (-t) 运行的Docker 提供即时标准输出,没有它就会发生缓冲

python - 关注使用 python tweepy 发布特定主题标签的用户?

graphviz - 如何在类似 HTML 的标签中左对齐多于两行?

python - 通过唯一标签合并 networkx 中的两个网络映射

python - PostgreSQL 物化 View 未从 Python 刷新

graphviz - graphviz中headlabel和taillabel的不同颜色

python - 如何在 google colab 上安装 pydot 和 graphviz?

python - 如何使用 networkx 反转有向图中的箭头?

python - 透明网络边缘标签