I'm trying to generate a Tree graph (left to right one), to illustrate an object reference tree.
Beside this, I want the leafs to appear vertically consequent, because this indicates some order of execution.
The dot code is as follows:
digraph G {
rankdir=LR
subgraph cluster_0 {
L1 L2 L3 L4 L5 L6
L10 L20 L30 L40 L50 L60
{ rank=same;
L1 -> L2 -> L3 -> L4 -> L5 -> L6 ->
L10 -> L20 -> L30 -> L40 -> L50 -> L60
}
}
subgraph cluster_1 {
R
D10 D11
D20 D21 D22 D23
D30 D31 D32 D33 D34 D35 D36 D37
}
R->D10
R->D11
D10 -> D20
D10 -> D21
D11 -> D22
D11 -> D23
D20 -> D30
D20 -> D31
D21 -> D32
D21 -> D33
D22 -> D34
D22 -> D35
D23 -> D36
D23 -> D37
D30 -> L1
D20 -> L2
D31 -> L3
D32 -> L4
D21 -> L5
D33 -> L6
D34 -> L10
D22 -> L20
D35 -> L30
D36 -> L40
D23 -> L50
D37 -> L60
}
What I've got far (using https://dreampuf.github.io/GraphvizOnline/ to render SVG):
The problem is, I want the leafs to show up in the order of declaration.
Following some posts on SO, I've been playing around with constraint / invisible edges / ranking system
but couldn't quite get my hands on it.
It'd be nice if some graphvizard could extend their hand over here.
note that this procedure will be later automated with python, so some robust idea will be more than appreciated.
note 2, the tree could have up to hundreds of leafs.
note 3, if you know some good python lib to generate Graphs which is more intuitive (for you at least) than Graphviz, please comment. I'm currently using pydot & graphviz (py3)
By moving the leaf nodes out and adding weights to them I have the following:
I changed the dot input to:
digraph G {
rankdir=LR
subgraph cluster_0 {
L1 L2 L3 L4 L5 L6
L10 L20 L30 L40 L50 L60
}
subgraph cluster_1 {
R
D10 D11
D20 D21 D22 D23
D30 D31 D32 D33 D34 D35 D36 D37
}
R->D10
R->D11
D10 -> D20
D10 -> D21
D11 -> D22
D11 -> D23
D20 -> D30
D20 -> D31
D21 -> D32
D21 -> D33
D22 -> D34
D22 -> D35
D23 -> D36
D23 -> D37
D30 -> L1
D20 -> L2
D31 -> L3
D32 -> L4
D21 -> L5
D33 -> L6
D34 -> L10
D22 -> L20
D35 -> L30
D36 -> L40
D23 -> L50
D37 -> L60
{ rank=same;
L1-> L2 [style=invis, weight=1000]
L2-> L3 [style=invis, weight=1100]
L3-> L4 [style=invis, weight=1200]
L4-> L5 [style=invis, weight=1300]
L5-> L6 [style=invis, weight=1400]
L6-> L10 [style=invis, weight=1500]
L10-> L20 [style=invis, weight=1600]
L20-> L30 [style=invis, weight=1700]
L30-> L40 [style=invis, weight=1800]
L40-> L50 [style=invis, weight=1900]
L50-> L60 [style=invis, weight=2000]
}
}
Related
This question is a continuation of this question.
In addition to strictly east-to-west arcs, I would also like them to be orthogonal (ie not curved.) So I added the attribute "splines=ortho" to the dot file, like this:
digraph net {
graph [splines=ortho]
"C0" [shape=oval label="C0"]
"C1" [shape=oval label="C1"]
"B0" [shape=box label="B0"]
rankdir="LR"
"C0":e -> "B0":w
"B0":e -> "C1":w
"C1":e -> "B0":w
}
Now I am getting this image, where the arcs are going through the nodes:
Is it possible to get a picture like this, where the orthogonal arc moves around the nodes, something like this?
It is possible, but you have to DIY. Here we add lots of invisible nodes and then "connect the dots" (puns!).
Note the use of dir (https://graphviz.org/docs/attrs/dir/), headclip (http://www.graphviz.org/docs/attrs/headclip/), and tailclip (https://graphviz.org/docs/attrs/tailclip/) attributes.
digraph net {
graph [splines=false]
// rankdir="LR" << turned it off, makes things easier?
graph [nodesep=.07]
{
node [style=invis label=""]
I1 I2 I3 I4 I5 I6 X2 X4 X6
}
{rank=same I1 I2 I3 I4 I5 I6}
{rank=same C0 B0 C1 X2 X4 X6}
"C0" [shape=oval label="C0"]
"C1" [shape=oval label="C1"]
"B0" [shape=box label="B0"]
C0 -> X2 [dir=none headclip=false]
X2 -> B0 [tailclip=false]
B0 -> X4 [dir=none headclip=false]
X4 -> C1 [tailclip=false]
C1 -> X6 [dir=none headclip=false]
{
edge [dir=none tailclip=false headclip=false]
I6 -> X6
I2 ->I3 ->I4 -> I5 ->I6
}
I2 -> X2 [tailclip=false headclip=false]
}
Giving:
How can I make the graphviz preserve the order of nodes in subgraph?
See the image and the code below. For some reason the second node (with the number 2) is displayed at the top and the first node is at the bottom.
I took a look at this questions but it did not solve the issue (or then I did not understand how to implement the suggestions properly):
Preventing graphviz from rearranging nodes
digraph G {
rankdir=LR
splines=line
nodesep=0.3;
ranksep=2
node [label=""];
// edge [dir=none];
edge[arrowhead="empty"];
// graph [ordering="out"];
subgraph cluster_0 {
color=white;
// {rank=same;x1;x2;x3;x4;x5}
node [style=solid,color=blue4, shape=circle];
x1 [label="1"] x2 [label="2"] x3 [label="3"] x4 [label="4"] x5 [label="5"];
}
subgraph cluster_1 {
color=white;
node [style=solid,color=red2, shape=circle];
edge[style=invisible]
a12 [label="1"] a22 [label="2"] a32 [label="3"] a42 [label="4"];
}
subgraph cluster_2 {
color=white;
node [style=solid,color=red2, shape=circle];
a13 a23 a33 a43;
}
subgraph cluster_3 {
color=white;
node [style=solid,color=seagreen2, shape=circle];
O1 O2 O3;
}
x1 -> a12;
x1 -> a22;
x1 -> a32;
x1 -> a42;
x2 -> a12;
x2 -> a22;
x2 -> a32;
x2 -> a42;
x3 -> a12;
x3 -> a22;
x3 -> a32;
x3 -> a42;
x4 -> a12;
x4 -> a22;
x4 -> a32;
x4 -> a42;
x5 -> a12;
x5 -> a22;
x5 -> a32;
x5 -> a42;
a12 -> a13
a22 -> a13
a32 -> a13
a42 -> a13
a12 -> a23
a22 -> a23
a32 -> a23
a42 -> a23
a12 -> a33
a22 -> a33
a32 -> a33
a42 -> a33
a12 -> a43
a22 -> a43
a32 -> a43
a42 -> a43
a13 -> O1
a23 -> O1
a33 -> O1
a43 -> O1
a13 -> O2
a23 -> O2
a33 -> O2
a43 -> O2
a13 -> O3
a23 -> O3
a33 -> O3
a43 -> O3
}
I could not find a way to use ordering successfully, either. Because they did not seem to be used, I removed the cluster references. This version uses weight attributes to keep the nodes in order.
digraph G {
rankdir=LR
splines=line
nodesep=0.3;
ranksep=2
node [label=""];
edge[arrowhead="empty"];
{
rank=same
node [style=solid,color=blue4, shape=circle];
x1 [label="1"] x2 [label="2"] x3 [label="3"] x4 [label="4"] x5 [label="5"];
edge [weight=50] // arbitrarily large integer
edge [style=invis]
x1->x2 x2->x3 x3->x4 x4->x5
}
{
rank=same
node [style=solid,color=red2, shape=circle];
edge[style=invisible]
a12 [label="1"] a22 [label="2"] a32 [label="3"] a42 [label="4"];
edge [weight=50] // arbitrarily large integer
edge [style=invis]
a12->a22 a22->a32 a32->a42
}
{
rank=same
node [style=solid,color=red2, shape=circle];
a13 a23 a33 a43;
}
{
rank=same
node [style=solid,color=seagreen2, shape=circle];
O1 O2 O3;
}
x1 -> a12;
x1 -> a22;
x1 -> a32;
x1 -> a42;
x2 -> a12;
x2 -> a22;
x2 -> a32;
x2 -> a42;
x3 -> a12;
x3 -> a22;
x3 -> a32;
x3 -> a42;
x4 -> a12;
x4 -> a22;
x4 -> a32;
x4 -> a42;
x5 -> a12;
x5 -> a22;
x5 -> a32;
x5 -> a42;
a12 -> a13
a22 -> a13
a32 -> a13
a42 -> a13
a12 -> a23
a22 -> a23
a32 -> a23
a42 -> a23
a12 -> a33
a22 -> a33
a32 -> a33
a42 -> a33
a12 -> a43
a22 -> a43
a32 -> a43
a42 -> a43
a13 -> O1
a23 -> O1
a33 -> O1
a43 -> O1
a13 -> O2
a23 -> O2
a33 -> O2
a43 -> O2
a13 -> O3
a23 -> O3
a33 -> O3
a43 -> O3
}
Giving:
(yes, there many failures in between)
I have a following code from .dot file:
digraph "fowchart" {
p1 [shape=point,label="",fixedsize=true,width=0.1,xlabel="Channel.fromFilePairs"];
p2 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="ifEmpty"];
p1 -> p2;
p2 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="ifEmpty"];
p3 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="map"];
p2 -> p3;
p3 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="map"];
p4 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="separate"];
p3 -> p4;
p4 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="separate"];
p5 [shape=point];
p4 -> p5 [label="bim_ch"];
p4 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="separate"];
p6 [label="maf"];
p4 -> p6 [label="raw_ch"];
p6 [label="maf"];
p7 [label="iteratCallRate"];
p6 -> p7 [label="qc1"];
p7 [label="iteratCallRate"];
p9 [label="HWEfilt"];
p7 -> p9 [label="qc2"];
p7 [label="iteratCallRate"];
p8 [label="checkIfMissingDroped"];
p7 -> p8 [label="qc2_A"];
p9 [label="HWEfilt"];
p10 [label="pruningLD"];
p9 -> p10 [label="qc3"];
p10 [label="pruningLD"];
p11 [label="PCA"];
p10 -> p11 [label="qc4"];
p10 [label="pruningLD"];
p11 [label="PCA"];
p10 -> p11 [label="qc4_PCA"];
p11 [label="PCA"];
p14 [label="heteroziogistyTes"];
p11 -> p14 [label="qc5_PCA"];
p11 [label="PCA"];
p14 [label="heteroziogistyTes"];
p11 -> p14 [label="qc5"];
p11 [label="PCA"];
p13 [shape=point];
p11 -> p13 [label="outliers_pca_evec"];
p11 [label="PCA"];
p12 [shape=point];
p11 -> p12 [label="PC_for_cov"];
p14 [label="heteroziogistyTes"];
p17 [label="plink"];
p14 -> p17 [label="qc6"];
p14 [label="heteroziogistyTes"];
p15 [shape=point];
p14 -> p15 [label="qc6_LD"];
p14 [label="heteroziogistyTes"];
p36 [label="filterByInfo"];
//p14 -> p36 [label="sample"];
p16 [shape=point,label="",fixedsize=true,width=0.1];
p17 [label="plink"];
p16 -> p17;
p17 [label="plink"];
p19 [label="shapeitCheck"];
p17 -> p19 [label="plinkOutChan"];
p18 [shape=point,label="",fixedsize=true,width=0.1];
p19 [label="shapeitCheck"];
p18 -> p19 [label="db_path"];
p19 [label="shapeitCheck"];
p21 [label="shapeit"];
p19 -> p21 [label="shapitCheckChan"];
p20 [shape=point,label="",fixedsize=true,width=0.1];
p21 [label="shapeit"];
p20 -> p21 [label="db_path"];
p21 [label="shapeit"];
p22 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="flatMap"];
p21 -> p22 [label="shapeitChan"];
p22 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="flatMap"];
p24 [label="impute2"];
p22 -> p24 [label="imputeChromChunckChannel"];
p23 [shape=point,label="",fixedsize=true,width=0.1];
p24 [label="impute2"];
p23 -> p24 [label="db_path"];
p24 [label="impute2"];
p25 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="toSortedList"];
p24 -> p25 [label="impute2Chan"];
p24 [label="impute2"];
p27 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="toSortedList"];
p24 -> p27 [label="impute2Chan2"];
p25 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="toSortedList"];
p26 [shape=point];
p25 -> p26;
p27 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="toSortedList"];
p28 [shape=point];
p27 -> p28;
p29 [shape=point,label="",fixedsize=true,width=0.1];
p30 [label="impute2Concat"];
p29 -> p30 [label="impute2MapChannel"];
p30 [label="impute2Concat"];
p33 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="toList"];
p30 -> p33 [label="addedChrNum"];
p31 [shape=point,label="",fixedsize=true,width=0.1];
p32 [label="impute2Concat2"];
p31 -> p32 [label="impute2MapChannel2"];
p32 [label="impute2Concat2"];
p34 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="toList"];
p32 -> p34 [label="addedChrNum_info"];
p33 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="toList"];
p35 [label="mergeChromosomes"];
p33 -> p35;
p34 [shape=circle,label="",fixedsize=true,width=0.1,xlabel="toList"];
p35 [label="mergeChromosomes"];
p34 -> p35;
p35 [label="mergeChromosomes"];
p36 [label="filterByInfo"];
p35 -> p36 [label="genome"];
p35 [label="mergeChromosomes"];
p36 [label="filterByInfo"];
p35 -> p36 [label="genome_info"];
p36 [label="filterByInfo"];
p37 [label="postImpQC"];
p36 -> p37 [label="plink_post_imp"];
p37 [label="postImpQC"];
p38 [label="associationTest"];
p37 -> p38 [label="chrposa1a2"];
p37 [label="postImpQC"];
p40 [label="PRS"];
p37 -> p40 [label="chrposa1a2_forPRS"];
p38 [label="associationTest"];
p39 [label="gwasGraphs"];
p38 -> p39 [label="GWAS_results"];
}
Which generates the following .png image:
Is there an easy way to edit code to at least make it one continuous graph?
This is a general output from nextflow pipeline making tool, thus would be quite useful for many (i don't consider q to be too specific thus).
I am trying to plot a finite state transducer in GraphViz. I already have the self-loops defined, but when I plot them, I cannot get a nice "flower"-like distribution of loops around the main node.
digraph G {
size="8,5"
splines=true;
nodesep=1.0;
node [shape=ellipse,width=1,height=1];
0 [peripheries=2];
0:n -> 0:n [label=" A:A" minlen=5.0 rotate=45]
0:ne -> 0:ne [headlabel=" A:B" minlen=5.0];
0:e -> 0:e [label=" B:A" minlen=5.0];
0:se -> 0:se [label=" B:A" labeldistance=-8 minlen=5.0];
0:s -> 0:s [label=" *e*:A" minlen=5.0];
0:sw -> 0:sw [label=" *e*:B" minlen=5.0];
0:w -> 0:w [label=" B:*e*" minlen=5.0];
0:nw -> 0:nw [label=" A:*e*" minlen=5.0];
overlap=false
}
My plot looks like the following
Is there a way I can rotate the edge orientation of the self-loops originating and terminating at NW, SE, SW, NE? I have tried the orientation and rotate commands, but I cannot get them to work in dot and neato.
I'm pretty sure this is not the answer you want, but it does answer your question.
As you can see, Graphviz has a sort of "perpendicular" approach when drawing the loops, i.e. it favors a horizontal or vertical major direction. I don't think you can avoid it.
That said, here is how to transform your graph into an orchid-like distribution of loops around the main node:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="http://viz-js.com/bower_components/viz.js/viz-lite.js"></script>
<script src="https://github.com/magjac/d3-graphviz/releases/download/v0.1.2/d3-graphviz.min.js"></script>
<div id="graph" style="text-align: center;"></div>
<script>
var dots = [
`
digraph G {
size="8,5"
splines=true;
nodesep=1.0;
node [shape=ellipse,width=1,height=1, orientation=22.5, group="hej"];
0 [peripheries=2];
0:n -> 0:n [id=1 label=" A:A" minlen=0.0 rotate=45];
0:ne -> 0:ne [id=2 headlabel=" A:B" minlen=0.0];
0:e -> 0:e [id=3 label=" B:A" minlen=0.0];
0:se -> 0:se [id=4 label=" B:A" labeldistance=-8 minlen=0.0];
0:s -> 0:s [id=5 label=" *e*:A" minlen=0.0];
0:sw -> 0:sw [id=6 label=" *e*:B" minlen=0.0];
0:w -> 0:w [id=7 label=" B:*e*" minlen=0.0];
0:nw -> 0:nw [id=8 label=" A:*e*" minlen=0.0];
overlap=false
}
`, `
digraph G {
size="8,5"
splines=true;
nodesep=1.0;
node [shape=ellipse,width=1,height=1, orientation=22.5, group="hej"];
0 [peripheries=2];
0:n -> 0:n [id=1 label=" A:A" minlen=0.0 rotate=45];
0:nw -> 0:ne [id=2 headlabel=" A:B" minlen=0.0];
0:e -> 0:e [id=3 label=" B:A" minlen=0.0];
0:ne -> 0:se [id=4 label=" B:A" labeldistance=-8 minlen=0.0];
0:s -> 0:s [id=5 label=" *e*:A" minlen=0.0];
0:se -> 0:sw [id=6 label=" *e*:B" minlen=0.0];
0:w -> 0:w [id=7 label=" B:*e*" minlen=0.0];
0:sw -> 0:nw [id=8 label=" A:*e*" minlen=0.0];
overlap=false
}
`
];
var dotIndex = 0;
var graphviz = d3.select("#graph").graphviz();
function render() {
var dot = dots[dotIndex % dots.length];
var transition1 = d3.transition()
.delay(1000)
.duration(1000 + 4000 * dotIndex);
graphviz
.tweenShapes(false)
.engine("dot")
.keyMode("id")
.dot(dot)
.transition(transition1)
.render();
dotIndex += 1;
transition1
.transition()
.duration(0)
.on('end', function () {
if (dotIndex != dots.length) {
render();
}
});
}
render();
</script>
I'm trying to draw a neural network in graphviz. Here is what my picture currently looks like:
As you can see, the order of the labels of the nodes don't appear correctly. For instance, I want $a_0^(2)$ sticks to the top of layer 2 and I want to arrange the rest of nodes in the same layer with numerical increasing order (i.e $a_1^(2)$, $a_2^(2)$, ...)
How can I do this? Much thanks!
Here is my code:
digraph G {
rankdir=LR;
splines=line;
nodesep=".05";
edge [comment="Wildcard node added automatic in EG."];
node [label=""];
subgraph cluster_0 {
color=white;
label="layer 1 (input layer)";
edge [comment="Wildcard node added automatic in EG."];
node [color=chartreuse,
style=filled,
shape=circle];
x0 [color=yellow,
fillcolor=yellow,
label=<x<sub>0</sub>>];
x1 [fillcolor=chartreuse,
label=<x<sub>1</sub>>];
x2 [fillcolor=chartreuse,
label=<x<sub>2</sub>>];
x3 [fillcolor=chartreuse,
label=<x<sub>3</sub>>];
}
subgraph cluster_1 {
color=white;
label="layer 2 (hidden layer)";
edge [comment="Wildcard node added automatic in EG."];
node [color=dodgerblue,
style=filled,
shape=circle];
a02 [color=yellow,
label=<a<sub>0</sub><sup>(2)</sup>>,
pos="0,0",
fillcolor=yellow];
a12 [label=<a<sub>1</sub><sup>(2)</sup>>,
pos="0,-1",
fillcolor=dodgerblue];
a22 [label=<a<sub>2</sub><sup>(2)</sup>>,
pos="0,-2",
fillcolor=dodgerblue];
a32 [label=<a<sub>3</sub><sup>(2)</sup>>,
pos="0,-3",
fillcolor=dodgerblue];
a42 [label=<a<sub>4</sub><sup>(2)</sup>>,
pos="0,-4",
fillcolor=dodgerblue];
a52 [label=<a<sub>5</sub><sup>(2)</sup>>,
pos="0,-5",
fillcolor=dodgerblue];
}
subgraph cluster_2 {
color=white;
label="layer 3 (hidden layer)";
edge [comment="Wildcard node added automatic in EG."];
node [color=dodgerblue,
style=filled,
shape=circle];
a03 [color=yellow,
fillcolor=yellow,
label=<a<sub>0</sub><sup>(3)</sup>>];
a13 [fillcolor=dodgerblue,
label=<a<sub>1</sub><sup>(3)</sup>>];
a23 [fillcolor=dodgerblue,
label=<a<sub>2</sub><sup>(3)</sup>>];
a33 [fillcolor=dodgerblue,
label=<a<sub>3</sub><sup>(3)</sup>>];
a43 [fillcolor=dodgerblue,
label=<a<sub>4</sub><sup>(3)</sup>>];
a53 [fillcolor=dodgerblue,
label=<a<sub>5</sub><sup>(3)</sup>>];
}
subgraph cluster_3 {
color=white;
label="layer 4 (output layer)";
edge [comment="Wildcard node added automatic in EG."];
node [color=coral1,
style=filled,
shape=circle];
O1 [fillcolor=coral1,
label=<a<sub>1</sub><sup>(4)</sup>>];
O2 [fillcolor=coral1,
label=<a<sub>2</sub><sup>(4)</sup>>];
O3 [fillcolor=coral1,
label=<a<sub>3</sub><sup>(4)</sup>>];
O4 [fillcolor=coral1,
label=<a<sub>4</sub><sup>(4)</sup>>];
}
x0 -> a12;
x0 -> a22;
x0 -> a32;
x0 -> a42;
x0 -> a52;
x1 -> a12;
x1 -> a22;
x1 -> a32;
x1 -> a42;
x1 -> a52;
x2 -> a12;
x2 -> a22;
x2 -> a32;
x2 -> a42;
x2 -> a52;
x3 -> a12;
x3 -> a22;
x3 -> a32;
x3 -> a42;
x3 -> a52;
a02 -> a13;
a02 -> a23;
a02 -> a33;
a02 -> a43;
a02 -> a53;
a12 -> a13;
a12 -> a23;
a12 -> a33;
a12 -> a43;
a12 -> a53;
a22 -> a13;
a22 -> a23;
a22 -> a33;
a22 -> a43;
a22 -> a53;
a32 -> a13;
a32 -> a23;
a32 -> a33;
a32 -> a43;
a32 -> a53;
a42 -> a13;
a42 -> a23;
a42 -> a33;
a42 -> a43;
a42 -> a53;
a52 -> a13;
a52 -> a23;
a52 -> a33;
a52 -> a43;
a52 -> a53;
a03 -> O1;
a13 -> O1;
a23 -> O1;
a33 -> O1;
a43 -> O1;
a53 -> O1;
a03 -> O2;
a13 -> O2;
a23 -> O2;
a33 -> O2;
a43 -> O2;
a53 -> O2;
a03 -> O3;
a13 -> O3;
a23 -> O3;
a33 -> O3;
a43 -> O3;
a53 -> O3;
a03 -> O4;
a13 -> O4;
a23 -> O4;
a33 -> O4;
a43 -> O4;
a53 -> O4;
}
I don't think changing the labels is a good solution.
If the ordering of the nodes within each layer is important, I suggest adding invisible edges within each layer, forcing the order of the nodes.
Something like this:
digraph G {
rankdir = LR;
splines=false;
edge[style=invis];
ranksep= 1.4;
{
rank=same;
x0->x1->x2->x3;
}
{
rank=same;
a0->a1->a2->a3->a4;
}
{
rank=same;
b0->b1->b2->b3->b4;
}
{
rank=same;
c0->c1->c2->c3;
}
edge[style=solid, tailport=e, headport=w];
{x0; x1; x2; x3} -> {a0;a1;a2;a3;a4};
{a0;a1;a2;a3;a4} -> {b0;b1;b2;b3;b4};
{b0;b1;b2;b3;b4} -> {c0,c1,c2,c3};
}
So, I use some dirty tricks to get the following picture:
I connect all the nodes together with the following code like the following:
x0 -> a02 [style=invisible, dir=none];
I relabel the nodes text according to each nodes position displayed in the picture (this is the really dirty one)
So, my complete code is available at here.
Please let me know if there is any better solution to this issue.