Graph in Graph Extraction - graphviz

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:

Related

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"]
}

In GraphViz, make node positions within a subgraph independent from nodes in other subgraphs?

Using dot, the basic layout puts nodes into layers. If you create subgraphs, it groups related nodes inside of rectangles, but the nodes are still in layers, and those layers are influenced by the nodes outside of the subgraph.
Sometimes, this is great. But sometimes, when a subgraph is an independent visual entity, it might be nice to be able to lay out its content without respect to the layers of the other parts of the graph. Take for example the following:
digraph x {
subgraph one {
a [ label="a\nvery\nlong\nlabel" ]
b [ label="another\nvery\nlong\nlabel" ]
c [ label="still\nmore\nlong\nlabels" ]
a -> b - > c
}
subgraph two {
w -> x -> y -> z
}
}
Because of the long labels, the nodes in subgraph one will take up a lot of space. But because of the layer-based layout, the nodes in subgraph two will be vertically aligned with the corresponding nodes from subgraph one.
Is there a way to make it layout subgraph two as if subgraph one did not exist?
Not directly with dot. Dot does rank alignment across the entire graph. However here are two ways to get close to what you want:
use neato -Goverlap=false -Gmode=hier to approximate a dot layout:
or split the various parts into separate graphs, use dot -Tdot to layout each, then use gvpack (https://graphviz.org/pdf/gvpack.1.pdf) to combine the parts into a single output. Like so:
dot -Tdot ComboGraph1a.gv >ComboGraph1a.dot
dot -Tdot ComboGraph1b.gv >ComboGraph1b.dot
gvpack -array_ib2 ComboGraph1?.dot |neato -Tpng -n2 >oooo.png
Giving:

What language construct is " {rank=same; A B C} " in graphviz

In graphviz/dot, I can place nodes on the same rank with {rank=same; ND1 ND2 ND3}.
Looking at the dot language, I conclude that {...} is part of the subgraph statement.
If this is the case, I don't understand why I need a subgraph to rank nodes. I assume this is because I don't have a correct mental image of what constitutes a subgraph in graphviz.
So, my question is: what is a subgraph in graphviz exactly and why do I have to start a subgraph to rank nodes that don't have anything to do with this subgraph.
From the documentation you cite:
In the second role, a subgraph can provide a context for setting attributes. For example, a subgraph could specify that blue is the default color for all nodes defined in it. In the context of graph drawing, a more interesting example is:
subgraph {
rank = same; A; B; C;
}
This (anonymous) subgraph specifies that the nodes A, B and C should all be placed on the same rank if drawn using dot.
This use of subgraphs to set rank of nodes is exactly the sort of context to which the documentation is referring (explicitly in this case). The syntax supports a special contextual meaning in this case.

Graphviz: Align tree roots in a forest

I defined a forest (a set of trees) in DOT.
I am using dot for layouting.
Now the problem: The trees have different depths. I would like to align the root nodes on the same level, however on default the nodes are aligned by the leaves.
I think you mixed up actual with expected in your question
digraph {
// create a forest hanging from the ceiling
node[shape=box]
edge[dir=back]
a->b->c
d->e->f->g
h->i
// ground the forest
ground_node[style=invis]
subgraph {
c;g;i
} -> ground_node [style=invis]
}

Graphviz subgraph doesn't get visualized

I'm trying to create a graph with two subgraphs in dot. The code is as follows:
digraph G {
subgraph step1 {
style=filled;
node [label="Compiler"] step1_Compiler;
node [label="Maschine"] step1_Maschine;
color=lightgrey;
}
subgraph step2 {
style=filled;
color=lightgrey;
node [label="Interpretierer"] step2_Interpretierer;
node [label="Maschine"] step2_Maschine;
label="Virtuelle Maschine";
}
"Programm (Java)" -> step1_Compiler;
step1_Compiler -> step1_Maschine;
step1_Maschine -> "Bytecode";
"Bytecode" -> step2_Interpretierer;
step2_Interpretierer -> step2_Maschine;
step2_Maschine -> "Ergebnis";
}
The result I am getting looks like the following:
I expected to see a box around both subgraphs. What am I missing here?
You'll have to prefix the name of your subgraphs with cluster:
subgraph clusterstep1 {
and
subgraph clusterstep2 {
in order to get the style and label.
From the graphiz documentation, section "Subgraphs and Clusters":
The third role for subgraphs directly involves how the graph will be
laid out by certain layout engines. If the name of the subgraph begins
with cluster, Graphviz notes the subgraph as a special cluster
subgraph. If supported, the layout engine will do the layout so that
the nodes belonging to the cluster are drawn together, with the entire
drawing of the cluster contained within a bounding rectangle. Note
that, for good and bad, cluster subgraphs are not part of the DOT
language, but solely a syntactic convention adhered to by certain of
the layout engines.

Resources