使用子图的Graphviz三层布局

3
我正在尝试以自动生成的流程图形式定位表单中的元素。一般来说,inputs(绿色)应该在最左边,outputs(红色)应该在最右边,其余内容应根据布局放置在中心。我使用rank=sourcerank=sink来实现这一点。在标准图内部,它运行得很好。
然而,当我开始嵌套图形时,rank=source似乎不起作用。我期望<>(电力、开关、室温)的三个输入被放置在最左边(因为在子图中就是这样),而子图+状态(棕色圆圈)和输入输出之间的蓝色框则在中间。
有没有一种方法可以指定“rank=center”(或类似的东西)?
我已经阅读了文档,但没有找到正确的属性(以及在哪里指定它们)。

MWE

digraph MyGraph {
    node [fontsize=8  margin=".1,.01" width=.5 height=.5 shape=box]
    edge [fontsize=8]
    rankdir=LR;
    ranksep = .25;
    nodesep= .5;

subgraph cluster_4386357488 {
    label = " <<GrowLamp>>"
    style=solid
    {rank=source;
        4386357544 [label="electricity" style=filled fillcolor="#b5fed9"]
        4386357712 [label="room_temperature" style=filled fillcolor="#b5fed9"]
        4386357768 [label="switch" style=filled fillcolor="#b5fed9"]
    }
    {
        4386357880 [label="off" style=filled fillcolor="#e2cbc1" shape=doublecircle]
        4386357936 [label="on" style=filled fillcolor="#e2cbc1" shape=circle]
        4386357656 [label="on_time" style=filled fillcolor="#d2ceef"]
    }
    {rank=sink;
        4386357600 [label="light" style=filled fillcolor="#fcc5b3"]
        4386357824 [label="temperature" style=filled fillcolor="#fcc5b3"]
    }
    4386357880 -> 4386357936
    4386357936 -> 4386357880
    {
        subgraph cluster_4386357992 {
            label = "<<Adder>>"
            style=dashed
            {rank=source;
                4386358048 [label="heat_in" style=filled fillcolor="#b5fed9"]
                4386358104 [label="room_temp_in" style=filled fillcolor="#b5fed9"]
            }
            {
                4386358216 [label="state" style=filled fillcolor="#e2cbc1" shape=doublecircle]
            }
            {rank=sink;
                4386358160 [label="temperature" style=filled fillcolor="#fcc5b3"]
            }
            4386358216 -> 4386358160 [style="dashed"]
        }


        subgraph cluster_4386358328 {
            label = "<<HeatElement>>"
            style=solid
            {rank=source;
                4386358384 [label="electricity" style=filled fillcolor="#b5fed9"]
            }
            {
                4386358496 [label="on" style=filled fillcolor="#e2cbc1" shape=doublecircle]
            }
            {rank=sink;
                4386358440 [label="heat" style=filled fillcolor="#fcc5b3"]
            }
            4386358496 -> 4386358440 [style="dashed"]
        }


        subgraph cluster_4386358608 {
            label = "<<LightElement>>"
            style=solid
            {rank=source;
                4386358664 [label="electricity" style=filled fillcolor="#b5fed9"]
            }
            {
                4386358776 [label="off" style=filled fillcolor="#e2cbc1" shape=doublecircle]
                4386358832 [label="on" style=filled fillcolor="#e2cbc1" shape=circle]
            }
            {rank=sink;
                4386358720 [label="light" style=filled fillcolor="#fcc5b3"]
            }
            4386358776 -> 4386358832
            4386358832 -> 4386358776
            4386358776 -> 4386358720 [style="dashed"]
            4386358832 -> 4386358720 [style="dashed"]
        }

        4386358160 -> 4386357824
        4386357712 -> 4386358104
        4386358440 -> 4386358048
        4386358720 -> 4386357600
        4386357936 -> 4386358384 [style="dashed"]
        4386357936 -> 4386358664 [style="dashed"]
        4386357936 -> 4386357656 [style="dashed"]
    }

}

希望的解决方案: 以下是我想要实现的目标。请注意,绿色框均位于各自子图的左侧,红色框位于右侧。它们之间应该是由graphviz定位的其他元素。

How it should look like


没有rank=center,但有其他方法可以使节点对齐。我有一个关于如何帮助你的想法,但是我不太清楚所需的排列方式。您是否希望所有绿色框在左侧,棕色圆圈在中间,橙色框在右侧?还是只想让其中一些呈现这种方式?您能否添加一个大致草图,说明您希望元素排列的方式? - Craig
我添加了一张图来解释我的要求。在每个方框中,绿色的方框(输入)应该在左边,红色的方框(输出)应该在右边,其余部分居中(由 dot 自行处理)。因此应该有一种从左到右的“流动”。 - stklik
1个回答

3

通过添加无形边连接三个输入和图表的其余部分,您可以获得所需的布局,以便Graphviz布局算法可以正确计算它们的等级。您可以通过在边缘格式中添加style=invis来使任何边缘变为无形边缘。

digraph MyGraph {
    node [fontsize=8  margin=".1,.01" width=.5 height=.5 shape=box]
    edge [fontsize=8]
    rankdir=LR;
    ranksep = .25;
    nodesep= .5;

subgraph cluster_4386357488 {
    label = " <<GrowLamp>>"
    style=solid
    {rank=source;
        4386357544 [label="electricity" style=filled fillcolor="#b5fed9"]
        4386357712 [label="room_temperature" style=filled fillcolor="#b5fed9"]
        4386357768 [label="switch" style=filled fillcolor="#b5fed9"]
    }
    {
        4386357880 [label="off" style=filled fillcolor="#e2cbc1" shape=doublecircle]
        4386357936 [label="on" style=filled fillcolor="#e2cbc1" shape=circle]
        4386357656 [label="on_time" style=filled fillcolor="#d2ceef"]
    }
    {rank=sink;
        4386357600 [label="light" style=filled fillcolor="#fcc5b3"]
        4386357824 [label="temperature" style=filled fillcolor="#fcc5b3"]
    }
    4386357880 -> 4386357936
    4386357936 -> 4386357880
    #invisible edges added to achieve correct layout
    4386357544 -> 4386357880 [style="invis"]
    4386357712 -> 4386357880 [style="invis"]
    4386357768 -> 4386357880 [style="invis"]

    {
        subgraph cluster_4386357992 {
            label = "<<Adder>>"
            style=dashed
            {rank=source;
                4386358048 [label="heat_in" style=filled fillcolor="#b5fed9"]
                4386358104 [label="room_temp_in" style=filled fillcolor="#b5fed9"]
            }
            {
                4386358216 [label="state" style=filled fillcolor="#e2cbc1" shape=doublecircle]
            }
            {rank=sink;
                4386358160 [label="temperature" style=filled fillcolor="#fcc5b3"]
            }
            4386358216 -> 4386358160 [style="dashed"]
        }


        subgraph cluster_4386358328 {
            label = "<<HeatElement>>"
            style=solid
            {rank=source;
                4386358384 [label="electricity" style=filled fillcolor="#b5fed9"]
            }
            {
                4386358496 [label="on" style=filled fillcolor="#e2cbc1" shape=doublecircle]
            }
            {rank=sink;
                4386358440 [label="heat" style=filled fillcolor="#fcc5b3"]
            }
            4386358496 -> 4386358440 [style="dashed"]
        }


        subgraph cluster_4386358608 {
            label = "<<LightElement>>"
            style=solid
            {rank=source;
                4386358664 [label="electricity" style=filled fillcolor="#b5fed9"]
            }
            {
                4386358776 [label="off" style=filled fillcolor="#e2cbc1" shape=doublecircle]
                4386358832 [label="on" style=filled fillcolor="#e2cbc1" shape=circle]
            }
            {rank=sink;
                4386358720 [label="light" style=filled fillcolor="#fcc5b3"]
            }
            4386358776 -> 4386358832
            4386358832 -> 4386358776
            4386358776 -> 4386358720 [style="dashed"]
            4386358832 -> 4386358720 [style="dashed"]
        }

        4386358160 -> 4386357824
        4386357712 -> 4386358104
        4386358440 -> 4386358048
        4386358720 -> 4386357600
        4386357936 -> 4386358384 [style="dashed"]
        4386357936 -> 4386358664 [style="dashed"]
        4386357936 -> 4386357656 [style="dashed"]
    }

}
}

使用版本为2.38的dot.exe,您应该得到如下图所示的图形:

节点正确对齐到图形源和汇点。


我一直在尝试理解为什么该解决方案在没有不可见边缘的情况下无法工作。我怀疑dot只能对连接到图的其余部分的节点进行对齐,但我不确定。你能告诉我这是否正确吗?@Craig - stklik
1
@S.K.- 我对此的理解来自于回答你的问题时进行的一些测试。 "room_temperature" 和 "room_temp_in" 之间的边缘导致 dot 将 "room_temperature" 排名比 "room_temp_in" 低一个等级。这似乎覆盖了将此节点定位在最低排名的位置,可能是一个错误。它还强制 "electricity" 和 "switch" 节点放置在同一排而不是最低排。如果从原始文件中删除此边缘,则会获得所需的布局,尽管缺少一个边缘。 - Craig

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