Reducing excessive Graphviz octagon margins - graphviz

The Graphviz output of octagon-shaped nodes has huge margins, even we set "margin=0.0,0.0".
Example:
digraph G {
foo [shape=octagon, label="one\ntwo", margin="0.0,0.0"];
}
Produces:
I want to have smaller margins than those, with the letter edges close to the diagonal edges of octagon. Can I do that?

simple answer: not easily. you are encountering two issues:
default node width & height are a bit bigger than you want (easy to fix)
Graphviz's suboptimal algorithm that sizes polygons
more complex: here is an improvement, but it is a (repeatable) kludge. It does graph layout & octagon sizing using a small font, then resets the fontsize to correct (desired) value. It uses gvpr (http://www.graphviz.org/pdf/gvpr.1.pdf) and neato -n2 (http://www.graphviz.org/faq/#FaqDotWithCoords)
give all your octagon nodes an explicit fontsize that is 3 points smaller that you actually want. Since default fontsize is 14 (https://graphviz.org/docs/attrs/fontsize/), try [fontsize=11]
run this pipeline to layout your graph, and then reset the fontsize:
dot myfile.gv |
gvpr -c 'N[shape=="octagon"]{$.fixedsize="true"; $.fontsize=$.fontsize + 3;}' | neato -n2 -Tpng >myfile.png
A modified version of "one two" (with reduced height & width):
digraph G {
foo [fontsize=11 height=.4 width=.6 fixedsize=true shape=octagon label="one\ntwo"]
}
Gives:
And a larger input file:
graph Y{
rankdir=LR
label="simple octagon"
aeiou
onemore [shape=rect]
node[fontsize=11]
foo1 [shape=octagon, label="ab\na"]
foo3 [shape=octagon, label="abcd\nabc"]
foo5 [shape=octagon, label="abcdef\nabcde"]
foo7 [shape=octagon, label="abcdefgh\nabcdefg"]
foo9 [shape=octagon, label="abcdefghij\nabcdefghi"]
foo11 [shape=octagon, label="abcdefghijkl\nabcdefghijk"]
foo13 [shape=octagon, label="abcdefghijklmn\nabcdefghijklm"]
foo15 [shape=octagon, label="abcdefghijklmnop\nabcdefghijklmno"]
foo17 [shape=octagon, label="abcdefghijklmnopqr\nabcdefghijklmnopq"]
foo19 [shape=octagon, label="abcdefghijklmnopqrst\nabcdefghijklmnopqrs"]
}
Gives:

Related

Add space between 2 connected nodes

I would like to add a little more horizontal space between the 2 nodes so the edge labels appear associated to their node (instead of in the middle of the edge):
The graphviz source:
digraph {
rankdir="LR";
node [shape=cylinder]
clone
initial
clone -> initial [headlabel="origin",taillabel="clone"]
}
Expected:
I tried using nodesep but it seems to only work when there are no edges.
nodesep was a good try, but your ranking is LR, so ranksep is the way to go
digraph {
rankdir="LR";
ranksep=1.2 // rank-to-rank in inches
node [shape=cylinder]
clone
initial
clone -> initial [headlabel="origin",taillabel="clone"]
}
Giving:

Increase curvature of connecting arcs

Consider:
digraph D {
0[pos="0,0!"]
1[pos="0,5!"]
0 -> 1[label=0.25]
1 -> 0[label=0.50]
}
Rendered under neato engine, this gives:
Is there a way to increase/control the curvature of the connecting arcs so that the rendering is something like the hand-drawn annotations below:
Edited to add: While I don't have to stick with neato, it is important in my application that the node pos coordinate values be upheld.
[there may be better ways, but edges are pretty hard to wrangle]
This solution requires neato -n (see https://graphviz.org/faq/#FaqDotWithNodeCoords) and (https://graphviz.org/docs/attrs/pos/)
Different versions of neato seem to produce different results when previous answer is input. This input file should work with older & newer versions of neato.
digraph D {
// next lines from the Graphviz FAQ
overlap=false
splines=true
0[pos="0,0!"]
1[pos="0,5!"]
// stick an invisible node in the middle, to force the edges out
half [pos="0,2.5!" width=1.1 height=1 style=invis]
0:nw -> 1:sw [label=0.25]
1:se -> 0:ne [label=0.50]
}
Giving:

How to draw a spline curve between 2 points with a control points with graphviz?

I would like to create a spline curve between the blue point and the green point with the red point as a control point.
Graphviz documentation says :
splines attribute, of type bool or string, is valid on Graphs
splineType with the pattern : spline ( ';' spline )* is a valid type for pos attribute
pos attribute is valid on Edges and Nodes
I Tried this graph
graph G{
layout ="neato" outputorder="edgesfirst" splines="true"
a[shape="point" pos="0,0!" color="blue"]
b[shape="point" pos="1,0!" color="green"]
c[shape="point" pos=" 0.5,0.5!" color="red"]
a -- b [pos="e,1,0 s,0,0 0.5,0.5!"]
}
then on Windows 10 PowerShell :
neato.exe -Tsvg .\spline.dot > .\spline.svg
with
neato - graphviz version 2.49.3 (20211023.0002)
result
What is the proper way of achieving this?
Thanks.
Close, but ...
! notation seems to only apply to nodes (not edges) (poorly documented, but see: https://graphviz.org/docs/attr-types/point/ and https://graphviz.org/docs/attrs/pin/)
by default, pos value units are points (inch/72). Your values are ~ too small
neato -n2 will use node & edge values you provide (https://graphviz.org/faq/#FaqDotWithCoords)
all edges (not just curves) are defined as cubic B-splines and are defined by 1 + n*3 points (n is integer >=1) (https://graphviz.org/docs/attr-types/splineType/) (i.e. 4 or 7 or 11 or ...)
So:
graph G{
// default units for pos values are in points (72/inch)
// multiplied by 100 out of laziness
// ! only applies to nodes, not edges
layout ="neato"
outputorder="edgesfirst" // why???
splines="true"
a[shape="point" pos="0,0!" color="blue"]
b[shape="point" pos="100,0!" color="green"]
c[shape="point" pos="50,50!" color="red"]
// "s" arrowhead must preceed "e" arrowhead, so swaped them
// BUT, "--" says non-directed graph, NO arrowheads, so they are deleted
// also need 4, 7, 11, ... points NOT including arrowhead points
// so added points (just guesses)
a -- b [pos="0,0 30,66 70,66 100,0"]
}
Gives:
Whew

How to specify the length of an edge in graphviz?

In a directed graph, if there is a cycle, the graphviz makes that edge really short.
Is there a parameter that would let me change the length of the cyclic edge, so that
the graph looks a bit uniform.
digraph ER {
rankdir="LR";
//orientation=landscape;
node [shape=ellipse, fontsize=30];
{node [label="Original"] old;}
{node [label="Final"] new;}
{node [label="Intermediate"] ir;}
old -> ir [label="suggest", fontsize=30];
ir -> ir [label="validate", fontsize=30, len=f];
ir -> new [label = "finalize", fontsize=30];
}
Edit: Sorry, my answer will make edges longer, but not the self referencing edges you need.
len doesn't work in dot, but minlen does.
https://www.graphviz.org/doc/info/attrs.html#d:minlen
x->y
[minlen=5]
len doesn't works in dot, but you can try this trick:
digraph G {
rankdir=LR
a->b[dir=both]
b->c[dir=both,label=" "]// Just use the space to increase the edge length
}
If rankdir=TB, use label="\n" (repeat the \n as necessary) to increase the length.
I found that the following attribute nodesep worked to solve this problem with sfdp.
From nodesep | Graphviz:
For layouts other than dot
nodesep affects the spacing between loops on a single node, or multiedges between a pair of nodes.
Note that this is a graph attribute, so the value is the same for all edges in the graph.
From dot(1):
len=f sets the optimal length of an edge. The default is 1.0.
You can make the cyclic edge longer by adding a bunch of invisible cyclic edges before your visible one, like this:
digraph ER {
rankdir="LR";
//orientation=landscape;
node [shape=ellipse, fontsize=30];
{node [label="Original"] old;}
{node [label="Final"] new;}
{node [label="Intermediate"] ir;}
old -> ir [label="suggest", fontsize=30];
ir -> ir [style="invis"]
ir -> ir [style="invis"]
ir -> ir [style="invis"]
ir -> ir [style="invis"]
ir -> ir [label="validate", fontsize=30, len=f];
ir -> new [label = "finalize", fontsize=30];
}
In .dot language, the edge connects two notes with different ranks.
The length of edge is equal to (difference in ranks)*ranksep
default ranksep (in graph attribute) is 0.75 inch, so edge of adjacent nodes will be 0.75 inch.
To reduce the edge length, you set ranksep into a smaller value in graph atrribute
There's another approach that I now use for this:
I use graphviz to output the file in dot format
dot -T dot -Kneato -o ./positioned.dot ./input.dot
This file will contain the Bezier curve definitions for every edge.
I manually change the points to curve the way I want it to draw.
This may look a little daunting at first but once you figure out, how they work this isn't hard, I'm inching towards a script that will do this for me automatically
then re-run dot with your edited positioned file as the input
dot -T png -Kneato -O ./positioned.dot
With this approach I've pretty much turned dot into my text based visio replacement

How to control subgraphs' layout in dot?

i have a digraph composed of many independant and simple subgraphs of various sizes. dot lays all these subgraphs horizontally, so i end up with a 40000x200 output file, e.g:
G1 G2 G3 G.....4 G5
How do i tell dot to layout these subgraphs in both dimensions to get something like:
G1 G2 G3
G.....4
G5
Thanks.
The steps to achieve this uses multiple graphviz tools which can be piped together.
The following line is a possible configuration, graph.dot being the file which contains your graph(s). You may have to fiddle with the options.
ccomps -x graph.dot | dot | gvpack -array3 | neato -Tpng -n2 -o graph.png
And here's the explanation:
1. Separate disconnected graphs
Tool: ccomps
decomposes graphs into their connected components
The -x option (Only the connected components are printed, as separate graphs) is probably all that is needed.
2. Layout each graph
Tool: dot
Each directed graph is layed out, one by one. This step is needed to get the position of the nodes and edges.
3. Pack all layed out graphs into one
Tool: gvpack
reads in a stream of graphs, combines the graphs into a single layout,
and produces a single graph serving as the union of the input graphs.
You should read the documentation of the options for this tool and play with the options. For example, -array is used to lay out the graphs in a grid like manner, and offers several flags to control the layout.
4. Create the output
Tool: neato
The option -n2 tells neato to not layout the input graphs but to use the existing position attributes.
Example graph:
digraph G {
subgraph G1 {
a->{b; c;};
}
subgraph G2 {
d -> {e; f;};
}
subgraph G3 {
g -> h;
}
subgraph G4 {
i -> j;
}
subgraph G5 {
{k; l;} -> m;
}
}
Edit: Sorting the digraphs in gvpack
In order to determine the order of appearance od the subgraphs in the combined layout created by gvpack, each subgraph will need a sortv attribute.
For example, the following graphs:
digraph G1 {
sortv=1;
a->{b; c;};
}
digraph G2 {
sortv=2;
d -> {e; f;};
}
digraph G3 {
sortv=3;
g -> h;
}
digraph G4 {
sortv=4;
i -> j;
}
digraph G5 {
sortv=5;
{k; l;} -> m;
}
can be transformed using
dot graph.dot | gvpack -array_u | neato -Tpng -n2 -o graph.png
resulting in

Resources