Graphviz - 叶节点的垂直顺序

Graphviz - Vertical order of leaf nodes

我正在尝试生成树图(从左到右),以说明对象引用树。 除此之外,我希望叶子垂直出现,因为这表明了一些执行顺序。

打点代码如下:

digraph G {

    rankdir=LR
    subgraph cluster_0 {

        L1   L2   L3   L4  L5  L6 
        L10  L20  L30   L40  L50  L60

        { rank=same;
            L1 -> L2 -> L3 ->  L4 -> L5 -> L6 ->
            L10 -> L20 -> L30 ->  L40 -> L50 -> L60 
        }
    }

    subgraph cluster_1 {
        R

        D10 D11

        D20 D21 D22 D23

        D30 D31 D32 D33 D34 D35 D36 D37
    }

    R->D10
    R->D11

    D10 -> D20
    D10 -> D21
    D11 -> D22
    D11 -> D23

    D20 -> D30
    D20 -> D31
    D21 -> D32
    D21 -> D33
    D22 -> D34
    D22 -> D35
    D23 -> D36
    D23 -> D37

    D30 -> L1
    D20 -> L2
    D31 -> L3

    D32 -> L4
    D21 -> L5
    D33 -> L6

    D34 -> L10
    D22 -> L20
    D35 -> L30

    D36 -> L40
    D23 -> L50
    D37 -> L60
}

我得到了什么(使用 https://dreampuf.github.io/GraphvizOnline/ 渲染 SVG):

问题是,我希望叶子按照声明的顺序出现。 在 SO 上的一些帖子之后,我一直在玩 constraint / invisible edges / ranking system 但无法完全掌握它。

如果有一些 graphvizard 能在这里伸出援手就好了。 请注意,此过程稍后将通过 python 自动执行,因此将不胜感激一些可靠的想法。

注 2,这棵树最多可以有数百片叶子。

注意 3,如果您知道一些很好的 python 库来生成比 Graphviz 更直观(至少对您而言)的图形,请发表评论。我目前正在使用 pydot & graphviz (py3)

通过移出叶节点并为其添加权重,我得到了以下结果:

我将点输入更改为:

digraph G {
    rankdir=LR
    subgraph cluster_0 {
        L1   L2   L3   L4  L5  L6 
        L10  L20  L30   L40  L50  L60
    }

    subgraph cluster_1 {
        R
        D10 D11
        D20 D21 D22 D23
        D30 D31 D32 D33 D34 D35 D36 D37
    }

    R->D10 
    R->D11 

    D10 -> D20 
    D10 -> D21 
    D11 -> D22 
    D11 -> D23 

    D20 -> D30 
    D20 -> D31 
    D21 -> D32 
    D21 -> D33 
    D22 -> D34 
    D22 -> D35 
    D23 -> D36 
    D23 -> D37 

    D30 -> L1 
    D20 -> L2 
    D31 -> L3 

    D32 -> L4 
    D21 -> L5 
    D33 -> L6 

    D34 -> L10 
    D22 -> L20 
    D35 -> L30 

    D36 -> L40 
    D23 -> L50 
    D37 -> L60 

    { rank=same;
      L1-> L2 [style=invis, weight=1000]
      L2-> L3 [style=invis, weight=1100]
      L3-> L4 [style=invis, weight=1200]
      L4-> L5 [style=invis, weight=1300]
      L5-> L6 [style=invis, weight=1400]
      L6-> L10 [style=invis, weight=1500]
      L10-> L20 [style=invis, weight=1600]
      L20-> L30 [style=invis, weight=1700]
      L30-> L40 [style=invis, weight=1800]
      L40-> L50 [style=invis, weight=1900]
      L50-> L60 [style=invis, weight=2000]
    }
}