edge-layout in graphviz for fixed node positions - graphviz

I was trying to write my own little algorithm for graph layout that only creates a node layout but does not define edge routes. When I use Graphviz to turn the resulting dot file into a graph, the edges are straight lines that cross the nodes and even overlap each other. Is there a way to use Graphviz to layout the edges as nicely as the dot algorithm does, but have the nodes in predetermined fixed positions?
You can see the effect for instance on the following graph:
digraph test {
"a" [pos="0.0,0.0"];
"b" [pos="50.0,50.0"];
"c" [pos="100.0,100.0"];
"a" -> "b";
"a" -> "c";
"b" -> "c";
}
When drawn with dot -Knop -Tpng -otest.png test.dotty the line between a and c crosses b. What I want is that all nodes keep their positions, but the line between a and c goes around b.

Just add:
splines=true;
to your graph - result is:

Related

GraphViz DOT output: What are the 4-6 "pos" coordinates for an "edge"

I just started to experiment with GraphViz's "neato" command for
Kamada-Kawai graph visualization (solved using stress majorization).
I am particularly interested in extracting the laid out node
coordinates for external processing.
I was looking at this
question
to figure out the "pos" attribute for graph edges in the output DOT
file. The attribute consists of 4 coordinate points. One helpful
answer says that the
series of coordinats (not necessarily 4) are the control points of a
spline, likely a Bezier
spline.
The answerer is "compound eye", who I'll refer to as "CE". Here is
the example given:
// digrfG.dot
//-----------
digraph G {
A [label = "A" xlabel="a" pos="0,100" ]
B [label = "B" xlabel="b" pos="100,0"]
A -> B [label = "A->B www" xlabel="a->b"]
[pos="0,100 0,0 0,0 100,0"]
}
In Bash, it is processed by GraphViz using:
# Make image:
#------------
dot -Kneato -n2 -Tpng digrfG.dot >| digrfG.png
# Make output DOT file:
#----------------------
dot -Kneato -n2 digrfG.dot >| digrfG_out.dot
The output is:
# digrfG_out.dot
#---------------
digraph G {
graph [bb="-7,0,154,151"];
node [label="\N"];
A [height=0.5, label=A, pos="27,118",
width=0.75, xlabel=a, xlp="-3.5,143.5"];
B [height=0.5, label=B, pos="127,18",
width=0.75, xlabel=b, xlp="96,43.5"];
A -> B [label="A->B www", lp="42.5,75.5",
pos="27,118 27,18 27,18 127,18",
xlabel="a->b", xlp="63.5,60.5"];
}
My edge coordinates do not match
CE's, neither in the
numerical quantities nor in the number of coordinates. While I have 4
coordinates, CE has 6, including 2 coordinates at the start of the
series prefixed by "s," and "e,". The Bezier curve
page
cited by CE gives the impression that typical Bezier splines have 4
control points, including start and end points, though the math
allows for more. This Micrsoft
page
reinforces this impression of a 4-point default.
This GraphViz
page shows that
an edge's "pos" attribute contains a spline, starting with start and
end points, prefixed with "s," and "e," as per CE's output, but the
syntax is puzzling. If it is regular expression syntax, then there
are 4 or more coordinates following optional start and end points.
That might explain why I have no coordinates prefixed with "s," or
"e,", but I have 4 coordinates.
In digrfG_out.dot above, if I compare the 4 coordinates with the
node coordinates, it is clear that the first and last of the 4
coordinates match the node coordinates. It seems that CE's GraphViz
defaults to 6 control points and explicitly designates start and end
points at the head of the list of coordinates, whereas my GraphViz
defaults to 4, without special treatment of the start and end
points. Since GraphViz's spline
page is so
ambiguous, I was wondering if this interpretation can be confirmed.
Thanks.
I would suggest skipping CE's explanation (not necessarily wrong, but maybe ambiguous) and go to the sources on the Graphviz website.
Yes, Bezier curves require 4 points per "segment" (my term) but the last point in a segment is also used as the first in the next segment. Graphviz's arrowheads use separate points - for one end of the arrowhead.
The optional s (start) and e (end) points are for optional arrowheads. Then 4 required points and then optional sets of 3 points.
See p.36 https://www.graphviz.org/pdf/dotguide.pdf, https://forum.graphviz.org/t/how-to-control-the-points-of-splines/1087, and https://forum.graphviz.org/t/fun-with-edges/888 - in addition to the (yes, regular expression) http://www.graphviz.org/docs/attr-types/splineType/
I hope this helps.
Any edge can have arrowheads, even in a non-directed graph. Digraph just sets the default (arrowhead or no arrowhead). The dir attribute (https://graphviz.org/docs/attrs/dir/) explicitly sets arrowheads.
Finally, arrowhead shape (https://graphviz.org/doc/info/arrows.html) can be "none".
graph {
A--B [dir=forward]
C--D [dir=back]
E--F [dir=both]
G--H [dir=none]
}
Dot produces this:

Graphviz (dot) control edge routing

In this graph the bottom edge is not drawn symmetrical to the top edge:
digraph G {
A:ne -> A:nw;
A:sw -> A:se;
}
I want it to look more like a "fat snowman" with the edge A:sw -> A:se; looping below the node. Is there a way?
Short answer no - or not easily.
Loops seem to be placed from the rankdir direction. If rankdir is TB (down), loops seem to be placed "up".
It you're willing to work at it, you can run your graph twice, once with rankdir=TB, once with rankdir=BT - both times with -Tdot. Then you'd have to replace the offending edge with the equivalent edge from the other graph. [I hope this makes some sense]
Here is a tweaked version of your graph run with different values of rankdir:
digraph G {
A:ne -> A:nw;
A:sw -> A:se;
dummy [style=invis]
dummy -> A [style=invis]
}

In GraphViz, make node positions within a subgraph independent from nodes in other subgraphs?

Using dot, the basic layout puts nodes into layers. If you create subgraphs, it groups related nodes inside of rectangles, but the nodes are still in layers, and those layers are influenced by the nodes outside of the subgraph.
Sometimes, this is great. But sometimes, when a subgraph is an independent visual entity, it might be nice to be able to lay out its content without respect to the layers of the other parts of the graph. Take for example the following:
digraph x {
subgraph one {
a [ label="a\nvery\nlong\nlabel" ]
b [ label="another\nvery\nlong\nlabel" ]
c [ label="still\nmore\nlong\nlabels" ]
a -> b - > c
}
subgraph two {
w -> x -> y -> z
}
}
Because of the long labels, the nodes in subgraph one will take up a lot of space. But because of the layer-based layout, the nodes in subgraph two will be vertically aligned with the corresponding nodes from subgraph one.
Is there a way to make it layout subgraph two as if subgraph one did not exist?
Not directly with dot. Dot does rank alignment across the entire graph. However here are two ways to get close to what you want:
use neato -Goverlap=false -Gmode=hier to approximate a dot layout:
or split the various parts into separate graphs, use dot -Tdot to layout each, then use gvpack (https://graphviz.org/pdf/gvpack.1.pdf) to combine the parts into a single output. Like so:
dot -Tdot ComboGraph1a.gv >ComboGraph1a.dot
dot -Tdot ComboGraph1b.gv >ComboGraph1b.dot
gvpack -array_ib2 ComboGraph1?.dot |neato -Tpng -n2 >oooo.png
Giving:

Add extra edges to a digraph in Graphviz

I have a .dot digraph which shows a graph as I want (depicting relationship between some tables). I want to add redundant edges to the graph (to represent redundant relationships in the database which exist only to write queries less effortly). These redundat edges, which will be written in a "dotted" style, must not change the deployment of nodes in the graph.
In other words, there's edges which must affect the node positions to print the graph pretty, and other edges which must to be added after the node positions are already computed (which will be styled differently --light gray, dotted, etc; to show that they're not main edges).
Is there options in Graphviz to specify "extra" edges?
Use constraint=false and color=gray on those additional edges.
digraph G {
a -> b -> c -> d;
d -> a [constraint=false,color=gray]
a -> z -> x -> d;
}
Play with that on http://graphviz.it/#/rhlWBZsz

Can you join edges when they go to the same node?

See the line on the leftmost side of this image.
This isn't a perfect example because the lines don't end on a node, but imagine that there is a node on the bottom left corner of the image. Normally in graphviz if I have a graph like this:
digraph G {
a->c
b->c
}
Then I get two separate lines going into c. Is it possible to have these two lines join before they reach c?
Yes, it is possible to have two lines join before they reach c but, as far as I can see, it requires inserting an invisible node to do it. e.g.:
digraph G {
x [style=invis, height=0, label=""]
a->x [dir=none]
b->x [dir=none]
x->c
}
... which gives:

Resources