Graphviz drawing - make a box that starts at one node and goes to the end of another one - graphviz

I have a timeline and would like a box to be drawn next to a particular number of years
digraph timeline {
node [fontsize=24, shape = plaintext];
1940 -> 1950;
1950 -> 1955;
1955 -> 1960;
node [fontsize=20, shape = box];
{ rank=same; 1940 test; }
}
This places a timeline on the left hand side going from 1940 to 1950 and so forth. I would like draw a box next to the numbers that starts at 1940 - which is what I do now with { rank=same; 1940 test; } and that ends with 1955.
Here is an example of the box drawn at 1940
Here is an example of the box drawn at 1955 with code { rank=same; 1955 test; }
I would like to have the box drawn from the start of 1940 position to the end of 1955 position, so encompassing these two boxes right now.

Tricky solution is to draw a cluster and place invisible nodes inside it using style=invis. Then align the cluster with the timeline using newrank.
Script:
digraph timeline {
newrank=true;
node [fontsize=24, shape = plaintext];
1940 -> 1950 -> 1955 -> 1960;
subgraph cluster_1 {
test [fontsize=20]
cl_start [shape=none style=invis]
cl_end [shape=none style=invis]
cl_start -> test -> cl_end [style=invis]
}
{rank=same;1940;cl_start}
{rank=same;1955;cl_end}
}
Result:

No easy way to do this with Graphviz.
dot does not allow nodes to span ranks. It centers all nodes in the same rank on the same line (horizontal, with rankdir=TB).
if you set rankdir=LR, you can get nodes to span years, but positioning & node sizing become difficult
you could put a node on every year you want the final node to span and the post-process the result to overwrite the several nodes with a single large node.
you can us the neato -n (https://graphviz.org/faq/#FaqDotWithNodeCoords) capability and position & size all the nodes yourself
or you could try another language entirely (maybe pikchr https://pikchr.org/home/doc/trunk/homepage.md)

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

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.

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.

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

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