Guiding "dot" towards desired edge placement - graphviz

I have the following Graphviz code.
digraph {
North -> West
North -> East
North -> South
West-> South
East -> South
}
When using dot on this input file, it renders the graph with the direct edge between the North and South nodes on the outside:
My question: how can I get dot to render the North-to-South edge in between the East and West nodes?
Note that the graph above is a much simplified version of the problem I am encountering in the graph I actually want to improve, shown below (the thick red edge is the one I'd like dot to route via the more obvious way).

Pretty gross, but this works.
Uses a 3x3 matrix of nodes (visible & invisible).
Aligns via rank=same (https://graphviz.org/docs/attrs/rank/) & the group (https://graphviz.org/docs/attrs/group/) attribute. There is probably a "better" way to do this, but ...
digraph {
splines=false
North -> West
North -> East
North -> South
West-> South
East -> South
node[shape=plain style=invis label=""]
edge[style=invis]
{rank=same West -> central -> East }
{rank=same l1 -> North -> r1 }
{rank=same l2 -> South -> r2 }
{ node [group=V] North-> central-> South}
{ node [group=L] l1 -> West-> l2}
{ node [group=R] r1 -> East -> r2}
}
Giving:

If you need a specific edge to dominate your layout, you can use the weight = <integer> (where integer is a small positive value of about 10) attribute to make it as direct as possible. Conversely, negative values allow the layout engine to use more circuitous routes for unimportant edges. Edges with different weights are prioritised, but the layout is difficult to predict and can unexpectedly become ugly.
Avoid placing these additional constraints unnecessarily as the layout becomes increasingly brittle and small changes to the source can completely change the output.

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.

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

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

Horizontally partitioning nodes in a graph

I'm using the dot command to generate a graph of, in this case, a series of software releases, showing the relationship among the releases.
Assumptions:
Each release has a number, with higher numbers denoting later releases.
Each release must appear above earlier releases in the graph.
Each release is based on a specific earlier release, not necessarily the most recent one.
Each "based-on" relationship is shown as an arrow from one node to another.
Some subset of the releases are separate, for reasons that aren't important to the question. I'll call them "alt" releases. "Alt" releases can be based on non-"alt" releases, and vice versa. (It happens that I'm more interested in the non-"alt" releases, but I want all releases in the graph.)
I can generate a graph that clearly shows the relationships among the releases, but I also want to put all the "alt" releases on the right side of the vertical graph, and all the non-"alt" releases on the left side -- while maintaining all the relationship information (which means arrows going from the left side of the graph to the right, and vice versa).
I've tried putting the "alt" nodes into a subgraph/cluster, but that loses the dependencies (arrows) between nodes in the cluster and nodes outside it.
I've also tried creating an invisible node in the "middle" and defining dependencies from every node to the "middle" node while specifying the direction, but I was unable to mix vertical and horizontal dependencies in the same graph.
Here's the demo.dot file I have so far, which does not do the partitioning I want:
digraph releases {
// Use a box shape for all nodes
node [shape=box];
// Define labels for nodes
v106 [style=bold];
v105 [label="v105 alt" style=dashed];
v104;
v103;
v102 [label="v102 alt" style=dashed];
v101 [style=bold];
// Define dependencies
v106 -> v104;
v106 -> v105 [style=dashed];
v105 -> v102;
v104 -> v101;
v103 -> v101;
v102 -> v101;
// Use [style=invisible dir=none] to ensure that a later node appears above
// an earlier one even if there's no dependency.
v106 -> v105 [style=invisible dir=none];
v105 -> v104 [style=invisible dir=none];
v104 -> v103 [style=invisible dir=none];
v103 -> v102 [style=invisible dir=none];
v102 -> v101 [style=invisible dir=none];
}
And here's the image file, generated with dot -Tpng demo.dot -o demo.png
What I want is to have all the "alt" nodes to the right of an invisible vertical line and all the other nodes to the left of it, with all the arrows still in place (distorted as necessary).
Is there a way to do this with dot? Or is there another tool (usable on Linux, specifically Debian) that can do the same thing?
This is a very late answer but may help others.
Graphviz tries to keep edges straight if both nodes belog to the same group.
digraph releases { nodesep=0.5
// Use a box shape for all nodes
node [shape=box];
// Define regular nodes
{
node [group=regular];
v106 [style=bold];
v104;
v103;
v101 [style=bold];
}
// Define alt nodes
{
node [group=alt style=dashed];
v102 [label="v102 alt"];
v105 [label="v105 alt"];
}
// Define dependencies
v106 -> v104;
v106 -> v105 [style=dashed];
v105 -> v102;
v104 -> v101;
v103 -> v101;
v102 -> v101;
// Use [style=invisible dir=none] to ensure that a later node appears above
// an earlier one even if there's no dependency.
edge [style=invisible dir=none];
v106 -> v105;
v105 -> v104;
v104 -> v103;
v103 -> v102;
v102 -> v101;
}
gives
Trying to do something similar. Adding this to your code gets close:
subgraph cluster_alt {
graph [style= invisible];
edge [style = invisible, arrowhead=none];
weight = 10;
v102 -> v105;
}
subgraph cluster_main {
graph [style= invisible];
edge [style = invisible, arrowhead=none];
weight = 10;
v106 -> v105-> v104->v103->v102->v101;
}
Gives me:
The "weight" attribute pushes the edges in these invisible subgraphs towards being more vertical than the other edges (the visible ones you've already defined).

Resources