graphviz: Create new node with this same label - graphviz

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.

Related

Can I make graphviz concentrate edges based on color?

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:

calculate the optimal order of a series of transformations

Not sure if I should ask here or a different stack exchange but.
Basically I'm wondering if there is a known way to find the shortest path between two values given a number of potential transformations?
Brute force solution/example in python
from itertools import permutations, groupby
start = ["A", "B", "C", "D"]
goal = ["A", "X", "C", "Y"]
Transforms = [
(None,None,"B","D"),
("F",None,None,"Y"),
(None,"X","C",None),
(None,None,"G","Y"),
("D","X",None,None),
(None,"X",None,None)
]
def apply_transform(value, transform):
for x in range(4):
if transform[x] is None: continue
value[x] = transform[x]
perms = permutations(range(len(Transforms)))
results = []
for order in perms:
value = start.copy()
moves = 0
for o in order:
moves += 1
apply_transform(value, Transforms[o])
if value == goal:
results.append([moves, order[0:moves]])
break
# just printing sorted unique in a formated way...I'd be just picking the first one not listing all potential ones
results.sort( key=lambda x: x[0])
results = list(k for k,_ in groupby(results))
print("\n".join(f"moves {m} | {' -> '.join(str(s) for s in ms)}" for m,ms in results))
results that correctly move the start to the goal.
moves 2 | 3 -> 2
moves 3 | 0 -> 3 -> 2
moves 3 | 3 -> 5 -> 2
moves 3 | 5 -> 3 -> 2
moves 4 | 0 -> 3 -> 5 -> 2
moves 4 | 0 -> 5 -> 3 -> 2
moves 4 | 5 -> 0 -> 3 -> 2
so picking the first item in the sorted list as the lowest number of transformations. (applying transformation "3" and then transformation "2").
Obviously, this exact brute force "algorithm" can be improved by breaking out of a permutation if its already started getting longer than the lowest number of jumps... but is there a better solution to this problem I'm not seeing? Some sort of graph? Permutations aren't the best for speed but it might be the only option. Are there other small optimizations that can be done with this?
One possible optimization would be to find transformations that have to be last ones, and work your way backwards.
So, here only transformations 2 and 5 can be the last ones, and 5 is the subgroup of 2 so it can be ignored (one more optimization: ignore transformations that are parts of other transformations), and the only that remains is 2.
Now you are looking how to reach state (A, *, *, Y) using remaining transformations. Transformations 1 and 3 are the only candidates, and 3 -> 2 makes the solution.
This algorithm is a bit complicated, because it requires recursion and backtracking (if you do it the easy way, depth-first), or some queue processing (if you do it the better way, breadth-first), but it will be faster than trying all possible permutations.
Think of it as a graph. Each value is a node, and the transformations are edges. There are known algorithms for the shortest path in a graph, e. g. Dijkstra or A*.

Longest common path between k graphs

I was looking at interview problems and come across this one, failed to find a liable solution.
Actual question was asked on Leetcode discussion.
Given multiple school children and the paths they took from their school to their homes, find the longest most common path (paths are given in order of steps a child takes).
Example:
child1 : a -> g -> c -> b -> e
child2 : f -> g -> c -> b -> u
child3 : h -> g -> c -> b -> x
result = g -> c -> b
Note: There could be multiple children.The input was in the form of steps and childID. For example input looked like this:
(child1, a)
(child2, f)
(child1, g)
(child3, h)
(child1, c)
...
Some suggested longest common substring can work but it will not example -
1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-g
4 m-x-o-p-f-g
1 and 2 will give abc, 3 and 4 give pfg
now ans will be none but ans is fg
it's like graph problem, how can we find longest common path between k graphs ?
You can construct a directed graph g with an edge a->b present if and only if it is present in all individual paths, then drop all nodes with degree zero.
The graph g will have have no cycles. If it did, the same cycle would be present in all individual paths, and a path has no cycles by definition.
In addition, all in-degrees and out-degrees will be zero or one. For example, if a node a had in-degree greater than one, there would be two edges representing two students arriving at a from two different nodes. Such edges cannot appear in g by construction.
The graph will look like a disconnected collection of paths. There may be multiple paths with maximum length, or there may be none (an empty path if you like).
In the Python code below, I find all common paths and return one with maximum length. I believe the whole procedure is linear in the number of input edges.
import networkx as nx
path_data = """1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-g
4 m-x-o-p-f-g"""
paths = [line.split(" ")[1].split("-") for line in path_data.split("\n")]
num_paths = len(paths)
# graph h will include all input edges
# edge weight corresponds to the number of students
# traversing that edge
h = nx.DiGraph()
for path in paths:
for (i, j) in zip(path, path[1:]):
if h.has_edge(i, j):
h[i][j]["weight"] += 1
else:
h.add_edge(i, j, weight=1)
# graph g will only contain edges traversed by all students
g = nx.DiGraph()
g.add_edges_from((i, j) for i, j in h.edges if h[i][j]["weight"] == num_paths)
def longest_path(g):
# assumes g is a disjoint collection of paths
all_paths = list()
for node in g.nodes:
path = list()
if g.in_degree[node] == 0:
while True:
path.append(node)
try:
node = next(iter(g[node]))
except:
break
all_paths.append(path)
if not all_paths:
# handle the "empty path" case
return []
return max(all_paths, key=len)
print(longest_path(g))
# ['f', 'g']
Approach 1: With Graph construction
Consider this example:
1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-g
4 m-x-o-p-f-g
Draw a directed weighted graph.
I am a lazy person. So, I have not drawn the direction arrows but believe they are invisibly there. Edge weight is 1 if not marked on the arrow.
Give the length of longest chain with each edge in the chain having Maximum Edge Weight MEW.
MEW is 4, our answer is FG.
Say AB & BC had edge weight 4, then ABC should be the answer.
The below example, which is the case of MEW < #children, should output ABC.
1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-h
4 m-x-o-p-f-i
If some kid is like me, the kid will keep roaming multiple places before reaching home. In such cases, you might see MEW > #children and the solution would become complicated. I hope all the children in our input are obedient and they go straight from school to home.
Approach 2: Without Graph construction
If luckily the problem mentions that the longest common piece of path should be present in the paths of all the children i.e. strictly MEW == #children then you can solve by easier way. Below picture should give you clue on what to do.
Take the below example
1 a-b-c-d-e-f-g
2 a-b-c-x-y-f-g
3 m-n-o-p-f-g
4 m-x-o-p-f-g
Method 1:
Get longest common graph for first two: a-b-c, f-g (Result 1)
Get longest common graph for last two: p-f-g (Result 2)
Using Result 1 & 2 we get: f-g (Final Result)
Method 2:
Get longest common graph for first two: a-b-c, f-g (Result 1)
Take Result 1 and next graph i.e. m-n-o-p-f-g: f-g (Result 2)
Take Result 2 and next graph i.e. m-x-o-p-f-g: f-g (Final Result)
The beauty of the approach without graph construction is that even if kids roam same pieces of paths multiple times, we get the right solution.
If you go a step ahead, you could combine the approaches and use approach 1 as a sub-routine in approach 2.

Represent array with indices using dot record nodes (Graphviz)

I'm using Graphviz to represent arrays, using subgraphs and record nodes:
subgraph cluster_array
{
label="my array"
Array [shape="record", label="A | B | C | D"]
Array
}
I would like to add external indices for each array elements, mapping 0 -> A, 1 -> B and so on.
I want to achieve a result similar to:
I've searched online and tried using xlabel but couldn't find a way to correctly add a label for each record element. I've also tried making the indices part of the label, and moving the label with lp, but it seems to have no effect on record nodes.
Is it possible to add external element labels to record nodes using GraphViz?
Not a real answer to your question (which, I think, would be "no") but a workaround that may give you what you want. I use a "parallel" record node with no borders (or paper color borders, to be exact), located very close and connected by an invisible edge:
digraph so
{
subgraph cluster0
{
rank = same{ Array notes }
color = white;
Array [ shape = record, label = "{ A | B | C | D }"] ;
notes [ shape = record, color = white, label = "{ a_1 | b_2 | c_3 | d_4 }" ];
Array -> notes[ style = invis ];
}
nodesep = .0;
X -> Array -> Z;
}
which yields

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