Graphviz点-奇怪边路由和节点放置

Graphviz点-奇怪边路由和节点放置,graphviz,dot,Graphviz,Dot,我是Graphviz/Dot新手,尝试创建我的第一个点图。 基本操作进行得很快,但修复布局花了我很多时间,我想我现在已经失去了足够的时间,最好向更有经验的人寻求帮助 这是关于边的路由问题,我已经尝试通过告诉在节点上的边的位置来修复该边,如下所述: 这是可行的,但路由是同样奇怪的事情(应该是双向右,而不是左通过所有内容) 第二个是左下方三个节点的节点放置。这可以放置得更好,这样图表就可以完美地放在A4纸上 digraph { "PassSlave1" [label="Pass command to

我是Graphviz/Dot新手,尝试创建我的第一个点图。 基本操作进行得很快,但修复布局花了我很多时间,我想我现在已经失去了足够的时间,最好向更有经验的人寻求帮助

这是关于边的路由问题,我已经尝试通过告诉在节点上的边的位置来修复该边,如下所述: 这是可行的,但路由是同样奇怪的事情(应该是双向右,而不是左通过所有内容)

第二个是左下方三个节点的节点放置。这可以放置得更好,这样图表就可以完美地放在A4纸上

digraph {
"PassSlave1" [label="Pass command to slave (2nd tier)"]
"PassSlave2" [label="Pass command to slave (2nd tier)"]
"Success1" [label="CMD_SIGNAL_SUCCESS", shape=box]
"Success2" [label="CMD_SIGNAL_SUCCESS", shape=box]
"PowerUp" [label="Power up / System reset", peripheries=2, color="red", fontcolor="red"]
"Acknowledge1" [label="CMD_SIGNAL_ACKNOWLEDGE", shape=box]
"Acknowledge2" [label="CMD_SIGNAL_ACKNOWLEDGE", shape=box]

subgraph bl {
    "PowerUp" -> "Wait for \"Enter bootloader\" request"

    "Wait for \"Enter bootloader\" request" -> "Enter bootloader" [label="\"Enter bootloader\" request received"]
    "Wait for \"Enter bootloader\" request" -> "Start Firmware" [label="Timeout while awaiting \"Enter bootloader\" request"]

    "Enter bootloader" -> "idle" // [constraint=false]
    "idle" -> "idle" [label="No command received"]
    "idle" -> "Check device ID" [label="SET_BOOTLOAD_TARGET (Device ID) received"]
}
subgraph {
    rankdir=LR

    subgraph match {
        "Check device ID" -> "Acknowledge1" [label="Match"]
        "Acknowledge1" -> "isTarget (flash mode)"
        "isTarget (flash mode)" -> "Acknowledge2" [label="CMD_START_DOWNLOAD (Byte count) received"]

            "Acknowledge2" -> "isTarget (flash mode)"
            "isTarget (flash mode)" -> "isTarget (flash mode)" [label="No data / commands received"]
            "isTarget (flash mode)" -> "Process data (Hex records)" [label="Data received"]
            "Process data (Hex records)" -> "isTarget (flash mode)" [constraint=false]
            "isTarget (flash mode)" -> "Success1" [label="CMD_END_DOWNLOAD received"]
            "Success1" -> "idle" [constraint=false]

            //"Process data (Hex records)" -> "isTarget (flash mode)" [label="No error occured"]
            //"Process data (Hex records)" -> "isTarget (flash mode)" [label="Error occured"]
    }

    subgraph mismatch {
        "Check device ID" -> "Pass command to slaves (2nd tier)" [label="Mismatch"]
        "Pass command to slaves (2nd tier)" -> "awaitingSlaveBootloadTargetAcknowledge"
        "awaitingSlaveBootloadTargetAcknowledge" -> "awaitingSlaveBootloadTargetAcknowledge" [label="No acknowledge received"]
        "awaitingSlaveBootloadTargetAcknowledge" -> "hasTarget" [label="Acknowledge received"]

        "hasTarget" -> "hasTarget" [label="No command received"]
        "hasTarget" -> "PassSlave1" [label="CMD_START_DOWNLOAD (Byte count) received"]
        "PassSlave1" -> "awaitingSlaveStartDownloadAcknowledge"
        "awaitingSlaveStartDownloadAcknowledge" -> "awaitingSlaveStartDownloadAcknowledge" [label="No acknowledge received"]
        "awaitingSlaveStartDownloadAcknowledge" -> "hasDownloadTarget" [label="Acknowledge received"]

        "hasDownloadTarget" -> "hasDownloadTarget" [label="No data / commands received"]
        "hasDownloadTarget" -> "Pass data (Hex records) to slave (2nd tier)" [label="Data received"]
        "Pass data (Hex records) to slave (2nd tier)" -> "hasDownloadTarget"
        //"hasDownloadTarget" -> "awaitingSlaveEndDownloadResponse" [label="CMD_END_DOWNLOAD received"]
        "hasDownloadTarget" -> "PassSlave2" [label="CMD_END_DOWNLOAD received"]
        "PassSlave2" -> "awaitingSlaveEndDownloadResponse"
        "awaitingSlaveEndDownloadResponse" -> "awaitingSlaveEndDownloadResponse" [label="No command received"]
        "awaitingSlaveEndDownloadResponse"  -> "Success2"
        "Success2":e -> "idle":n [constraint=false]
    }
}


}

如果边缘放置问题指的是边缘“Success2”:e->“idle”:n向左而不是笔直向上,原因是dot希望最小化边缘交叉。任何其他路径都会导致至少1次交叉,因此当前路径被选为只有1次交叉。对于左下角的3个节点,点算法希望使边尽可能短,同时尽量尊重边的方向,因此“最佳”解决方案是将它们并排放置。所以dot正在做它应该做的事情。解决第二个问题的一种方法是将minlen=2添加到边缘“isTarget(闪存模式)”->“Acknowledge2”

然而,我会推荐一个不同的课程,使用更少的约束。如果图形具有自然流,则节点和边的描述顺序就是这样。这将最大限度地减少添加constraint=false属性的需要。例如,您显然希望Success2和Success1位于底部,因此不应在图表顶部提及它们。如果将“PUPUP”节点视为根,其余的边和节点应该出现在DFS顺序中。此外,如果节点A出现在节点B之前,并且它们位于同一列,则节点A很可能位于节点B的左侧。因此,我会在“等待\”进入引导加载程序\“请求”->“启动固件”之前列出“等待\”进入引导加载程序\“请求”->“进入引导加载程序”。基本上,只需以自然的自上而下的顺序描述图形,并避免添加结构约束,除非确实需要获得所需的约束

另一个建议涉及边缘标签。边标签在虚拟节点处处理。这通常效果很好,但有时这种重量级方法会扭曲布局,特别是对于长标签。我会考虑改变一些或许多较长的边缘标签到X标签。这样,它们将在基本布局完成后放置

请注意,rankdir属性在子图中不起作用。它只影响根图

不管怎样,这就是我如何重新构造图形文件并给出结果的方法
(来源:)

.

嘿,我现在设法让它几乎完全符合我的要求……:D非常感谢你对定义顺序的暗示,我不知道这真的很重要。。。太感谢您的xlabel提示!这有时帮助我获得了更好的布局。最后,为了正确使用左边的“Success”,我必须“后退”(idle->Success->istarget)并使用dir=back。不幸的是,atm我不能在graphviz论坛上发布,在这里我不能发布点代码。