Nested directed subgraphs - graphviz

I'm trying to obtain nested subgraphs in graphviz.
Graphviz version is 2.38.0 (20140413.2041)
Here is the code:
digraph G {
subgraph cluster_win {
style=filled;
color=lightgrey;
label = "Windows"
subgraph extra_enabled {
fillcolor = "#EDF1F2";
color = "#028d35";
label="Subdirectory extra included";
node [style=filled,color=white];
config_debug1 [label = "Configure Debug"];
config_release1 [label = "Configure Release"];
build_debug1 [label = "Build"];
build_release1 [label = "Build"];
config_debug1 -> build_debug1;
config_release1 -> build_release1;
shape=rect;
style=rounded;
}
subgraph extra_disabled {
label = "Subdirectory extra excluded";
config_debug2 [label = "Configure Debug"];
config_release2 [label = "Configure Release"];
build_debug2 [label = "Build"];
build_release2 [label = "Build"];
config_debug2 -> build_debug2;
config_release2 -> build_release2;
}
checkout [style=filled, color=white];
checkout -> extra_enabled;
checkout -> extra_disabled;
}
start -> checkout;
start [label="git push"; shape=Mdiamond];
}
And this is the result.
Graphviz draws two ordinary nodes "extra_enabled" and "extra_disabled". However, I want them to be subgraphs, containing nodes "Configure Release", "Configure Debug", "Build" and another "Build".
How can I fix it?

You need to do two things:
Connect nodes only, you cannot connect to a cluster
Cluster names need to be prefixed by cluster_
Applying this to your code
digraph G {
subgraph cluster_win {
style=filled;
color=lightgrey;
label = "Windows "
subgraph cluster_extra_enabled {
fillcolor = "#EDF1F2";
color = "#028d35";
label="Subdirectory extra included";
node [style=filled,color=white];
config_debug1 [label = "Configure Debug"];
config_release1 [label = "Configure Release"];
build_debug1 [label = "Build"];
build_release1 [label = "Build"];
config_debug1 -> build_debug1;
config_release1 -> build_release1;
shape=rect;
style=rounded;
}
subgraph cluster_extra_disabled {
label = "Subdirectory extra excluded";
config_debug2 [label = "Configure Debug"];
config_release2 [label = "Configure Release"];
build_debug2 [label = "Build"];
build_release2 [label = "Build"];
config_debug2 -> build_debug2;
config_release2 -> build_release2;
}
checkout [style=filled, color=white];
checkout -> config_debug1;
checkout -> config_release2;
}
start -> checkout;
start [label="git push"; shape=Mdiamond];
}
I get
which is probably close to what you want. Note that I have added a few spaces to the label "Windows " to get it out of the way of the arrow. You could also use labeljust. There are also ways to make the edge end at the boundary of the cluster, but that would have needed a lot more editing on my part which I was not sure you want it.

I just wanted to append to the answer that vaettchen added. While it is correct that you cannot directly connect edges to clusters, edges must travel between nodes, there is a way to do so visually with lhead and ltail.
You can do the following:
node1 -> node2 [lhead=cluster_name_1, ltail=cluster_name_2]
Which will cut the connectors off at the limit of the cluster to connect clusters, this is just visual and is logged as a node connection, but it is a nicer way to visually display connections between whole clusters.

Related

How can I separate with vertical bar in ellipse shape node in dot file?

I want to draw a clean network graph like this image.
But I couldn't find how can I do this. I have to use css for removing part of cell border line, but, as far as I know, dot file is not supported css. I want to insert ellipse shape node, separate node with vertical bar,
How can I draw a graph that satisfies these conditions? My dot file has self loop, so I can't use networkx. Any other ways are exist? or can I solve use dot file?
My dot file code is
digraph {
// size = "6,8.5";
// ratio = "fill";
// layout = "circo"
forcelabels = True;
graph[overlap=False];
node [shape = ellipse];
node [fontsize = 10];
// node [penwidth = 3];
edge [fontsize = 10];
// A [pos = "0,2"]
// B [pos = "-2,-2"]
// C [pos = "0,1"]
// D [pos = "2,-2"]
// E [pos = "0,-3"]
A
B
C
D
E;
node[shape = point];
x1[style = invis]
{rank=same; A,C}
{rank=same; B,E}
A -> C [label = "4|1.0\l"];
B -> B [label = "1|:0.979\l"];
C:nw -> C:ne [label = "3|0.167\l"];
C -> D [label = "5|0.115\l"];
D:nw -> C:sw [xlabel = "3|0.103\l4|0:0.315\l"];
D:se -> x1 [dir = none]
x1 -> D:sw [xlabel = "5|0.308\l6|0:0.253\l"];
E -> B [label = "4|0.5\l"];
E -> D [label = "6|0.5\l"];
}
Two ways to create your nodes, one fairly close (well to my eyes) and pretty easy to replicate. The other will allow you to recreate your example, but requires using two programs (dot and a program to create individual nodes in svg - like Inkscape)
digraph structs {
// if oblong is good enough, this works
node [shape=none]
try3 [label=<
<TABLE border="1" cellborder="0" cellspacing="0" cellpadding="0" style="rounded" >
<TR><TD width="40">A</TD><VR/><TD width="40">*111<BR/>*101<BR/>*011</TD></TR>
</TABLE>>];
// if you really want a circular node, perfectly split
// create the node images with another program (like Inkscape)
// and include as an image
try5 [image="/tmp/split1.svg" label=""]
}
producing:

how to define a graph with graphviz without overlapping labels

The follow dot file demonstrates the issue I am trying to resolve:
digraph G {
splines=line;
rankdir=LR;
A -> B [label="a long label"];
A -> C [label="a long label"];
A -> A [label="a very long label"];
A -> A [label="a very long label"];
A -> D [label="a long label"];
}
It generates the follow the graph:
The labels are poorly positioned, nearly overlapping.
What can be done to improve the look of this graph?
I would define improve by saying (1) labels do not overlap with each other, (2) labels do not overlap edges, and (3) optionally / ideally labels are drawn along the edge. #3 may not be possible, but #1 and #2 should be sufficient. Using ortho splines would always provide an edge where a which a label could be drawn along and still be read normally, but this I know is not currently supported by graphviz.
"Improve" is in the eye of the beholder, but this uses ports, headlabels, spaces and newlines to rearrange the labels.
digraph G {
splines=line;
rankdir=LR;
// use ports to rearrange edges
// then headlabel, spaces, and newlines (\n)
A:n -> A:w [headlabel="a very long label "];
A:s -> A:w [headlabel="a very long label "];
A -> B [label="a long label"];
A -> C [label="a long label"];
A -> D [label="\n\na long label"];
}
There does not appear to be any supported solution in GraphViz that meet the desired criteria for edge labels. My work around is to split the edges between two nodes and insert another node containing the text of the edge label. The new node is styled to distinguish it from regular nodes.
The GraphViz layout algorithm does a good job of keep nodes separated and not allowing edges to overlap nodes.
Updating the test case with this workaround, I have the following dot file:
digraph G {
splines=ortho;
rankdir=LR;
AA1 [label="a very long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
AA2 [label="a very long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
AB1 [label="a long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
AC1 [label="a long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
AD1 [label="a long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
A -> AA1 [arrowhead = "none" ];
AA1 -> A
A -> AA2 [arrowhead = "none" ];
AA2 -> A
A -> AB1 [arrowhead = "none" ];
AB1 -> B
A -> AC1 [arrowhead = "none" ];
AC1 -> C
A -> AD1 [arrowhead = "none" ];
AD1 -> D
}
which produces this

Align nodes in a Graphviz directed graph

I have the following Graphviz code:
digraph {
Technique [shape = box];
Path [shape = box];
KnowledgeObservation [shape = box, label = "Knowledge\nObservation"];
ManagementIntervention [shape = box, label = "Management\nIntervention"];
ResultsModification [shape = box, label = "Results\nModification"];
SharedCode [label = "Shared Code"];
MediatedRelationship [label = "Mediated Relationship"];
Art -> Technique;
Therapy -> Path;
{Technique Path} -> KnowledgeObservation -> ManagementIntervention -> ResultsModification;
{MediatedRelationship SharedCode} -> {KnowledgeObservation ResultsModification}
subgraph {
rank = same
Technique -> Path [dir = none]
}
subgraph {
rank = same
SharedCode
ManagementIntervention
MediatedRelationship
}
}
It currently produces the following output:
How can I vertically align "Management Intervention" with both "Knowledge Observation" and "Results Modification"?
"Shared Code" should be moved to the left of "Management Intervention".
"Mediated Relationship" should be moved to the right of "Management Intervention".
"Shared Code", "Management Intervention" and "Mediated Relationship" should stay horizontally aligned.
How can I accomplish this?
This can be achieved without subgraphs; the most important modification is the line
{ rank = same; SharedCode -> ManagementIntervention -> MediatedRelationship[ style = invis ] }
which keeps the three nodes not only on the right level, but also within the desired order.
Altogether, this code here
digraph
{
// node definition
Art Therapy;
Technique[ shape = box ];
Path[ shape = box ];
KnowledgeObservation[ shape = box, label = "Knowledge\nObservation" ];
ManagementIntervention[ shape = box, label = "Management\nIntervention" ];
ResultsModification[ shape = box, label = "Results\nModification" ];
SharedCode[ label = "Shared Code" ];
MediatedRelationship[ label = "Mediated Relationship" ];
// edges
Art -> Technique;
Therapy -> Path;
{ rank = same; Technique -> Path [dir = none] }
{ Technique Path} -> KnowledgeObservation -> ManagementIntervention -> ResultsModification;
{ rank = same; SharedCode -> ManagementIntervention -> MediatedRelationship[ style = invis ] }
{ MediatedRelationship SharedCode } -> { KnowledgeObservation ResultsModification }
}
gives you
which is, in my understanding, what you are looking for.
Still I would recommend to replace the last line of code with these three
KnowledgeObservation -> { SharedCode MediatedRelationship }[ dir = back ];
SharedCode -> ResultsModification;
MediatedRelationship -> ResultsModification;
Reason is that once your graph gets more complicated, graphviz will recognize and maintain the hierarchical relationships, rather than interpreting ambiguous instructions in surprising ways.
How can I vertically align "Management Intervention" with both "Knowledge Observation" and "Results Modification"?
This can be achieved with increasing the weight of the edge. Edges with higher weight tend to be straighter and shorter than with the lower.
"Mediated Relationship" should be moved to the right of "Management Intervention".
You can control this with the order in which the nodes are defined. If you define "Management Intervention" before the "Shared Code", it (MI) will be drawn first, i. e., to the left of the SI.
"Shared Code", "Management Intervention" and "Mediated Relationship" should stay horizontally aligned.
You did it right, using the rank=same subgraph attribute. Though I would put the subgraph already in the moment of node definitions. This will shorten the source size and limit the rank specification to the place where the nodes are defined, which is good for readability (everything stated in one place).
Your modified example:
digraph {
Technique [shape = box];
Path [shape = box];
KnowledgeObservation [shape = box, label = "Knowledge\nObservation"];
ResultsModification [shape = box, label = "Results\nModification"];
subgraph {
rank=same
ManagementIntervention [shape = box, label = "Management\nIntervention"];
MediatedRelationship [label = "Mediated Relationship"];
SharedCode [label = "Shared Code"];
}
Art -> Technique;
Therapy -> Path;
{Technique Path} -> KnowledgeObservation
KnowledgeObservation -> ManagementIntervention -> ResultsModification [weight=3]
{MediatedRelationship SharedCode} -> {KnowledgeObservation ResultsModification}
subgraph {
rank = same
Technique -> Path [dir = none]
}
}
Result:

How to set a graph-filling-area?

How to set the graph to try to fill the area allocated to it? With an increase in the number of nodes, it simply decreases in size, but also remains in one line, although the vertical size (40) allows placement down. If you remove the rankdir, then it places vertically, but also in one line.
digraph "test_graph"{
rankdir = LR;
bgcolor = whitesmoke;
graph [size = "15, 40"];
node [shape = circle,
style = filled,
margin = 0,
fontsize = 14,
color = sandybrown];
edge [fontsize = 10,
arrowhead = vee];
1->2 [label = "R"];
2->3 [label = "R"];
3->4 [label = "R"];
3->5 [label = "B"];
4->1 [label = "R"];
5->6 [label = "U"];
6->7 [label = "U"];
7->8 [label = "U"];
7->9 [label = "F"];
8->5 [label = "U"];
9->10 [label = "F"];
10->11 [label = "D"];
11->12 [label = "D"];
12->13 [label = "D"];
13->10 [label = "D"];
13->14 [label = "L"];
14->15 [label = "L"];
15->16 [label = "D"];
16->17 [label = "D"];
17->18 [label = "D"];
17->19 [label = "L"];
18->15 [label = "D"];
19->20 [label = "F"];
20->21 [label = "F"];
21->22 [label = "F"];
21->23 [label = "L"];
22->19 [label = "F"];
23->24 [label = "L"];
24->25 [label = "F"];
}
You will need to select suitable nodes that
are connected by one edge
connect to other nodes in a way that fills the available width as you like it
and then
connect them in the desired order by invisible edges (so that you avoid graphviz reordering them)
ranking them on the same lavel so that they appear one below the other
In concrete terms this means that adding
1 -> 10 -> 19[ style = invis ];
{ rank = same; 1 10 19 }
just before the closing curly brace, as the last two lines, will produce
which is, as far as I understand your requirement, what you want.

How to set bend direction for edges with splines="curved" in GraphViz? (using neato)

I am creating a graph with manually positioned nodes and use the splines="curved" type of edges between them.
digraph graphname {
splines="curved";
node[shape = box, margin="0.03,0.03", fontsize=11, height=0.1, width=0.1, fixedsize=false];
"LeftFoot\nRightHand" [pos="-150,-150!"];
"RightFoot\nRightHand" [pos="-90,-150!"];
"LeftFoot\nRightFoot" [pos="0,-150!"];
...
edge[style = solid,fontsize=11];
"LeftFoot\nRightFoot":n -> "RightFoot\nRightHand":n [label = "3", penwidth = 1, color = "red"];
"LeftFoot\nRightFoot":s -> "LeftFoot\nRightHand":s [label = "7", penwidth = 1, color = "red"];
...
}
The problem is that one of the edges is bent to the wrong side, so it passes through a node:
Is there an easy way to fix this, like e.g. "bend left" or "bend right" in TikZ?
I tried to use the pos attribute on the edge to set a spline control point to change the bend, however this does not appear to change the edge at all.
In Grapvhiz 2.38 this seems to be fixed. I've scaled the pos slightly but left the rest of the code alone:
Dot source:
digraph graphname {
splines="curved";
node[shape = box, margin="0.03,0.03", fontsize=11, height=0.1, width=0.1, fixedsize=false];
"LeftFoot\nRightHand" [pos="-2,-2!"];
"RightFoot\nRightHand" [pos="-1.2,-2!"];
"LeftFoot\nRightFoot" [pos="0,-2!"];
edge[style = solid,fontsize=11];
"LeftFoot\nRightFoot":n -> "RightFoot\nRightHand":n [label = "3", penwidth = 1, color = "red"];
"LeftFoot\nRightFoot":s -> "LeftFoot\nRightHand":s [label = "7", penwidth = 1, color = "red"];
}
Command:
dot -Kneato -Tpng input.gv > output.png
Output:

Resources