GraphViz - How to make subgraph contain shape? - graphviz

I have a graph that represents one large process made up of two smaller processes. Each of the smaller processes is represented by a subgraph. But when I connect the end of one of those subprocesses (let's say "one") to the start of the other ("two"), the starting shape for the other process ("two") ends up in the same cluster as the ending of "one". How can I get the arrow from the end of one to point to the start of two, but keep the starting shape of two within its cluster?
digraph BigProcess {
graph [ label="Some big process" ]
subgraph clusterSubProcess1 {
graph [ label="Subprocess one", color="red" ]
start1_1 -> start1_2;
start1_2 -> start1_3a;
start1_2 -> start1_3b;
start1_3a -> start1_4;
start1_3b -> start1_5;
start1_4 -> start1_1;
start1_5 -> start2_1;
}
subgraph clusterSubProcess2 {
graph [ label="Subprocess two", color="blue" ]
start2_1 -> start2_2;
start2_2 -> start2_3a;
start2_2 -> start2_3b;
start2_3a -> start2_4;
start2_3b -> start2_5;
start2_4 -> start2_1;
start2_5 -> end1;
}
}
This results in the following, where I really want start2_1 to be the top node within the blue bounded box.

That's happening because the line start1_5 -> start2_1; in the first subgraph is defining start2_1 in that subgraph. You need to define start1_5 in the first subgraph but leave it unconnected until after you define start2_1 in the second subgraph.
digraph BigProcess {
graph [ label="Some big process" ]
subgraph clusterSubProcess1 {
graph [ label="Subprocess one", color="red" ]
start1_1 -> start1_2;
start1_2 -> start1_3a;
start1_2 -> start1_3b;
start1_3a -> start1_4;
start1_3b -> start1_5;
start1_4 -> start1_1;
start1_5;
}
subgraph clusterSubProcess2 {
graph [ label="Subprocess two", color="blue" ]
start2_1 -> start2_2;
start2_2 -> start2_3a;
start2_2 -> start2_3b;
start2_3a -> start2_4;
start2_3b -> start2_5;
start2_4 -> start2_1;
start2_5 -> end1;
}
//Now connect the nodes in the two different subgraphs
start1_5 -> start2_1;
}

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];

Control spacing in twopi (Graphviz)

I'm a newbie with Graphviz, and I'm trying to draw a tree centered in an entity (I'm using the twopi command).
If I put overlap=true it overlaps even if it has a lot of space aroud the overlapped labels.
If I put overlap=false, labels become too small.
How can I have the first situation without overlapping?
Complete code:
digraph g {
graph [ fontname = "Helvetica",
fontsize = 10,
size = "500,500",
splines=true,
overlap=false,
ratio=.5 ];
node [ shape = plaintext,
fontname = "Helvetica" ];
root="owl:Thing";
"owl:Thing" -> "Work";
"Work" -> "WrittenWork";
"Work" -> "Software";
"Work" -> "Website";
"Work" -> "Film";
"owl:Thing" -> "Agent";
"Agent" -> "Organisation";
"Organisation" -> "Non-ProfitOrganisation";
"Organisation" -> "GeopoliticalOrganisation";
"Organisation" -> "SambaSchool";
"Agent" -> "Person";
"Person" -> "Athlete";
"Person" -> "OfficeHolder";
"Person" -> "Astronaut";
"Person" -> "Philosopher";
"Person" -> "Architect";
"owl:Thing" -> "Drug";
"owl:Thing" -> "Place";
"Place" -> "SiteOfSpecialScientificInterest";
"Place" -> "PopulatedPlace";
"PopulatedPlace" -> "Country";
"PopulatedPlace" -> "Continent";
"PopulatedPlace" -> "Atoll";
"Place" -> "ProtectedArea";
"Place" -> "ArchitecturalStructure";
"Place" -> "HistoricPlace";
"Place" -> "NaturalPlace";
"NaturalPlace" -> "Mountain";
"NaturalPlace" -> "Volcano";
"NaturalPlace" -> "MountainRange";
}
Thank you,
Alessio
For this particular graph, you may use overlap=true and then increment ranksep until no labels overlap anymore. ranksep=1.3 seems to be a good value.

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