Horizontally placing clusters with node outside - graph

I'm fiddling around in Graphviz trying to make a graph of an architecture, but no matter what I try, dot always seems to want to connect some of the nodes with the longest possible path.
Here's a sketch of how I want it to more or less look:
Here's how it actually looks:
And here's the code in question:
digraph ngsys {
graph [dpi = 300];
rankdir="LR";
subgraph cluster_client {
style=filled;
color=lightgrey;
node [style=filled, color=white];
ngcontroller -> ngmodel;
ngmodel -> ngview;
label="Client";
}
ngview -> user [style=dashed];
user -> ngcontroller [style=dashed];
subgraph cluster_server {
style=filled;
color=lightgrey;
node [style=filled, color=white];
apicontroller -> apimodel;
label="Server";
}
ngcontroller -> apicontroller [label="REST", dir=both, style=dashed];
ngmodel [label="NG-Model" shape=box];
user [label="User"];
ngview [label="NG-View", shape=box];
ngcontroller [label="NG-Controler", shape=box];
apicontroller [label="API-Controller", shape=box];
apimodel [label="API-Model", shape=box];
}
Is there anything I can do to make the output look a little more akin to the sketch?

a little change fixes the order:
ngview -> ngmodel [dir=back];
ngmodel -> ngcontroller [dir=back];
another little change improves the look:
nodesep=1;
...
ngview:s -> user [style=dashed];
user -> ngcontroller:s [style=dashed];

Related

graphviz no line break (.dot)

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;

How to bind an ObjectBinding<BigDecimal> to a Label with a Formatter?

I have an ObservableList<Items> items and can calculate the sum of the items prices (BigDecimal) and bind the result to a labels text property in the following way:
totalSumLabel.textProperty().bind(
Bindings.createObjectBinding(() -> items.stream()
.map(item -> item.getPrice())
.reduce(BigDecimal.ZERO, BigDecimal::add),
items)
.asString("%.2f €"));
But now i would like to use a formatter (DecimalFormat) instead of the asString("%.2f €") method to be more flexible and i don't know how to realize that. It would be nice if someone could show how to implement the binding with a formatter (without the use of a listener when possible). Thank you.
With the help of Slaw's comment i was able to figure out the following working solution:
ObjectBinding<BigDecimal> totalSumObjectBinding = Bindings.createObjectBinding(() ->
items.stream()
.map(item -> item.getPrice())
.reduce(BigDecimal.ZERO, BigDecimal::add),
items);
DecimalFormat formatter = (DecimalFormat) NumberFormat.getCurrencyInstance(Locale.getDefault());
StringBinding totalSumStringBinding = Bindings.createStringBinding(() ->
formatter.format(totalSumObjectBinding.getValue()), totalSumObjectBinding);
totalSumLabel.textProperty().bind(totalSumStringBinding);
If there is an even more eloquent way, please let me know.

ArangoDB: traverse only edges within a time range

I am experimenting with time based versioning.
I have created a vertex that is connected to other vertices with this edge on one side:
{
"_id": "edges/426647569364",
"_key": "426647569364",
"_rev": "426647569364",
"_from": "nodes/426640688084",
"_to": "nodes/426629284820",
"valid_from": "1385787600000",
"valid_till": "9007199254740991"
}
And this edge on the other:
{
"_id": "edges/426679485396",
"_key": "426679485396",
"_rev": "426845488084",
"_from": "nodes/426675749844",
"_to": "nodes/426629284820",
"valid_from": "1322629200000",
"valid_till": "1417323600000"
}
The valid_till value in the first edge is the output of the Number.MAX_SAFE_INTEGER function.
I looked at custom vistors a little and it looks like its focused on filtering vertices rather than edges.
How can I restrict my traversal to edges with a valid_till value between new Date().getTime() and Number.MAX_SAFE_INTEGER?
You can use the followEdges attribute in a traversal.
followEdges can optionally be a JavaScript function for filtering edges. It will be invoked for each edge in the traversal:
var expandFilter = function (config, vertex, edge, path) {
return (edge.vaild_till >= new Date().getTime() &&
edge.valid_till <= Number.MAX_SAFE_INTEGER);
};
require("org/arangodb/aql/functions").register("my::expandFilter", expandFilter);
It can then be used in a traversal like a regular custom filter by specifying it in the followEdges attribute of the traversal options, e.g.:
LET options = {
followEdges: 'my::expandFilter'
}
FOR doc IN TRAVERSAL(nodes, edges, 'nodes/startNode', 'inbound', options)
RETURN doc.vertex

Graphviz Dot placing node inside subgraph even though it was defined elsewhere

I am trying to make a dot script generator for a homework problem, it's going well except I have this issue where some nodes that are not defined in subgraphs are being placed in them. For example the following dot script:
digraph dg {
compound=true;
labelloc="t";
label="test.cpp";
Vehicle;
Make;
subgraph clusterFord {
label="Ford"
Ford[shape="none"][style="invis"][label=""];
Mustang -> Vehicle [label="private"];
Thunderbird -> Vehicle [label="private"];
}
Ford -> Make [label="public"][ltail ="clusterFord"];
subgraph clusterChevrolet {
label="Chevrolet"
Chevrolet[shape="none"][style="invis"][label=""];
Camero -> Vehicle [label="private"];
}
Chevrolet -> Make [label="public"][ltail ="clusterChevrolet"];
}
Generates this image:
The "Vehicle" node is supposed to be outside of the "Ford" subrgraph. What am I missing here?
This will give what you want:
digraph dg {
compound=true;
labelloc="t";
label="test.cpp";
subgraph clusterFord {
label="Ford"
Ford[shape="none"][style="invis"][label=""];
Mustang
Thunderbird
}
subgraph clusterChevrolet {
label="Chevrolet"
Chevrolet[shape="none"][style="invis"][label=""];
Camero
}
Ford -> Make [label="public"][ltail ="clusterFord"];
Chevrolet -> Make [label="public"][ltail ="clusterChevrolet"];
Mustang -> Vehicle [label="private"];
Thunderbird -> Vehicle [label="private"];
Camero -> Vehicle [label="private"];
}

Graphviz subgraph alignment issue

I am trying to force the nodes to have a specified position in the graph. While doing so, the different sub-graphs are not aligned properly. The code to generate this graph is :
digraph {
rankdir=LR;
labeljust="l";
subgraph cluster0{
label="t=0"
n_3_0_0[label="192.168.8.6"
pos="15,12!"
];
n_3_0_1[label="192.168.8.3"
pos="10,10!"
];
n_3_0_0 -> n_3_0_1 ;
n_3_0_1 -> n_3_0_0 ;
};
subgraph cluster1{
label="t=5"
n_3_1_0[label="192.168.8.6"
pos="15,12!"
];
n_3_1_1[label="192.168.8.3"
pos="10,10!"
];
n_3_1_2[label="192.168.8.9"
pos="10,12!"
];
n_3_1_0 -> n_3_1_1 ;
n_3_1_1 -> n_3_1_0 ;
};
subgraph cluster2{
label="t=10"
n_3_2_0[label="192.168.8.6"
pos="14,10!"
];
n_3_2_1[label="192.168.8.3"
pos="10,10!"
];
n_3_2_2[label="192.168.8.9"
pos="15,11!"
];
n_3_2_3[label="192.168.8.8"
pos="18,12!"
];
n_3_2_0 -> n_3_2_1 ;
n_3_2_2 -> n_3_2_3 ;
n_3_2_1 -> n_3_2_0 ;
n_3_2_3 -> n_3_2_2 ;
};
}
I compiled this code by forcing the node position:
dot -Kfdp -n -Tpng -o sample.png test2.dot
The output graph is:
http://imageshack.us/photo/my-images/826/samplebg.png/
The problem with the output I got is:
1. the subgraph are NOT displayed in sequence of t=0, t-5, t=10...
2. the subgraph are NOT aligned to left.
I need to have output graph like this:
http://imageshack.us/photo/my-images/253/needed.png/
Thnak You.
Since you already precalculated the positions of all the nodes, you don't really need fdp - you just nead a layout which respects the pos attribute.
So you could generate the output like this:
neato -Tpng sourcedot.gv -O
But you'd have to adjust node positions before that, in order to have the subgraphs correctly stacked and not super-posed:
digraph {
rankdir=LR;
labeljust="l";
subgraph cluster0{
label="t=0"
n_3_0_0[label="192.168.8.6"
pos="15,4!"
];
n_3_0_1[label="192.168.8.3"
pos="10,2!"
];
n_3_0_0 -> n_3_0_1 ;
n_3_0_1 -> n_3_0_0 ;
};
subgraph cluster1{
label="t=5"
n_3_1_0[label="192.168.8.6"
pos="15,7!"
];
n_3_1_1[label="192.168.8.3"
pos="10,5!"
];
n_3_1_2[label="192.168.8.9"
pos="10,7!"
];
n_3_1_0 -> n_3_1_1 ;
n_3_1_1 -> n_3_1_0 ;
};
subgraph cluster2{
label="t=10"
n_3_2_0[label="192.168.8.6"
pos="14,8!"
];
n_3_2_1[label="192.168.8.3"
pos="10,8!"
];
n_3_2_2[label="192.168.8.9"
pos="15,9!"
];
n_3_2_3[label="192.168.8.8"
pos="18,10!"
];
n_3_2_0 -> n_3_2_1 ;
n_3_2_2 -> n_3_2_3 ;
n_3_2_1 -> n_3_2_0 ;
n_3_2_3 -> n_3_2_2 ;
};
}
Resulting in
(Some minor adjustments still needed for the label of the middle subgraph)
Or just use dot and let it align the nodes, too:

Resources