Silvan Hofer
Silvan Hofer

Reputation: 1421

Graphviz Dot - Strange edge routing and node placement

I'm new to Graphviz/Dot and tried to create my first Dot-Diagram. The Basics went very quick but Fixing the layout took me much time and I think I'm lost enough time now and better ask for help by more experienced People...

It's about the routing of an edge which I already tried to fix by telling where to locate the edge at the nodes as describe here: Strange edge placement in Graphviz Dot This worked but the Routing is the same strange Thing (should bi right instead of left through all content).

The second one is the node Placement of the three bottom nodes left. This could be placed much better so that the diagram would fit perfect on a Portrait A4 page...

State Diagram

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]
    }
}

}

Upvotes: 2

Views: 2643

Answers (1)

Emden
Emden

Reputation: 336

If the edge placement problem refers to the edge "Success2":e -> "idle":n going to the left rather than straight up, the reason is that dot wants to minimize edge crossings. Any other path would cause at least 1 crossing, so the current path is picked as having only 1 crossing. As for the 3 left bottom nodes, the dot algorithm wants to make the edges as short as possible, while trying to respect edge directions, so the "best" solution is to place them side by side. So dot is doing what it supposed to do given the constraints. One way to fix the second problem would be to add minlen=2 to the edge "isTarget (flash mode)" -> "Acknowledge2".

However, I would recommend a different course, using fewer constraints. If your graph has a natural flow, that is the order in which the nodes and edges should be described. This should minimize the need to add constraint=false attributes. For example, you obviously want Success2 and Success1 at the bottom, so they should not be mentioned at the top of the graph. If you consider the "PowerUp" node as the root, the remaining edges and nodes should occur in DFS order. Also, if node A appears before node B, and they are on the same rank, it is likely that node A will be to the left of node B. For this reason, I would list "Wait for \"Enter bootloader\" request" -> "Start Firmware" before "Wait for \"Enter bootloader\" request" -> "Enter bootloader". Basically, just describe the graph in a natural top-down order, and avoid adding structural constraints unless it is really necessary to get what you want.

Another suggestion concerns edge labels. Edge labels are treated at dummy nodes. This often works well, but sometimes this heavyweight approach can distort the layout, especially for long labels. I would consider changing some, or many, of the longer edge labels to xlabels. In this way, they are placed after the basic layout is done.

Note that the rankdir attribute has no effect within a subgraph. It only affects the root graph.

Anyway, here is how I would restructure your graph file giving the result result
(source: graphviz.org)
.

Upvotes: 1

Related Questions