Bisecting dashed curved lines ala Threat Model - graphviz

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

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:

How do I force nodes to be drawn next to each other with Graphviz dot?

I'm looking to have a series of nodes in a row, joined by an edge. This works fine when the graph's rankdir is set to TB or BT, but it rearranges the nodes when I set it to LR or RL so they're no longer next to each other. Example images are included.
I've taken my code and stripped it down to it's minimum point for demonstration. The code is the same for both of the following graphs, aside from line 2 (which specifies rankdir):
digraph{
rankdir=LR;
node[shape=box,fontcolor=white,color=black,fillcolor=black,style=filled];
edge[dir=none,color=black];
Josh -> JoshParent;
JoshParent -> Hero;
JoshParent[shape=circle,label="",height=0.0001,width=0.0001];
{
rank=same;
Kae[label="Kae"];
Hero[label="Hero"];
Kae -> Hero;
}
Kae -> KaeParent;
Hero -> HeroParent;
KaeParent -> Liz;
KaeParent[shape=circle,label="",height=0.0001,width=0.0001];
HeroParent -> George;
HeroParent[shape=circle,label="",height=0.0001,width=0.0001];
{
rank=same;
George[label="George"];
Liz[label="Liz"];
Ocean[label="Ocean"];
Egg[label="Egg"];
Liz -> Ocean -> Egg;
}
}
This is what's shown with rankdir=TB:
This is what's shown with rankdir=LR:
As you can see, from the LR image, the nodes have been drawn in the order "Ocean, George, Egg", rather than "Ocean, Egg, George" as it is with the TB image.
You can force the order by adding an explicit but invisible edge from Egg to George:
Liz -> Ocean -> Egg; // last line of your code
Egg -> George[ style = invis ]; // additional edge
This produces
I don't have an explanation for the different behaviour between TB and LR, though.

Graphviz (dot) control edge routing

In this graph the bottom edge is not drawn symmetrical to the top edge:
digraph G {
A:ne -> A:nw;
A:sw -> A:se;
}
I want it to look more like a "fat snowman" with the edge A:sw -> A:se; looping below the node. Is there a way?
Short answer no - or not easily.
Loops seem to be placed from the rankdir direction. If rankdir is TB (down), loops seem to be placed "up".
It you're willing to work at it, you can run your graph twice, once with rankdir=TB, once with rankdir=BT - both times with -Tdot. Then you'd have to replace the offending edge with the equivalent edge from the other graph. [I hope this makes some sense]
Here is a tweaked version of your graph run with different values of rankdir:
digraph G {
A:ne -> A:nw;
A:sw -> A:se;
dummy [style=invis]
dummy -> A [style=invis]
}

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:

Add extra edges to a digraph in Graphviz

I have a .dot digraph which shows a graph as I want (depicting relationship between some tables). I want to add redundant edges to the graph (to represent redundant relationships in the database which exist only to write queries less effortly). These redundat edges, which will be written in a "dotted" style, must not change the deployment of nodes in the graph.
In other words, there's edges which must affect the node positions to print the graph pretty, and other edges which must to be added after the node positions are already computed (which will be styled differently --light gray, dotted, etc; to show that they're not main edges).
Is there options in Graphviz to specify "extra" edges?
Use constraint=false and color=gray on those additional edges.
digraph G {
a -> b -> c -> d;
d -> a [constraint=false,color=gray]
a -> z -> x -> d;
}
Play with that on http://graphviz.it/#/rhlWBZsz

Resources