I want to render several trees simultaneously and place all root nodes and all leaf nodes on the same level.
Here's an example of what I'm trying to do. Root nodes A and X are on the same level, and so are leaf nodes B, D, and Z.
I unsuccessfully tried putting roots in one rank and leaves in another as follows:
digraph G {
rankdir = TB;
subgraph {
A -> B
A -> C
C -> D
X -> Y
rank = same; A; X;
rank = same; B; D; Y;
} /* closing subgraph */
}
And got this outcome where everything is on the same rank.
Any suggestions about what I should be trying? I've already got roots and leaves identified.
Putting the rank = same; ... statements in braces, e.g.:
digraph G {
rankdir = TB;
subgraph {
A -> B
A -> C
C -> D
X -> Y
// note that rank is used in the subgraph
{rank = same; A; X;}
{rank = same; B; D; Y;}
} /* closing subgraph */
}
... gives the desired result:
The ideal structure is actually rank max and rank min. No need for a subgraph or any other shenanigans. GraphViz has explicit facilities for this.
With complex graphs, rank=same will often end up near the middle of the graph. If you mean top and bottom, say top and bottom.
digraph G {
rankdir = TB;
A -> B;
A -> C -> D;
X -> Y;
{ rank=min; A; X; }
{ rank=max; B; D; Y; }
}
Here's a simple example inspired by #William John Holden's comment -
graph {
rankdir=LR;
a -- b -- c;
d -- e -- f;
b -- d; {rank = same; b; d;};
}
Related
How might one highlight an edge in graphviz? I'd like to highlight the edge between D and E. One thing I've tried is to put a transparent edge between them on top of the existing edge, but Graphviz does not want to let them overlap the way I would like, instead placing the edges side by side.
I would like a yellow highlight around the edge from D to E.
graph K5 {
graph [splines = false, layout=circo];
edge [penwidth=3];
node [shape=circle];
A;
B;
C;
D;
E;
{
edge [color="red"];
A -- B;
A -- C;
C -- D;
B -- D;
C -- E;
}
{
edge [color="blue"];
node [comment="Wildcard node added automatic in EG."];
D -- E;
A -- E;
B -- C;
B -- E;
A -- D;
}
{
edge [color="#95a616aa" penwidth=5];
node [comment="Wildcard node added automatic in EG."];
E -- D;
}
}
Not sure if this is what you are after, but look at colorlist example here (http://www.graphviz.org/docs/attrs/color/)
graph K5 {
graph [splines = false, layout=circo];
edge [penwidth=3];
node [shape=circle];
A;
B;
C;
D;
E;
{
edge [color="red"];
A -- B;
A -- C;
C -- D;
B -- D;
C -- E;
}
{
edge [color="blue"];
node [comment="Wildcard node added automatic in EG."];
D -- E;
A -- E;
B -- C;
B -- E;
A -- D;
}
{
// see color/colorlist http://www.graphviz.org/docs/attrs/color/
edge [color="lightpink:red:orange:orange:red:lightpink" penwidth=1];
node [comment="Wildcard node added automatic in EG."];
E -- D;
}
}
Giving:
I have a digraph which I've set to "rankdir=LR;" so that "rank=same" will be top-to-bottom.
I decided to add a few clusters to this graph, but as a result "rank=same" has now become bottom-to-top.
A minimal example shows the problem:
digraph graph {
graph [
rankdir=LR;
nodesep = "0.5 equally",
newrank = true;
];
/* Guide Nodes */
rank1 [style=dotted];
rank2 [style=dotted];
rank1 -> rank2 [style=dotted];
/* Node Clusters */
subgraph cluster1 {
A;
B;
C;
}
/* Node Hierarchy */
A -> Z;
B -> Z;
C -> Z;
/* Node Rank */
{ rank=same;
rank1 -> A -> B -> C [style=dotted];
}
} /* Closes the digraph */
The result that I want is to have from top to bottom: rank1, A, B, C.
The result that I get is from top to bottom: C, B, A, rank1 --- as seen in the picture below.
How can I get the correct order back?
Option 1: Just don't use clusters.
Option 2: Rewrite the "rank=same" line to fit the bottom-to-top direction.
Given the size of my graph, option 2 is simply too much work for too little gain. Is there another option?
EDIT: The answer that marapet gave, does most of what I wanted. However, that solution doesn't work with the following minimal problem:
digraph g {
graph [
rankdir=LR;
nodesep = "0.5 equally",
newrank = true;
];
/* Node Clusters */
subgraph cluster1 {
subgraph cluster2 {
A;
B;
C;
}
P;
subgraph cluster4 {
D;
E;
F;
}
Z;
}
/* Guide Nodes */
rank1 [style=dotted];
rank2 [style=dotted];
/* Guide Nodes Hierarchy */
rank1 -> rank2 [style=dotted];
/* Node Hierarchy */
A -> Z;
B -> Z;
C -> Z;
P -> Z;
D -> Z;
E -> Z;
F -> Z;
/* Rank Constraints */
rank1 -> A -> B -> C -> P -> D -> E -> F [style=dotted, constraint=false];
} /* Closes the digraph */
This results in the following picture:
I can only conclude that the issue I'm having is the result of mixing clusters and non-clusters in the same-rank-edges.
Instead of using rank=same, you may use constraint=false for the same-ranke-edges:
/* Node Rank */
rank1 -> A -> B -> C [style=dotted, constraint=false];
The order of appearance of the nodes (guide nodes and node clusters) should also be changed:
digraph g {
graph [
rankdir=LR;
nodesep = "0.5 equally",
newrank = true;
];
/* Node Clusters */
subgraph cluster1 {
A;
B;
C;
}
/* Guide Nodes */
rank1 [style=dotted];
rank2 [style=dotted];
rank1 -> rank2 [style=dotted];
/* Node Hierarchy */
A -> Z;
B -> Z;
C -> Z;
/* Node Rank */
rank1 -> A -> B -> C [style=dotted, constraint=false];
}
In general, for LR layouts, it helps to lay out the graph top-down and imagine it rotate 90 degrees counterclockwise.
Small extension to edit in the question.
In the edit the lone node 'p' is used, packing it in a subgraph gives a better result, especially when setting the color to white: like:
subgraph cluster3 {
P;
graph[color=white];
}
Only strange thing I get in my output is that there are 2 dotted lines between 'C' and 'P'/
Playing around with the 'dir=back' gave a solution.
Complete code:
digraph g {
graph [
rankdir=LR;
nodesep = "0.5 equally",
newrank = true;
];
/* Node Clusters */
subgraph cluster1 {
subgraph cluster2 {
A;
B;
C;
}
subgraph cluster3 {
P;
graph[color=white];
}
subgraph cluster4 {
D;
E;
F;
}
Z;
}
/* Guide Nodes */
rank1 [style=dotted];
rank2 [style=dotted];
/* Guide Nodes Hierarchy */
rank1 -> rank2 [style=dotted];
/* Node Hierarchy */
A -> Z;
B -> Z;
C -> Z;
P -> Z;
D -> Z;
E -> Z;
F -> Z;
/* Rank Constraints */
rank1 -> A -> B -> C [style=dotted, constraint=false];
D -> E -> F [style=dotted, constraint=false];
P -> C [dir=back, style=dotted, constraint=false];
P -> D [style=dotted, constraint=false];
} /* Closes the digraph */
I'm attempting to implement a BFS search on a maze, specifically the Apollo and Diana maze puzzle. Upon running my BFS algorithm the initial neighbors of the starting vertex are added however subsequent neighbors are added causing the algorithm to terminate after three iterations when run using the example maze below. The code for my algorithm is:
BFS_Algo(){
NodeQueue.push(NodeMatrix[0][0]);
while( !NodeQueue.empty() )
{
Node current;
current = NodeQueue.front();
NodeQueue.pop();
if( !current.visited )
{
current.visited = true;
for ( int i = 0; i < current.neighbors.size(); ++i )
{
if ( !current.neighbors[i].visited )
{
NodeQueue.push(current.neighbors[i]);
current.neighbors[i].predecessor = &NodeMatrix[current.x][current.y];
}
}
}
}
}
I know that the neighbors vectors are properly filled since I have a helper function that prints the contents of all the vectors like so:
B E: |R SE|R SW|
R SE: |empty vector
R SW: |B N|B N|
R SE: |B E|
B N: |R SE|
R E: |empty vector
B N: |R SE|
B E: |O O|
O O: |empty vector
/empty vectors signify that there are no neighbors./
I don't believe this to be a logical error, but I feel this might be more in line with local references instead. Any guidance would be greatly appreciated.
Additional Info:
Ive read in the information for the graph from a file similar to this example:
B E |R SE|R SW|
R SE|B N |R E |
B N |B E |O O |
I have created a class that contains a node struct that holds all the appropriate data.
private:
struct Node{
int x; position in graph
int y; position in graph
std::string color; graph attr
std::string direction; graph attr
bool visited; bfs bool
Node * predecessor; ancestor for path backtracking
std::vector<Node> neighbors; vector of neighbors
};
short rows;
short columns;
Node **NodeMatrix;
std::queue<Node> NodeQueue;
Consider this DOT sample:
digraph Foo
{
subgraph clusterA
{
A -> B;
}
subgraph clusterB
{
X -> Y;
}
subgraph connection_type_1
{
edge [color=red];
A -> Y;
}
subgraph connection_type_1
{
edge [color=green];
B -> X;
}
subgraph node_type_1
{
node [style=filled, color=".5,.5,.5"]; // THIS LINE DOESN'T WORK
X [label="foo"];
A;
}
}
The structure is set out in the two clusters and the edges are added later in semantically/cosmetically equivalent groups. The edges are coloured as expected.
But this doesn't work with styling nodes. The marked line has no effect unless I move it into one of the cluster* subgraphs, but then it applies to all nodes within that subgraph.
What's odd is that label=foo works in the final subgraph, whereas style doesn't.
I have a feeling that the answer is going to be "you can only set node attributes the first time you mention them", but is there a way to say "the following nodes, wherever they are, should all have the following attributes"?
the line does not work, as it sets default attributes only and the nodes have been created already. the default attributes have no effect. the label is a concrete attribute overriding any default values and therefore takes effect.
So you should reorder the code to
create all nodes (with default attributes)
create all edges (again with default attributes)
assign the nodes to clusters
steps 2 and 3 would create the nodes with the defauls attributes then active. your example did work for the edges only by accident, as you did try it for non existing edges only. it would not have worked for the 2 already defined edges in the clusters.
digraph Foo {
subgraph node_type_1 {
node [style=filled, color=".5,.5,.5"];
A;
X [label="foo"];
}
subgraph node_type_2 {
node [style=none];
B;
Y;
}
subgraph connection_type_1 {
edge [color=red];
A -> Y;
A -> B;
}
subgraph connection_type_2 {
edge [color=green];
B -> X;
X -> Y;
}
subgraph clusterA {
A;
B;
}
subgraph clusterB {
X;
Y;
}
}
l - adiacency list
x - starting vertex
dfst, q - empty array of vertex size
std::list <int> q;
std::vector<bool> visited(cols + 1);
for(int i = 0; i < cols; i++) visited[i] = false;
visited[x] = true;
if(!l[x].empty())
for(std::list<int>::iterator i = l[x].begin(); i != l[x].end(); i++)
{
q.push_back(x); q.push_back(* i);
}
while(!q.empty())
{
y = q.back(); q.pop_back();
x = q.back(); q.pop_back();
if(!visited[y])
{
visited[y] = true;
if(!l[y].empty())
for(std::list<int>::iterator i = l[y].begin(); i != l[y].end(); i++)
{
q.push_back(y); q.push_back(* i);
}
dfst[x].push_back(y);
dfst[y].push_back(x);
}
}
I just can't see why does this give wrong results...I don't know if you are familiar with this algorithm, but if you are, I hope you can see what's wrong here.
EDIT:
Adjacency list is:
1: 2, 3
2: 3
3: 4
4: 3
MST should here be something like:
1: 2, 3
3: 4
But instead it's:
2: 3
3: 2, 4
4: 3
And the current code is: (I used brackets where it was needed):
std::list <int> q;
std::vector<bool> visited(cols + 1);
for(int i = 0; i < cols; i++) visited[i] = false;
visited[x] = true;
if(!l[x].empty())
{
for(std::list<int>::iterator i = l[x].begin(); i != l[x].end(); i++)
{
q.push_back(x); q.push_back(* i);
}
while(!q.empty())
{
y = q.back(); q.pop_back();
x = q.back(); q.pop_back();
if(!visited[y])
{
visited[y] = true;
if(!l[y].empty())
for(std::list<int>::iterator i = l[y].begin(); i != l[y].end(); i++)
{
if(!visited[*i])
{q.push_back(y); q.push_back(* i);}
}
dfst[x].push_back(y);
dfst[y].push_back(x);
}
}
}
I worked through your code, it appears to be correct. However, keep in mind that there are multiple DFS trees if your input tree has a cycle. The tree that you get depends on the order in which you process your vertices. Perhaps your input has a cycle? If so, your code might be processing the nodes in an order different from the order that they are processed in the solution.
For example, take the following adjacency list for an input tree, where nodes are lettered:
a: b,c
b: a,d
c: a,c,e
d: b,c,e
e: c,d
Starting at a, if we look in the adjacency list for the next node based on alphabetical order, we get the following DFS tree:
a: b
b: a,d
c: d,e
d: b,d
e: c
Using your algorithm though, we get the following:
a: c
b: d
c: a,e
d: b,e
e: c,d
If this is happening, perhaps try a recursive approach.
Seeing some sample input and output would help further with ansering this question though, as this may not be your problem.
EDIT: I should clarify that the multiple DFS trees in a graph with a cycle applies where the cycle is bidirectional, such as with an undirected graph. The point is, you might be finding a DFS tree that is also correct, but not the same as the one that has been identified as correct.
EDIT (again): Another issue you may have: your algorithm appears to be for undirected graphs since you have the satements dfst[x].push_back(y); dfst[y].push_back(x);in your code, but your input graph given in your example looks like it's directed. Removing the second statement (dfst[y].push_back(x);) should correct this
Code looks little confusing actually i thought its BFS first..but its DFS
You should check if the node is visited before adding to the stack(back of list)
while(!q.empty())
{
y = q.back(); q.pop_back();
x = q.back(); q.pop_back();
if(!visited[y])
{
visited[y] = true;
if(!l[y].empty())
for(std::list<int>::iterator i = l[y].begin(); i != l[y].end(); i++)
{
if(!visited[*i])
{q.push_back(y); q.push_back(* i);}
}
dfst[x].push_back(y);
dfst[y].push_back(x);
}
}