Graphviz/DOT: How to have arrow "redirected" - graphviz

This is what I want to produce in a DOT graph:
I have the following code:
\digraph
[scale=0.7]{g1}
{
margin="0 0 0 0";
rankdir="TB";
"X" [shape=invhouse];
" " [shape=house];
"100" [shape=cylinder];
"X" -> "100"
"X" -> "+";
"100" -> "+"
"+" -> " ";
}
I also have the following code, which is closer in a sense but visually looks nothing like what I want:
digraph {
node[ shape = plaintext ];
a [label="X", shape = invhouse]
b [label="+", shape = ellipse]
ab1 [label="dummy", style=invis, shape=point]
ab2 [label="dummy", style=invis, shape=point]
c [label="100", shape = cylinder]
d [label=" ", shape=house]
subgraph cluster_0 {
style=invis
a -> ab1 [arrowhead=none];
ab1 -> c;
c -> ab2;
ab1 -> ab2 [arrowhead=none];
ab2 -> b;
b -> d;
}
}
How can I change my code(s) appropriately? Any help would be greatly appreciated.

the group attribute helps to bring nodes in line.
digraph {
node[ shape = plaintext group=abd];
a [label="X", shape = invhouse]
b [label="+", shape = ellipse]
ab1 [label="dummy", style=invis, shape=point]
ab2 [label="dummy", style=invis, shape=point]
c [label="100", shape = cylinder, group=c]
d [label=" ", shape=house]
subgraph cluster_0 {
style=invis
a -> ab1 [arrowhead=none];
ab1 -> c;
c -> ab2;
ab1 -> ab2 [arrowhead=none];
ab2 -> b;
b -> d;
}
}

Related

Graphviz ordering of nodes on the same rank

I made a graph and it looks like I want it to with one exception: the cluster containing nodes D and E should be placed between nodes B and C.
Here is the .dot:
digraph {
node[shape=rectangle]
graph [
newrank=true
];
Z
A
B
C
{
rank=same;
A -> B -> D;
D -> C[style=invis];
}
subgraph clusterSS {
style=dashed;
D[group=ss]
E[group=ss]
D -> E[style="dashed"; dir = none];
}
Z -> A
Z -> B
Z -> D
Z -> C
A -> P[dir = back]
B -> S
S -> B[constraint = false];
C -> S
S -> E[constraint = false]
E -> S[label = "Label"]
}
I expected that having edges between nodes
{
rank=same;
A -> B -> D;
D -> C[style=invis];
}
would ensure correct ordering, but it doesn't.
The ordering becomes correct once I delete the edge label between S and E, but I do need to keep the labels.
[non-trivial, not guaranteed to work as desired in any other circumstance]
Added clusters, invisible nodes,and more. ugh
digraph {
node[shape=rectangle]
graph [
newrank=true
];
{
rank=same;
A -> B -> D;
D -> C[style=invis];
}
subgraph clusterSS {
style=dashed;
D [group=ss]
E [group=ss]
D -> E[style="dashed"; dir = none];
}
subgraph clusterAP {
peripheries=0
A -> P[dir = back]
}
subgraph clusterB {
peripheries=0
B
bogus [style=invis shape=plain]
B->bogus [style=invis]
}
Z -> A
Z -> B
Z -> D
Z -> C
S [group=ss]
B -> S:nw
B -> S:w [dir=back]
C -> S
S -> E[constraint = false]
E -> S[label = "Label"]
}
Giving:

Is it possible to generate a small GraphViz chart?

I need to generate a small graphviz graph that represents a "price map" of the main graphviz. The main graph is:
digraph g {
graph [rankdir = "LR"];
a [label = "<f0>a | <f1> $139 | <f2> Chair | Brown" shape = "record"];
b [label = "<f0>b | <f1> $280 | <f2> Speakers | Grey" shape = "record"];
c [label = "<f0>c | <f1> $89 | <f2> Jacket | Beige" shape = "record"];
d [label = "<f0>d | <f1> $19 | <f2> Mug | Green" shape = "record"];
e [label = "<f0>e | <f1> $180 | <f2> Printer | Grey" shape = "record"];
a -> b; a -> c; c -> d; c -> e;
}
and it generates:
When I try to generate a "small" price map like:
digraph g {
graph [rankdir = "LR"];
node [shape=box];
a[color=black, fillcolor=yellow, style=filled];
b[color=black, fillcolor=red, style=filled];
c;
d;
e[color=black, fillcolor=yellow, style=filled];
a -> b; a -> c; c -> d; c -> e;
}
I get:
But I wanted a really small price map, like:
Is this possible?
You should really read the dot guide which is a pretty impressive view across using dot (although HTMl nodes don't feature so much): http://graphviz.org/pdf/dotguide.pdf
Try changing the shape to plain:
node [shape=plain];
Result:
Another possibility is to use HTML nodes - my answer in this example shows compact nodes https://stackoverflow.com/a/68320427/2318649
Another way to control spacing is useing nodesep and ranksep on the graph, for example:
digraph g {
graph [rankdir="LR" nodesep=0.1 ranksep=0.2];
node [shape=plain];
a[color=black, fillcolor=yellow, style=filled];
b[color=black, fillcolor=red, style=filled];
c;
d;
e[color=black, fillcolor=yellow, style=filled];
a -> b; a -> c; c -> d; c -> e;
}
Result:
Another way to minimize the space inside a box node is setting margin, width and height all to 0:
digraph g {
graph [rankdir="LR" nodesep=0.1 ranksep=0.2];
node [shape=box margin=0 width=0 height=0];
a[color=black, fillcolor=yellow, style=filled];
b[color=black, fillcolor=red, style=filled];
c;
d;
e[color=black, fillcolor=yellow, style=filled];
a -> b; a -> c; c -> d; c -> e;
}
Result:
You can control the arrow size on each edge, e.g.:
a -> b [arrowsize=0.5]; a -> c [arrowsize=0.5]; c -> d [arrowsize=0.5]; c -> e;
result:
Or you can control arrowsize across all edges:
digraph g {
graph [rankdir="LR" nodesep=0.1 ranksep=0.2];
node [shape=box margin=0 width=0 height=0];
edge [arrowsize=0.5]
a[color=black, fillcolor=yellow, style=filled];
b[color=black, fillcolor=red, style=filled];
c;
d;
e[color=black, fillcolor=yellow, style=filled];
a -> b; a -> c; c -> d; c -> e;
}
Result:
Read about attributes: http://graphviz.org/doc/info/attrs.html
Read about nodes: http://graphviz.org/doc/info/shapes.html
Read about using dot: http://graphviz.org/pdf/dotguide.pdf

How can I create named edge "types" in Graphviz/dot/neato?

I need to draw a diagram with graphviz/dot where there are common edge types between nodes and am trying to find a way to define a label for each type of edge and then use that label multiple times in the diagram.
For example imagine the traditional ceiling fan FSM example where it's initially in state OFF and every time someone pulls the cord it changes to a new state based on the speed of the fan:
Pull Pull Pull
OFF ------> HIGH ------> MED ------> LOW
^ |
| Pull |
+------------------------------------+
Every edge is named "Pull" and I can define that in dot by using:
digraph fan {
OFF -> HIGH [label="Pull"];
HIGH -> MED [label="Pull"];
MED -> LOW [label="Pull"];
LOW -> OFF [label="Pull"];
}
BUT I don't want to keep specifying the same textual label every time because
My labels can get quite long so that's error-prone, and
My edges have other attributes like color in addition to label, and
I have a selection of multiple different types of edge so I want to make SURE that edge type "A" used in different contexts in the diagram always has all the same attributes.
I expected dot to have a syntax that would let me define names for my edge types, something like:
digraph fan {
edge_a [label="Pull"];
OFF -> HIGH edge_a;
HIGH -> MED edge_a;
MED -> LOW edge_a;
LOW -> OFF edge_a;
}
but of course what the really does is create a node named "Pull" and unlabeled edges.
I've been searching online for a few hours with no success. Anyone know how to define edge types up front to be used in multiple locations?
Update: #vaettchen had suggested defining an edge type then listing all of the transitions for that edge type, then defining the next edge type followed by it's transitions. While that would technically solve my problem, it would introduce a couple of others because my graphs today can look like:
digraph {
subgraph cluster_1 {
a -> b [label="type x", color=red, style=solid];
b -> a [label="type y", color=green, style=dashed];
b -> c [label="type x", color=red, style=solid];
c -> b [label="type y", color=green, style=dashed];
c -> d [label="type z", color=blue, style=dotted];
}
subgraph cluster_2 {
d -> e [label="type x", color=red, style=solid];
e -> d [label="type y", color=green, style=dashed];
e -> f [label="type x", color=red, style=solid];
f -> e [label="type y", color=green, style=dashed];
f -> c [label="type z", color=blue, style=dotted];
}
}
and to rearrange that by edge type I'd lose the immediate visual clarity in the code of having the bidirectional edges next to each other (a->b and b->a) and I'd have to explicitly list the nodes within each subgraph and I'd have to pull the subgraph-internal edge definitions up into the main graph:
digraph {
edge [label="type x", color=red, style=solid];
a -> b;
b -> c;
d -> e;
e -> f;
edge [label="type y", color=green, style=dashed];
b -> a;
c -> b;
e -> d;
f -> e;
edge [label="type z", color=blue, style=dotted];
c -> d;
f -> c;
subgraph cluster_1 {
a; b; c;
}
subgraph cluster_2 {
d; e; f;
}
}
So while it would solve the problem I asked about and I appreciate the suggestion, I'm not sure it's worth the tradeoff as you end up with the equivalent of a C program where you had to define all of your variables outside of the functions and organize them by their type rather than logical associations.
To be clear, given the above example what I was really hoping for would look like the following if such an "edge_type" definition keyword existed:
digraph {
edge_type edge_x [label="type x", color=red, style=solid];
edge_type edge_y [label="type y", color=green, style=dashed];
edge_type edge_z [label="type z", color=blue, style=dotted];
subgraph cluster_1 {
a -> b edge_x;
b -> a edge_y;
b -> c edge_x;
c -> b edge_y;
c -> d edge_z;
}
subgraph cluster_2 {
d -> e edge_x;
e -> d edge_y;
e -> f edge_x;
f -> e edge_y;
f -> c edge_z;
}
}
I think I got your solution, using m4 (thanks to Simon). Using and adapting your sample, I created a file called gv.m4:
digraph {
define(`edge_x',`[label="type x", color=red, style=solid]')
define(`edge_y',`[label="type y", color=green, style=dashed]')
define(`edge_z',`[label="type z", color=blue, style=dotted]')
subgraph cluster_1 {
a -> b edge_x;
b -> a edge_y;
b -> c edge_x;
c -> b edge_y;
c -> d edge_z;
}
subgraph cluster_2 {
d -> e edge_x;
e -> d edge_y;
e -> f edge_x;
f -> e edge_y;
f -> c edge_z;
}
}
and converted it with the simple command
m4 gv.m4 > gv.dot
which now contains your defined edges
digraph {
subgraph cluster_1 {
a -> b [label="type x", color=red, style=solid];
b -> a [label="type y", color=green, style=dashed];
b -> c [label="type x", color=red, style=solid];
c -> b [label="type y", color=green, style=dashed];
c -> d [label="type z", color=blue, style=dotted];
}
subgraph cluster_2 {
d -> e [label="type x", color=red, style=solid];
e -> d [label="type y", color=green, style=dashed];
e -> f [label="type x", color=red, style=solid];
f -> e [label="type y", color=green, style=dashed];
f -> c [label="type z", color=blue, style=dotted];
}
}
and yields the expected graph:
You can do much more with m4 - stuff that is missing in graphViz, like maintaining and (even conditionally) including subfiles. For example, if you put your two subgraphs into two separate files gv1.txt and gv2.txt, this would work nicely:
digraph incl
{
define(`edge_x',`[label="type x", color=red, style=solid]')
define(`edge_y',`[label="type y", color=green, style=dashed]')
define(`edge_z',`[label="type z", color=blue, style=dotted]')
include(gv1.txt)
include(gv2.txt)
e -> d[ color = yellow, label = "this is new!"];
}
Not really an answer but "food for thought" as I don't think named labels exist in graphviz: You could define a default label for the following edges. That works well if your workflow allows to define edges all in one place. Example:
digraph rs
{
node[ shape = box, style = rounded]
edge[ label = "pull" ];
{ A B } -> C;
G -> H;
C -> D[ label = "stop" ];
edge[ label = "push"];
D -> { E F };
edge[ color = red, fontcolor = red ];
{ E F } -> G;
}
which yields
I have also tried to implement your diagramm with
digraph fan
{
splines = ortho;
node [ shape=box ]
edge [ xlabel = "Pull", minlen = 4 ];
{ rank = same; OFF -> HIGH -> LOW; }
LOW:s -> OFF:s;
}
which produces
so it looks good but with all the tweaking is difficult to expand.
I struggled to download m4 on my machine and so opted for using graphviz through the python API where you can define a style as a dictionary and apply to nodes / edges as desired.
import graphviz
dot = graphviz.Digraph(comment='Test File')
nodeAttr_statement = dot.node_attr = {"shape": 'box', "style": 'filled', "fillcolor":"red"}
nodeAttr_question = dot.node_attr = {"shape": 'diamond', "style": 'filled', "fillcolor":"blue"}
dot.edge_attr
edge_Attr_sample = dot.edge_attr = {"arrowhead":'vee',"color":"yellow"}
edge_Attr_sample2 = dot.edge_attr = {"arrowhead": 'diamond', "color": "green"}
dot.node("A", "A", nodeAttr_statement)
dot.node("B", "B", nodeAttr_question )
dot.edge("A", "B", _attributes=edge_Attr_sample)
dot.edge("B", "A", _attributes=edge_Attr_sample2)
dot.format = 'pdf'
dot.render('test', view=True)
Output
// Test File
digraph {
node [fillcolor=blue shape=diamond style=filled]
edge [arrowhead=diamond color=green]
A [label=A fillcolor=red shape=box style=filled]
B [label=B fillcolor=blue shape=diamond style=filled]
A -> B [arrowhead=vee color=yellow]
B -> A [arrowhead=diamond color=green]
}
Output image from python script

How to make a subgraph visible?

In the graph below the two subgraphs are not visible, but instead all nodes seem to be placed randomly. How can I create the visible subgraphs, like one box with my PlayerChars inside, and the other with the NonPlayerChars inside?
digraph "All Characters" {
subgraph PlayerChars {
label = "Player Characters";
node [style=filled,color=yellow];
Char1 -> Char2 [ label = "is sister of" ];
Char1 -> Char2 [ label = "is brother of" ];
label = "PCs";
}
subgraph NonPlayerChars {
label = "Non-Player Characters";
Person1 -> Char2 [label="hates"];
Char2 -> Person1 [label="is indifferent"];
Person2 -> Char2 [label="stole from"];
Person1 -> Person2 [label="is father of"];
Person2 -> Person1 [label="is daughter of"];
Char1 -> Person2 [label="is in love with"];
Person2 -> Char1 [label="is annoyed by"];
}
}
What you are looking for is called a "cluster" in Graphviz. Use the special subgraph names cluster_ to draw the subgraphs in rectangular regions. E.g. from http://www.graphviz.org/Gallery/directed/cluster.html
digraph G {
subgraph cluster_0 {
style=filled;
color=lightgrey;
node [style=filled,color=white];
a0 -> a1 -> a2 -> a3;
label = "process #1";
}
subgraph cluster_1 {
node [style=filled];
b0 -> b1 -> b2 -> b3;
label = "process #2";
color=blue
}
start -> a0;
start -> b0;
a1 -> b3;
b2 -> a3;
a3 -> a0;
a3 -> end;
b3 -> end;
start [shape=Mdiamond];
end [shape=Msquare];
}

Graphviz - Box positioning Problem

My structure has two main chains with side nodes in sub graphs. Every thing looks nice but when i close the two chains all the boxes in the sub graphs jumps to the right side.
At the end of my code you can remove the "I"->"J" then you can see the best what I mean.
I am not a native English speaker, sorry about my English and I am a graphviz newbie.
digraph G {
size ="6,6";
node [color=black fontsize=12, shape=box, fontname=Helvetica];
subgraph {
rank = same;
"b"->"B"[arrowhead=none];
}
subgraph {
rank=same;
"c"->"C"[arrowhead=none];
}
subgraph {
rank=same;
"e"->"E" [arrowhead=none];
}
subgraph {
rank = same;
"f"->"F"[arrowhead=none];
}
subgraph {
rank = same;
"g"->"G"[arrowhead=none];
}
"0" -> "A" -> "B" -> "C"->"D" -> "E" -> "F" -> "G" -> "H"->"I";
"0" -> "K"->"L"->"M"->"N"->"O" ->"P"->"1";
subgraph {
rank = same;
"L"->"l"[arrowhead=none];
}
subgraph {
rank=same;
"M"->"m"[arrowhead=none];
}
subgraph {
rank=same;
"N"->"n" [arrowhead=none];
}
subgraph {
rank = same;
"O"->"o"[arrowhead=none];
}
subgraph {
rank = same;
"P"->"p"[arrowhead=none];
}
"1"->"J";
"I"->"J";
}
and with "I"->"J"; removed:
This is how I'd go about it: Create a cluster for each main chain with its side nodes:
digraph G {
size ="6,6";
node [color=black fontsize=12, shape=box, fontname=Helvetica];
subgraph[style=invis];
subgraph cluster0 {
A -> B -> C -> D -> E -> F -> G -> H -> I;
edge[arrowhead=none];
{rank = same; b->B;}
{rank = same; c->C;}
{rank = same; e->E;}
{rank = same; f->F;}
{rank = same; g->G;}
}
subgraph cluster1 {
K -> L -> M -> N -> O -> P -> 1 -> J;
edge[arrowhead=none];
{rank = same; L->l;}
{rank = same; M->m;}
{rank = same; N->n;}
{rank = same; O->o;}
{rank = same; P->p;}
}
0 -> A;
0 -> K;
I -> J;
}
Resulting in:

Resources