Drawing ellipsis between nodes in graphviz - graphviz

I'm interested in drawing vertical ellipsis between nodes in graphviz like seen below:
The problem I'm having is whenever I try to do this I cannot seem to get x3 and xn to line up vertically as seen here:
Here is what I have tried:
digraph G {
rankdir=LR
splines=line
subgraph cluster_0 {
color=white;
node [style=solid, color=black, shape=circle];
x1 x2 x3 xn [group=g1];
label = "Input Features";
}
subgraph cluster_1 {
color=white;
node [style=solid, color=red2, shape=circle];
a1 [group=g2];
label = "Activation";
}
subgraph cluster_2 {
color=white;
node [style=solid, color=green, shape=circle];
out [group=g3];
label = "Output";
}
x1 -> a1;
x2 -> a1;
x3 -> a1;
a1 -> out;
x3 -> xn [arrowhead="none", color="black:invis:black"];
}
I'm very new to graphviz so I'm not even sure if I'm using subgraph properly here. I also tried adding the nodes in the subgraphs to groups, but that didn't seem to do anything.

Add
{ rank = same; x1 x2 x3 xn }
x1 -> x2 -> x3[ style = invis ];
to your first subgraph. This has the effect that
the four nodes are all one one level, i.e. lining up vertically
the three numbered nodes stay together
Here my version:
digraph G
{
rankdir = LR
splines = line
subgraph cluster_0
{
color = white;
node[ style = solid, color = black, shape = circle];
{ rank = same; x1 x2 x3 xn }
x1 -> x2 -> x3[ style = invis ];
label = "Input Features";
}
subgraph cluster_1
{
color = white;
node[ style = solid, color = red2, shape = circle ];
a1;
label = "Activation";
}
subgraph cluster_2
{
color =white;
node[ style = solid, color = green, shape = circle ];
out;
label = "Output";
}
x1 -> a1;
x2 -> a1;
x3 -> a1;
a1 -> out;
x3 -> xn[ arrowhead = "none", color = "black:invis:black" ];
}
which gives you
E D I T to answer the question in your comment; the key is reversing the order of node definitions and edge direction within the same rank, probably caused by the rankdir = LR layout. After all, there is a simple solution!
digraph G
{
rankdir = LR
splines = line
subgraph cluster_0
{
color = white;
label = "Input Features";
node[ style = solid, color = black, shape = circle ];
/* define and connect in reverse order */
{ rank = same; xn x3 x2 x1 }
x3 -> x2 -> x1[ style = invis ];
xn -> x3[ arrowhead = "none", color = "black:invis:black" ];
}
subgraph cluster_1
{
color = white;
node[ style = solid, color = red2, shape = circle ];
a1;
label = "Activation";
}
subgraph cluster_2
{
color =white;
node[ style = solid, color = green, shape = circle ];
out;
label = "Output";
}
{ x1 x2 x3 } -> a1;
a1 -> out;
}

Related

how to define a graph with graphviz without overlapping labels

The follow dot file demonstrates the issue I am trying to resolve:
digraph G {
splines=line;
rankdir=LR;
A -> B [label="a long label"];
A -> C [label="a long label"];
A -> A [label="a very long label"];
A -> A [label="a very long label"];
A -> D [label="a long label"];
}
It generates the follow the graph:
The labels are poorly positioned, nearly overlapping.
What can be done to improve the look of this graph?
I would define improve by saying (1) labels do not overlap with each other, (2) labels do not overlap edges, and (3) optionally / ideally labels are drawn along the edge. #3 may not be possible, but #1 and #2 should be sufficient. Using ortho splines would always provide an edge where a which a label could be drawn along and still be read normally, but this I know is not currently supported by graphviz.
"Improve" is in the eye of the beholder, but this uses ports, headlabels, spaces and newlines to rearrange the labels.
digraph G {
splines=line;
rankdir=LR;
// use ports to rearrange edges
// then headlabel, spaces, and newlines (\n)
A:n -> A:w [headlabel="a very long label "];
A:s -> A:w [headlabel="a very long label "];
A -> B [label="a long label"];
A -> C [label="a long label"];
A -> D [label="\n\na long label"];
}
There does not appear to be any supported solution in GraphViz that meet the desired criteria for edge labels. My work around is to split the edges between two nodes and insert another node containing the text of the edge label. The new node is styled to distinguish it from regular nodes.
The GraphViz layout algorithm does a good job of keep nodes separated and not allowing edges to overlap nodes.
Updating the test case with this workaround, I have the following dot file:
digraph G {
splines=ortho;
rankdir=LR;
AA1 [label="a very long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
AA2 [label="a very long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
AB1 [label="a long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
AC1 [label="a long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
AD1 [label="a long label", shape="box", style = "filled", fillcolor = "#E6E6E6", color = "#FFFFFF" ]
A -> AA1 [arrowhead = "none" ];
AA1 -> A
A -> AA2 [arrowhead = "none" ];
AA2 -> A
A -> AB1 [arrowhead = "none" ];
AB1 -> B
A -> AC1 [arrowhead = "none" ];
AC1 -> C
A -> AD1 [arrowhead = "none" ];
AD1 -> D
}
which produces this

Center alignment of clusters when connecting them

I have a two clusters that are connected but I can't seem to align the left most cluster (with node nd_6) with the center of the other node (cluster_circ). Here is an example:
digraph d1 {
# configs
rankdir = "LR";
compound=true;
node [shape = plaintext];
edge [arrowhead = "vee"];
nd_1 [group = g1]
nd_2 [group = g1]
# cluster for circular pattern
subgraph cluster_circ {
color=none;
node [shape = plaintext];
nd_3 [group = g1]
{rank=same nd_4[group = g2]; nd_5[group = g3]};
nd_3 -> nd_4:nw;
nd_4 -> nd_5:ne;
nd_5 -> nd_3:se;
}
# right-most cluster
subgraph cluster_r {
color=none;
node [shape = plaintext];
nd_6 [group = g1];
}
# edge connections
nd_1 -> nd_2;
nd_2 -> nd_3;
# connect clusters
nd_5 -> nd_6 [ltail=cluster_circ lhead=cluster_r]
}
Producing the following result:
What I am trying to achieve is to place the node nd_6 and its respective edge connecting to cluster_circ aligned with nd_3.
Thanks!
You need to do two things to achieve your goal:
match your compass points
have an invisible edge from nd_4 that that moves nd_6 up.
Both items are explained in the comments of the source code below. In the course of editing, I have removed a lot of stuff that were not material in the context, for easier reading.
digraph d1
{
// configs // comment characters changed to "standard"
rankdir = "LR";
node [ shape = plaintext ];
edge [ arrowhead = "vee" ];
// nodes
nd_1 nd_2 nd_3;
{ rank=same; nd_4 nd_5 }
nd_6
// edges / connections
nd_1 -> nd_2 -> nd_3;
nd_3 -> nd_4:nw; // matching :s and :n keeps the center:
nd_4:se -> nd_5:ne; // balance nd_4:n with nd_4:s
nd_3 -> nd_5:sw[ dir = back ]; // balance nd_5:n with nd_5:s
nd_4 -> nd_6[ style = invis ]; // this gives you a counterweight
nd_5 -> nd_6; // to nd_5 and thus "centers" nd_6
}
yields
E D I T to show the alternative with an empty node.
This is the result I like best, I have inserted some lines where you could play around with alternative settings. To the best of my knowledge, groups or subgraphs don't help, as edges only go between nodes, not between clusters.
digraph d1
{
// configs // comment characters changed to "standard"
rankdir = "LR";
node [ shape = plaintext ];
edge [ arrowhead = "vee" ];
// nodes
nd_1 nd_2 nd_3;
x[ shape = point, height = 0 ]; // "empty" node
// x[ shape = point, height = .25, color = white ]; // alternative
{ rank = same; nd_4 nd_5 }
// { rank = same; nd_4 x nd_5 } // try also with x in the same rank
nd_6
// edges / connections
nd_1 -> nd_2 -> nd_3;
nd_3 -> nd_4:nw;
nd_4:e -> x:n[ dir = none ]; // route edge via x
x:s -> nd_5:e; // you can try other compass points
nd_3 -> nd_5:sw[ dir = back ]; // balance nd_4:n with nd_5:s
x -> nd_6; // connect the empty node in the middle
}
which produces

How to adjust outer labels for nodes

I want to plot graph with some outer labels.
I found that there some helpful attributes - xlabel,taillabel,headlabel but the result still looks weird.
MCVE
digraph {
forcelabels=true;
node [shape=point,style=filled;label="",height=0.2];
y3[color=black;xlabel=<"y3 (2)">];x3[color=gray;xlabel=<"x3 [0.25]">];
y2[color=black;xlabel=<"y2 (3)">];x2[color=gray;xlabel=<"x2 [0.3]">];
y1[color=black;xlabel=<"y1 (2)">];x1[color=gray;xlabel=<"x1 [0.1]">];
y5[color=black;xlabel=<"y5 (4)">];x5[color=gray;xlabel=<"x5 [0.15]">];
x4[color=gray;xlabel=<"x4 [0.2]">];
y3->y2[dir=none;taillabel = 0.75];
y2->y1[dir=none;taillabel = 0.45];
y1->y5[dir=none;taillabel = 0.35];
y3->x3[dir=none];
y2->x2[dir=none];
y1->x1[dir=none];
y5->x5[dir=none];
y5->x4[dir=none];
}
it looks like
As you can see, conformity between labels and nodes not always obvious.
So, the Q is - is there any way to change location of labels ?
This may not be the answer to your question as it still does not look great and takes a lot of manual adjustment, but I post it anyway: I spent quite some time fiddling around, and there may be some ideas that could be helpful for your actual context:
digraph
{
forcelabels = TRUE;
splines = FALSE;
// nodes
node[ shape = point, style = filled, color = gray, label = "", height = 0.2 ];
x3[ xlabel = <"x3 [0.25]"> ];
x2[ xlabel = <"x2 [0.3]"> ];
x1[ xlabel = <"x1 [0.1]"> ];
x5[ xlabel = <"x5 [0.15]"> ];
x4;
node[ color = black ];
y3, y2, y1, y5;
node[ shape = plaintext, fillcolor = white ];
y_3[ label = "y3 (2)" ];
y_2[ label = "y2 (3)" ];
y_1[ label = "y1 (2)" ];
y_5[ label = "y5 (4)" ];
// edges
edge[ dir = none ];
y3:se -> y2[ label = " 0.75" ];
y2:se -> y1[ label = " 0.45" ];
y1:se -> y5[ label = " 0.35" ];
y3 -> x3;
y2 -> x2;
y1 -> x1;
y5 -> x5;
y5 -> x4[ headlabel = <"x4 [0.2]"> ];
edge[ style = invis ];
{ rank = same; y3 -> y_3 }
{ rank = same; y2 -> y_2 }
{ rank = same; y1 -> y_1 }
{ rank = same; y5 -> y_5 }
}
yields

Why does Graphviz/Dot act so weirdly to this particular code?

I am using GraphViz 2.28 (the current stable version) on Windows 7, and Graphviz/Dot crashes for the following code.
digraph G {
ranksep = 1.0; size = "10,10";
{
node [shape = plaintext, fontsize = 20];
GAWM1 -> GAWM2 -> 0;
}
node [shape = box];
{rank = same;0;wx1;wx2;rx1;}
wx1 -> wx2;
wx2 -> rx1;
wx1 -> rx1[color = blue];
subgraph struct
{
node [shape = record];
rx11 [shape = record, label = "rx1 | [x=[wx2]]"];
}
{rank = same; GAWM1; "rx11";}
// W'WR Order:
wx2 -> wx1[style = dashed, color = red, label = "1"]; }
Things become weird when I perform some experiments on this example:
It works well when only the last statement "wx2 -> wx1[style = dashed, color = red, label = "1"];" is removed;
It works well when only the eighth line "{rank = same;0;wx1;wx2;rx1;}" is removed;
It also works well when only the label (that is ", label = "1"") in the last statement is removed.
I have reported the problem to Graphviz Issue Tracker, without reply yet. Could you help to find out the reason?
Thank you.
The following variation of your script does not crash:
digraph G {
ranksep = 1.0; size = "10,10";
{
node [shape = plaintext, fontsize = 20];
GAWM1 -> GAWM2 -> 0;
}
node [shape = box];
{rank = same;0;wx1;wx2;rx1;}
wx1 -> wx2;
wx2 -> rx1;
wx1 -> rx1[color = blue];
subgraph struct
{
node [shape = record];
rx11 [shape = record, label = "rx1 | [x=[wx2]]"];
}
{rank = same; GAWM1; "rx11";}
// W'WR Order:
//wx2 -> wx1[style = dashed, color = red, label = "1"];
wx2 -> wx1 [style=dashed, color=red];
}
Looks like a bug with the label of the short edge between wx1 and wx2.

how to control edge placements and labels in dot (graphviz)

I have trouble controlling the layout of graphviz.
Trying to produce a simple automaton.
The source:
digraph mygraph {
rankdir=LR;
size="13,13"
node [shape = circle];
init -> Ready [ label = "" ];
Ready -> P1 [ label = "t<T\n----TexT----" ];
P1 -> Ready [ label = "t>T" ];
P1 -> B1 [ label = "t<T" ];
B1 -> P1 [ label = "----TexT----" ];
B1 -> U1 [ label = "----TexT----" ];
Ready -> P2 [ label = "t<T\n----TexT----" ];
P2 -> Ready [ label = "t>T" ];
P2 -> B2 [ label = "t<T" ];
B2 -> P2 [ label = "----TexT----" ];
B2 -> U2 [ label = "----TexT----" ];
U1 -> Ready [ label = "----TexT----", constraint=false];
U2 -> Ready [ label = "----TexT----", constraint=false];
P1 -> P2 [ label = "t<T\n----TexT----", constraint=false];
P2 -> P1 [ label = "t<T\n----TexT----", constraint=false];
}
trouble is, the labels are intertwined. I probably need:
1. larger spacing
2. move some of the edges up
3. control label placings
how do I do it?
Since the conflict occurs on vertical edges going in opposite directions between nodes placed by dot on the same rank (P1 & P2) you could use vertical rank direction (drop the "rankdir=LR" line) so that the labels for theses specific edges are placed one below the other rather than side by side.
Granted, it's not a universal cure for this sort of issues but should help here without unnecessarily bloating the graph (which increasing node separation via "nodesep" would do).

Resources