How to set the 'spring' force with graphviz for compact graph layouts - graphviz

I'm generating diagram with graphviz and I have a problem - there are several nodes that are very large - and large number of small nodes. I tried generating png with neato and fdp but both generate very large graphics, which are mostly blank (nodes are very far apart). Is there a way to set a larger spring 'strength' for these tools to force nodes closer together?

When using neato, you may fiddle with the overlap and with the sep attribute.
overlap can be set to false, compress, scalexy, and more.
sep may either designate an additive margin when used with a preceding plus sign, otherwise the margin is defined by scaling the node's size with 1 + the value of sep. It seems that the default
Don't hesitate to post a sample graph. Not knowing your particular graph, I made an example containing some big and some small nodes:
layout=neato;
overlap=scalexy; //false, compress, ...
sep="+1"; // 0.1, +1
node[label="Large node", width=2, height=2];
l1; l2; l3;
node[label="\N", width=0.5, height=0.3];
1 -> l1;
2 -> l1;
3 -> l1;
4 -> l1;
5 -> l1;
5 -> l2;
6 -> l2;
7 -> l2;
8 -> l2;
8 -> l3;
9 -> l3;
10 -> l3;

Related

Finding all possible paths in a cyclic directed graph given a starting vertex and a depth limitation

Consider the directed cyclic graph given below;
If a starting point (eg: vertex 0) and a maximum depth allowed is specified (eg: 5), what algorithm can be used to find all possible paths (note: a given vertex can be visited more than once)?
What is the most efficient algorithm to implement this graph problem?
Some of the possible paths for the above graph are given below in no particular order (starting with vertex 0 and maximum depth allowed is 5).
0 -> 1 -> 2 -> 4 -> 1 -> 3
0 -> 1 -> 2 -> 4 -> 5 -> 1
0 -> 1 -> 2 -> 4 -> 5 -> 6
0 -> 1 -> 3 -> 5 -> 1 -> 3
Pseudo algorithm for this will be an augmented BFS that keeps track of the path it has gone through. When it hits the required depth, it registers the path and then terminates.
Something like this (node.js style syntax):
const requiredDepth = X
const relevantPaths = {}
const runBFS = (curNode, curPath = []) => {
if (crPath.length === requiredDepth) {
relevantPaths.push(curPath)
return
}
for (let neighbor of curNode.neighbors) {
const newPath = [ ...curPath, getEdge(curNode, neighbor) ]
runBFS(neighbor, newPath)
}
}
runBFS(root)
Hope this helps

Random position of nodes in hierarchical tree with alternate paths

I'm struggling with directed graph hierarchy tree visualization (distributed network in this case). Using graphviz: dot I have this tree:
digraph G {
node[width=0.14, height=0.14];
edge[weight=3, color = "0.000 0.000 0.0"];
1 -> 2;
1 -> 3;
edge[weight=2, color = "0.000 0.000 0.175"];
2 -> 4;
2 -> 5;
3 -> 6;
3 -> 7;
edge[weight=1, color = "0.000 0.000 0.825"];
3 -> 4;
3 -> 5;
2 -> 6;
2 -> 7;
}
Resulting in:
You can see that the primary paths (edges with higher weights) are crossed. The goal is to have the preferred path nodes as close as possible. I can do it by changing the order of nodes randomly so the output looks like this:
However I don't want to think about the ordering algorithm as I want to automate this on hundreds of nodes.
From documentation:
The weight of an edge provides another way to keep edges straight. An edge’s weight suggests some measure of an edge’s importance; thus, the heavier the weight, the closer together its nodes should be. dot causes edges with heavier weights to be drawn shorter and straighter.
But this is not the case as the nodes are drawn in random order. What am I doing wrong?
Probably not the answer you were looking for, but since dot doesn't seem to work with edge weights in this case:
You may just use constraint=false for the lightgray edges.
Could you live with a solution like this, which places invisible ranks and invisible edges to enforce the left-to-right ordering of your nodes? While it adds some white space to the left of the diagram, at least it neatly solves the random-ordering issue within each rank, and lends itself to being automated.
digraph G {
node[width=0.14, height=0.14];
{
rankdir="TB";
edge [style=invis];
rank1 [style=invis];
rank2 [style=invis];
rank3 [style=invis];
rank1 -> rank2 -> rank3 [style=invis];
}
edge[weight=3, color = "0.000 0.000 0.0"];
1 -> 2;
1 -> 3;
edge[weight=2, color = "0.000 0.000 0.175"];
2 -> 4;
2 -> 5;
3 -> 6;
3 -> 7;
{
edge [style=invis];
rank=same;
rank2 -> 2 -> 3;
}
edge[weight=1, color = "0.000 0.000 0.825"];
3 -> 4;
3 -> 5;
2 -> 6;
2 -> 7;
{
rank=same;
edge [style=invis];
rank3 -> 4 -> 5 -> 6 -> 7 ;
}
}

merging linear lists - reconstruct railway network

I need to reconstruct the sequence of stations in a railway network from the sequences of single trips requested from a arbitrary station. There's no direction given in the data. But every request returns an terminal stop. The sequences of single trips can have gaps.
The (end-) result is always a linear list - forking is not allowed.
For example:
Result trips from requested station "4" :
4 - 3 - 2 - 1
4 - 1
4 - 5 - 6
4 - 8 - 9
4 - 6 - 7 - 8 - 9
manually reordered:
1 - 2 - 3 - 4
1 - 4
- 4 - 5 - 6
- 4 - 8 - 9
- 4 - 6 - 7 - 8 - 9
After merging result should be:
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9
start/stop: 1, 9
Is there an algorithm to calculate the resulting "rope of pearls" list? I tried to figure it out with perls graph-module, but no luck. My books on algorithms doesn't help either.
I think, there are pathologic cases, where multiple solutions are possible, depending on input data.
Maybe someone has an idea to solve it!
As you see in the answers, there is more than one solution. So here's a real-world dataset:
2204236 -> 2200007 -> 2200001
2204236 -> 2203095 -> 2203976 -> 2200225 -> 2200007 -> 2200001
2204236 -> 2204805 -> 2204813 -> 2204401 -> 2219633 -> 2204476 -> 2202024 -> 2202508 -> 2202110 -> 2202026
2204236 -> 2204813 -> 2204401 -> 2219633 -> 2202508 -> 2202110 -> 2202026 -> 3011047 -> 3011048 -> 3011049
2204236 -> 2204813 -> 2204401 -> 2219633 -> 2204476 -> 2202024 -> 2202508 -> 2202110 -> 2202352 -> 2202026
2204236 -> 2204813 -> 2204401 -> 2219633 -> 2204476 -> 2202024 -> 2202508 -> 2209637 -> 2202110
solution of the example data with perl:
use Graph::Directed;
use Graph::Traversal::DFS;
my $g = Graph::Directed->new;
$g->add_path(1,2,3,4);
$g->add_path(1,4);
$g->add_path(4,5,6);
$g->add_path(4,8,9);
$g->add_path(4,6,7,8,9);
print "The graph is $g\n";
my #topo = $g->toposort;
print "g toposorted = #topo\n";
Output
> The graph is 1-2,1-4,2-3,3-4,4-5,4-6,4-8,5-6,6-7,7-8,8-9
> g toposorted = 1 2 3 4 5 6 7 8 9
Using the other direction
$g->add_path(4,3,2,1);
$g->add_path(4,1);
$g->add_path(4,5,6);
$g->add_path(4,8,9);
$g->add_path(4,6,7,8,9);
reveals the second solution
The graph is 2-1,3-2,4-1,4-3,4-5,4-6,4-8,5-6,6-7,7-8,8-9
g toposorted = 4 3 2 1 5 6 7 8 9
Treat the lists node links in a graph. 4-3-2-1 should mean 4 must come before 3, 3 before 2 and 2 before 1. So add arcs from 4 to 3, 3 to 2, 2 to 1.
Once you have all of those you run a topological sort(look it up on wikipedia) on the resulting graph. This will guarantee that the order you get will always respect the partial orderings you are given.
The only case when you are not going to find a solution is when the data is contradicting itself (if you have 4-3-2 and 4-2-3 there's no possible ordering).
You are right, there are multiple cases. Another good solution is 4-5-6-7-8-9-3-2-1, for your example.
Terminal stop station is articulation node and it splits graph into multiple partitions: all nodes inside partition are reachable from one another, nodes in different partitions are reachable only via known terminal stop station. Number of partitions is 2 in your example, but may be much larger, e.g. consider star-like structure 1 - 2, 1 - 3, 1 - 4, 1 - 5.
First of all you need to enumerate partitions. You treat your graph as undirected graph and run DFS from stop station in each of directions. At first run you discover partition #1, at second run partition #2 and so on.
Then you treat you graph as directed with stop station as root node for all partitions and run topological sorting (TS) for each of partitions.
Possible outcomes:
TS for one of partitions fails. This means there is no solution.
Number of partitions is one and TS for it succeeds. Solution is unique.
Number of partitions is more than one and TS succeeds for all of them. This means there are multiple solutions. To get any single valid result, you choose some partition and declare that it contains another terminal station. All other partitions are inserted into the first one in between arbitrary pair of nodes.

How to enforce sub graphs to be on the same horizontal line in Graphviz

I'm using graphviz (dot) to generate time expanded graph to use in my master thesis. However, my drawing results the following graph:
As you can see, the third line is a little bit shifted to the right.I want all the lines in the same horizontal line. Also i want the x.th node in each line to stay at the same horizontal line of other x.th nodes of lines. Changing the edge weights would not helped me.
I could not find anything related to this problem so far.
What i want to achieve is something like this:
Here is my code:
digraph G {
1[label="1"]
2[label="1"]
3[label="1"]
4[label="1"]
5[label="1"]
6[label="1"]
7[label="2"]
8[label="2"]
9[label="2"]
10[label="2"]
11[label="2"]
12[label="2"]
13[label="3"]
14[label="3"]
15[label="3"]
16[label="3"]
17[label="3"]
18[label="3"]
19[label="4"]
20[label="4"]
21[label="4"]
22[label="4"]
23[label="4"]
24[label="4"]
rankdir="LR";
node[width=0.15, height=0.15, shape=point];
edge[weight=500, label="1"];
1 -> 2 -> 3 -> 4 -> 5 -> 6 ;
7 -> 8 -> 9 -> 10 -> 11 -> 12 ;
13 -> 14 -> 15 -> 16 -> 17 -> 18 ;
19 -> 20 -> 21 -> 22 -> 23 -> 24 ;
edge[weight=3];
1 -> 9;
2 -> 9;
3 -> 11;
13 -> 22;
14 -> 22;
15 -> 24;
edge[weight=1];
1 -> 14;
2 -> 15;
3 -> 17;
7 -> 21;
8 -> 23;
9 -> 22;
}
Any help would be appreciated.
Instead of using weight try using the attribute constraint=false for all edges which go from one "line" to another.
Setting constraint to false makes graphviz to not consider those edges when laying out the nodes of the graph.
See also this very similar question & answer
As far as I know, the only way is to specify an explicit position for each individual node.
See: How to force node position (x and y) in graphviz

Pairwise swap of linkedlist

I have been trying to do pairwise swap of linkedlist elements. In place of swapping the elements by data, I am swapping them by swapping the links.
C# code:
public LinkedList pairWiseSwapLinks(LinkedList ll)
{
LinkedList curr = ll;
LinkedList next = curr.nextNode;
ll = curr;
while (curr.nextNode != null && next.nextNode != null)
{
curr.nextNode = next.nextNode;
next.nextNode = curr;
Console.WriteLine(curr.data);
Console.WriteLine(next.data);
curr = curr.nextNode;
next = curr.nextNode;
Console.WriteLine(curr.data);
Console.WriteLine(next.data);
}
return ll;
}
The input is: 1 -> 3 -> 10 -> 14 -> 16 -> 20 -> 40
Output: 1 -> 10 -> 16 -> 40
Can someone help me out with what mistake I am making?
There are 2 issues:
after all swaps, your first node should be 3 instead of 1 in your case, so you should return the originally second node (what if there's only 1?).
The reason why 14 is skipped in your case is because you only involve 2 nodes as a pair in each swap. So what happens after the first swap is that the list becomes 3 -> 1 -> 10 -> 16 ... and 14 -> 10 -> 16 so essentially you've lost 14 (i.e. you didn't change the "nextNode" ref in node 1, which should be pointed to 14 in that case).
I don't want to give you the direct solution here but I can give you some hints:
You need to involve 3 nodes in each swap.
However, what if there are only 1/2 nodes?
Adding all the corner cases into your code would make it kinda unreadable, so what if I add a dummy node to the head of the list so eventually I can just write "return dummy.next" instead of bothering finding the current first node?

Resources