Search code examples
graphviz

Graphviz outputs a mess


I'm trying to visualise the following data in dot format using GraphViz:

digraph n {
  node [nodesep=2.0, fontsize=11];
  graph [ overlap=false];
  edge[weight=0.2];
  A -> B [label="I/5"]
  A -> A [label="*/0"]
  A -> C [label="ii/2"]
  A -> H [label="vii/1"]
  B -> D [label="iii/1"]
  B -> E [label="IV/2"]
  B -> F [label="V/2"]
  B -> B [label="vi/2"]
  C -> F [label="V/2"]
  C -> H [label="vii/1"]
  D -> E [label="IV/2"]
  E -> D [label="iii/2"]
  E -> G [label="iv/1"]
  E -> F [label="V/3"]
  F -> B [label="I/4"]
  F -> B [label="vi/1"]
  F -> B [label="*/0"]
  G -> B [label="I/5"]
  H -> B [label="vi/1"]
}

Running the following command: neato -Tpng Chord_NFA.dot > Chord_NFA.png

gives me this output:

I'd like it to fit on A4 and for none of the edges to overlap or cross over a node. This is possible (mathematically) because I did it myself with a biro.


Solution

  • I played with it a few and got this:

    digraph n {
      node [nodesep=2.0, fontsize=11];
      graph [overlap = false];
      subgraph cluster_a {
        style=invisible;
        A; B; H;
      }
      subgraph cluster_b {
        style=invisible;
        D; E; G;
      }
      subgraph cluster_c {
        style=invisible;
        C; F;
      }
      A -> B [label="I/5"];
      A -> A [label="*/0"];
      A -> C [label="ii/2"];
      A -> H [label="vii/1"];
      B:w -> D [label="iii/1"];
      B:nw -> E [minlen=3 label="IV/2"];
      B -> F [minlen=2 label="V/2"];
      B -> B [label="vi/2"];
      C -> F [minlen=2 label="V/2"];
      C -> H [label="vii/1"];
      D -> E [label="IV/2"];
      D -> E [minlen=2 dir=back label="iii/2"];
      G -> E [minlen=2 dir=back label="iv/1"];
      F -> E [dir=back label="V/3"];
      B -> F [minlen=2 dir=back label="I/4"];
      B -> F [minlen=2 dir=back label="vi/1"];
      B -> F [minlen=2 dir=back label="*/0"];
      B -> G [dir=back label="I/5"];
      H -> B [label="vi/1"];
    }
    

    Compile with:

    dot -Tpng -o Chord_NFA.png Chord_NFA.gv
    

    The output is this, without any line crossings:

    graph

    The trick is:

    1. To add the minlen attribute to force some separation, giving more spacing for rendering without overlaps and crossings.

    2. To invert the logic of some edges (rendering them uninverted with dir=back). This way, dot always sees an acyclic graph and can order the edges without getting confused.

    3. Focusing in some subgraphs first and grouping their nodes in clusters to give they some "protection" from interference when rendering the rest of the graph.