Python graphviz:如何对根树的相同深度的节点进行排序

Python graphviz: how to order nodes at the same depth of a rooted tree

我不知道如何对有根树中相同深度的节点强制执行顺序。它已在 this thread 中被问到但没有解决。问题是,就像那个问题的作者所说的那样,graphviz(至少是 graphviz 的 python 库)无法维持创建顺序

例如:

g = Graph(format="png")
g.node("x", shape="doublecircle")
g.node("y", shape="circle")  # removed in graph 2
g.node("z", shape="circle")  # removed in graph 2
g.node("nil1", shape="none", label="NIL")
g.node("nil2", shape="none", label="NIL")
g.edge("x", "nil1")
g.edge("x", "y")
g.edge("y", "z")
g.edge("y", "nil2")

上面的代码在我的电脑上生成了这张图

如您所见,y 节点和 nil1 节点交换了位置,但它们不应该。

但是在我从上面的代码中删除第 3 行和第 4 行之后,输出发生了变化!

这很有趣。我不知道为什么删除定义两个节点及其形状的两条线会改变输出。即使这两条线确实影响了输出,但预期输出无论如何都不同于两个产生的输出中的任何一个。知道发生了什么以及我的代码有什么问题吗?

在同一等级上,Graphviz 按照定义的顺序绘制节点。在TB(从上到下)中,同一级别的布局节点按从左到右的顺序绘制。

在您的情况下,如果您希望 nil1 节点出现在 之前 (左侧) y 节点 - 您必须定义它之前。与 znil2.

相同

这应该有效:

g = Graph(format="png")
g.node("x", shape="doublecircle")
g.node("nil1", shape="none", label="NIL")
g.node("y", shape="circle")  # removed in graph 2
g.node("nil2", shape="none", label="NIL")
g.node("z", shape="circle")  # removed in graph 2
g.edge("x", "nil1")
g.edge("x", "y")
g.edge("y", "z")
g.edge("y", "nil2")

为了清楚起见,这里有一个基本示例。

digraph name {
    rankdir=TB
    a b c d
}

这里我们按字母顺序定义了节点,因此我们将在图表上得到相同的顺序:

如果我们颠倒顺序:

digraph name {
    rankdir=TB
    d c b a
}

图表上的顺序也会颠倒:


回答为什么删除节点定义会影响顺序的问题。如果不需要特殊属性,您实际上可以省略定义节点。在这种情况下,graphviz 将在看到带有未定义节点的边缘语句时隐式添加节点定义,例如这个:

digraph {
  a -> b
  c -> d
}

翻译为:

digraph {
  a
  b
  a -> b
  c
  d
  c -> d
}

所以在你的例子中,从一开始就删除了 yz 的定义,这使得它们出现得更晚,就在它们的边缘定义之前。这隐含地将 nil1nil2 定义置于 yz 之上。这与我一开始建议的显式解决方案具有相同的效果。