Vertically align nodes in Graphviz using FDP - graphviz

Could someone let me know how to vertically align the nodes? Here is my code
subgraph clusterDatabase {
label="Databases" style=filled;
bgcolor="#D0C0A0";
node [fillcolor="yellow" style="filled" ]"DB 3.3.3.3";
node [fillcolor="yellow" style="filled" ]"DB 1.1.1.1";
node [ fillcolor="yellow" style="filled" ]"DB 2.2.2.2";
}
and my output is attached in the image

With fdp, by adding position coordinates, the following code might proximate what you want:
graph dfd {
node[shape=box]
subgraph clusterDatabase {
label="Databases" style=filled;
bgcolor="#D0C0A0";
node [pos="0.2,0.2!" fillcolor="yellow" style="filled" ]"DB 3.3.3.3";
node [pos="0.0,0.1!" fillcolor="yellow" style="filled" ]"DB 1.1.1.1";
node [pos="0.2,0.0!" fillcolor="yellow" style="filled" ]"DB 2.2.2.2";
}
}
I experimented and found out that the vertical alignment is achieved by specifying the positions such that there is no overlapping of the boxes on either of the dimension. Once there is such overlapping, then the boxes overlapping might be moved to avoid the overlapping, and the alignment would not be realized.
In your case, the box "DB 1.1.1.1" intrudes the space for "DB 2.2.2.2", the "DB 2.2.2.2" is moved to the right to avoid the overlapping.
I have not figured out a way to let the layout to accept overlapping but keep the alignment. (If an expert knows how to do that, please comment.)

Related

Graph in Graph Extraction

I want to draw a graph with "dot" format. The graph I want is a (sub)graph in a graph style. The subgraph (a child) has internal graph, and the (parent) graphs are connected among the parents, and does not connect to children that are connected only in the subgraph.
Could you please guide how writing such style with the dot-format, with an example?
Good news:
creating your "parent nodes" is pretty easy. Graphviz, (dot) calls them "cluster subgraphs" (or clusters). (well documented on p. 19 of https://www.graphviz.org/pdf/dotguide.pdf) see below for an example.
Bad news:
explicitly sizing clusters is very difficult. Dot sizes a cluster to be just big enough to contain its nodes.
explicitly positioning clusters is also quite difficult. Dot positions clusters based on the "best" positioning of the component nodes, specifically the edges that connect nodes within the various clusters.
drawing edges from one cluster to another is a kludge. You define an edge from a node contained within one cluster to another node contained within a different cluster and instruct dot to clip that edge so it appears to be from cluster to cluster. This uses the attribute compound=true. (again, read the documentation listed above)
Finally: the fdp engine allows cluster-to-cluster edges, but you lose the directionality of the edges
Drawn with dot:
digraph C {
graph [compound=true] // allows edges to/from clusters
// create an extra cluster to try to keep clusterA above clusterB
subgraph clusterWrapper {
graph [peripheries=0] // no box around
subgraph clusterA {
graph [peripheries=1] // box around
a -> c
b->c
c->d
}
subgraph clusterB {
graph [peripheries=1] // box around
f->g
e->g
}
} // end of wrapper
subgraph clusterC {
edge [dir=none ] // no arrowheads
h->k
i->k
i->l
j->l
{rank=same h->i->j [style=invis]}
}
b->f [ltail=clusterA, lhead=clusterB];
l:s->b:n [ltail=clusterC, lhead=clusterA];
l->f [style=invis weight=50]
}
Giving:

Bisecting dashed curved lines ala Threat Model

Is there a way to add a curved dash line similar to the one present here for Privilege Boundaries? I'd like to have a threat model checked into GIT that is procedurally generated as part of my CI/CD builds as apposed to drawing it online or in some tool like OmniGraffle and exporting image only to loose the original docs.
You can get fairly close by adding some extra edges and invisible nodes and using attribute for extra edge arrowhead=icurve, but it will not be a dashed line. Graphviz allows you to draw dashed cluster boundaries, or dashed edges from node to node, but the perpendicular line to the one or two edges will be impossible to draw without manual positioning, as you drawing it online, and as I assume you need to draw without human involvement.
Also with some extra effort with PostScript you can create half-drawn nodes with dashed border like A -> Internet Boundary [shape=yourshape color=red] -> B, but this is also not actually a line crossing.
Image:
and script for arrowhead=icurve variant:
digraph threat_model {
graph [
splines=false
ranksep=0
nodesep=2]
User [shape=box xlabel=<<FONT COLOR="ORANGE"><B>Actor</B></FONT>>]
a [shape=circle label=<<FONT><B>a. Static<BR/>front-end<BR/>files</B></FONT>> xlabel=<<FONT COLOR="ORANGE"><B>Process</B></FONT>>]
b [shape=circle label=<<FONT><B>b. App<BR/>back-end</B></FONT>> xlabel=<<FONT COLOR="ORANGE"><B>Data<BR/>Flow</B></FONT>>]
// Two extra nodes:
boundary_User_b_1 [shape=point height=.01]
boundary_User_b_2 [shape=point height=.01]
User -> a [minlen=3 dir=both xlabel="1. Retrieve static\nfront-end files"]
// Three extra edges:
User -> boundary_User_b_1 [minlen=3 dir=back xlabel="2. Modify report"]
boundary_User_b_1 -> boundary_User_b_2 [arrowhead=icurve arrowsize=6 color=red headlabel=<<FONT COLOR="RED">Internet<BR/>Boundary</FONT>>]
boundary_User_b_2 -> b [minlen=3]
}
Another fairly close variant using cluster, note that the arrow can rest against boundary, with the compound=true attribute for graph and lhead attribute for arrow:
digraph {
graph[
ranksep=1
compound=true
]
A
B
subgraph cluster_IB {
graph [
label="Internet Boundary"
fontcolor=red
margin=20
style="dashed, rounded"
color=red
]
C
}
A -> C
B -> C [lhead="cluster_IB"]
}

How to have multiple label one above and one below the edges in graphviz?

I've the following output currently I want to place a label below the edge between p and z in the figure.Is it possible to do in graphviz I've tried using xlabels but it doesn't work.
Current Code:
digraph GPG{
node [shape=box];
subgraph cluster0{
node[shape=circle];
0[label=0,style=invis];
}
subgraph cluster1{
node[shape=circle];
1[label=1,style=invis];
p->z [label="2 | 1",minlen=1];
{
rank = same;
p;z;
}
}
subgraph cluster2{
node[shape=circle];
2[label=2,style=invis];
}
0->1
1->2
}
I want a label below edge p->z as well above the edge.Is it possible in graphviz?
Kind of ugly, but:
digraph overunder{
splines=false
{ rank=same
a -> b [label=" over " ]
a -> b [label="under" penwidth=0.0 dir=none]
}
}
Produces:
You may have to add the non-breaking space characters (see above) because Graphviz seems to position labels based on the length of the text - longer labels are placed above shorter labels.

Arranging graphviz clusters

I'm trying to generate the following construct:
I have four graphs. Three of them are supposed to be in the first "row", all vertically aligned by their vertical center. The fourth graph is supposed to be below the other three, in the second "row". It should be horizontally aligned with either the horizontal center of the upper row's middle graph or the horizontal center of the entire upper row. Additionally there will be edges between some members of separate clusters/graphs.
Here there are only edges between members of cluster_a and cluster_d, but there may be edges between members of any combination of clusters.
Ususal you can do this by adding some additional invisible scarfolding nodes and edges e.g.:
digraph G {
rankdir=LR
edge[minlen=2]//enable finer control over node location when scarfolding
subgraph cluster_d { label=cluster_d
d_0->d_2
d_1->d_0
//d_1->d_3
//extra node to simulate edge between edges
d_13[shape=point]
d_1->d_13[dir=none minlen=1]
d_13->d_3[minlen=1]
d_3->d_2
d_3->d_3
}
subgraph cluster_abc { // better align cluster
subgraph cluster_a { label=cluster_a
a_0->a_2
a_0->a_3
a_1->a_0
a_1->a_1
a_1->a_2
a_1->a_3
//a_2->a_3
//extra node to simulate edge between edges
a_23[shape=point]
a_2->a_23[dir=none minlen=1]
a_23->a_3[minlen=1]
a_3->a_2
a_3->a_3
}
subgraph cluster_c { label=cluster_c
c_0->c_0
c_0->c_1
c_0->c_2
c_0->c_3
c_1->c_3
c_3->c_3
c_2->c_0
c_2->c_1
c_2->c_2
c_2->c_3
}
subgraph cluster_b { label=cluster_b
b_0->b_0
b_0->b_2
b_0->b_3
b_1->b_1
b_1->b_2
b_1->b_3
b_2->b_0
b_3->b_2
}
color=invis
}
{//scarfolding
edge[style=invis]node[style=invis] //hide scarfolding
{
rank=same
node[shape=point] //minimize impact on edge routing around the scarfolding nodes
x_0
x_1
}
a_3->c_0
c_3->b_0
// we can not use same rank across cluster boundary so instead of a_3->d_1 we do a_2->x_0 + x_1->d_1
a_2->x_0
x_1->d_1[minlen=3]
}
{
edge[headclip=false tailclip=false]
a_2->d_1[dir=none constraint=false]
a_3->d_3[dir=none]
}
a_23->d_13[dir=none constraint=false]
}

graphviz/dot: can the distance between two nodes be set individually?

I'm trying to use dot (version 2.28.0) in order to make a flow chart of my source code. For that, I would like the graph to consist of subgraphs where each of these subgraphs represents a source file in the code base. At the top of each subgraph, there should be the file name as a node in a visually easily distinguishable fashion (i.e. bold, white text on dark blue background). Below the file name node should be the nodes representing the flow of routines in that file in the order they are being called.
My problem now is that I would like the distance between "filename nodes" and "routine nodes" to be smaller than the distance between individual "routine nodes", plus, there should be no arrow between.
I tried to use the minlen attribute for the edge connecting the "filename node" to the first "routine node", but when I set that to a value below 1.0, the two nodes come out next to each other rather than stacked.
Is there any way to make the first two nodes be closer to each other than the other two, yet top/bottom oriented?
digraph "prog.c"
{
edge [fontname="FreeSans",fontsize="12",labelfontname="FreeSans",labelfontsize="10"];
node [fontname="FreeSans",fontsize="14",shape=record,height=0.2];
compound=true;
subgraph cluster_main {
Node1_0 [label="main.c", shape=folder, fontcolor="white", style=filled, fillcolor="#00008b"];
Node1_1 [label="routine1()"];
Node1_2 [label="routine2()"];
edge [color="transparent", minlen="0.5"]; // stacking not ok
// edge [color="transparent", minlen="1.0"]; // stacking ok
Node1_0 -> Node1_1 ;
edge [color="black", minlen="1.0"];
Node1_1 -> Node1_2 ;
}
}
Edit: I should have commented out the line which lead to the undesired result rather than the one leading to the desired result (I had planned to attach two pngs for clarification, but I'm not allowed to do so as a newbie); so here is the code I would actually want to modify in a way that the first two nodes have a different (smaller) distance to each than the last two.
digraph "prog.c"
{
edge [fontname="FreeSans",fontsize="12",labelfontname="FreeSans",labelfontsize="10"];
node [fontname="FreeSans",fontsize="14",shape=record,height=0.2];
compound=true;
subgraph cluster_main {
Node1_0 [label="main.c", shape=folder, fontcolor="white", style=filled, fillcolor="#00008b"];
Node1_1 [label="routine1()"];
Node1_2 [label="routine2()"];
//edge [color="transparent", minlen="0.5"]; // stacking not ok
edge [color="transparent", minlen="1.0"]; // stacking ok
Node1_0 -> Node1_1 ;
edge [color="black", minlen="1.0"];
Node1_1 -> Node1_2 ;
}
}
There are a couple of "graph" properties that can control what you need.
pad, ranksep, nodesep
Also, I increased your node size, but only for my own ease of use...
digraph "prog.c"
{
graph [pad=".75", ranksep="0.25", nodesep="0.25"];
node [fontname="FreeSans",fontsize="14",shape=record,width=2, height=.5];
edge [fontname="FreeSans",fontsize="12",labelfontname="FreeSans",labelfontsize="10"];
compound=true;
subgraph cluster_main {
Node1_0 [label="main.c", shape=folder, fontcolor="white", style=filled, fillcolor="#00008b"];
Node1_1 [label="routine1()"];
Node1_2 [label="routine2()"];
edge [color="transparent", minlen="0.5"]; // stacking not ok
// edge [color="transparent", minlen="1.0"]; // stacking ok
Node1_0 -> Node1_1 ;
edge [color="black", minlen="1.0"];
Node1_1 -> Node1_2 ;
}
}

Resources