Graphviz中的图形图

时间:2013-05-10 18:02:02

标签: graphviz dot

我有一组用DOT语言编码的有向图。我想构建一个图形图形,使得超图中的每个节点都是这些有向图之一。有没有办法在GraphViz框架内执行此操作?

我知道gvpack允许我将多个图组合成一个.dot文件。但我不知道它是否允许我在这些图之间声明边缘。

2 个答案:

答案 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

enter image description here

如您所见,gvpack重新标记了重复的节点名称。但是,我们可以使用gvpack -u 1.dot 2.dot 3.dot | sed 's/_gv[0-9]\+//g' | dot -Tjpg -ogvsub.jpg轻松撤消重新标记,生成以下图gvsub.jpg

enter image description here

此方法依赖于具有共同节点名称的子图,因此可能需要在子图.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

enter image description here

因此,在头文件中,我为每个子图添加了一个invisble节点,其名称与子图相同,使用compound=true来允许集群之间的边缘。我已经指定了在簇之间绘制的边缘,并且我为不可见节点之间的每个边设置了lheadltail,以确保将正确的簇用作头部和尾部。每个边缘。在使用sed将每个子图转换为集群的过程中,我还为每个子图添加了适当的不可见节点。

显示节点D,G和A之间的边缘,因为这些节点在群集之间是公共的。此外,它们中的每一个仅显示在一个群集中。如果节点对于簇是唯一的,则在簇之间显示的唯一边缘将是不可见节点之间的边缘。这可以在下图中看到,我在3.dot中重命名了节点:

enter image description here

还有一个我无法解决的缺陷。不可见节点仍占用一点空间,因此集群框看起来不平衡,因为隐藏节点位于可见节点旁边。这也意味着簇之间的边缘的头部指向簇盒的一侧而不是中间。目前,我无法看到可以做些什么,除非我们准备查看每个子图并找到一个已经在该子图/集群中的节点作为该子图/集群的代表节点(即我们为该集群绘制边缘的一个或多个。对于一些子图,这可以很容易地手工完成,但如果有很多子图则会很乏味。

相比之下,我上面使用的方法只需要知道集群的名称,并可以将其插入hdr.dot文件中。

我为这种情况手动构建了hdr.dot文件,但hdr.dot文件的内容可以从其他.dot文件中提取sed,{如果有需要,请{1}},awkperl。如果有关哪些集群应该连接的信息在某处可用,脚本还可以插入边缘以将集群链接到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"];
}

您应该从最初的第一步中获得想要的结果