how to set partial nodes as same rank in graphviz with python - graphviz

source code
digraph G {
node_18 [label=2 color=BLACK fontcolor=BLACK]
node_19 [label=1 color=BLACK fontcolor=BLACK]
node_18 -> node_19
node_20 [label=4 color=RED fontcolor=RED]
node_18 -> node_20
node_21 [label=3 color=BLACK fontcolor=BLACK]
node_20 -> node_21
node_22 [label=5 color=BLACK fontcolor=BLACK]
node_20 -> node_22
node_23 [label=-1 color=BLACK fontcolor=BLACK style=invis]
node_22 -> node_23 [style=invis]
node_24 [label=6 color=RED fontcolor=RED]
node_22 -> node_24
label="step6---add 6 succeed"
node_19 -> node_20 [style=invis]
node_21 -> node_22 [style=invis]
node_23 -> node_24 [style=invis]
{rank=same; node_19;node_20}
{rank=same; node_21;node_22}
{rank=same; node_23;node_24}
}
The last 3 lines("{rank=same ...") are added manually, can I add them with python graphviz?
I have searched the solution from google, but the solution is to make them in the same subgraph.
But they should not be in the subgraph. How to achieve this?

Related

How to dynamically increase the distance between two nodes in GraphViz?

I'm using this Python project "Family Tree Maker" to generate a family tree. It works with GraphViz, creates a nice DOT file and then a PNG. "Minimum Viable Product" check. It works :D
Now I'd like to make it a bit nicer.
Is there a simple way (e.g. not having to increase the length of the edge per hand) to force the right-most vertical edge (between Father1-Mother2 and Franz) to be straight/vertical like displayed below?
Thanks!
Edit: as correctly stated by #albert in the comments, webgraphviz.com displays the correct output while viz-js.com doesn't.
PS: Here's the DOT code that generate this Graph:
digraph {
graph [splines=ortho];
node [shape=box, fontname = "calibri"];
edge [dir=none];
Father1[label="Father1",style=filled,fillcolor=azure2];
Mother1[label="Mother1",style=filled,fillcolor=bisque];
Child1[label="Child 1",style=filled,fillcolor=azure2];
Child2[label="Child 2",style=filled,fillcolor=bisque];
Child3[label="Child 3",style=filled,fillcolor=azure2];
Child4[label="Child 4",style=filled,fillcolor=azure2];
Mother2[label="Mother2",style=filled,fillcolor=bisque];
Franz[label="Franz",style=filled,fillcolor=azure2];
{ rank=same;
Mother1 -> h0 -> Father1;
h0[shape=circle,label="",height=0.01,width=0.01];
Father1 -> h1 -> Mother2;
h1[shape=circle,label="",height=0.01,width=0.01];
}
{ rank=same;
h0_0 -> h0_1 -> h0_2 -> h0_3 -> h0_4;
h0_0[shape=circle,label="",height=0.01,width=0.01];
h0_1[shape=circle,label="",height=0.01,width=0.01];
h0_2[shape=circle,label="",height=0.01,width=0.01];
h0_3[shape=circle,label="",height=0.01,width=0.01];
h0_4[shape=circle,label="",height=0.01,width=0.01];
h0_4 -> h1_0 [style=invis];
h1_0;
h1_0[shape=circle,label="",height=0.01,width=0.01];
}
h0 -> h0_2;
h0_0 -> Child1;
h0_1 -> Child2;
h0_3 -> Child3;
h0_4 -> Child4;
h1 -> h1_0;
h1_0 -> Franz;
{ rank=same;
Child1 -> Child2 [style=invis];
Child2 -> Child3 [style=invis];
Child3 -> Child4 [style=invis];
Child4 -> Franz [style=invis];
}
{ rank=same;
}
}
As expected after discussing with #Albert in the comments, using version 2.28 of GraphViz, I get the result I wanted.
I created an issue report on GraphViz's Gitlab: https://gitlab.com/graphviz/graphviz/issues/1627

Can DOT produce a more structured graph?

I'm not really sure how to describe what my client wants, so I'll let a picture do most of the talking. I'm using DOT to produce graphs for what is more or less the bill of materials problem. (Show an incoming lot and all the outgoing lots, at all levels, that were created from the material in the incoming lot.) I've got the code to create a graph that contains the data structured appropriately. For example, I generate this GV file:
digraph LotTrc {
rankdir=LR;
graph[label="Lot #AD626", labelloc=top, labeljust=left, fontsize=24];
PO_AD626_0000003333[shape=triangle,color=greenyellow,style=filled,label=AD626];
AJ_AD626_SJ00000099[shape=circle,color=red2,style=filled,label=AD626];
PO_AD626_0000003333 -> AJ_AD626_SJ00000099;
AJ_AD626_SJ00000103[shape=circle,color=red2,style=filled,label=AD626];
PO_AD626_0000003333 -> AJ_AD626_SJ00000103;
WO_AD627_RE00002230[shape=ellipse,color=lemonchiffon,style=filled,label=AD627];
PO_AD626_0000003333 -> WO_AD627_RE00002230;
SO_AD627_OZ00025429[shape=box,color=cyan3,style=filled,label=AD627];
WO_AD627_RE00002230 -> SO_AD627_OZ00025429;
SO_AD627_OZ00025434[shape=box,color=cyan3,style=filled,label=AD627];
WO_AD627_RE00002230 -> SO_AD627_OZ00025434;
SO_AD627_OZ00025439[shape=box,color=cyan3,style=filled,label=AD627];
WO_AD627_RE00002230 -> SO_AD627_OZ00025439;
SO_AD627_OZ00025444[shape=box,color=cyan3,style=filled,label=AD627];
WO_AD627_RE00002230 -> SO_AD627_OZ00025444;
WO_AD628_RE00002231[shape=ellipse,color=lemonchiffon,style=filled,label=AD628];
PO_AD626_0000003333 -> WO_AD628_RE00002231;
SO_AD628_OZ00025430[shape=box,color=cyan3,style=filled,label=AD628];
WO_AD628_RE00002231 -> SO_AD628_OZ00025430;
SO_AD628_OZ00025435[shape=box,color=cyan3,style=filled,label=AD628];
WO_AD628_RE00002231 -> SO_AD628_OZ00025435;
SO_AD628_OZ00025440[shape=box,color=cyan3,style=filled,label=AD628];
WO_AD628_RE00002231 -> SO_AD628_OZ00025440;
SO_AD628_OZ00025445[shape=box,color=cyan3,style=filled,label=AD628];
WO_AD628_RE00002231 -> SO_AD628_OZ00025445;
WO_AD629_RE00002232[shape=ellipse,color=lemonchiffon,style=filled,label=AD629];
PO_AD626_0000003333 -> WO_AD629_RE00002232;
SO_AD629_OZ00025431[shape=box,color=cyan3,style=filled,label=AD629];
WO_AD629_RE00002232 -> SO_AD629_OZ00025431;
SO_AD629_OZ00025436[shape=box,color=cyan3,style=filled,label=AD629];
WO_AD629_RE00002232 -> SO_AD629_OZ00025436;
SO_AD629_OZ00025441[shape=box,color=cyan3,style=filled,label=AD629];
WO_AD629_RE00002232 -> SO_AD629_OZ00025441;
SO_AD629_OZ00025446[shape=box,color=cyan3,style=filled,label=AD629];
WO_AD629_RE00002232 -> SO_AD629_OZ00025446;
WO_AD630_RE00002233[shape=ellipse,color=lemonchiffon,style=filled,label=AD630];
PO_AD626_0000003333 -> WO_AD630_RE00002233;
SO_AD630_OZ00025432[shape=box,color=cyan3,style=filled,label=AD630];
WO_AD630_RE00002233 -> SO_AD630_OZ00025432;
SO_AD630_OZ00025437[shape=box,color=cyan3,style=filled,label=AD630];
WO_AD630_RE00002233 -> SO_AD630_OZ00025437;
SO_AD630_OZ00025442[shape=box,color=cyan3,style=filled,label=AD630];
WO_AD630_RE00002233 -> SO_AD630_OZ00025442;
SO_AD630_OZ00025447[shape=box,color=cyan3,style=filled,label=AD630];
WO_AD630_RE00002233 -> SO_AD630_OZ00025447;
WO_AD631_RE00002234[shape=ellipse,color=lemonchiffon,style=filled,label=AD631];
PO_AD626_0000003333 -> WO_AD631_RE00002234;
SO_AD631_OZ00025433[shape=box,color=cyan3,style=filled,label=AD631];
WO_AD631_RE00002234 -> SO_AD631_OZ00025433;
SO_AD631_OZ00025438[shape=box,color=cyan3,style=filled,label=AD631];
WO_AD631_RE00002234 -> SO_AD631_OZ00025438;
SO_AD631_OZ00025443[shape=box,color=cyan3,style=filled,label=AD631];
WO_AD631_RE00002234 -> SO_AD631_OZ00025443;
SO_AD631_OZ00025448[shape=box,color=cyan3,style=filled,label=AD631];
WO_AD631_RE00002234 -> SO_AD631_OZ00025448;
}
and it produces this graph:
But what my client really wants is something that looks more like this, where the edges are straight lines, using 90 degree angles as needed. (Note that this is generic, not based on the example above.)
Is there a way to use DOT to produce something like that?
You can experiment with splines=ortho graph attibute. It makes the very straight connections with 90 degree angles.
But I won't recommend it. It's almost impossible to control them, port specification often doesn't work with them, and also, ortho splines may eat up some of the edge lables.
Possible solution would be using dummy nodes with point shape (this shape is convenient because it removes node lable by default) and width=0. Use these dummy nodes in places where the 90 degree turn is needed. You will have to group them with main nodes in subgraphs and add rank=same attribute to force these nodes to stay at the same level.
You would probably also need to add weight to some edges to prevent them from being bent (edges with higher weight tend to be straight).
Example
I've implemented part of your example graph using mentioned techniques, the code and image are below:
digraph {
rankdir=LR
ranksep=1
nodesep=0.5
LOT1 [shape=rect]
LOT2 [shape=rect]
LOT3 [shape=rect]
LOT4 [shape=rect]
LOT5 [shape=rect]
{rank=same
PO
dot1 [shape=point width=0]
dot2 [shape=point width=0]
PO -> dot1 -> dot2 [arrowhead=none]
}
dot1 -> WO1 [weight=20]
{
rank=same
WO1
dot21 [shape=point width=0]
dot22 [shape=point width=0]
WO1 -> dot21 -> dot22 [arrowhead=none]
}
dot21 -> LOT1 [weight=20]
dot22 -> LOT2 [weight=20]
{
rank=same
dot31 [shape=point width=0]
dot32 [shape=point width=0]
dot33 [shape=point width=0]
dot31 -> dot32 -> dot33 [arrowhead=none]
}
dot2 -> WO2 [weight=20]
{
WO2
rank=same
dot23 [shape=point width=0]
dot24 [shape=point width=0]
dot25 [shape=point width=0]
WO2 -> dot23 -> dot24 -> dot25 [arrowhead=none]
}
dot23 -> LOT3 [weight=20]
dot24 -> LOT4 [weight=20]
dot25 -> LOT5 [weight=20]
dot31 -> SO1
dot33 -> SO2
LOT1 -> dot32
}
Result:

Graphviz removes node from cluster

I'm using dot to compile. So I have two nodes in cluster0 (MATH1036 and MATH1034). When I try to make an edge from MATH1034 to a node outside the cluster (n1), it freaks out and removes MATH1034 from cluster0.
digraph G {
labelloc="t";
label="";
graph [splines=spline, nodesep=1]
compound=true;
subgraph cluster0{
label="Math 1";
MATH1034[label="MATH1034\nAlgebra"];
MATH1036[label="MATH1036\nCalculus"];
{rank=same;MATH1036->MATH1034;}
}
COMS1015[label="COMS1015\nBCO"];
COMS1017[label="COMS1017\nALG"];
COMS1016[label="COMS1016\nDCS"];
COMS1018[label="COMS1018\nADS"];
subgraph cluster1{
label="Math 2";
MATH2007[label="MATH2007\nMC"];
MATH2018[label="MATH2018\nGT"];
MATH2019[label="MATH2019\nLA"];
STAT2XXX[label="STAT2XXX\nIntro to MS\nor\nSTAT1003\nStats 1"];
}
COMS2003[label="COMS2003\nAAA"];
COMS2XXX[label="COMS2XXX\nMC"];
COMS2002[label="COMS2002\nDBF"];
COMS2001[label="COMS2001\nOS"];
COMS3000[label="COMS3000\nAAI"];
COMS3003[label="COMS3003\nFLA"];
COMS3004[label="COMS3004\nAN"];
COMS3002[label="COMS3002\nSE"];
// This line will hide the formatting nodes.
//node[shape=none,width=0,height=0, label=""];
// THIS NEXT LINE CAUSES THE PROBLEM
// If I remove MATH1034 from this line, things go normal.
{rank=same;MATH1034->n1[ltail=cluster0,dir=none ]; n1->n2->n3->n4->n5[dir=none];}
n1->COMS1015[style=dotted];
n2->COMS1016[style=dotted];
n4->COMS1017[style=dotted];
n5->COMS1018[style=dotted];
MATH1034 -> MATH2007[lhead=cluster1, ltail=cluster0];
MATH2018 -> STAT2XXX[style=invis];
MATH2007 -> MATH2019[style=invis];
//edge[dir=none];
n3->n6->n7[arrowhead=none];
{rank=same; COMS1016->n6->COMS1017[style=invis];}
{rank=same; COMS2001->n7[style=invis]; n7->COMS2003;}
COMS1015 -> COMS2001;
//{rank=same; COMS1017 -> p1 -> COMS1018;}
//p1 -> COMS2003;
//p1 -> COMS2XXX;
COMS1017 -> COMS2XXX;
COMS1017 -> COMS2001;
COMS1017 -> COMS2003;
COMS1018 -> COMS2003;
COMS1018 -> COMS2XXX;
COMS1018 -> COMS2002;
COMS1016 -> COMS2003;
COMS1016 -> COMS2001[weight=100,style=invis];
MATH2007 -> COMS2001[ltail=cluster1,style=dotted]
MATH2007 -> COMS2003[ltail=cluster1,style=dotted]
{rank=same;COMS2XXX -> COMS2002[dir=back, style=dotted]}
{rank=same;COMS2003 -> COMS2XXX[dir=back]}
subgraph cluster5{
label="";
{rank=same;COMS3004 -> COMS3003 -> COMS3000 -> COMS3002[style=invis];}
}
COMS2003 -> COMS3000[weight=1000];
COMS1016 -> COMS3003;
COMS2001 -> COMS3004[weight=1000];
COMS2002 -> COMS3002[weight=1000];
MATH2007 -> COMS3004[ltail=cluster1,lhead=cluster5];
}
The MATH modules should be next to each other and in a box.
Here is the very broken one:
Here is the correct layout, but without the edge between MATH1034 and n1:
Any help would really be appreciated I've looked everywhere and nothing seems to work.
The node Math1034 is in two different subgraphs which isn't allowed. dot actually emits the following warning:
Warning: MATH1034 was already in a rankset, deleted from cluster G
Warning: MATH1034 -> MATH2007: tail not inside tail cluster cluster0
Warning: MATH1034 -> n1: tail not inside tail cluster cluster0
The solution is to remove MATH1034 from the second cluster, and add the edge without constraining ranks:
{rank=same; n1[ltail=cluster0,dir=none ]; n1->n2->n3->n4->n5[dir=none];}
MATH1034 -> n1[constraint=false];

GraphViz custom back arrow

I have the following code:
digraph "Classes utilisées par Git"
{
subgraph mother
{
O [shape=record, label = "{GitObject| ref (sha1)}"];
}
subgraph herited
{
rankdir=LR;
rank="same";
"Tree" [shape=box];
"Tag" [shape=box];
"Blob" [shape=box];
"Commit" [shape=box];
}
O -> "Tree" [arrowhead="onormal", dir=back];
O -> "Blob" [arrowhead="onormal", dir=back];
O -> "Commit" [arrowhead="onormal", dir=back];
O -> "Tag" [arrowhead="onormal", dir=back];
"Tree" -> "Tree" [arrowhead="vee", label=" 0..*\n0..*1"];
"Tree" -> "Blob" [arrowhead="vee", label=" 0..*\n1"];
"Commit" -> "Tree" [arrowhead="vee", label=" 1..*\n1"];
"Tag" -> "Commit" [arrowhead="vee", label=" 0..*\n1"];
}
which gives me:
I works well but arrows in direction of GitOject are not onormal, is their a way to fiw that?
For your help,
Thanks by advance.
Just use arrowtail="onormal" instead of arrowhead="onormal" for the edges not displaying properly.
arrowtail always refers to the tail of the edge as defined, and doesn't take into account dir=back.

DOT - how to reduce the lines connecting two nodes

I have a function that records the how methods are called at run-time. I am trying to use dot to visualize this information. Some methods are called many times- eg, in the case of a loop - in the graph i would want to have only one line connecting both nodes - Is there a switch do to this... See example diagram "RawFitsData._method" calls "RawFitsData.init"; multiple times, in the graph, i would like to display only one line
digraph G{
splines=false;
ranksep=1;
node[shape=box, color=grey, style=filled];
"DBProxy.fetch_from_database" -> "RawFitsData._method";
"RawFitsData._method" -> "RawFitsData.__init__";
"RawFitsData._method" -> "RawFitsData.__init__";
"RawFitsData._method" -> "RawFitsData.__init__";
"RawFitsData._method" -> "RawFitsData.__init__";
"RawFitsData._method" -> "RawFitsData.__init__";
"RawFitsData.__init__" -> "RawFitsData._method";
"RawFitsData._method" -> "RawFitsData.__init__";
"RawFitsData.__init__" -> "RawFitsData._set_pathname";
"RawFitsData._set_pathname" ->"split";
"RawFitsData._set_pathname" ->"setter";
"RawFitsData.__init__" -> "RawFitsData._get_pathname";
"RawFitsData._get_pathname" ->"getter";
"RawFitsData._get_pathname" ->"join";
"deepcopy" ->"RawFitsData._method";
"RawFitsData._method" -> "RawFitsData.__reduce__";
"RawFitsData.__reduce__" -> "WeakValueDictionary.__setitem__";
"RawFitsData.__reduce__" ->"getter";
"RawFitsData.__reduce__" -> "RawFitsData._get_pathname";
"RawFitsData._get_pathname" ->"getter";
}
Use strict digraph.
strict digraph G {
splines=false;
...
It will omit repeating edges. Reference: DOT documentation.

Resources