我有这个Graphviz图:
digraph
{
rankdir="LR";
overlap = true;
Node[shape=record, height="0.4", width="0.4"];
Edge[dir=none];
A B C D E F G H I
A -> B -> C
D -> E -> F
G -> H -> I
Edge[constraint=false]
A -> D -> G
subgraph clusterX
{
A
B
}
subgraph clusterY
{
E
H
F
I
}
}
产生这个输出:
我原本期望A和D之间边缘的长度最小化,以便节点排列为:
A B C
D E F
G H I
而不是
D E F
G H I
A B C
如果删除子图定义,这将按预期工作。
为什么Graphviz在引入子图时将A B C置于底部?
答案 0 :(得分:6)
这并不是最小化边长,尤其是在示例中,边是使用属性constraint=false
定义的。
虽然这不是一个完整的答案,但我认为它可以在以下两点内找到:
rankdir
更改为LR
包含不可预测(或至少难以预测)的行为,和/或可能仍然是一两个错误(search rankdir)。我会尽力解释并理解graphviz,但你可能想继续阅读this reply of Emden R. Gansner on the graphviz mailing list以及Stephen North的以下答案 - 他们应该知道,所以我会引用一些......
为什么节点的外观顺序很重要?默认情况下,在自上而下的图形中,首先提到的节点将出现在以下节点的左侧,除非边和约束导致更好的布局。
因此,如果没有群集和rankdir=LR
,图表就会显示为这样(没有惊喜):
A D G
B E H
C F I
到目前为止,这么好。但是在应用rankdir=LR
时会发生什么?
ERG写道:
Dot通过普通TB布局处理rankdir = LR,然后旋转 逆时针旋转90度(当然,然后处理 节点旋转,边缘方向等)。因此,第一个是 您可以像在TB布局中一样位于子图2的左侧 期待,然后在旋转后最终低于它。如果你想 第一个要在顶部,在图表中将其列为第二个。
因此,如果这是正确的,没有集群,节点应该如下所示:
G H I
D E F
A B C
实际上,它们看起来像这样:
A B C
D E F
G H I
为什么呢?斯蒂芬·诺斯回答说:
在某些时候,我们决定从上到下应该是默认的,
即使图表被旋转,也有翻转平面的代码 内部边缘。
因此,图表布局为TB,逆时针方向旋转,平面边缘翻转:
A D G G H I A B C
B E H --> D E F --> D E F
C F I A B C G H I
虽然这对于简单图表非常有效,但似乎在涉及集群时,事情会有所不同。通常边缘也会在簇内翻转(如clusterY
中所述),但有时平边翻转不能像人们想象的那样工作。你的例子就是其中一例。
为什么翻转这些边缘的错误或限制?因为使用rankdir=TB
时,相同的图表通常会正确显示。
幸运的是,解决方法通常很简单 - 例如,您可以使用节点外观的顺序来影响布局:
digraph
{
rankdir="LR";
node[shape=record, height="0.4", width="0.4"];
edge[dir=none];
E; // E is first node to appear
A -> B -> C;
D -> E -> F;
G -> H -> I;
edge[constraint=false]
A -> D -> G;
subgraph clusterX { A; B; }
subgraph clusterY { E; F; H; I; }
}