我有一系列用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
文件,但是如果需要,可以使用 sed
、awk
、perl
或 python
从其他 .dot
文件中提取 hdr.dot
文件的内容。如果某处有关于连接哪些簇的信息,则该脚本还可以将连接群集的边缘插入到 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"];
}
你应该从你的原始第一步中得到想要的结果