Search code examples
graphvizdot

How position elements with dot for a control system diagram?


I want control over the positioning of some elements in the following sample:

digraph {
        graph [splines=ortho];

        /* Node customization. */
        node [shape=box];
        join [shape=point];
        set [label="set\npoint"];

        /* Define node levels; driving elements on top, feed back below. */
        { rank = min; set; PID; P1; P2; join; OUT;}
        { rank = max; M1;}

        /* Edges */
        set -> PID -> P1 -> P2;
        P2-> join [arrowhead=none];
        join -> {OUT; M1};
        PID -> M1 [dir=back];
}

Control system block diagram

  1. If I add more elements to the M1 rank the edges connect to random points (north/top side). I would like to keep them connect horizontally. Can this be done?
  2. How can I increase spacing (edge length) between PID/P1/P2?
  3. It would be nice to align P1/M1 vertically. Can this be done?
  4. Traditional control system diagrams don't have the join node and an edge just comes out of another edge. Is this possible? I removed the arrow head for this.

Maybe some of the questions are extraneous as proper positioning of one will make the others happen naturally.


Solution

    1. Generally you can control the point where the arrow enters node with headport attribute. But with ortho splines this rarely works. Ortho splines live their own life and can cause a variety of different problems, including disappearing edge labels. So there's no definite answer to your first question, each situation has to be handled specifically.

    2. You can increase distance between all nodes by setting a nodesep graph attribute. But if you need to increase distance only between specific nodes, you can use a trick: Add a label with big number of spaces for value.

    3. You can accomplish it with invisible edges.

    Points 2 and 3 illustrated in edited example below:

    digraph {
            graph [splines=ortho];
    
            /* Node customization. */
            node [shape=box];
            join [shape=point];
            set [label="set\npoint"];
    
            /* Define node levels; driving elements on top, feed back below. */
            { rank = min; set; PID; P1; P2; join; OUT;}
            { rank = max; M1;}
    
            /* Edges */
            set -> PID;
            P2-> join [arrowhead=none];
            join -> {OUT; M1}
            PID -> M1 [dir=back];
    
    
            PID -> P1 -> P2 [label="               "] /* #2 increase space between specific nodes */
            P1 -> M1 [style=invis] /* #3 align P1 an M1 */
    }
    

    result:

    example