Lost x y edge when using rank=same - graphviz

I'm trying to visualize doubly linked lists using GraphViz.
An example:
digraph List {
rankdir=LR;
node [shape=record];
0 [label="{<prev> | <length> 2 | <tone> 1 | <next>}"];
1 [label="{<prev> | <length> 1 | <tone> A | <next>}"];
0:<next>:c -> 1:n [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false, arrowsize=1.2];
1:<prev>:c -> 0:s [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false, arrowsize=1.2];
}
The result is fine except for one thing; the height of the elements. With each consecutive element added the height decreases, I want all elements to be on the same height. But when I add
{rank=same; 0; 1;}
a GraphViz error occurs (Error: lost 1 0 edge). Now, the only fix I could find for this error is to replace the record shaped nodes with plaintext nodes and using HTML labels to create the record shape.
I tried this, but it produces the same error.
The code using HTML labels:
digraph List {
rankdir=LR;
node [shape=plaintext];
0 [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD PORT="prev"> </TD>
<TD PORT="length">2</TD>
<TD PORT="note">1</TD>
<TD PORT="next"> </TD>
</TR>
</TABLE>>];
1 [label=<
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR>
<TD PORT="prev"> </TD>
<TD PORT="length">1</TD>
<TD PORT="note">A</TD>
<TD PORT="next"> </TD>
</TR>
</TABLE>>];
0:next:c -> 1:n [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false, arrowsize=0.8];
1:prev:c -> 0:s [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false, arrowsize=0.8];
}
I would appreciate any suggestions on how to solve this issue.
A previous attempt looked like this:
digraph List {
rankdir=LR;
node [shape=record];
0 [label="{<prev> | <firstName> Wolfgang Amadeus | <lastName> Mozart | <instrument> Klavier | <next>}"];
1 [label="{<prev> | <length> 1 | <tone> A | <next>}"];
0:<next>:c -> 1:<prev> [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false, arrowsize=0.8];
1:<prev>:c -> 0 [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false, arrowsize=0.8];
}
Here there is no clear distinction between the two arrows. Getting two distinct arrows between the nodes would also solve my problem.

You can align the nodes using a strong ("heavy") link, an invisible edge, between the last element of the first and the first element of the second node.
Add this line as the last one to your HTML-like code (which gives you much more flexibility than record shapes)
0:next:e -> 1:prev:w[ weight = 100, style = invis ];
and you get
which is what I think you want.

Related

Graphviz: Loop to the left should have the same shape as loop to the right

Consider this small graph:
digraph G {
{rank = same; node12; node11;}
node11 [ label = "node left", shape=square ]
node11 -> node11 [label=" i[2,9]"]
node11 -> node12 [label=" k[2]"]
node12 [ label = "node right", shape=square ]
node12 -> node12 [label=" i[9]"]
}
I converted it to pdf with dot -Tpdf
$ dot -V
dot - graphviz version 2.40.1 (20161225.0304)
As you can see the (self-)loop of the left node and the edge connecting the left and right node overlap. I was trying to fix this by using the compass functionality of graphviz. My first try was: node11:w -> node11:w [label=" i[2,9]"]:
However, the resulting shape of the loop has changed. I do not want this and I agree that it looks uglier. Increasing nodesep=1; does not give you the same shape as the right one. Of course you can make the right loop identical to the left loop by adding :e. But I prefer the shape of the original right loop.
Are there any other possibilities to achieve this?
BTW: Mathematica graph drawing is cleverer here: it automatically places the self loop to the other side. But IMHO needs a lot of customization to get a neutral style:
Graph[{1 -> 1, 1 -> 2, 2 -> 2},
EdgeLabels -> {(1 -> 1) -> "i[2,9]", (1 -> 2) -> "k[2]", (2 -> 2) ->
"i[9]"}, EdgeLabelStyle -> Directive[15, Background -> White],
VertexSize -> 0.3, VertexShapeFunction -> "Rectangle",
VertexStyle -> White, EdgeStyle -> Black,
VertexLabels -> {1 -> Placed["node left", Center],
2 -> Placed["node right", Center]}]
And just to be clear: this is only a fragment of the graph. The final graph looks like:
You might be able to do it somewhat like this:
digraph G {
node[margin=0 _color=invis shape=none height=.2
label=<<table BORDER="1" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0">
<tr>
<td port="a1"></td>
<td port="b1"></td>
<td port="c1"></td>
<td port="d1"></td>
<td port="e1"></td>
</tr>
<tr>
<td port="a2"></td>
<td rowspan="3" colspan="3">
\N
</td>
<td port="e2"></td>
</tr>
<tr>
<td port="a3"></td>
<td port="e3"></td>
</tr>
<tr>
<td port="a4"></td>
<td port="e4"></td>
</tr>
<tr>
<td port="a5"></td>
<td port="b5"></td>
<td port="c5"></td>
<td port="d5"></td>
<td port="e5"></td>
</tr>
</table>>]
x:a2:w->x:a4:w
x:e2:e->x:e4:e
x->y
y:a2:w->y:a4:w
}
rendered by viz-js.com:

Nested graphviz trees?

TL;DR: Is there some short-notation in graphviz for creating trees, that doesn't require re-typing the node names?
I am trying to create a mindmap with graphviz's twopi tool. In order to avoid rewriting the same labels over and over (or using obscure shorthands), I was trying to use nested braces.
Essentially I expected the two subgraphs here to have the same structure:
digraph example {
subgraph AA {
root -> {a b c}
a -> {a1 a2 a3}
b -> {b1 b2 b3}
c -> {c1 c2 c3}
}
subgraph XX {
_root -> {
_a -> { _a1 _a2 _a3 }
_b -> { _b1 _b2 _b3 }
_c -> { _c1 _c2 _c3 }
}
}
}
but instead, the first one has the hierachical structure I wanted, while the second has unintended connections from the root node. Compiled with twopi -Tpng example.dot -o example.png:
The first form is fine with such short symbolic names, but when the labels contain actual text, the text file quickly becomes hard to read.
The second form would help, but obviously I understood the effect of grouping in graphviz.
Is there some syntax, that would allow to avoid repeating node names as I tried in subgraph XX?
I'm pretty sure there isn't. From https://www.graphviz.org/doc/info/lang.html:
An edge statement allows a subgraph on both the left and right sides of the edge operator. When this occurs, an edge is created from every node on the left to every node on the right.
This means that you have to repeat something in order not to have edges from a branch (including the root) in the tree to everything on that branch. I usually resort to repeat the nodes that are easiest to write.
I don't think this will make you much happier, but here's an approach where only the root node is repeated:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://d3js.org/d3.v5.js"></script>
<script src="https://unpkg.com/viz.js#1.8.2/viz.js" type="javascript/worker"></script>
<script src="https://unpkg.com/d3-graphviz#2.4.2/build/d3-graphviz.js"></script>
<div id="graph" style="text-align: center;"></div>
<script>
var dotSrc = `
digraph example {
subgraph AA {
root -> {a b c}
a -> {a1 a2 a3}
b -> {b1 b2 b3}
c -> {c1 c2 c3}
}
subgraph XX {
_root -> _a -> { _a1 _a2 _a3 }
_root -> _b -> { _b1 _b2 _b3 }
_root -> _c -> { _c1 _c2 _c3 }
}
}
`;
d3.select("#graph").graphviz()
.engine("twopi")
.renderDot(dotSrc);
</script>

Graphviz family tree with fixed nodes

I just had the idea to overlay a family tree over a table plan such that guests of my event can see where other family members sit. I have the table plan as pdf file. Would it be possible to fix the positions of the nodes such that they coincide with the persons seat and to let graphviz optimize the routing of the edges?
You can certainly fix the node positions (using the pos attribute with ! or the node attribute pin=true -- see the answer to graphviz - fixed node positions, which appears to be by one of the GraphViz team members, however the edge routing might require some aesthetic help.
For example, given familytree.dot:
digraph G {
node [ shape="plaintext" ]
graph [ splines="ortho" ]
dad -> parents
mom -> parents
parents -> son1
parents -> son2
parents -> daughter1
parents -> daughter2
granddad -> dad
granddad [pos = "0,2!"]
dad [pos = "0,4!"]
mom [pos = "0,6!"]
son1 [pos = "2,2!"]
son2 [pos = "2,4!"]
daughter1 [pos = "2,6!"]
daughter2 [pos = "2,8!"]
}
... running neato -Tpng -ofamilytree.png familytree.dot gives the following result:

How to select certain child nodes in xpath?

If I have some XML structure like this
A
B C
D E F G
So A has two children nodes B and C, and B has two children nodes D and E, and C has two children nodes F and G. How can I write an xpath to select E and G? I'm looking for a way to union two selectors something like /A/(B/E)|(C/G).
I was trying something like
/A/B/E + /A/C/G
but that has syntax errors...
I have built an XML input from your scenario above, as follows:
<A>
<B>
<D>DDD</D>
<E>EEE</E>
</B>
<C>
<F>FFF</F>
<G>GGG</G>
</C>
</A>
if you run this query:
/A[B]//E|/A[C]//G
it outputs:
<E>EEE</E>
<G>GGG</G>

simple "T shaped" graph in graphviz

Need draw a graph with dot/graphviz like this image:
The texts can be above arrows, like graphviz does it. But how to achieve the T-layout? Need make a cluster for the top row?
This is one possibility using rank=same for a subgraph:
digraph g {
node[shape=point, width=0.2];
{
rank=same;
p1 -> n [label="text1"];
n -> p2 [label="text2"];
}
n -> p3 [label="text3", dir=back];
n[label="node", shape=rect, style=rounded];
}
You could also use a left-right layout instead of top-down.
An other possibility is to disable the effect of some edges using constraint=false:
digraph g {
node[shape=point, width=0.2];
p1 -> n [label="text1", constraint=false];
n -> p2 [label="text2", constraint=false];
n -> p3 [label="text3", dir=back];
n[label="node", shape=rect, style=rounded];
}
The result is the same.
dot usually layouts trees in layers. To force an edge to not be a layer separation you can add the constraint=false option. So something like:
digraph {
A [shape=point]
B [shape=point]
C [shape=point]
N [label="node"]
A -> N [label="text1", constraint=false]
N -> B [label="text2", constraint=false]
N -> C [label="text3", dir=back]
}
should work.
Note that the edge from the lower node to "node" has to be backwards, since dot layouts trees from top to bottom. Therefore the logical edge direction has to be from top to bottom, even though the display direction might be the other way round (which is the case here).

Resources