Graphviz 子图的点聚类排序

Graphviz 子图的点聚类排序,graphviz,dot,Graphviz,Dot,我正在尝试使用媒体维基上的graphviz作为软件的文档工具 首先,我记录了一些运行良好的类关系。一切都按预期进行了垂直排列 但是,我们的一些模块是DLL,我想把它们分成一个盒子。当我将节点添加到集群时,它们被边缘化了,但是集群似乎有一个LR排序规则。或者添加到集群会破坏节点的TB排名,因为集群现在显示在图的一侧 此图表示我正在尝试执行的操作:此时,cluster1和cluster2显示在cluster0的右侧 我希望/需要它们出现在下面 <graphviz> digraph d {

我正在尝试使用媒体维基上的graphviz作为软件的文档工具

首先,我记录了一些运行良好的类关系。一切都按预期进行了垂直排列

但是,我们的一些模块是DLL,我想把它们分成一个盒子。当我将节点添加到集群时,它们被边缘化了,但是集群似乎有一个LR排序规则。或者添加到集群会破坏节点的TB排名,因为集群现在显示在图的一侧

此图表示我正在尝试执行的操作:此时,cluster1和cluster2显示在cluster0的右侧

我希望/需要它们出现在下面

<graphviz>
digraph d {
    subgraph cluster0 {
      A -> {B1 B2}
      B2 -> {C1 C2 C3}
      C1 -> D;
    }
    subgraph cluster1 {
      C2 -> dll1_A;
      dll1_A -> B1;
    }
    subgraph cluster2 { 
      C3 -> dll2_A;
    }
    dll1_A -> dll2_A;
}
</graphviz>

有向图d{
子图簇0{
A->{B1 B2}
B2->{C1 C2 C3}
C1->D;
}
子图簇1{
C2->dll1_A;
dll1_A->B1;
}
子图簇2{
C3->dll2_A;
}
dll1_A->dll2_A;
}

这将生成您要查找的图形:

digraph d {
  subgraph cluster0 {
    A -> {B1 B2}
    B2 -> {C1 C2 C3}
    C1 -> D;
  }

  subgraph {
    rankdir="TB"
    subgraph cluster1 {
      C2 -> dll1_A;
      dll1_A -> B1;
    }

    subgraph cluster2 {
      C3 -> dll2_A;
    }
  }
  dll1_A -> dll2_A;
}

这样做的目的是创建一个子图,该子图仅用于布局目的,以提供所需的从上到下的顺序。

该布局是Dot为最小化总体高度而进行的尝试

比要求的布局更紧凑的一个原因是使用了从dll1_aB1的反向边缘。它尝试将集群拉回到尽可能靠近目标节点的位置。要避免此边影响图形,请如图所示,放松向上边上的约束,或沿正向绘制边,并使用dir属性反转箭头

这将有助于许多布局,但仅此一点还不足以修复给出的示例。为了防止Dot保持其首选的紧凑布局,您可以向应保持(接近)垂直的边添加minlen属性。一般来说,这可能很难计算,但对于手动调整的布局来说是实用的

digraph d {
    subgraph cluster0 {
        A -> {B1 B2}    
        B2 -> {C1 C2 C3}
        C1 -> D;
    }
    subgraph cluster1 {
        C2 -> dll1_A [minlen = 2];
        dll1_A -> B1 [constraint = false];
        /* B1 -> dll1_A [dir = back]; */
    }
    subgraph cluster2 {
        C3 -> dll2_A;
    }
    dll1_A -> dll2_A;
}

我的经验表明,
constraint=false
通常会产生不必要的卷积边。似乎
weight=0
可以提供更好的结果:

digraph d {
    subgraph cluster0 {
        A -> {B1 B2}    
        B2 -> {C1 C2 C3}
        C1 -> D;
    }
    subgraph cluster1 {
        C2 -> dll1_A [minlen = 2];
        dll1_A -> B1 [weight = 0];
        /* B1 -> dll1_A [dir = back]; */
    }
    subgraph cluster2 {
        C3 -> dll2_A;
    }
    dll1_A -> dll2_A;
}

对不起,我误解了作为问题的一部分给出的图表,并认为这是你正在寻找的目标,而不是你正在得到的。这对我来说非常有效。关于自动化的一点意见:如果您的问题涉及结构(在我的案例中是控制流图),其中某些边可以标识为“向后”(从循环出口到入口),那么自动标记那些带有
constraint=false
的边可以解决问题。更一般地说,可以基于图的BFS或DFS树(假设选定的根节点)计算后向边集。@johntex通常
constraint=false
按预期工作。但是,有时,如果反向意图
dir=back
变得更加清晰,那么已经受约束的图形将导致不那么令人惊讶的布局。特别值得注意的是,当节点具有许多边时,这些边可能会在层次中向上或向下拉动节点。