Graphviz中的图形图

问题描述 投票:7回答:2

我有一些用DOT语言编码的有向图。我想构造一个图图,以使超图中的每个节点都是这些图中的一个。有没有办法在GraphViz框架中做到这一点?

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

graphviz dot
2个回答
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

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS83NzB6bS5qcGcifQ==” alt =“在此处输入图像描述”>

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

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS93blVtNC5qcGcifQ==” alt =“在此处输入图像描述”>“ >>

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

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS84WGpjVC5qcGcifQ==” alt =“在此处输入图像描述”>

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

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

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9Fc0c5ay5qcGcifQ==” alt =“在此处输入图像描述”>

还有一个尚无法解决的缺陷。不可见的节点仍占据一点空间,因此群集框看起来偏斜,因为不可见的节点位于可见节点旁边。这也意味着群集之间的边缘的头部指向群集框的一侧而不是中间。目前,我看不到有什么办法,除非我们准备查看每个子图并找到该子图/群集中已经存在的节点作为该子图/群集的代表节点(即我们向该群集绘制边缘或从中绘制边缘)。手动完成几个子图就可以很容易地做到这一点,但是如果有很多子图,那将是乏味的。

相反,我上面使用的方法仅要求我们知道集群的名称,并将其插入hdr.dot文件即可。

在这种情况下,我已经手动构建了hdr.dot文件,但可以从其他hdr.dot文件中使用.dotsedawkperl提取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"];
}

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


0
投票

处理此问题的最简单方法是允许gvpack执行重命名,而不是尝试反向重命名,以声明节点的标签。

© www.soinside.com 2019 - 2024. All rights reserved.