我有一组用 DOT 语言编码的有向图。我想构建一个图图,使得超图中的每个节点都是这些有向图之一。有没有办法在 GraphViz 框架内做到这一点?
我知道这gvpack
将允许我将多个图形组合成一个 .dot 文件。但我不知道它是否允许我声明这些图之间的边。
简短的回答是gvpack
不声明子图之间的边。事实上,当子图之间有共同的节点名称时,gvpack
重命名它们以避免冲突。但是,这是可以修复的。
例如,给定三个.dot
文件1.dot
:
digraph {
A -> B
A -> C
}
2.dot
:
digraph {
D -> E
E -> F
}
...和3.dot
:
digraph {
D -> G
G -> A
}
...运行gvpack -u 1.dot 2.dot 3.dot | dot -Tjpg -ogvp1.jpg
给出以下图表gvp1.jpg
:
如您所见,gvpack
已重新标记重复的节点名称。但是,我们可以使用 轻松反转重新标记gvpack -u 1.dot 2.dot 3.dot | sed 's/_gv[0-9]\+//g' | dot -Tjpg -ogvsub.jpg
,从而生成以下图形gvsub.jpg
:
这种方法依赖于具有共同节点名称的子图,因此可能需要在子图.dot
文件中插入额外的节点来实现这一点。
(编辑:上面的解决方案显示了节点合并但不与集群中的子图合并的图。以下解决方案显示了集群中的子图。)
给定.dot
文件1.dot
(这些文件与上面的文件相同,除了我给每个有向图命名):
digraph g1 {
A -> B
A -> C
}
2.dot
:
digraph g2 {
D -> E
E -> F
}
...和3.dot
:
digraph g3 {
D -> G
G -> A
}
...连同hdr.dot
:
digraph GMaster {
compound = true;
g1 [style=invisible, height = 0, width = 0, label=""];
g2 [style=invisible, height = 0, width = 0, label=""];
g3 [style=invisible, height = 0, width = 0, label=""];
g1 -> g2 [lhead=clusterg2, ltail=clusterg1];
g1 -> g3 [lhead=clusterg3, ltail=clusterg1]
...和tail.dot
:
}
...我们可以运行cat 1.dot 2.dot 3.dot | sed 's/digraph \(\w*\) *{/subgraph cluster\1 { \1/' | cat hdr.dot - tail.dot | dot -Tjpg -oclust1.jpg
以提供文件clust1.jpg
:
因此,在头文件中,我为每个子图添加了一个不可见节点,与子图同名,用于compound=true
允许集群之间的边。我已经指定了要在集群之间绘制的边缘,并且我已经为不可见节点之间的每个边缘设置了lhead
和ltail
,以确保将正确的集群用作每个边缘的头部和尾部。在使用sed
.
显示了节点 D、G 和 A 之间的边,因为这些节点在集群之间是公共的。此外,它们中的每一个都只显示在一个集群中。如果节点对集群来说是唯一的,那么集群之间唯一显示的边将是不可见节点之间的边。这可以在下图中看到,其中我已将节点重命名为3.dot
:
还有一个我还没有完全修复的缺陷。不可见节点仍然占用一点空间,因此集群框看起来不平衡,因为不可见节点位于可见节点旁边。这也意味着簇之间的边的头部指向簇框的一侧而不是中间。目前,我看不出对此能做些什么,除非我们准备好查看每个子图并找到一个已经在该子图/集群中的节点作为该子图/集群的代表节点(即我们为该集群绘制边缘的对象)。对于几个子图,这可以很容易地手动完成,但如果有很多子图,那就太乏味了。
相比之下,我上面使用的方法只需要我们知道集群的名称并可以将其插入到hdr.dot
文件中。
我已经hdr.dot
为这种情况手动构建了文件,但文件的内容hdr.dot
可以从其他.dot
文件中提取,使用sed
, awk
,perl
或者python
如果有需要。hdr.dot
如果有关应连接哪些集群的信息在某处可用,该脚本还可以插入边缘以将集群链接到其中。
处理此问题的最简单方法是允许gvpack
执行重命名,而不是尝试反转它,而是断言节点的标签。
从...开始
digraph g1 {
A -> B;
A -> C;
A [label="A"];
B [label="B"];
C [label="C"];
}
和
digraph g2 {
D -> E
E -> F
D [label="D"];
E [label="E"];
F [label="F"];
}
和
digraph g3 {
D -> G
G -> A
D [label="D"];
G [label="G"];
A [label="A"];
}
你应该从最初的第一步得到你想要的结果