Graphviz aligning subgraphs horizontally - alignment

I have the following code:
digraph G {
bgcolor=antiquewhite;
compound=true;
{
rankdir=LR ;
rank=same g0 p1 p2 p3 h1;
}
subgraph cluster0 {
style=filled;
color=khaki;
g0 [label="G",shape=circle,style="filled", color="red", fillcolor="lightpink"]
label = "Cluster 0";
g0 -> p1;
}
subgraph cluster1 {
style=filled;
color=khaki;
p1 [label="S2",shape=box,style="filled", color="blue", fillcolor="skyblue"];
p2 [label="S3",shape=box,style="filled", color="blue", fillcolor="skyblue"];
p3 [label="S3",shape=box,style="filled", color="blue", fillcolor="skyblue"];
label = "Cluster 1";
p1 -> p2 -> p3 [arrowhead=none] ;
}
subgraph cluster2 {
style=filled;
color=khaki;
h1 [label="h1",shape=box,style="invis"];
label = "Cluster 2";
p3 -> h1;
}
}
Everything works perfect except the subgraphs don't show up. As soon as rank is defined outside the clusters the subgraphs disappear.
If defined inside a cluster body, same rank between clusters is lost.

rankdir is only applicable at graph level
a node may belong to one cluster only
.
digraph G {
rankdir=LR ;
bgcolor=antiquewhite;
compound=true;
subgraph cluster0 {
style=filled;
color=khaki;
g0 [label="G",shape=circle,style="filled", color="red", fillcolor="lightpink"]
label = "Cluster 0";
}
subgraph cluster1 {
style=filled;
color=khaki;
p1 [label="S2",shape=box,style="filled", color="blue", fillcolor="skyblue"];
p2 [label="S3",shape=box,style="filled", color="blue", fillcolor="skyblue"];
p3 [label="S3",shape=box,style="filled", color="blue", fillcolor="skyblue"];
label = "Cluster 1";
p1 -> p2 -> p3 [arrowhead=none] ;
}
subgraph cluster2 {
style=filled;
color=khaki;
h1 [label="h1",shape=box,style="invis"];
label = "Cluster 2";
}
g0 -> p1;
p3 -> h1;
}
gives

Related

Tail recursive addition of Peano numbers in F# using accumulators

At Uni we were given a challenge of creating a tail recursive addition of Peano numbers using an accumulator. We aren't allowed to use any library function or other functions that we have created, but we are allowed to 'hide' the accumulator in an auxiliary function
Here's the type
type Peano =
| O
| S of Peano
I'm stuck at how to execute the accumulator as it has no operation on the type defined, i.e. the following is not possible
let tailAdd p1 p2 =
let rec aux p1 p2 acc =
match p1, p2 with
| O, _ -> acc
| S v, b -> aux v b (acc + v)
aux p1 p2 O
Help xD
I don't want to give away the answer, since this is a homework problem, but I'll give you a hint: In the case where p1 matches with S v, you know that v = p1 - 1. Therefore, p1 + p2 = v + (p2 + 1). So how do you write p2 + 1 in Peano numbers?
Figured it out
let tailAdd p1 p2 =
let rec aux p1 p2 acc =
match p1, p2 with
| O, O -> acc
| a, S v -> aux v a (S (acc))
| S v, b -> aux v b (S (acc))
aux p1 p2 O

Ray Tracing F# - Missing triangles creates holes in figure: Hit properly?

I have worked on this quite a while and is stuck with this bug.
We have build a ray-tracer in F# for a school project. (Link explaining Ray tracer: https://blog.frogslayer.com/kd-trees-for-faster-ray-tracing-with-triangles/)
We have a made hit function for triangles, boundingboxes, a KD tree to handle figures with thousands of triangles, such as the Stanford Bunny and a traverse algorithm for the KD tree.
We have debugged both the creation of the KD tree, made sure to add a epsilon value for float points and checked that duplicates between the boundingboxes are not removed. We are certain that we split the list of shapes in the scene corretly, but we get "holes" in the figure we try to render.
This is our KD tree implementation and I've attached pictures of the holes:
Stanford Bunny
Helix
module TmKdtree
open Point
open Shapes
type BoundingBox = BasicShape.BoundingBox
type Shape = BasicShape.Shape
type TmKdtree =
| Leaf of BasicShape.Triangle list * BoundingBox
| Node of BasicShape.Triangle list * TmKdtree * TmKdtree * BoundingBox * (string*Point)
let epsilon = 0.001
//Making a boundingbox for the KD-tree, by finding max H point in the boundingboxlist and min l point in the boundingbox list.
let mkKdBbox (shapes : BasicShape.Triangle list) : BoundingBox =
let shapeX = List.map(fun x -> x:> Shape) shapes
let sbbox = List.map (fun (c:Shape) -> c.getBounding().Value) shapeX
let bL = List.map (fun (b:BasicShape.BoundingBox) -> b.getL) sbbox
let bH = List.map (fun (b:BasicShape.BoundingBox) -> b.getH) sbbox
let minX = List.minBy (fun x -> Point.getX x) bL
let minY = List.minBy (fun x -> Point.getY x) bL
let minZ = List.minBy (fun x -> Point.getZ x) bL
let maxX = List.maxBy (fun x -> Point.getX x) bH
let maxY = List.maxBy (fun x -> Point.getY x) bH
let maxZ = List.maxBy (fun x -> Point.getZ x) bH
{p1=(mkPoint (Point.getX minX - epsilon) (Point.getY minY - epsilon) (Point.getZ minZ - epsilon) )
; p2=(mkPoint (Point.getX maxX + epsilon) (Point.getY maxY + epsilon) (Point.getZ maxZ + epsilon) )}
//Splitting existing boundingbox according to left and right list of shapes
let BoundingBoxL (bbox:BoundingBox) axis midp : BoundingBox =
match axis with
| "x" -> {p1 = bbox.getL - epsilon; p2 = Point.mkPoint ((Point.getX midp)) ((Point.getY (bbox.getH))) ((Point.getZ (bbox.getH))) + epsilon}
| "y" -> {p1 = bbox.getL - epsilon; p2 = Point.mkPoint (Point.getX (bbox.getH)) ((Point.getY midp)+epsilon) ((Point.getZ (bbox.getH))) + epsilon }
| "z" -> {p1 = bbox.getL - epsilon; p2 = Point.mkPoint (Point.getX (bbox.getH)) (Point.getY (bbox.getH)) (Point.getZ midp) + epsilon}
let BoundingBoxR (bbox:BoundingBox) axis midp : BoundingBox =
match axis with
| "x" -> {p1 = (Point.mkPoint (Point.getX midp) (Point.getY (bbox.getL)) (Point.getZ (bbox.getL))) - epsilon; p2 = bbox.getH + epsilon}
| "y" -> {p1 = (Point.mkPoint (Point.getX (bbox.getL)) (Point.getY midp) (Point.getZ (bbox.getL))) - epsilon; p2 = bbox.getH + epsilon}
| "z" -> {p1 = (Point.mkPoint (Point.getX (bbox.getL)) (Point.getY (bbox.getL)) (Point.getZ midp)) - epsilon; p2 = bbox.getH + epsilon}
//Get left node
let getLeft s =
match s with
| Node(_,l,_,_,_) -> l
| Leaf(_,_) as leaf -> leaf
let getRight s =
match s with
| Node(_,_,r,_,_) -> r
| Leaf(_,_) as leaf -> leaf
//Get the triangle list
let getShapes s =
match s with
| Node(b,_,_,_,_) -> b
| Leaf(b,_) -> b
let getAxis s =
match s with
| Node(_,_,_,_,a) -> a
| Leaf(_,_) -> failwith "leaf ramt af axis"
//Get bounding box
let getBox s =
match s with
| Node(_,_,_,b,_) -> Some b
| Leaf(_,b) -> Some b
let closestHit (triList : BasicShape.Triangle list) ray =
let sndRects = List.map(fun x -> x:> Shape) triList
let min = List.map(fun (x:Shape) -> x.hit ray) sndRects |> List.choose id
match min with
|[] -> None
|_ -> Some(List.minBy (fun (di, nV, mat) -> di) min)
let searchLeaf leaf ray t' =
match leaf with
| Leaf(s,_) -> let hit = closestHit s ray
match hit with
|Some(f,_,_) -> if (f<t') then Some hit else None
|None -> None
| Node(_,_,_,_,_) -> failwith "Expected leaf"
let order(d, left, right) =
if d > 0.0
then (left, right)
else (right, left)
let rec search node ray t t' =
match node with
|Leaf(_,_) -> searchLeaf node ray t'
|Node(_,_,_,_,a') ->
let direction = Ray.getDirection ray (fst a')
let origin = Ray.getOrigin ray (fst a')
let nodeValue = Point.getFromAxis (snd a') (fst a')
if(direction) = 0.0 then
printfn("%s") "flatsite"
if(origin <= nodeValue) then search (getLeft node) ray t t'
else search (getRight node) ray t t'
else
let tHit = (nodeValue - origin) / direction
let (fst, snd) = order(direction,getLeft node, getRight node)
if tHit <= t || tHit < 0.0 then
search snd ray t t'
else if tHit >= t' then
search fst ray t t'
else
match search fst ray t tHit with
|Some hit -> Some hit
|_ -> search snd ray tHit t'
let traverse tree ray (bawx:BasicShape.BoundingBox) =
match(bawx).hit(ray) with
|Some(t,t') -> search tree ray t t'
|None -> None
//Finding the midpoint in the triangles in Shapes-list - we do this (recursively) to find out what axis to split
let rec mkTmKdtree (shapes : BasicShape.Triangle list) (box:BasicShape.BoundingBox) =
//Finding biggest dimension in the shapes list
let axis = snd (box.getLongestAxis)
let axisMidPoint =
let midPoint = List.fold (fun acc (ele:BasicShape.Triangle) -> (acc + ele.getMidPoint())) (Point.mkPoint 0.0 0.0 0.0) shapes
let avgMid = midPoint / float(shapes.Length)
avgMid
let rec largerThanSplit (xs:BasicShape.Triangle list) =
let results = List.choose(fun (elem:BasicShape.Triangle) ->
match axis with
|"x" -> if (Point.getX (elem.getMidPoint())) >= (Point.getX axisMidPoint) then Some elem else None
|"y" -> if (Point.getY (elem.getMidPoint())) >= (Point.getY axisMidPoint) then Some elem else None
|"z" -> if (Point.getZ (elem.getMidPoint())) >= (Point.getZ axisMidPoint) then Some elem else None) xs
results
let rec lessThanSplit (xs:BasicShape.Triangle list) =
let results = List.choose(fun (elem:BasicShape.Triangle) ->
match axis with
|"x" -> if ((Point.getX (elem.getMidPoint())) <= (Point.getX (axisMidPoint))) then Some elem else None
|"y" -> if ((Point.getY (elem.getMidPoint())) <= (Point.getY (axisMidPoint))) then Some elem else None
|"z" -> if ((Point.getZ (elem.getMidPoint())) <= (Point.getZ (axisMidPoint))) then Some elem else None) xs
results
//Creating the left and right list from the above
let rightTest = largerThanSplit shapes
let leftTest = lessThanSplit shapes
//If one of the trees are empty, we add make left and right equivelant.
let left = if(leftTest.IsEmpty && rightTest.Length > 0) then rightTest else leftTest
let right = if(rightTest.IsEmpty && leftTest.Length > 0) then leftTest else rightTest
//Check for duplicates among the lists.
if(((float(left.Length+right.Length-shapes.Length)/float(shapes.Length)) < 0.4) && left.Length <> shapes.Length && right.Length<>shapes.Length) then
let leftTree = mkTmKdtree left (BoundingBoxL box axis axisMidPoint)
let rightTree = mkTmKdtree right (BoundingBoxR box axis axisMidPoint)
Node(shapes,leftTree, rightTree, (box),(axis,axisMidPoint))
else Leaf(shapes, (box))
Thank you for the responses! I turned out that the bug was in our reflections of the figures, and had nothing to do with the data structure of the program.
But thank you anyway! :-)

How to align subgraphs in dot files

I am trying to align three or more subgraphs using dot files and graphviz. I think my problem is best shown using a few examples:
My first try:
digraph FutopJobFlow {
rankdir=LR;
node [shape=box]
compound=true
subgraph clusterA {label = " A ";
A -> a1;
a1 -> a2;
a2 -> a3;
}
subgraph clusterB {label = " B ";
B -> b1;
b1 -> b2;
}
subgraph clusterC {label = " C ";
C -> c1;
c1 -> c2;
}
A -> B [lhead=clusterB];
B -> C [lhead=clusterC];
X -> A [lhead=clusterA];
Y -> B [lhead=clusterB];
Z -> C [lhead=clusterC];
}
giving this result:
Here the individual subgraphs looks like i would like but the are not aligned. I therefore tried wit the command rank:
digraph FutopJobFlow {
rankdir=LR;
node [shape=box]
compound=true
subgraph clusterA {label = " A ";
A -> a1;
a1 -> a2;
a2 -> a3;
}
subgraph clusterB {label = " B ";
B -> b1;
b1 -> b2;
}
subgraph clusterC {label = " C ";
C -> c1;
c1 -> c2;
}
{rank=same; A; B; C;}
A -> B [lhead=clusterB];
B -> C [lhead=clusterC];
X -> A [lhead=clusterA];
Y -> B [lhead=clusterB];
Z -> C [lhead=clusterC];
}
which result in this graph:
Here the alignment looks good but now the 'A', 'B' and 'C' is no longer inside the subgraphs!
I have tried several other ways to achieve both the alignment and that 'A', 'B' and 'C' is inside their respective subgraphs but with no succes.
Can anybody help?
# Marapet - Thanks it is almost perfect now - it looks like this when i add the 'constraint=false' parameter:
Graph with constraint parameter
It would be perfect if the subgraph 'A' is above 'B' which again is above 'C'.
In the first version of your graph, you can disable the effect on node ranking for the edges between A-B and B-C by adding the attribute constraint=false:
A -> B [lhead=clusterB, constraint=false];
B -> C [lhead=clusterC, constraint=false];
The subgraphs should then be aligned.

Calculating similarity index between two movies(Neo4j, cypher)

In extension to this
Multiple relationships in Match Cypher
MATCH (m:Movie { title: "The Matrix" })-[h1:HAS_TAG]->(t:Tag),
(t)<-[h2:HAS_TAG]-(sm:Movie),
(m)-[h:HAS_TAG]->(t0:Tag),
(sm)-[H:HAS_TAG]->(t1:Tag)
WHERE m <> sm
WITH DISTINCT sm, h
RETURN sm, collect(h.weight)
I am finding trouble in getting the distinct values of h1, h2, H, h all at the same time.
I want to calculate the similarity index between any two movies which will be dependent on h1, h2, h, H (h1.h2/|h||H|)
MATCH (m:Movie { title: "The Matrix" })-[h1:HAS_TAG]->(t:Tag),
(t)<-[h2:HAS_TAG]-(sm:Movie),
(m)-[h:HAS_TAG]->(t0:Tag),
(sm)-[H:HAS_TAG]->(t1:Tag)
WHERE m <> sm
WITH sum(h1.weight*h2.weight) as num, sm, H, m, h
WITH DISTINCT m, sqrt(sum(h.weight^2)) as den1, sm, H, num
WITH DISTINCT sm, sqrt(sum(H.weight^2)) as den2, den1, num
RETURN num/(den1*den2)
This is all messed up..But I am unable to figure out the right way to solve this. Please help.
This works and gives the correct answer...
MATCH (m:Movie { title: "The Matrix" })-[h1:HAS_TAG]->(t:Tag)<-[h2:HAS_TAG]-(sm)
WHERE m <> sm
WITH SUM(h1.weight * h2.weight) AS num,
SQRT(REDUCE(xDot = 0.0, a IN COLLECT(h1)| xDot + a.weight^2)) AS xLength,
SQRT(REDUCE(yDot = 0.0, b IN COLLECT(h2)| yDot + b.weight^2)) AS yLength, m, sm
RETURN num, xLength, yLength
Take a look at this example I generated using the Neo4j Console:
http://console.neo4j.org/?id=aq6cb3
The query should be:
MATCH (m:Movie { title: "The Matrix" })-[h1:HAS_TAG]->(t:Tag),
(t)<-[h2:HAS_TAG]-(sm:Movie),
(m)-[h:HAS_TAG]->(t0:Tag),
(sm)-[H:HAS_TAG]->(t1:Tag)
WHERE m <> sm
WITH m, sm,
collect(DISTINCT h) AS h,
collect(DISTINCT H) AS H,
sum(h1.weight*h2.weight) AS num
WITH m, sm, num,
sqrt(reduce(s = 0.0, x IN h | s +(x.weight^2))) AS den1,
sqrt(reduce(s = 0.0, x IN H | s +(x.weight^2))) AS den2
RETURN m.title, sm.title, (num/(den1*den2)) AS similarity
Which results in the following:
+---------------------------------------------------------------+
| m.title | sm.title | similarity |
+---------------------------------------------------------------+
| "The Matrix" | "The Matrix: Revolutions" | 3.859767091086958 |
| "The Matrix" | "The Matrix: Reloaded" | 1.4380667053087486 |
+---------------------------------------------------------------+
I used the reduce function to aggregate the relationship values from a distinct collection and perform the similarity index calculation.

Vertically aligning a node joining subgraphs in Graphviz

I give the following input to Dot:
digraph G {
subgraph cluster1 {
fontsize = 20;
label = "Group 1";
A -> B -> C -> D;
style = "dashed";
}
subgraph {
O [shape=box];
}
subgraph cluster2 {
fontsize = 20;
label = "Group 2";
Z -> Y -> X -> W [dir=back];
style = "dashed";
}
D -> O [constraint=false];
W -> O [constraint=false, dir=back];
}
And it produces:
How can I align node O so that it has the same rank as D and W? That is, a graph that looks like:
A Z
| |
B Y
| |
C X
| |
D-O-W
Adding
{ rank=same; D; O; W; }
yields the error
Warning: D was already in a rankset, ignored in cluster G
Warning: W was already in a rankset, ignored in cluster G
I'm thinking I can hack it by adding invisible nodes and edges to the subgraph of O, but I was wondering if I was missing some Dot magic.
You could use an approach with rankdir=LR and use constraint=false for the edges inside the clusters:
digraph G {
rankdir=LR;
subgraph cluster1 {
fontsize = 20;
label = "Group 1";
rank=same;
A -> B -> C -> D [constraint=false];
style = "dashed";
}
subgraph cluster2 {
fontsize = 20;
label = "Group 2";
rank=same;
Z -> Y -> X -> W [dir=back, constraint=false];
style = "dashed";
}
O [shape=box];
D -> O -> W;
}
It's not dot magic :-), but it achieves this:
Hacking with invisible nodes does also work:
digraph G {
subgraph cluster1 {
fontsize = 20;
label = "Group 1";
A -> B -> C -> D;
style = "dashed";
}
subgraph {
O1[style=invis];
O2[style=invis];
O3[style=invis];
O [shape=box];
O1 -> O2 -> O3 -> O [style=invis];
}
subgraph cluster2 {
fontsize = 20;
label = "Group 2";
Z -> Y -> X -> W [dir=back];
style = "dashed";
}
edge[constraint=false];
D -> O -> W;
}
The result is almost identical:

Resources