Move 2 nodes to the side without affecting the rest of the layout

36 views Asked by At

I have the following dot layout:

digraph {
  a b c

  a -> b b -> c

  b -> g1 [dir=back,constraint=false]
  b -> g2 [dir=back,constraint=false]

  g1 -> g2 [style=invis]
}

result of the dot layout above

I would like g1 and g2 to be closer to each other and vertically centered around b like this:

what I want instead

I tried with a subgraph and cluster for g1 and g2 and with some invisible edges. I never managed to do anything good enough.

2

There are 2 answers

1
sroush On BEST ANSWER

The easiest way is to set rankdir=LR to make node alignment vertical instead of horizontal. Then use rank=same to keep a, b, and c aligned.

digraph {
  rankdir=LR  // now alignment is vertical

  {rank=same
    a b c
  }
  a -> b
  b -> c

  b -> g1 [dir=back] 
  b -> g2 [dir=back] 
}

Giving:
enter image description here

0
sroush On

Shortish answer: No. Because you are using the dot algorithm with rankdir=TB (default), all the nodes will be positioned on a horizontal rank (or row in this case).
However, you can post-process the result to modify the positioning. (Look for -n option here https://graphviz.org/doc/info/command.html)
Here is a small gvpr (https://www.graphviz.org/pdf/gvpr.1.pdf) script that will modify ("slide down") the positions of every node that has a new slideDown=1 attribute. (Yes, the Graphviz language allows you to make up your own attributes).
Your input, modified:

digraph {
  a b c
  g1 [slideDown=1]
  g2 [slideDown=1]
  
  a -> b b -> c
  b -> g1 [dir=back,constraint=false]
  b -> g2 [dir=back,constraint=false]
  g1 -> g2 [style=invis]
}

The gvpr script:

/*******************************************
  assumes rankdir=TB & no sliding down from bottom rank
*******************************************/
BEGIN{
  int   R=0, rPos[], Rank2P[], P2Rank[];
  float  YP;
}
N{
  YP=$.Y;
  rPos[YP]=1;
}
BEG_G{  // resets the graph traverse
 for (rPos[YP]){
   Rank2P[++R]=YP;
   P2Rank[YP]=R;
 }
}
N [slideDown=="1"]{
  float  nextY;
  nextY=Rank2P[P2Rank[$.Y]-1];
  $.oldPos=$.pos;
  $.pos=(string)$.X + "," + (string)(nextY+($.Y-nextY)/2);
}

the bash command line:
dot myFile.gv |gvpr -cf slideNodes.gvpr |neato -n -Tpng >myFile.png
Giving:
enter image description here