简体   繁体   English

Python Networkx graphviz: Plot 对 position 个节点

[英]Python Networkx graphviz: Plot right position of nodes

I want to plot the following graph using Graphvize:我想使用 Graphvize plot 下图:

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

With matplotlitb i geht the right position of all nodes:使用 matplotlitb,我得到了所有节点的正确 position:

在此处输入图像描述

With Graphviz a graph without postion.使用 Graphviz 一个没有位置的图。

在此处输入图像描述

My question: Is there a possibility to add the correct positions in Graphviz?我的问题:是否有可能在 Graphviz 中添加正确的位置? And is it possible to open the file "66666.dot" directly in python?是否可以直接在python中打开文件“66666.dot”?

Thank you very much for your help!非常感谢您的帮助!

Since the NetworkX library has had time to update and break backward compatibility and the problem described in the question is still in the new version of the library, I will try to update the example code for NetworkX 2.8.7 variant and provide a solution.由于NetworkX库来不及更新和打破向后兼容性,问题中描述的问题仍然存在于新版本的库中,我将尝试更新NetworkX 2.8.7变体的示例代码并提供解决方案。

Update the example code for NetworkX 2.8.7更新 NetworkX 2.8.7 的示例代码

  • Error: NameError: name 'nx' is not defined错误: NameError: name 'nx' is not defined
    How to fix: it's not a version problem, it's an Minimal, Reproducible Example problem, so just install NetworkX library ( pip install.networkx ) and include the library at the beginning of the code:如何解决:这不是版本问题,这是一个最小的、可重现的示例问题,所以只需安装 NetworkX 库 ( pip install.networkx ) 并在代码开头包含该库:
     import.networkx as nx
  • Error: AttributeError: 'DiGraph' object has no attribute 'node'错误: AttributeError: 'DiGraph' object has no attribute 'node'
    How to fix: Use xx.nodes["C1"]['pos'] instead of xx.node["C1"]['pos'] .如何修复:使用xx.nodes["C1"]['pos']而不是xx.node["C1"]['pos'] Reference: NetworkX Migration guide from 1.X to 2.0参考: 从 1.X 到 2.0 的 NetworkX 迁移指南
  • Error: AttributeError: 'DiGraph' object has no attribute 'nodes_iter'错误: AttributeError: 'DiGraph' object has no attribute 'nodes_iter'
    How to fix: Use xx.nodes() instead of xx.nodes_iter() .如何修复:使用xx.nodes()而不是xx.nodes_iter() Reference . 参考
  • Error: AttributeError: module.networkx has no attribute write_dot错误: AttributeError: module.networkx has no attribute write_dot
    How to fix: Use nx.drawing.nx_agraph.write_dot(xx,'66666.dot') instead of nx.write_dot(xx,'66666.dot') .如何修复:使用nx.drawing.nx_agraph.write_dot(xx,'66666.dot')而不是nx.write_dot(xx,'66666.dot') Reference: AttributeError: 'module' object has no attribute 'write_dot' for.networkx library参考: 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.注意:如果您还没有安装graphvizpygraphviz ,您可能需要安装它。 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 . pygraphviz的 pygraphviz 库可以作为从非官方 Windows 扩展包的非官方 Windows 二进制文件下载的预编译二进制文件安装,命令为pip install nameOfDownloadedPackage.whl

The code of the example now looks like this:该示例的代码现在如下所示:

# 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')

Solution to correct output image纠正output图像的解决方案

TLDR: Use the format pos="x,y!" TLDR:使用格式pos="x,y!" to record the positions of the nodes in the file instead of pos=("x,y") .记录文件中节点的位置而不是pos=("x,y")
Now that we have a workable example, we can move on to how to plot right position of nodes.现在我们有了一个可行的例子,我们可以继续讨论如何 plot 正确 position 的节点。
The created file 66666.dot contains text in dot language :创建的文件66666.dot包含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;
}

If you have graphviz installed, you can run the command in terminal:如果你安装了graphviz ,你可以在终端中运行命令:

dot -Tpng 66666.dot -o output.png

and check what will be drawn in the file output.png :并检查将在文件output.png中绘制的内容:
使用 graphviz 将图形绘制为 PNG 图像

The thing is that in graphviz library there are different layout engines , which are responsible for what positions will be drawn nodes and dot layout engine does not understand the attribute pos="(4, 1)" , so we will use the neato layout engine that understands this attribute (as mentioned in its documentation).问题是在 graphviz 库中有不同的布局引擎,它们负责绘制节点的位置和dot布局引擎不理解属性pos="(4, 1)" ,所以我们将使用neato布局引擎了解此属性(如其文档中所述)。 And we get the output in the terminal:我们在终端中得到 output:

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

and file output.png :和文件output.png
使用 graphviz neato 布局引擎将图形绘制为 PNG 图像

We see that the coordinates do not affect the drawing positions and an error is written about the incorrect format of the input data .我们看到坐标不影响绘图位置,并且会写入有关输入数据格式不正确的错误。 As mentioned there ( converting.network graph to graphviz ), this error is due to an incorrect entry of the coordinate value.正如那里提到的( converting.network graph to graphviz ),这个错误是由于坐标值输入不正确造成的。 The format that graphviz understands is pos="x,y" , not pos="(x,y)" . graphviz 理解的格式是pos="x,y" ,而不是pos="(x,y)"

Note: Full value format looks like this %f,%f('?')?注意:全值格式看起来像这样%f,%f('?')? (eg pos="42,24!" ). (例如pos="42,24!" )。 The optional !可选的! indicates the node position should not change .指示节点 position 不应更改

Let's change the format of positions in the graph object before writing it to the file:让我们在将图表 object 写入文件之前更改其位置格式:

# 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')

Result in the file 66666.dot now:现在在文件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;
}

Result in output.png :结果为output.png
使用 graphviz neato 布局引擎将图形绘制为 PNG 图像
Looks good.看起来挺好的。 To make it look like the result from matplotlib, you need to add more attributes label , shape to nodes and arrowhead to edges:为了使它看起来像 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')

Result in output.png :结果为output.png
使用 graphviz neato 布局引擎将图形绘制为 PNG 图像

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() .注意(可选):要显示 matplotlib 的结果,请在文件开头添加import matplotlib.pyplot as plt并在末尾plt.show()

Opening the .dot file directly in Python Python中直接打开.dot文件

  • You can read the file using the functions of the standard Python library .您可以使用标准 Python 库的函数读取该文件。
  • For opening the file filename.dot directly in Python and get a graph object, you can use function networkx.drawing.nx_agraph.read_dot .要直接在 Python 中打开文件filename.dot并得到图形 object,可以使用 function networkx.drawing.nx_agraph.read_dot
  • If you need to embed the graph in GUI, it depends on the framework, there are many answers on SO and inte.net about how to embed graph using Matplotlib in wxPython, PyQt5, Tkinter.如果你需要在 GUI 中嵌入图形,这取决于框架,SO 和 inte.net 上有很多关于如何在 wxPython 中使用 Matplotlib、PyQt5、Tkinter 嵌入图形的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM