Search code examples
graphvizdot

How to lay out nodes so that edges don't overlap in Graphviz


I'm trying to create a fairly simple graph with Graphviz using the dot engine. For the most part my auto-generated code is okay, but I can sometimes run into issues in regard to how Graphviz lays out nodes for me - in particular how it decides adjacent nodes and parent nodes should relate.

I am trying to make it so that my given edges don't overlap, which I would have thought was fairly easy. Apparently this is not the case when using rank=same though.

I have the following graph:

digraph {
    edge [dir=none];

    {
        rank=same;
        N_Ash[label="Ash"];
    }
    J_Ash [shape=point,width=0.001];
    N_Ash:s -> J_Ash:c;
    J_Ash:c -> N_Beck:n;
    J_Ash:c -> N_Camel:n;
    {
        rank=same;
        N_Megan[label="Megan"];
        N_Camel -> N_Megan;
        N_Beck[label="Beck"];
        N_Brock[label="Brock"];
        N_Camel[label="Camel"];
        N_Beck -> N_Brock;
    }
    J_Beck [shape=point,width=0.001];
    J_Camel [shape=point,width=0.001];
    N_Beck:s -> J_Beck:c;
    J_Beck:c -> N_Daisy:n;
    J_Beck:c -> N_Hubby:n;
    N_Camel:s -> J_Camel:c;
    J_Camel:c -> N_Rae:n;
    {
        rank=same;
        N_Tea[label="Tea"];
        N_Tea -> N_Hubby;
        N_Daisy[label="Daisy"];
        N_Rae[label="Rae"];
        N_Hubby[label="Hubby"];
    }
}

It produces this output:

A generated Graphviz graph

As you can see, the nodes "Camel" and "Megan", "Beck" and "Brock", and "Hubby" and "Tea" are all split apart despite being directly joined. I would like those nodes to be adjacent, so that the edges don't overlap. I have no interest in the order of the nodes in a single given rank.

I believe this issue is in relation to my use of rank=same - if I omit that line form the final subgraph, none of the edges overlap.

A generated Graphviz graph

Obviously, I can't use that as a solution as the final four aren't in the same rank.

As far as I can tell, I can't use the weight attribute on the edge to make the horizontal joins shorter/higher priority, nor can I use len at all in dot (according to its docs).


Solution

  • This encloses each pair/group within a cluster and rearranges the code a bit for (my) readability.

    digraph {
        edge [dir=none];
        N_Ash[label="Ash"];
        J_Ash [shape=point,width=0.001];
    
        subgraph clusterA{  peripheries=0
          {   rank=same;
            N_Beck[label="Beck"];
            N_Brock[label="Brock"];
          }
        }
        subgraph clusterB{  peripheries=0
          { rank=same;
            N_Megan[label="Megan"];
            N_Camel[label="Camel"];
          }
        }
        J_Beck [shape=point,width=0.001];
        J_Camel [shape=point,width=0.001];
    
        subgraph clusterC{  peripheries=0
          {  rank=same;
            N_Tea[label="Tea"];
            N_Daisy[label="Daisy"];
            N_Hubby[label="Hubby"];
          }
        }
        N_Rae[label="Rae"];
    
        N_Ash:s -> J_Ash:c;
        J_Ash:c -> N_Beck:n;
        J_Ash:c -> N_Camel:n;
        N_Camel -> N_Megan;
        N_Beck -> N_Brock;
        N_Tea -> N_Hubby;
        N_Beck:s -> J_Beck:c;
        J_Beck:c -> N_Daisy:n;
        J_Beck:c -> N_Hubby:n;
        N_Camel:s -> J_Camel:c;
        J_Camel:c -> N_Rae:n;
    }
    

    Giving:
    enter image description here