Cluster Alignment

Hey.

I am new to graphviz and dot, and need your help in figuring out something that I am guessing may be very easy to accomplish.

I need to draw this diagram that may have one or two clusters. If there are two clusters, i need that the two of them to be aligned horizontally, as seen in image 1. I noticed that when I create two clusters, and there are no link between any of their nodes, the clusters are always aligned as I would like them to. However, when I create a connection (or more) between one node of cluster 1 and another node of cluster 2 (see dot below), the clusters are never aligned horizontally (see image 2).

So my question is: what attribute, property or command line should I se to get the clusters always horizontally aligned?

digraph G {
subgraph cluster_box1 {
a -> b;
b -> c;
c -> d;
label = "BOX 1"
}

subgraph cluster_box2 {
x -> z;
z -> y;
label = "BOX 2"
}
a -> y;
}

AttachmentSize
image 112.45 KB
image 216.09 KB

There are two things you need

There are two things you need to consider. First, dot is going to make edges as short as possible, so the edge between nodes a and y will have length 1 (i.e., the nodes will be on adjacent ranks). Second, clusters aren't really first-class objects. They will simply be the smallest box you can put around the nodes contained in the cluster. So, there are two ways to get the cluster boxes to align. The simplest is to make sure the top node in each cluster always belongs to the same rank. You can do this by adding the line

  {rank=same a x}

to your graph and using the -Gnewrank flag when you run dot. The tops of the clusters will be aligned, but you'll have long edge from a to y.

An alternative is to use nodes to represent the cluster labels by nodes on the same rank, and attach them to all the nodes in the cluster (or the top nodes) by a weak invisible edge.

digraph G {
{rank=same c1 c2}
subgraph cluster_box1 {
c1 [margin=0 shape=none label="BOX 1"]
c1 -> a [style=invis weight=0]
a -> b;
b -> c;
c -> d;
}

subgraph cluster_box2 {
c2 [margine=0 shape=none label="BOX 2"]
c2 -> x [style=invis weight=0]
x -> z;
z -> y;
}
a -> y;
}

Now the top of the clusters are aligned, and the a->y edge is short. But you have more space between the label and the top node in the cluster. If this is unacceptable, then the only recourse is a tad of post-processing. You would take the output of dot applied to your original graph and tweak the bounding box and label position of each cluster to align them. This can be done using a gvpr script. You would then run the command

   dot al.gv | gvpr -c -fal.g | neato -n2 -Tpng > out.png

where al.gv is your original graph and al.g is a file containing the gvpr script

BEG_G {
  graph_t sg;
  double delta, y, maxy = 0;
  string ur;
  for (sg=fstsubg($);sg;sg=nxtsubg(sg)) {
    if (sg.name != "cluster*") continue;
    y = (double)yOf(urOf(sg.bb));
    maxy = MAX(y,maxy);
  }
  for (sg=fstsubg($);sg;sg=nxtsubg(sg)) {
    if (sg.name != "cluster*") continue;
    ur = urOf(sg.bb);
    y = (double)yOf(ur);
    if (y < maxy) {
      sg.bb = sprintf ("%s,%s,%.03f",llOf(sg.bb),xOf(ur),maxy);
      if (sg.lp != "") {
        delta = maxy-y;
        y = (double)yOf(sg.lp);
        sg.lp = sprintf ("%s,%.03f",xOf(sg.lp),y+delta);
      }
    }
  }
}

Another advantage to this last approach is that you don't have to know beforehand which are the top nodes in the cluster.

Recent comments