Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Graphviz edges not discernible / edge labels overwritten

I've reduced my problem to the following simple example:

digraph {
subgraph {rank=same; 0 -> 1 -> 2;}
0 -> 2 [label="A"];
2 -> 0 [label="B"];
}

which produces

enter image description here

While keeping 0, 1 and 2 in the same rank (the original example is in the context of a larger graph), I need A and B edges to be discernible. i.e. the edges to clearly match to labels and the labels to be readable.

One solution I imagined was using ports on the edge connections specified by

0:ne -> 2:nw [label="A"];
2:sw -> 0:se [label="B"];

however this produces

enter image description here

Other ideas? I am generating larger graphs with the same issue so a best solution would not be a completely ad-hoc manual placement of edges/labels.

Edit: A (still simplified) example of the larger generated graph is the following.

digraph {
size = "6,8.5";
ratio = "fill";
node [shape = circle];
node [fontsize = 24];
edge [fontsize = 24];
{graph [rank=same]; edge[color=invis];1;}
{graph [rank=same]; edge[color=invis];2 -> 0 -> 3 -> 4;}
0 -> 0 [label="6: 0.1764"];
0 -> 4 [label="4: 0.1304"];
0 -> 3 [label="5: 0.1551"];
0 -> 2 [label="7: 0.1489"];
0 -> 1 [label="Z: 0.3893"];
4 -> 0 [label="6: 0.1237"];
4 -> 3 [label="5: 0.05201"];
4 -> 2 [label="7: 0.15  "];
4 -> 1 [label="Z: 0.4585"];
3 -> 0 [label="6: 0.1658"];
3 -> 4 [label="4: 0.13  "];
3 -> 3 [label="5: 0.1038"];
3 -> 2 [label="7: 0.1616"];
3 -> 1 [label="Z: 0.4388"];
2 -> 0 [label="6: 0.1661"];
2 -> 4 [label="4: 0.1295"];
2 -> 3 [label="5: 0.2078"];
2 -> 2 [label="7: 0.1406"];
2 -> 1 [label="Z: 0.356 "];
1 -> 0 [label="6: 0.1103"];
1 -> 4 [label="4: 0.2591"];
1 -> 3 [label="5: 0.1382"];
1 -> 2 [label="7: 0.08581"];
1 -> 1 [label="Z: 0.1906"];
}

This produces:

enter image description here

which exhibits the same edge/label overlap problem in the simpler example above.

Other notes:

  • This problem exists when there is a node in the middle of a bidirectionally connected pair of nodes in a same rank subgraph. This may be a subset of conditions where the bug is seen.
  • This problem exists also for undirected graphs.
like image 877
watsonic Avatar asked Apr 26 '14 07:04

watsonic


3 Answers

You can get part way there with dir="both" and a colorList.

digraph {
    subgraph {rank=same; 0 -> 1 -> 2;}
    0 -> 2 [dir="both", color="black:gray", labeldistance="2", headlabel="A", taillabel="B"];
}

results in this:

using dir="both"

I had to use labelDistance to keep the "A" label from being drawn on top of the arrowhead. Unfortunately, I couldn't figure out how to change font color individually for the head label and tail label to make it more clear as to which label applies to which arrowhead.

like image 114
SSteve Avatar answered Oct 23 '22 05:10

SSteve


The first example is clearly a bug; the edge labels should be positioned in separate locations, which would then separate the edges. (In general, we know there are holes in the flat edge code, especially dealing with labels.) One workaround is to treat some or all of the edges labels as exterior labels:

digraph {
subgraph {rank=same; 0 -> 1 -> 2;}
0 -> 2 [xlabel="A"];
2 -> 0 [xlabel="B"];
}

Concerning the issue of changing the font color for labels mentioned in the previous answer, this can be done using HTML-like labels:

0 -> 2 [dir="both", color="black:gray", labeldistance="2", 
  headlabel=<<font color="red">A</font>>, taillabel="B"];

This can be used for any text in place of the usual double-quoted strings.

like image 2
Emden Avatar answered Oct 23 '22 06:10

Emden


Answers from both ssteve and emden were very useful and have been upvoted. (thank you both!)

I am incorporating input from both and answering this question in its more complex version. I still do not feel like the solution is perfect, but it is the best I can generate so far. Future answers that improve on this (see below for what seems to be still lacking) and which address the larger graph version (see question) in a way that can be automated will be accepted in lieu of this answer.

First, the best solution so far in summary: turn labels in to xlabels for some of the edges (e.g. half of all bidirectional edges, chosen randomly) and randomly color edges and corresponding labels (via fontcolor).

In specific, here is an instantiation of this solution, where edges are randomly red, green or black:

digraph {
size = "6,10.5";
ratio = "fill";
node [shape = circle];
node [fontsize = 24];
edge [fontsize = 24];
{graph [rank=same]; edge[color=invis];1;}
{graph [rank=same]; edge[color=invis];2 -> 0 -> 3 -> 4;}
0 -> 0 [label="6: 0.1764"];
0 -> 4 [xlabel="4: 0.1304" color=blue fontcolor=blue];
0 -> 3 [xlabel="5: 0.1551" color=green fontcolor=green];
0 -> 2 [label="7: 0.1489" color=red fontcolor=red];
0 -> 1 [label="Z: 0.3893"];
4 -> 0 [xlabel="6: 0.1237" color=green fontcolor=green];
4 -> 3 [xlabel="5: 0.05201 " color=green fontcolor=green];
4 -> 2 [xlabel="7: 0.15" color=blue fontcolor=blue];
4 -> 1 [label="Z: 0.4585" color=red fontcolor=red];
3 -> 0 [xlabel="6: 0.1658"];
3 -> 4 [xlabel="4: 0.13" color=red fontcolor=red];
3 -> 3 [label="5: 0.1038" color=blue fontcolor=blue];
3 -> 2 [xlabel="7: 0.1616"];
3 -> 1 [label="Z: 0.4388"];
2 -> 0 [label="6: 0.1661" color=blue fontcolor=blue];
2 -> 4 [xlabel="4: 0.1295" color=red fontcolor=red];
2 -> 3 [label="5: 0.2078" color=green fontcolor=green];
2 -> 2 [label="7: 0.1406"];
2 -> 1 [label="Z: 0.356 "];
1 -> 0 [label="6: 0.1103" color=red fontcolor=red];
1 -> 4 [label="4: 0.2591" color=blue fontcolor=blue];
1 -> 3 [label="5: 0.1382" color=green fontcolor=green];
1 -> 2 [label="7: 0.08581 "];
1 -> 1 [label="Z: 0.1906"];
}  

This produces: enter image description here

This is still not completely satisfactory because:

  1. Although its now easier to trace labels back to their edges, some labels appear in strange locations when xlabel is used. (e.g above the 2 -> 4 label)
  2. Randomly choosing which labels become xlables seems arbitrary. Also there is no way (I know of) to guarantee this is always going to work out.

Other things I tried:

  • Make every label an xlabel. Result: everything is compacted and labels overlap and obscure one another.
  • Use xlabel for all bi-directional edges. Result: same problem as above.
  • Use xlabels without colors. Result: hard to trace which label belongs to what.
  • Use ssteve's dir="both" + colorlist solution. Color edges randomly. And set labeldistance randomly between 3 and 11 for head and tail labels to avoid label overlap at nodes. Result: this is harder to automate and still results in both edge label overlap and labels which are hard to trace back to the edges they correspond to. (see below)

Here's an example of the last item in the "other things I tried" solutions list above.

size = "6,8.5";
ratio = "fill";
node [shape = circle];
node [fontsize = 24];
edge [fontsize = 24];
{graph [rank=same]; edge[color=invis];1;}
{graph [rank=same]; edge[color=invis];2 -> 0 -> 3 -> 4;}
0 -> 0 [label="6: 0.1764"];
0 -> 4 [dir="both", color="yellow:blue", labeldistance="5", headlabel=<<font color="yellow">4: 0.1304</font>>, taillabel=<<font color="blue">6: 0.1237</font>>];
0 -> 3 [dir="both", color="blue:black", labeldistance="8", headlabel=<<font color="blue">5: 0.1551</font>>, taillabel=<<font color="black">6: 0.1658</font>>];
0 -> 1 [label="Z: 0.3893"];
4 -> 1 [label="Z: 0.4585"];
3 -> 4 [dir="both", color="green:red", labeldistance="5", headlabel=<<font color="green">4: 0.13</font>>, taillabel=<<font color="red">5: 0.05201</font>>];
3 -> 3 [label="5: 0.1038"];
3 -> 1 [label="Z: 0.4388"];
2 -> 0 [dir="both", color="yellow:blue", labeldistance="11", headlabel=<<font color="yellow">6: 0.1661</font>>, taillabel=<<font color="blue">7: 0.1489</font>>];
2 -> 4 [dir="both", color="black:red", labeldistance="5", headlabel=<<font color="black">4: 0.1295</font>>, taillabel=<<font color="red">7: 0.15</font>>];
2 -> 3 [dir="both", color="blue:green", labeldistance="8", headlabel=<<font color="blue">5: 0.2078</font>>, taillabel=<<font color="green">7: 0.1616</font>>];
2 -> 2 [label="7: 0.1406"];
2 -> 1 [label="Z: 0.356 "];
1 -> 0 [label="6: 0.1103"];
1 -> 4 [label="4: 0.2591"];
1 -> 3 [label="5: 0.1382"];
1 -> 2 [label="7: 0.08581 "];
1 -> 1 [label="Z: 0.1906"];
}

This produces:

enter image description here

Other ideas / improvements solicited...

like image 1
watsonic Avatar answered Oct 23 '22 04:10

watsonic