Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to influence layout of graph items?

Tags:

I am trying to visualize a simple Finite State Machine graph using Graphviz. The layout created by Graphviz is not completely to my liking. I was expecting a more compact result with shorter edges.

So far, I have tried using groups and changing the weights of edges, but not much luck. It is not clear to me why Graphviz draws the graph the way it does and how to adjust its algorithm to my liking. Are there any parameters I can set to achieve that? Or should I use another command than dot? I tried neato, but the result looked completely messed up and again, I do not really understand what I am doing...

This is my best result so far:

Finite State Machine, best result so far

Trying to visualize a better lay-out than this, I think the graph would look nicer if the red boxes were aligned differently, more compact for example like indicated by the arrows in this picture:

Finite State Machine, imagined better result

I used dot to create the graph and he source code is as follows:

  1 digraph JobStateDiagram
  2 {
  3   rankdir=LR;
  4   size="8,5";
  5 
  6   node  [style="rounded,filled,bold", shape=box, fixedsize=true, width=1.3, fontname="Arial"];
  7   Created   [fillcolor=black, shape=circle, label="", width=0.25];
  8   Destroyed [fillcolor=black, shape=doublecircle, label="", width=0.3];
  9   Empty     [fillcolor="#a0ffa0"];
 10   Announced [fillcolor="#a0ffa0"];
 11   Assigned  [fillcolor="#a0ffa0"];
 12   Working   [fillcolor="#a0ffa0"];
 13   Ready     [fillcolor="#a0ffa0"];
 14   TimedOut  [fillcolor="#ffa0a0"];
 15   Failed    [fillcolor="#ffa0a0"];
 16 
 17   {
 18     rank=source; Created Destroyed;
 19   }
 20 
 21   edge  [style=bold, fontname="Arial" weight=2]
 22   Empty     -> Announced [ label="announce"   ];
 23   Announced -> Assigned  [ label="assign"     ];
 24   Assigned  -> Working   [ label="start"      ];
 25   Working   -> Ready     [ label="finish"     ];
 26   Ready     -> Empty     [ label="revoke"     ];
 27 
 28   edge  [fontname="Arial" color="#aaaaaa" weight=1]
 29   Announced -> TimedOut  [ label="timeout"    ];
 30   Assigned  -> TimedOut  [ label="timeout"    ];
 31   Working   -> TimedOut  [ label="timeout"    ];
 32   Working   -> Failed    [ label="error"      ];
 33   TimedOut  -> Announced [ label="announce"   ];
 34   TimedOut  -> Empty     [ label="revoke"     ];
 35   Failed    -> Announced [ label="announce"   ];
 36   Failed    -> Empty     [ label="revoke"     ];
 37 
 38   edge  [style=bold, fontname="Arial" weight=1]
 39   Created   -> Empty     [ label="initialize" ];
 40   Empty     -> Destroyed [ label="finalize"   ];
 41   Announced -> Empty     [ label="revoke"     ];
 42   Assigned  -> Empty     [ label="revoke"     ];
 43   Working   -> Empty     [ label="revoke"     ];
 44 }

Also, anybody please let me know if I do any strange things in the Graphviz file above -- any feedback is appreciated.


Update:

More experimenting and trying some suggestions like ports, given by user marapet, have increased my confusion... For example, in the picture below, why does dot choose to draw these strange detours for Working->Failed and Failed->Announced, as opposed to straighter lines?

Graph with strange long edges

like image 941
Reinier Torenbeek Avatar asked Jul 21 '12 00:07

Reinier Torenbeek


People also ask

What are the 4 most important parts of any graph?

Review: Essential Graph ElementsClearly visible data points. Appropriate labels on each axis that include units. A trend line showing the mathematical model of the fit of your data, when appropriate. A legend if more than one type of information is included.


2 Answers

To me your output looks alright. TimedOut and Failed are of course all the way to the right because there is an edge going from Working to them. That's what dot does best, and while you can make some tweaks to adjust graphviz layouts, I think it's better to use an other tool if you want to create a particular graph layout and control everything.

That being said, I did give it a quick try with graphviz. I changed some lines to create a straight line with all the green nodes, and to align the red nodes as indicated in your question. I also added edge concentrators - the result doesn't look better to me:

digraph JobStateDiagram
{
  rankdir=LR;
  size="8,5";
  concentrate=true;

  node  [style="rounded,filled,bold", shape=box, fixedsize=true, width=1.3, fontname="Arial"];
  Created   [fillcolor=black, shape=circle, label="", width=0.25];
  Destroyed [fillcolor=black, shape=doublecircle, label="", width=0.3];
  Empty     [fillcolor="#a0ffa0"];
  Failed    [fillcolor="#ffa0a0"];
  Announced [fillcolor="#a0ffa0"];
  Assigned  [fillcolor="#a0ffa0"];
  Working   [fillcolor="#a0ffa0"];
  Ready     [fillcolor="#a0ffa0"];
  TimedOut  [fillcolor="#ffa0a0"];

  {
    rank=source; Created; Destroyed;
  }
  {
    rank=same;Announced;Failed;
  }
  {
    rank=same;Assigned;TimedOut;
  }

  edge  [style=bold, fontname="Arial", weight=100]
  Empty     -> Announced [ label="announce"   ];
  Announced -> Assigned  [ label="assign"     ];
  Assigned  -> Working   [ label="start"      ];
  Working   -> Ready     [ label="finish"     ];
  Ready     -> Empty     [ label="revoke", weight=1     ];

  edge  [color="#aaaaaa", weight=1]
  Announced -> TimedOut  [ label="timeout"    ];
  Assigned  -> TimedOut  [ label="timeout"    ];
  Working   -> TimedOut  [ label="timeout"    ];
  Working   -> Failed    [ label="error"      ];
  TimedOut  -> Announced [ label="announce"   ];
  TimedOut  -> Empty     [ label="revoke"     ];
  Failed    -> Announced [ label="announce"   ];
  Failed    -> Empty     [ label="revoke"     ];

  Created   -> Empty     [ label="initialize" ];
  Empty     -> Destroyed [ label="finalize"   ];
  Announced -> Empty     [ label="revoke"     ];
  Assigned  -> Empty     [ label="revoke"     ];
  Working   -> Empty     [ label="revoke"     ];
}

graphviz output

You may also improve by using ports in order to control where edges start and end.

As to your question about strange things in your dot file: Except line numbers (which finally allowed me to put column mode of my text editor to good use) and aligning, your file looks fine to me. I do structure my dot files similarly (graph properties, node list, groupings, edges) whenever possible. Just be aware that the order of first appearance of nodes may have an impact on the final layout.

like image 100
marapet Avatar answered Oct 11 '22 13:10

marapet


Although this is a very old question, I had similar problem and would like to share my result. Besides the "weight", "rank=same" tricks, I just found these methods can be used to adjust the layout result:

  • dir=back
  • add more edges or nodes and set style=invis

When it comes to this particular graph in the question, actually rank=same and weight would do the main job and style=invis can do some fine tuning. So by adding these lines

 {
  rank=same;Announced;Failed;
 }
 {
  rank=same;Assigned;TimedOut;
 }

to the file and adding weight=1 to the 'Ready to Empty' edge, and with some invisible edges to fine tune the spaces I got this:

GraphViz layout result

The complete graph dot source:

digraph JobStateDiagram
{
  rankdir=LR;
  size="8,5";

  node  [style="rounded,filled,bold", shape=box, fixedsize=true, width=1.3, fontname="Arial"];
  Created   [fillcolor=black, shape=circle, label="", width=0.25];
  Destroyed [fillcolor=black, shape=doublecircle, label="", width=0.3];
  Empty     [fillcolor="#a0ffa0"];
  Announced [fillcolor="#a0ffa0"];
  Assigned  [fillcolor="#a0ffa0"];
  Working   [fillcolor="#a0ffa0"];
  Ready     [fillcolor="#a0ffa0"];
  TimedOut  [fillcolor="#ffa0a0"];
  Failed    [fillcolor="#ffa0a0"];

  {
    rank=source; Created Destroyed;
  }
  {
    rank=same;Announced;Failed; #change here
  }
  {
    rank=same;Assigned;TimedOut; #change here
  }

  edge  [style=bold, fontname="Arial" weight=20] #change here
  Empty     -> Announced [ label="announce"   ];
  Announced -> Assigned  [ label="assign"     ];
  Assigned  -> Working   [ label="start"      ];
  Working   -> Ready     [ label="finish"     ];
  Ready     -> Empty     [ label="revoke" weight=1 ]; #change here

  edge  [fontname="Arial" color="#aaaaaa" weight=2] #change here
  Announced -> TimedOut  [ label="timeout"    ];
  Assigned  -> TimedOut  [ label="timeout" weight=1]; #change here
  Working   -> TimedOut  [ label="timeout"    ];
  Working   -> Failed    [ label="error"      ];
  TimedOut  -> Announced [ label="announce"   ];
  TimedOut  -> Empty     [ label="revoke"     ];
  Failed    -> Announced [ label="announce"   ];
  Failed    -> Empty     [ label="revoke"     ];

  edge  [style=bold, fontname="Arial" weight=1]
  Created   -> Empty     [ label="initialize" ];
  Empty     -> Destroyed [ label="finalize"   ];
  Announced -> Empty     [ label="revoke"     ];
  Assigned  -> Empty     [ label="revoke"     ];
  Working   -> Empty     [ label="revoke"     ];
  
  Assigned  -> Working   [ label="start"  style=invis     ]; #change here 
  Assigned  -> Working   [ label="start"  style=invis     ]; #change here 
}

Update: instead of putting 'Failed' and 'Announced' at the same rank, putting 'Failed', 'Assigned' and 'TimedOut' the same rank might produce a better result like below, which IMO better illustrates the similarity and difference between Failed and TimedOut. (You have to remove the invis edges though to get the graph below)

enter image description here

like image 27
Jacob Wu Avatar answered Oct 11 '22 13:10

Jacob Wu