顶向下子图,左右内部子图。

58

我希望我的图表看起来像这样:

但我只能得到这个:

问题在于,在子图中,rankdir 无效。那么,如何模拟它呢?

代码:

digraph G {
    node [shape = circle]
    0 [style = invis]

    0 -> "0A"

    subgraph clusterA {
        label=A
        "0A"
        "1A"
        "2A" -> "0A" [label=•]
    }

    subgraph clusterB {
        label=B
        "0B"
        "1B"
        "2B" -> "0B" [label=•]
    }

        subgraph clusterC {
        label=C
        "0C"
        "1C"
        "2C" -> "0C" [label=•]
    }

    subgraph clusterD {
        label=D
        "0D"
        "1D"
        "2D" -> "0D" [label=•]
    }

    subgraph clusterE {
        label=E
        "0E"
        "1E"
        "2E" -> "0E" [label=•]
    }

    subgraph clusterF {
        label=F
            {node [shape = doublecircle] "0F" "1F"}
        "2F" -> "0F" [label=•]
    }

    "0A" -> "1B" [label=a]
    "1A" -> "2B" [label=a]
    "0B" -> "1C" [label=b]
    "1B" -> "2C" [label=b]
    "0C" -> "1D" [label=c]
    "1C" -> "2D" [label=c]
    "0D" -> "1E" [label=d]
    "1D" -> "2E" [label=d]
    "0E" -> "1F" [label=e]
    "1E" -> "2F" [label=e]
}

1
https://gitlab.com/graphviz/graphviz/issues/887 - morpheus
5个回答

69

通常可以通过以下方式实现特定图形布局的复制:

  • 使用无形节点和边缘
  • 等级约束

以下是我如何复制您的图形 - 或者至少是其中的一部分:

digraph g {
    rankdir="LR";
    node[shape = circle, fontsize=14];
    fontsize=18;
    labeljust="l";

    edge[style=invis, fontsize=12];

    { rank=same;
        0 [style = invis];
        01 [style = invis];
        02 [style=invis];
        0 -> 01 -> 02;
    }

    subgraph clusterA {
        "0A" -> "1A" -> "2A";
        "2A" -> "0A" [label=".", constraint=false, style=solid];
        label="A";
    }

    subgraph clusterB {
        "0B" -> "1B" -> "2B";
        "2B" -> "0B" [label=".", constraint=false, style=solid];
        label="B";
    }

    subgraph clusterC {
        "0C" -> "1C" -> "2C";
        "2C" -> "0C" [label=".", constraint=false, style=solid];
        label="C";
    }

    0 -> "0A"[style=solid];
    01 -> "0B"[style=invis];
    02 -> "0C"[style=invis];

    // edges between clusters
    edge[constraint=false, style=solid];
    "0A" -> "1B" [label=a]
    "1A" -> "2B" [label=a]
    "0B" -> "1C" [label=b]
    "1B" -> "2C" [label=b]
}

这个解决方案并不是很直观。实现它需要注意以下几点:

  • 我选择了 rankdir="LR",这比 TB 有更好的边缘效果,虽然它并没有真正反映出图的方向
  • 隐形节点和边缘 用于顶级节点(0、01、02),以便使集群靠左对齐。
  • (隐形)顶级节点被强制排列在同一排,并通过隐形的边缘链接 - 这将确保与每个节点相关联的集群按正确的顺序出现。

结果如下:

graphviz output


1
似乎算法已经改变了。当我在viz.js中粘贴您的解决方案时,我得到了一个奇怪的0C。 - nachocab
1
我使用 group 成功解决了它。请看我的答案。 - nachocab

5

看起来 rank=same 可能是更加简洁的解决方案。请查看 在Graphviz中将聚类放置在同一排

您也可以使用 'constraint=false' 和不可见的边缘来仔细控制节点的排名。这基本上与上面给出的答案相同。

digraph G {
    newrank=true; // rank without respect to cluster
    rankdir="LR"; 
    node [shape = circle]
    
    subgraph clusterA {
        a0 -> a1 -> a2 [style = invis] // set node order in cluster
        a2 -> a0 [constraint=false] //don't use this edge for ranking
    }

    subgraph clusterB {
        b0 -> b1 -> b2 [style = invis]
        b2 -> b0  [constraint=false]
    }
    
    a0 -> b1 [constraint=false]
    a1 -> b2 [constraint=false]
    
}

enter image description here


我认为这并没有帮助,因为这些聚类不在同一级别上。 - Björn Lindqvist
一个非常干净的答案,而且可以轻松扩展,我试过最多达到5个框。 - Wolf
没有 newrank=true; 也能正常工作。 - Wolf

2
使用constraint=false应该可以让您的子图节点按照您想要的方式显示。 http://www.graphviz.org/doc/info/attrs.html#d:constraint
subgraph clusterB {
    label=B
    "0B"
    "1B"
    "2B" -> "0B" [constraint=false label=•]
}

之后,您会发现您的子图不像您希望的那样对齐。像这样的方法可以解决这个问题。

"0A" -> "0B" -> "0C" -> "0D" -> "0E" [weight=999 style=invis];

2
使用group更新@marapet答案的说明:
digraph g {
rankdir="LR";
node[shape = circle, fontsize=14];
fontsize=18;
labeljust="l";

edge[style=invis, fontsize=12];

{ rank=same;
    0 [group=a style = invis];
    01 [style = invis];
    02 [group=b style=invis];
    0 -> 01 -> 02;
}

subgraph clusterA {
    "0A" [group=a]
    "0A" -> "1A" -> "2A";
    "2A" -> "0A" [label=".", constraint=false, style=solid];
    label="A";
}

subgraph clusterB {
    "0B" -> "1B" -> "2B";
    "2B" -> "0B" [label=".", constraint=false, style=solid];
    label="B";
}

subgraph clusterC {
    "0C" [group=b]
    "1C" [group=b]
    "0C" -> "1C" -> "2C";
    "2C" -> "0C" [label=".", constraint=false, style=solid];
    label="C";
}

0 -> "0A"[style=solid];
01 -> "0B"[style=invis];
02 -> "0C"[style=invis];

// edges between clusters
edge[constraint=false, style=solid];
"0A" -> "1B" [label=a]
"1A" -> "2B" [label=a]
"0B" -> "1C" [label=b]
"1B" -> "2C" [label=b]
}

1

rankdir在子图中不能直接使用,但是如果您添加另一组花括号(不管它叫什么),rankdir将起作用。请参见下文。然后,显然您需要更多的技巧来恢复所需的对齐和排序。

digraph G {
    node [shape = circle]
    0 [style = invis]

    0 -> "0A"

    subgraph clusterA {
        label=A
        {
            rank=same
            "0A"
            "1A"
            "2A" -> "0A" [label=•]
        }
    }

    subgraph clusterB {
        label=B
        {
            rank=same
            "0B"
            "1B"
            "2B" -> "0B" [label=•]
        }
    }

    subgraph clusterC {
        label=C
        {
            rank=same
            "0C"
            "1C"
            "2C" -> "0C" [label=•]
        }
    }

    subgraph clusterD {
        label=D
        {
            rank=same
            "0D"
            "1D"
            "2D" -> "0D" [label=•]
        }
    }

    subgraph clusterE {
        label=E
        {
            rank=same
            "0E"
            "1E"
            "2E" -> "0E" [label=•]
        }
    }

    subgraph clusterF {
        label=F
        {
            rank=same
            {node [shape = doublecircle] "0F" "1F"}
            "2F" -> "0F" [label=•]
        }
    }

    "0A" -> "1B" [label=a]
    "1A" -> "2B" [label=a]
    "0B" -> "1C" [label=b]
    "1B" -> "2C" [label=b]
    "0C" -> "1D" [label=c]
    "1C" -> "2D" [label=c]
    "0D" -> "1E" [label=d]
    "1D" -> "2E" [label=d]
    "0E" -> "1F" [label=e]
    "1E" -> "2F" [label=e]
}

enter image description here


这非常有效,并且比其他答案更容易阅读。 - CodeMonkey
1
你没有使用rankdir,是吗?看起来你使用的是rank=same,这会破坏图形:集群中节点的顺序会改变。 - Clément

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接