I would like to point an edge towards another edge in graphviz using the dot format.
What I got so far:
digraph G {
Hello->dummy;
dummy->World;
dummy[shape=point width=0];
Test->dummy;
}
which produces
what I would like to get is something more similar to this:
Any ideas how to do so?
Maybe rank = same does the trick?
digraph G
{
{ rank = same; Test; dummy } // dummy and Test on the same level
dummy[ shape = point, width = 0 ]; // connector
Hello -> dummy[ arrowhead = none ]; // remove arrowhead to connector
dummy -> Test[ dir = back ]; // you want Test on the right side
dummy -> World;
}
yields
[arrowhead=none] with you dummy middleman does the job for me.
digraph G {
Hello->dummy[arrowhead=none];
dummy->World;
dummy[shape=point width=0];
Test->dummy;
}
I've added feature request for it in Graphviz's issue tracker.
Related
I'm working with graphviz on LinuxArch. If I print my .svg I use the command dot -Tsvg example.dot -o exampale.svg. My graph is printed and that works fine. I read some other questions on that topic Link 1, Link 2, also the documentation on graphviz.org didn't give me a clue.
Question: I want to line break in a node. How I can do it?
The following code is working, but not always. Full Code:
digraph G {
//general settings
graph [fontname="Arial"];
node [fontname="Arial"];
edge [fontname="Arial"];
//data of graph
subgraph cluster_1
{
label = "Cluster 1";
style=filled;
color="#E0E0E0";
margin=20;
node [style=filled,color=white];
"I'm text" -> "I want a donat.";
"I want a donat." -> a1[label="Love food,\nlove it so much!"];
}
subgraph cluster_2
{
label = "Cluster 2";
style=filled;
color="#E0E0E0";
margin=20;
node [style=filled,color=white];
Start -> a2[label="sit amet,\nconsetetur"];
a2 ->
{
b2[label="Lorem Impsum\ndollar sit amet."];
}
}
}
Result: (Green marked is working and the problem is Red marked.)
It seems to me you are confusing node and edge declarations.
Try changing the lines
"I'm text" -> "I want a donat.";
"I want a donat." -> a1[label="Love food,\nlove it so much!"];
into
a1[label="Love food,\nlove it so much!"];
"I'm text" -> "I want a donat.";
"I want a donat." -> a1;
What this actually does is that a1 is defined as a node with a label. The node id a1 can then be used to declare edges between nodes.
Here is an other example, with explicit node declarations for all nodes, and then the edge declarations using the node identifiers:
imtext[label="I'm text"];
donat[label="I want a donat."];
a1[label="Love food,\nlove it so much!"];
imtext -> donat -> a1;
I would like to create nice curved edges in my Cotoscape.js graph using the unbundled-bezier style. According to the database I have to set the control-point-distance(s) automatically, so I came up with following code:
{
selector: 'edge',
css: {
'curve-style': 'unbundled-bezier',
'target-arrow-shape': 'triangle',
'control-point-weights': '0.25 0.75.',
'control-point-distance': function( ele ){
console.log(ele.source().position());
var pos1 = ele.source().position().y;
var pos2 = ele.target().position().y;
var str = '' + Math.abs(pos2-pos1) + 'px -' + Math.abs(pos2-pos1) + 'px';
console.log(pos1, pos2, str);
return str;
}
}
}
My problem is, that the graph is rendered with straight lines ant the curvy line appears only when I click on some. Also, when I move the nodes the curve moves nicely with the node, but the node positions (ele.source().position().y) does not change
A style function ought to be a pure function. Yours is technically not: It depends on state outside of the edge's data.
The only way an arbitrary function could be used to specify style is if the function is continuously polled. That would be hacky and prohibitively expensive.
You must use a pure function if you want to use a custom function. Either rewrite your function to rely on only the edge's data or use a passthrough data() mapping and change the edge's data whenever you want to modify the edge.
I've a network graph
Now I've some connected nodes and as you can see most of the nodes only have one connected node that is their degree is 1. Now I'd like to remove such nodes to clear the clutter. Unable to find how to since last 2 days. No such helper functions available in visjs documentation. Would appreciate help.
I believe the algorithm suggested by the 1st answer -by macramole- (before updates) would actually hide the non-connected nodes (degree 0), instead of the ones with degree 1.
I would probably just iterate over all the edges in the network while keeping 'degree' counters for each node that is an endpoint in the edge you are visiting (you can obtain these nodes by grabbing the edge.from and edge.to values, as shown above). You would increment the degree counter for a node, whenever the node is 'hit' in this search through the edges.
Eventually you'll end up with the degree value for each node in the network, at which point you can decide which ones to hide.
Updating this answer now to include my suggested code (note: nodes and edges are vis DataSet instances):
Example code:
var nodeToDegrees = {}; // keeps a map of node ids to degrees
var nodeFrom, nodeTo;
for (edge in edges) {
nodeFrom = edge.from;
nodeTo = edge.to;
nodeToDegrees[nodeFrom] = nodeToDegrees[nodeFrom] ? nodeToDegrees[nodeFrom] + 1 : 0;
nodeToDegrees[nodeTo] = nodeToDegrees[nodeTo] ? nodeToDegrees[nodeTo] + 1 : 0;
}
for (node in nodes) {
if (nodeToDegrees[node.id] = 1) nodes.update([{node.id, hidden: true}]);
}
This might work:
var DEGREES_HIDDEN = 1;
for ( var node of nodes ) {
node.cantLinks = 0;
for ( var link of links ) {
if ( link.from == node.id || link.to == node.id ) {
node.cantLinks++;
}
}
}
for ( var node of nodes ) {
if ( node.cantLinks <= DEGREES_HIDDEN ) {
node.hidden = true;
}
}
Nodes and links are arrays not vis.DataSet, I create the latter after doing that.
Doesn't look very nice perfomance wise but it does get the job done. Hope you find it useful.
I'm trying too see whether I can use the Dot programming language to apply it to an old project of mine.
The task is simple: create a high quality graph with ease.
Unfortunately, while it has been fairly easy to implement the details of my graph, I wound up having to take loads of time just for adjusting the layout.
Furthermore, it is quite unclear to me how the order of my instructions impact my graph, but it actually looks like putting the last instruction of my code at the beginning produces a completely different output!
Here is the code:
digraph {
TOP [shape=doublecircle]
TOP->TOP->{rank=same a->b->c->b->a}
a:s->c:s
a:nw->a:sw
c:ne->c:se
b:s->b:s
}
so. firstly, i finally mastered the 'get nodes to be on the same horizontal/vertical line' through ranking...
I also kinda fixed the problem of edges doing stupid interconnections (all free space below the graph for connections, and the edge winds up zig-zagging through the whole graph in an awkward way and overlapping everything?) using the direction indicators ":e" and the such (i believe they are called routes...), but it looks like graphviz isn't using them in a smart way, because the result looks funny to me.
Here is the output, how do I get it to avoid edge overlappings and make enough space for future (long) labels?
(made with dot -Tpng test.dot -o test.png)
(also, I would need to add a c->a edge at the bottom too, but adding one the "normal" way ruined everything)
You can use invisible nodes to "re-route" your edges as desired (edited as per comments below):
digraph
{
/* layout */
// node width to create space for longer labels
node [ width = 1.75 ];
{ rank=same; a; b; c }
/* nodes */
t [ label = "TOP", shape = doublecircle, width = 1];
a [ label = "short" ];
b [ label = "medium" ];
c [ label = "rather l o n g"]
// invisible nodes to 're-route' the edges
x [ style = invis, shape = point, width = 0 ];
y [ style = invis, shape = point, width = 0 ];
/* edges */
t -> t;
t -> { a b c }
t -> { a b c } [dir = back ]; // added for reverse arrows
a -> b -> c -> b -> a;
a:nw -> a:sw;
c:ne -> c:se;
b:s -> b:s;
// put the invisible nodes at the desired places with invisible edges
b -> x -> y [ style = invis ];
// edges to invisible nodes must not have heads
c:sw -> x [ arrowhead = "none" ];
x -> a:se;
a:s -> y [ arrowhead = "none" ];
y -> c:s;
}
yields
I have a very simple task I am trying to do in Groovy but cannot seem to get it to work. I am just trying to loop through a map object in groovy and print out the key and value but this code does not work.
// A simple map
def map = [
iPhone : 'iWebOS',
Android: '2.3.3',
Nokia : 'Symbian',
Windows: 'WM8'
]
// Print the values
for (s in map) {
println s + ": " + map[s]
}
I am trying to get the output to look like this:
iPhone: iWebOS
Android: 2.3.3
Nokia: Symbian
Windows: WM8
Could someone please elaborate on how to do this??
Quite simple with a closure:
def map = [
'iPhone':'iWebOS',
'Android':'2.3.3',
'Nokia':'Symbian',
'Windows':'WM8'
]
map.each{ k, v -> println "${k}:${v}" }
Alternatively you could use a for loop as shown in the Groovy Docs:
def map = ['a':1, 'b':2, 'c':3]
for ( e in map ) {
print "key = ${e.key}, value = ${e.value}"
}
/*
Result:
key = a, value = 1
key = b, value = 2
key = c, value = 3
*/
One benefit of using a for loop as opposed to an each closure is easier debugging, as you cannot hit a break point inside an each closure (when using Netbeans).
When using the for loop, the value of s is a Map.Entry element, meaning that you can get the key from s.key and the value from s.value
Another option:
def map = ['a':1, 'b':2, 'c':3]
map.each{
println it.key +" "+ it.value
}