In graphviz how to force a straight edge between two nodes? - graphviz

Here is my graphviz code:
digraph G {
rankdir="LR"
node [shape=square]
exDNS [label="External DNS"]
inDNS [label="Internal DNS"]
tm [label="Traffic Manager"]
pri [label="App Service\nPrimary Region"]
sec [label="App Service\nSecondary Region"]
Browser -> {inDNS,exDNS} -> Imperva-> tm -> {pri,sec}
Browser -> Imperva -> {pri,sec}
}
It produces the following result:
I would the edge Browser -> Imperva to go straight between the nodes External DNS and Internal DNS.
How can I do it?
I am using the dot renderer.

It is difficult to make edges behave (explicitly position them). But by attaching edges to ports, you can have some influence on edge locations.
I think this is what you're after:
digraph G {
rankdir="LR"
// graph [splines=polyline]
node [shape=square]
exDNS [label="External DNS"]
inDNS [label="Internal DNS"]
tm [label="Traffic Manager"]
pri [label="App Service\nPrimary Region"]
sec [label="App Service\nSecondary Region"]
Browser:ne -> exDNS -> Imperva
Browser:e -> Imperva
Browser:se -> inDNS -> Imperva
Imperva-> tm -> {pri,sec}
Imperva -> {pri,sec}
}

You can do this without fiddling about with ports.
Your current dot first explicitly defines exDNS and inDNS, then Imperva is implicitly defined in the edges - i.e. it's defined third.
All I've added in the dot below is the explicit declaration of node Imperva between exDNS and inDNS, i.e. so it is defined second, before inDNS.
I think this works because there's this wording in the dotguide section 2.6 (NOTE in these words rankdir is the default top-to-bottom so for rankdir=LR read left as top and right as bottom) :
If a subgraph has ordering=out, then out-edges within the subgraph that have the same tail node wll fan-out from left to right in their order of creation.
TBH I'm not completely sure this is the reason because the dotguide doesn't give a default for ordering.
Regardless of the dotguide, in my dot below if I move the definition of Imperva up one line to be above the exDNS node declaration then the edge from Browser to Imperva passes over exDNS (because Imperva is defined first). Move the definition of node Imperva below the line for inDNS - or omit this explicit definition of the node completely like your dot does - so Imperva is defined after inDNS, and the edge goes below inDNS like your graph.
digraph G {
rankdir="LR"
node [shape=square]
exDNS [label="External DNS"]
Imperva;
inDNS [label="Internal DNS"]
tm [label="Traffic Manager"]
pri [label="App Service\nPrimary Region"]
sec [label="App Service\nSecondary Region"]
Browser -> {inDNS,exDNS} -> Imperva-> tm -> {pri,sec}
Browser -> Imperva -> {pri,sec}
}
produces:

Related

In graphviz, can you bring two vertices closer together?

When describing a graph with graphviz, I sometimes find I want two vertices to appear closer together than the layout engine I chose places them. Is there a way to hint that I want them closer?
I'm mostly interested in the case of two connected vertices, so an answer specific to that case is fine.
Concrete example:
digraph G {
node [shape="circle"];
Start [shape="none" label=""];
C [shape="doublecircle"];
Start -> A;
A -> B [label="0,1"];
B -> C [label="0,1"];
C -> D [label="0,1"];
D -> D [label="0,1"];
}
I want the vertices Start and A to be closer.
You can't do that, but you can make nearly everything else twice as big, here is a start.
(But you can't increase the size of an edge to self)
digraph G {
rankdir=LR
edge[minlen=2 fontsize=28 arrowsize=2 penwidth=2]
node[fontsize=28 height=1 penwidth=2]
graph[fontsize=28 penwidth=2]
node [shape="circle"];
Start [shape="none" label=""];
C [shape="doublecircle"];
Start -> A[minlen=1]; // not twice the size to get the requested effect
A -> B [label="0,1"];
B -> C [label="0,1"];
C -> D [label="0,1"];
D -> D [label="0,1"];
}
[this answer applies specifically to dot]
there is no edge-level attribute that explicitly sets or changes edge length
the graph-level nodesep attribute sets minimum distance between two nodes of same rank
so:
digraph G {
nodesep=.17
{
rank=same
node [shape="circle"];
Start [shape="none" label=""];
C [shape="doublecircle"];
Start -> A;
A -> B [label="0,1"];
B -> C [label="0,1"];
C -> D [label="0,1"];
D -> D [label="0,1"];
}
}
produces:
To increase the distance between the other nodes, you can add spaces to the labels.
I'm not wild about it either, but this change:
B -> C [label=" 0,1 "]; // pad to make label (and edge) longer
produced this:

How can I cross out a node in Graphviz?

I would like to indicate that a node should be there, but is currently lacking in the process.
Intuitively I would like to cross it out as shown in below image (now done manually in Paint):
Is there a node attribute in Graphviz that I can use for this?
I can't find an attribute or node shape to do what you want, but here are two ways to do it:
build an image outside of Graphviz (with the text and the X) and use the image attribute to use the image as the node (yes, a pain if you want to do this frequently):
b [image="myB.png"]
For every X'd out node, add 2 new edges from .ne to .sw and .nw to .se (see below) Each with this (new) attribute: straightline=1. Then run this command:
dot -Tdot Xout2.gv |gvpr -f straightline.gvpr -c | neato -n2 -Tpng >out.png
Where this is straightline.gvpr:
E[straightline==1]{
int i, n;
string pt[int];
double x1, y1, x2, y2, xI1, yI1, xI2, yI2;
n=split($.pos, pt, " ");
for (i=0;i<=1;i++){
if (match(pt[i],"e,")>=0){
print ("// BEFORE: ", pt[i]);
pt[n-1]=substr(pt[i],2);
print ("// AFTER: ", pt[i]);
pt[i]=pt[i+1];
}
}
for (i=0;i<=1;i++){
if (match(pt[i],"s,")>=0){
pt[0]=substr(pt[i],2);
}
}
sscanf (pt[0], "%f,%f", &x1, &y1);
sscanf (pt[n-1], "%f,%f", &x2, &y2);
xI1=x1+(x2-x1)*.3;
yI1=y1+(y2-y1)*.3;
xI2=x1+(x2-x1)*.7;
yI2=y1+(y2-y1)*.7;
$.pos=sprintf("%s %.3f,%.3f %.3f,%.3f %s", pt[0], xI1, yI1, xI2, yI2, pt[n-1]);
}
From this input:
digraph X{
graph [outputorder=edgefirst]
b [ label="X me"]
a -> b -> c
a -> d
d -> c
e -> f
g -> i -> k
edge [color="#ff000080" penwidth=2] // note translucent color
b:ne -> b:sw [straightline=1]
b:se -> b:nw [straightline=1]
edge [color="green" penwidth=2]
e:n -> e:s [straightline=1]
f:w -> f:se [straightline=1]
edge [color="orange" penwidth=2]
g:n -> g:se [dir=back straightline=1]
edge [color="blue" penwidth=2]
g:n -> g:sw [dir=back straightline=1]
i:e -> i:w [dir=none straightline=1]
k -> k:s [dir=both straightline=1]
}
Sorry, convoluted, but it works.
While the answer of sroush gives me the exact output I need, it requires that I understand how to introduce gvpr in my workflow which will take a bit of time.
In the meantime I came up with a dot only approach, which approximates crossing out a node sufficiently for my purpose.
In below graph I would like to cross out the node Some process:
digraph graphname {
rankdir=LR
node [fillcolor="lightblue3", style="filled"]
a
c
d
b [label="Some\nprocess"]
a -> b -> c
a -> d -> c
{rank=same a;d}
}
To do so I change:
the nodestyle of the Some process node to have a diagonal hard gradient
use a HTML-like label to strikethrough the text
Make the fontcolor and node outline a shade of gray
digraph graphname {
rankdir=LR
node [fillcolor="lightblue3", style="filled"]
a
c
d
node [fillcolor="lightblue3;0.5:white", style="filled", fontcolor="gray50", color="gray50", gradientangle=100]
b [label=<<s>Some<br/>process</s>>]
a -> b -> c
a -> d -> c
{rank=same a;d}
}

Weird node placement of dot graph

I have the following source code for a graph in dot:
digraph name {
rankdir="LR";
node [shape="record"];
1 [label="OUTPUT"];
A [label="FWD|<i>i|<r_in>r_in|<r_out>r_out|<o>o"];
B [label="FIFO|<r_in>r_in|<o>o"];
C [label="Cons|<i>i|<r_out>r_out|<o>o"];
A:o:e -> C:i:w;
C:r_out:w -> A:r_in:e;
B:o:e -> A:i:w;
C:o:e -> 1:w;
A:r_out:w -> B:r_in:e;
}
It consists of 4 nodes, which essentially could be placed one after another, in the order B -> A -> C -> OUTPUT. If dot would place the nodes in this order, only few edge would cross between two nodes.
However, calling dot like this:
dot mygraph.dot -Tpng -o mygraph.png
creates the following mess:
Edit: It seems, the order of the nodes in the source is important. However, as the source is generated from a program, outputting its internal signal flow structure, I cannot rely on it to put the nodes in the right order. I thought, dot and its graph layout engine can figure out on its own, which nodes are the first ones, such that the wires do not cross.
Just define the nodes in the desired order:
digraph name {
rankdir="LR";
node [shape="record"];
B [label="FIFO|<r_in>r_in|<o>o"];
A [label="FWD|<i>i|<r_in>r_in|<r_out>r_out|<o>o"];
C [label="Cons|<i>i|<r_out>r_out|<o>o"];
1 [label="OUTPUT"];
A:o:e -> C:i:w;
C:r_out:w -> A:r_in:e;
B:o:e -> A:i:w;
C:o:e -> 1:w;
A:r_out:w -> B:r_in:e;
}
yields

Change edge placement from beneath to above nodes in Graphviz

It took me some time to make the graph below look like it does right now, and I'm almost satisfied. The one thing that still bothers me is that the connection between D and B should be above all nodes for the sake of aesthetics.
The funny thing is, that supplying the ports for the edge doesn't impress dot which just makes the edge cross the connected nodes.
Do you have an idea on how to avoid this?
digraph {
graph [splines=ortho, nodesep=0.2, fontname="DejaVu Sans", rankdir=LR]
node [shape=box, fontsize=8]
edge [arrowsize=0.5]
subgraph cluster {
style=invis;
A -> B -> C;
A -> B -> C;
A -> B -> C -> D;
D -> E;
D:nw -> B:ne;
}
{
D -> F -> { C; E };
}
}
PS: You need the latest Graphviz version in order to get orthogonal edges.
It may be a function of the version of the engine you use. I'm not sure what version of dot the GraphViz Workspace http://graphviz-dev.appspot.com/ uses but it does run your problem connector across the top.

simple "T shaped" graph in graphviz

Need draw a graph with dot/graphviz like this image:
The texts can be above arrows, like graphviz does it. But how to achieve the T-layout? Need make a cluster for the top row?
This is one possibility using rank=same for a subgraph:
digraph g {
node[shape=point, width=0.2];
{
rank=same;
p1 -> n [label="text1"];
n -> p2 [label="text2"];
}
n -> p3 [label="text3", dir=back];
n[label="node", shape=rect, style=rounded];
}
You could also use a left-right layout instead of top-down.
An other possibility is to disable the effect of some edges using constraint=false:
digraph g {
node[shape=point, width=0.2];
p1 -> n [label="text1", constraint=false];
n -> p2 [label="text2", constraint=false];
n -> p3 [label="text3", dir=back];
n[label="node", shape=rect, style=rounded];
}
The result is the same.
dot usually layouts trees in layers. To force an edge to not be a layer separation you can add the constraint=false option. So something like:
digraph {
A [shape=point]
B [shape=point]
C [shape=point]
N [label="node"]
A -> N [label="text1", constraint=false]
N -> B [label="text2", constraint=false]
N -> C [label="text3", dir=back]
}
should work.
Note that the edge from the lower node to "node" has to be backwards, since dot layouts trees from top to bottom. Therefore the logical edge direction has to be from top to bottom, even though the display direction might be the other way round (which is the case here).

Resources