我有一组用DOT语言编码的有向图。我想构建一个图形图形,使得超图中的每个节点都是这些有向图之一。有没有办法在GraphViz框架内执行此操作?
我知道gvpack
允许我将多个图组合成一个.dot文件。但我不知道它是否允许我在这些图之间声明边缘。
答案 0 :(得分:8)
简短的回答是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
:
因此,在头文件中,我为每个子图添加了一个invisble节点,其名称与子图相同,使用compound=true
来允许集群之间的边缘。我已经指定了在簇之间绘制的边缘,并且我为不可见节点之间的每个边设置了lhead
和ltail
,以确保将正确的簇用作头部和尾部。每个边缘。在使用sed
将每个子图转换为集群的过程中,我还为每个子图添加了适当的不可见节点。
显示节点D,G和A之间的边缘,因为这些节点在群集之间是公共的。此外,它们中的每一个仅显示在一个群集中。如果节点对于簇是唯一的,则在簇之间显示的唯一边缘将是不可见节点之间的边缘。这可以在下图中看到,我在3.dot
中重命名了节点:
还有一个我无法解决的缺陷。不可见节点仍占用一点空间,因此集群框看起来不平衡,因为隐藏节点位于可见节点旁边。这也意味着簇之间的边缘的头部指向簇盒的一侧而不是中间。目前,我无法看到可以做些什么,除非我们准备查看每个子图并找到一个已经在该子图/集群中的节点作为该子图/集群的代表节点(即我们为该集群绘制边缘的一个或多个。对于一些子图,这可以很容易地手工完成,但如果有很多子图则会很乏味。
相比之下,我上面使用的方法只需要知道集群的名称,并可以将其插入hdr.dot
文件中。
我为这种情况手动构建了hdr.dot
文件,但hdr.dot
文件的内容可以从其他.dot
文件中提取sed
,{如果有需要,请{1}},awk
或perl
。如果有关哪些集群应该连接的信息在某处可用,脚本还可以插入边缘以将集群链接到python
。
答案 1 :(得分:0)
处理此问题的最简单方法是允许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"];
}
您应该从最初的第一步中获得想要的结果