1

I have a graph which can be summarized in English as:

A -> [B -> C -> D] -> E
B -> A
E -> B

Where the square braces indicate a subgraph, with a box drawn around it.

I have implemented it in graphViz/dot as follows:

digraph {
  rankdir = LR
  graph [overlap = true, fontname = Helvetica]

  A [shape="box", style="dashed", label="Alab"]

  subgraph clusterx {
    node [shape="box"]
    B [label="Blab"]
    C [label="Clab"]
    D [label="Dlab"]

    B -> C -> D
    label = "Subgraph Box Label";
    labeljust = "l";
  }

  E [shape="box", style="dashed", label="Elab"]
  A -> B [label = " ", headport="nw", tailport="ne"]
  B -> A [label = " ", headport="se", tailport="sw"]
  D -> E
  E -> B [tailport="s", headport="s"]
}

Current Graph

This renders in a valid way, but I would like to correct a few visual things.

  1. I want there to be more space between A and the subgraph, and less space between nodes of the subgraph.
  2. I want E to be on the same vertical alignment as the other nodes. I want the D -> E edge to be a flat line.
  3. I want the E -> B edge to bend in a more aesthetically pleasing way. I would prefer it come out of the 's' port of E, take a rounded 90 left turn, continue left until it's reached node B, and then take a rounded 90 degree turn up, and enter the 's' port of B in a perpendicular way. I believe this occurs because of the way that graphViz spaces the spline points -- I guess what I actually want to do is drag every intermediate spline point down a little bit so that the left-traveling portion of the edge is flat.

I have tried adjusting nodesep and ranksep parameters to solve the first two problems and not been able to consistently understand why the changes I make produce the changes they do. I have not been able to solve #3 at all.

Additionally, I am using diagrammeR in R to render this to PDF and HTML documents, so any answer here should be output format agnostic, in case it matters.

Any advice? I've tried scouring the graphViz documentation to no avail and I can't find any worked examples that exhibit these problems.

aaron
  • 315
  • 1
  • 7

1 Answers1

1

To improve the position of the nodes and the shape of the Edge (though this is not exactly what you imagined), use constraint=false:

E -> B [tailport="s", headport="s", constraint=false]

The space between A and B is trickier - rank Separation is the same in the graph and in subgraph. You can insert an invisible node to increase the distance, though this may not be worth it:

ranksep=0.2;
invisnode[style=invis, shape=point, width=0.2];
A -> invisnode [style=invis];
invisnode -> B [style=invis];

and invert the direction of the edge going from B to A with dir=back:

A -> B [label = " ", headport="sw", tailport="se", dir=back]

not perfect

marapet
  • 54,856
  • 12
  • 170
  • 184
  • First of all, thank you very much. This is great. I'll probably not add the invisible node because the complexity tradeoff isn't the best. Can you help me understand why "constraint = false" works on the `E -> B` problem? I understand that this parameter is telling graphViz not to consider this edge in the ranking -- but not why this works. The `E` node was already ranked higher (lower) than every other node, and the weird placement of the node wasn't along the rank axis, it was off-axis. Thanks again. – aaron Oct 23 '19 at 16:13
  • 1
    As I understand, node positions are optimized to allow the placement of all edges going from and to the center of the nodes. The edges themselves are layed out in a second step, taking into consideration the ports etc. It therefore makes sense to place node E not in a straight line to accomodate for the edge back to B. `constraint=false` not only disables the edges influence in ranking, but also in placing the node within its rank as needed to connect all edges. – marapet Oct 24 '19 at 06:53