Optimize label position in Graphviz - graphviz

The following dotfile is creating a massive output :
digraph G {
"Bob"->"A" [label=" A very long label"]
"Bob"->"B" [label=" A very long label"]
"Bob"->"C" [label=" A very long label"]
"Bob"->"D" [label=" A very long label"]
"Bob"->"E" [label=" A very long label"]
"Bob"->"F" [label=" A very long label"]
"Bob"->"G" [label=" A very long label"]
}
Outputs something like this :
Is there a way to change the label positions to reduce the graph size ?

Labels can be positioned with lp. You could change the labelangle. There are also headlabel and taillabel labels.
Search for 'label' in the documentation.

Very simple \n solution
digraph G {
"Bob"->"A" [label=" A very\nlong\nlabel"]
"Bob"->"B" [label=" A very\nlong\nlabel"]
"Bob"->"C" [label=" A very\nlong\nlabel"]
"Bob"->"D" [label=" A very\nlong\nlabel"]
"Bob"->"E" [label=" A very\nlong\nlabel"]
"Bob"->"F" [label=" A very\nlong\nlabel"]
"Bob"->"G" [label=" A very\nlong\nlabel"]
}

Related

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

Graphviz/DOT: How to have arrow "redirected"

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

How can I direct dot to use a shorter edge path?

The diagram below is laid out almost perfectly, apart from the edge from the left "named pipe" node to "cat", which takes a long circuitous route, instead of the obvious short one I've marked with red on the diagram below. Is there a way to direct dot to use the short edge path? Note that the sequence diagram on the diagram's bottom, must be rendered as it currently appears, i.e. in the left to right order.
This is the code that draws the diagram.
digraph D {
fontname="Arial";
subgraph cluster_async {
label="Asynchronous processes";
style=filled;
color=lightgrey;
node [shape=box, style=solid, fillcolor=white, fontname="Arial"];
{
rank=same;
npi_0_0_0 [label="named\npipe"];
npi_0_3_0 [label="named\npipe"];
npi_0_2_0 [label="named\npipe"];
}
node [shape=box, style=bold];
tee [label="sgsh-tee"];
"ls -l" -> tee;
tee -> npi_0_0_0;
tee -> npi_0_3_0;
tee -> npi_0_2_0;
NBYTES [label="sgsh-writeval -s NBYTES"];
npi_0_3_0 -> "awk '{s += $5} END {print s}'" -> NBYTES;
NDIRS [label="sgsh-writeval -s NDIRS"];
npi_0_2_0 -> "grep -c '^d'" -> NDIRS;
// Put some order in the appearance
{
rank=same;
NDIRS;
NBYTES;
}
}
subgraph clustersync {
label="Synchronous sequence";
style=dashed;
start [shape=circle, style=filled, label="", fillcolor=black, width=.2];
node [shape=box, style=bold, fontname="Arial"];
npi_0_0_0:sw -> cat:nw [constraint=false];
"sgsh-readval -s NDIRS" -> echo;
"sgsh-readval -s NBYTES" -> echo;
NBYTES -> "sgsh-readval -s NBYTES";
NDIRS -> "sgsh-readval -s NDIRS";
end [shape=doublecircle, style=filled, label="", fillcolor=black, width=.2];
{
rank=same;
edge [arrowhead=open];
start -> cat -> echo -> end;
}
}
}
(In case you're interested, the diagram illustrates the setup of an example from sgsh.)
For this graph, setting splines=ortho will produce a desirable result.

GraphViz creating regular edges

I'm using GraphViz inside a Mediawiki site, that means that I cannot work on the svg file (unluckily).
I created this graph
digraph GPPubProcess{
rankdir="TB";
node [shape = box fontsize=10];
edge [fontsize=10];
graph[size="7.75,10.25" overlap = false];
subgraph c2 {
rank="same";
N02 [label="Two?" shape=hexagon margin=0];
N03 [label="Three"];
}
subgraph c4 {
rank="same";
N07 [label="Seven"];
N06 [label="Six?" shape=hexagon margin=0];
N05 [label="Five"];
}
subgraph c8 {
rank="same";
N11 [label="Eleven)" shape=hexagon margin=0];
N12 [label="Twelve"];
}
subgraph c9 {
rank="same";
N13 [label="Thirteen?" shape=hexagon margin=0]];
N14 [label="Fourteen"];
N17 [label="COMPLETED"];
}
N00 [shape=point];
N01 [label="One"];
N02 [label="Two?" shape=hexagon margin=0];
N04 [label="Four?" shape=hexagon margin=0];
N08 [label="Eight"];
N09 [label="Nine"];
N10 [label="Ten?" shape=hexagon margin=0];
N99 [shape=point];
N00->N01:n;
N01:s->N02:n;
N02:s->N04:n [label=" yes"];
N04:s->N05:n [label=" no" weight=30];
N05:s->N08:n [weight=30];
N08:s->N09:n [weight=30];
N09:s->N10:n [weight=30];
N10:s->N11:n [label=" no" weight=30];
N11:s->N17:n [label=" no"];
N17:s->N99;
N02 -> N03 [weight=0];
N04:e -> N06:n [label=" yes"];
N06 -> N05 [label=" no"] [weight=0];
N06 -> N07 [label=" yes"];
N10:e -> N06:s [label=" yes" weight=5];
N03:s -> N07:n;
N07:e -> N09:e [weight=0];
N11:e -> N12:w;
N15 [label="Fifteen"];
N16 [label="Sixteen"];
N12:s->N13:n [weight=5];
N13:s->N15:n [label=" no"];
N15:s->N16:n;
N13:e->N14:w [label=" yes" weight=5];
N14:n->N07:s;
N16:w->N05:w [weight=0];
}
that produces almost what I like, but links sixteen->five, ten->six and thirteen->fourteen make a lot of slalom between nodes. Is there a way to regularize them?
Also the link between six and five goes in the wrong direction but I wasn't able to make it right? Is there any trick?
Thank you very much.
Giorgio
I would start by removing the weight and compass point instructions (:n, :e, :s, :w). Those are forcing dot to make some weird decisions, especially the compass points. If you need to make changes to the default version, make one small change at a time. Unfortunately, the more you try to force dot to make a specific graph, the weirder it tends to get.
Since you can't work with an SVG, at some point you have to give up getting exactly the graph you want and accept the graph that dot creates. There's a limit to how much you can coerce dot.
The link between six and five (N06 -> N05) should have the arrowhead going from six to five. If you're seeing the arrowhead pointing at six, I think that's a bug in an earlier version of Graphviz. Try updating to the most recent release.
This code:
digraph GPPubProcess{
rankdir="TB";
node [shape = box fontsize=10];
edge [fontsize=10];
graph[size="7.75,10.25" overlap = false];
subgraph c2 {
rank="same";
N02 [label="Two?" shape=hexagon margin=0];
N03 [label="Three"];
}
subgraph c4 {
rank="same";
N07 [label="Seven"];
N06 [label="Six?" shape=hexagon margin=0];
N05 [label="Five"];
}
subgraph c8 {
rank="same";
N11 [label="Eleven)" shape=hexagon margin=0];
N12 [label="Twelve"];
}
subgraph c9 {
rank="same";
N13 [label="Thirteen?" shape=hexagon margin=0];
N14 [label="Fourteen"];
N17 [label="COMPLETED"];
}
N00 [shape=point];
N01 [label="One"];
N02 [label="Two?" shape=hexagon margin=0];
N04 [label="Four?" shape=hexagon margin=0];
N08 [label="Eight"];
N09 [label="Nine"];
N10 [label="Ten?" shape=hexagon margin=0];
N99 [shape=point];
N00->N01;
N01->N02;
N02->N04 [label=" yes"];
N04->N05 [label=" no"];
N05->N08;
N08->N09;
N09->N10;
N10->N11 [label=" no"];
N11->N17 [label=" no"];
N17->N99;
N02 -> N03;
N04 -> N06 [label=" yes"];
N06 -> N05 [label=" no"];
N06 -> N07 [label=" yes"];
N10 -> N06 [label=" yes"];
N03 -> N07;
N07 -> N09;
N11 -> N12;
N15 [label="Fifteen"];
N16 [label="Sixteen"];
N12->N13;
N13->N15 [label=" no"];
N15->N16;
N13->N14 [label=" yes"];
N14->N07;
N16->N05;
}
created this graph:
adding [constraint=false] to N06 -> N05 helps eliminate intersections around N06, but then pushes N11 and N17 way off to the left:

Resources