Search code examples
graphvizdot

How can I adjust the nodes in this dot program into a 2 by 3 table?


I use graphviz to draw a diagram.

enter image description here

The placement of the nodes are not ideal. I would like the six nodes to be roughly placed in a 2 by 3 table:

file_in   stdin_in     string_in

file_out  stdout_out   variable_out

I have tried to add weights to some edges but still fails to move the nodes into such a table. See my dot program below. Thanks.

digraph G {

/* directly betw inputs */
node [color=black]
string_in -> stdin_in [label="redirection"];
 file_in -> stdin_in [label="redirection"];
 stdin_in -> file_in [label="device file /dev/stdin, or arg -", weight=8];
 stdin_in -> string_in [label="xargs"]; 

/* directly betw outputs */
node [color=red]
edge [color=red]
  stdout_out -> file_out [label="redirection" fontcolor="red"];
  file_out -> stdout_out [label="/dev/stdout or arg -" fontcolor="red"];

/* directly from input to output */
edge [color=blue]
 stdin_in -> stdout_out [label="cat or tee" fontcolor="blue" weight=8];
 stdin_in -> file_out [label = "tee > /dev/null" fontcolor = "blue"]; 
 string_in -> stdout_out [label="echo -n" fontcolor="blue" weight=2];
 file_in -> stdout_out [label="cat" fontcolor="blue"];
 file_in -> file_out [label="none" fontcolor="blue"];
 string_in -> variable_out [label="assignment" fontcolor="blue"];

/* directly from output to input */
edge [color=green]
 stdout_out -> stdin_in [label="pipe" fontcolor="green"];
 stdout_out -> file_in  [label="process substitution"  fontcolor="green"];
 stdout_out -> string_in [label="command substitution"  fontcolor="green"];
 file_out -> file_in [label="none"  fontcolor="green"];
 variable_out -> string_in [label="parameter expansion"  fontcolor="green"];
}

Solution

  • The key point here is using rank = same; I have added this instruction at the top of your code. I have also increased the distance between the two rank levels so that there is more space for the edge labels. I have also changed the weights you had given to the edges in order to have a matrix like appearance.

    Two more things I would recommend:

    • rather than the HTML-like syntax for the node, use the standard graphviz format; matter of taste, but I find it easier to read and it is more flexible, see (How shall escape `>` in an edge label?),
    • when creating edges from nodes lower in the hierarchy to higher ones, don't use b->a, rather write a->b[dir="back"]; this avoids graphviz getting confused when the number of nodes increases

    I have not completely edited the file, as it is not strictly necessary for the two items just mentioned - here the job I have done:

    digraph G {
    
    # layout
    ranksep = 2
    { rank = same; file_in stdin_in string_in }
    { rank = same; file_out stdout_out variable_out }
    
    /* directly betw inputs */
    node [color=black]
     string_in -> stdin_in [label="redirection"];
     file_in -> stdin_in [label="redirection"];
     stdin_in -> file_in [label="device file /dev/stdin, or arg -"] 
     stdin_in -> string_in [label="xargs"]; 
    
    /* directly betw outputs */
    node [color=red]
    edge [color=red]
      stdout_out -> file_out [label=<<font color="red">redirection</font>>];
      file_out -> stdout_out [label=<<font color="red">/dev/stdout or arg -</font>>];
    
    /* directly from input to output */
    edge [color=blue]
     stdin_in -> stdout_out [label=<<font color="blue">cat or tee</font>> weight = 10];
     # stdin_in -> file_out [label=<<font color="blue">tee /dev/null</font>>]; 
     stdin_in -> file_out[ label = "tee > /dev/null" fontcolor = "blue" ];
     string_in -> stdout_out [label=<<font color="blue">echo -n</font>> ];
     file_in -> stdout_out [label=<<font color="blue">cat</font>> ];
     file_in -> file_out [label = "none" fontcolor = "blue" weight = 10];
     string_in -> variable_out [label = "assignment" fontcolor = "blue" weight = 10 ];
    
    /* directly from output to input */
    edge [color=green]
     stdout_out -> stdin_in [label=<<font color="green">pipe</font>>];
     stdout_out -> file_in  [label=<<font color="green">process substitution</font>>];
     stdout_out -> string_in [label=<<font color="green">command substitution</font>>];
     file_in -> file_out [label="none" fontcolor="green" dir = back ];
     variable_out -> string_in [label=<<font color="green">parameter expansion</font>>];
    }
    

    which gives you

    enter image description here