Can I make graphviz concentrate edges based on color? - graphviz

I have a directed graph where the color of the edges matters:
Current Diagram
digraph {
splines=ortho
node [shape=box];
1 -> 4 [color="#51dbf4"];
4 -> 7 [color="#51dbf4"];
7 -> 1 [color="#ac043e"];
7 -> 1 [color="#51dbf4"];
1 -> 7 [color="#ac043e"];
}
I want to combine the maroon colored arrows to make the graph more clear.
Desired Diagram
digraph {
splines=ortho
node [shape=box];
1 -> 4 [color="#51dbf4"];
4 -> 7 [color="#51dbf4"];
7 -> 1 [color="#ac043e" dir=both];
7 -> 1 [color="#51dbf4"];
}
However, this requires me to manually change each arrow that needs to be combined into a double-headed arrow. I wanted to merge these automatically. I tried using concentrate=true to make the arrows merge, but that kind of destroys the meaning of the graph:
Incorrect Diagram
digraph {
splines=ortho
concentrate=true
node [shape=box];
1 -> 4 [color="#51dbf4"];
4 -> 7 [color="#51dbf4"];
7 -> 1 [color="#ac043e"];
7 -> 1 [color="#51dbf4"];
1 -> 7 [color="#ac043e"];
}
Graphviz insists on merging the arrows regardless of their color, which is not correct in this case because it kind of just obliterates most of the edges.
Question
For my use case, I have a large, code-generated graph with tons of edges and I don't want to manually change so many edges to be double-ended. Is there a way to specify to graphviz that I only want to merge edges of the same color? Like maybe I could tag each edge with a group ID and then it would only merge edges that have the same ID? Any ideas are appreciated.

There may be an easier way, but this gvpr (http://www.graphviz.org/pdf/gvpr.1.pdf) program does what you want.
For each edge, it checks if a "reverse" edge exists, and if so checks if both have the same color.
If so, set dir=both & delete the "reverse" edge.
E{
edge_t N2;
N2=isEdge($.head, $.tail,"");
if (N2!=NULL && N2.color==$.color){
print("// bingo : ", $.name, " <--> ", N2.name);
$.dir="both";
delete($G, N2);
}
}
And a (Linux) command line of
gvpr -c -f single2double.gvpr myfile.gv | dot -Tpng >o.png
Giving:

Related

Graphviz: control minimum rank of nodes in subgraph

In the graph below, how do I move the ClassB subgraph to the right of ClassA aligned at the top? I.e. I want to increase the rank of the nodes in ClassB to 3.
I guess it might be possible using invisible dummy nodes, but I can't figure it out. Also I'm hoping there's a less "ad hoc" solution.
digraph G {
graph [rankdir=LR];
0 -> 1 -> 2 -> 3;
subgraph cluster_SEM_SAD_analysis {
graph [label="main"];
main [label="main"];
}
subgraph cluster_ClassA {
graph [label="ClassA"];
ClassA__method1 [label="method1"];
ClassA__method2 [label="method2"];
}
subgraph cluster_ClassB {
graph [label="ClassB"];
ClassB__method1 [label="method1"];
ClassB__method2 [label="method2"];
}
main -> ClassA__method1;
ClassA__method1 -> ClassB__method1;
ClassA__method1 -> ClassA__method2;
ClassA__method1 -> ClassB__method2
}
You need to tell graphviz that you want the nodes in the Class B cluster on the level below method2 of Class 1. You achieve that by introducing an invisble edge between them. This is not "ad hoc", but inherent graphviz logic.
Add, as a last line of your code
ClassA__method2 -> ClassB__method1[ style = invis, weight = 100 ];
and you get
which is probably what you want. Aligning the third cluster at the top is achieved by the weight = 100 element.

is there a way to consistently have dot subgraph order controlled?

The 'constraint=false'sometimes' allows the clusters to get out of order, even when doing so, causes longer edges. I wish to both have all subgraph clusters line up 'and' keep the order of the subgraph clusters intact. (which in my case, since I alway will only connect the edge to an node neighboring cluster, will result in edge that don't cross over an intervening subgraph. Sometimes it works as expected, but in the example I am posting, you can see the '2nd' subgraph for some reason shows up in the third position (which causes the links to go farther than they need to.)
Is there a way to achieve both the lining up of all the tops of the subgraphs 'and' maintaining a specific order of subgraphs left to right?
I have read many posts, and have tried many of the things suggested, but I can't seem to find a combination that works. When constraint=true, the 'order' seems to be correct, but the alignment is wrong. When constraint=false... The alignment is correct and 'sometimes' the order is correct, but other like the example posted, the order is invalid.
digraph G {
ranksep=.05;
splines=line;
subgraph cluster_1 {
label="1";
choice0_0[label="1"];
choice0_1[label="2"];
choice0_2[label="3"];
choice0_0 -> choice0_1 -> choice0_2 [style="invis"];
}
subgraph cluster_2 {
label="2";
choice1_0[label="1"];
choice1_1[label="2"];
choice1_2[label="3"];
choice1_0 -> choice1_1 -> choice1_2 [style="invis"];
}
subgraph cluster_3 {
label="3";
choice2_0[label="1"];
choice2_1[label="2"];
choice2_2[label="3"];
choice2_0 -> choice2_1 -> choice2_2 [style="invis"];
}
edge[constraint=false];
choice0_2 -> choice1_1;
choice1_1 -> choice2_2;
}
dot -Tps x.gv -o x.ps
(where x.gv contains the code pasted above)
No errors are displayed when this is run, but this example the order of the 2nd and 3rd subgraph is swapped.

Order cluster nodes in graphviz

I have the following (simplified) graph which is generated by the following .dot:
digraph Configurations {
subgraph cluster_1 {
s_0_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=yellowgreen]
s_0_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=yellowgreen]
}
subgraph cluster_2 {
s_1_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=yellowgreen]
s_1_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=white]
}
subgraph cluster_3 {
s_2_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=white]
s_2_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=yellowgreen]
}
subgraph cluster_4 {
s_3_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=white]
s_3_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=white]
}
s_0_1 -> s_1_1
s_0_0 -> s_2_0
s_2_1 -> s_3_1
s_1_0 -> s_3_0
}
I would like to be able to be able to enforce ordering inside the subgraphs so that the nodes of each subgraph are displayed in ascending order (each cluster should have nodes placed (0, 1), never (1, 0)). As I understand it, rankdir, which was my first attempt, is not supported in subgraphs, so what is a proper way to do this? I am looking for a solution which gives me a reasonably similar layout (which would then include more intersecting arrows) and is scalable, since the real graphs will be huge.
Turns out this could be solved by adding invisible edges inside and forcing same rank inside the graphs, like so:
subgraph cluster_1 {
{rank=same; s_0_0 s_0_1}
s_0_0 -> s_0_1 [style=invis]
s_0_0 [shape=circle,style=filled,fixedsize=true,width=0.5,label="0",fillcolor=yellowgreen]
s_0_1 [shape=circle,style=filled,fixedsize=true,width=0.5,label="1",fillcolor=yellowgreen]
}
If there are more nodes than 2 nodes, we need to change the solution.
subgraph cluster1 {
{
HL_1_n HL_1_1 HL_1_2 HL_1_3 HL_1_m
}
HL_1_1 [label="Hidden Layer 1 Node 1" color=3]
HL_1_2 [label="Hidden Layer 1 Node 2" color=3]
HL_1_3 [label="Hidden Layer 1 Node 3" color=3]
HL_1_m [label="Hidden Layer 1 Node ..." color=3]
HL_1_n [label="Hidden Layer 1 Node H_1" color=3]
label = "Hidden Layer"
}
It seems the order is determined, so we just need to change nodes' positions to fit the output. The solution does not use edge constraints and rank.

graphviz: Create new node with this same label

I'm starting working with graphviz and I have problem with creating new nodes with this same label.
For example for word "sentence" I would like to create graph with 8 nodes:
s -> e -> n -> t -> e -> n -> c -> e
Now I'm receiving graph with only 5 nodes (one "e" instead of 3 and one "n" instead of 2). I need to create more nodes with this same label (value).
Example of my problem may be this image http://rdftwig.sourceforge.net/paper/diagrams/bfsdeep.png where there are 2 nodes with value "C", "E" and "D".
Is it possible? If it is possible how can I access in my example with word "sentence" first, second or third "e" node?
You could define your nodes explicitly and set the label for them. Then each node has an unique id, but can have the same labels. Consider this example:
strict graph G {
1 [label="A"];
2 [label="B"];
3 [label="B"];
4 [label="A"];
1 -- 2;
2 -- 3;
3 -- 4;
}
which will output (with dot):
It might sound wired, but just put a whitespace at the end of the character that repeated will solve the problem.

Why does a top to bottom graphviz dot graph get layed out counter clockwise?

I updated the question with graphics and more details. Thanks to marapet, without the hack I couldnĀ“t have generated the desired results as images.
why does this code produce this graph?
digraph {
rankdir = TB;
1 -> 2 -> 3 -> 1;
}
How can I get graphviz/dot to produce a clockwise direction like this?
Update
This is the final graph I want to generate (afaik logically correct this way)
digraph {
rankdir = TB
start -> 1
1 -> 2 -> 3 -> 1
3 -> end
3 -> increment
end -> product
{rank = same; 2; 3; increment}
{rank = same; end; product}
}
Which produces this result
While I want this
Thanks
Why does this code produce this graph?
A directed graph puts its nodes on different ranks depending on their relations. Since 1 points to 2, it must be above 2, and since 2 points to 3 it gets to be above 3.
But since 3 also points to 1, the circle is completed - any of the 3 nodes could be on top. Graphviz simply puts the first mentioned node on top. Therefore, if you write instead:
2 -> 3 -> 1 -> 2;
node 2 will be on top, and when using
3 -> 1 -> 2 -> 3;
node 3 will be the top node.
Probably the layout engine neato would be more appropriate for this graph, producing a graph with a clockwise direction:
If you absolutely must use the dot layout engine, the following dot code
digraph {
rankdir = TB;
1 -> 2;
3 -> 2 [dir=back];
3 -> 1;
{rank=same; 2; 3;}
}
produces the desired output by changing the edge 2->3 into 3->2 and at the same time inverting the direction of the arrow.
Or, an other variant of the same technique, easier to explain: We reverse the order of all arrows (1->3->2->1), but display them backwards (dir=back), and force node 2 and 3 to be on the same rank:
rankdir = TB;
edge[dir=back];
1 -> 3 -> 2 -> 1;
{rank=same; 2;3;}
This hack yields the following result:

Resources