Control the layout of nodes in graphviz (dot2tex)? - layout

I am new to graphviz and am just wondering how to determine the relative node positioning in a graph. For example, if I want to draw a simple triangle 'abc', with node 'a' being at the top and nodes 'b' and 'c' on the same level at the bottom, how should I tell graphviz to lay out the nodes as desired?
I tried the following:
graph G
{
node [shape="circle"];
edge [lblstyle="auto"];
{rank=min; "a"}
a -- b [label = "-"];
a -- c [label = "-"];
{rank=same; "b" "c"}
b -- c [label = "+"];
}
but the output positions nodes 'a' and 'b' on the same level at the top, with node 'c' at the bottom.
In addition, is it possible to draw two such triangles side-by-side (with a nice appropriate space in between) in the same graph? if so, how is it implemented?
Thanks a lot.

but the output positions nodes 'a' and 'b' on the same level at the
top, with node 'c' at the bottom.
I actually get a on top, centered above b and c (see image).
Your markup, slightly simplified (what's lblstyle ?), seems to achieve what you want when rendered with dot:
graph G
{
node[shape=circle];
a -- b [label = "-"];
a -- c [label = "-"];
{rank=same; b -- c [label="+"];}
}
What version of graphviz do you use?
And to have two triangles side by side:
graph G
{
node[shape=circle];
edge[label="-"];
a -- b;
a -- c;
{rank=same; b -- c [label="+"];}
d -- e;
d -- f;
{rank=same; e -- f [label="+"];}
}
However, if things get more complex, it may be difficult to have graphviz layout everything exactly as one would like. That's actually the strength of graphviz - applying layout algorithms in order to not have a user intervene.

Related

Is there a container type in Haskell Diagrams?

I am trying to map out some data in Diagrams. I am completely new to Diagrams, but I essentially want to have a rectangle, that grows when I put other diagrams atop of it. I have scoured the docs, but havn't found anything.
Does there exist such a shape, or a way to know how much to scaleY?
If all you need is a rectangle surrounding some diagram(s), boundingRect might be enough. It could look like this (note the pad is entirely optional):
-- Arbitrary example, taken from the manual.
contents :: Diagram B
contents = c ||| hrule 1 ||| c
where
c = circle 1 <> vrule 2
-- Adding a bounding rectangle around it, with a little padding.
example :: Diagram B
example = contents <> bounds
where
bounds = boundingRect (contents # pad 1.1)
# lc red

Breadth-first search with spiral ordered list of coordinates in Haskell

edit: This is getting down voted but it's not been made clear what data structure I should be using instead of a list of coordinates. Unfortunately my data comes as a flat list and it needs to be distributed with in an outwards clockwise spiral. Then run a BFS on that to work out islands. I used coordinates which is what the C++ code tutorial seem to do (I have zero C++ experience though) but seems that was a bad route to take in Haskell
I'm trying to accumulate a list of touching land cells grouped by islands.
Looking at the image bellow I'd expect 5 islands and each with the cells on that island. [[Cell]].
My input is currently a flat list of cells ordered in a clockwise spiral (red dotted line) and a number of the population of the cell. 0 making it sea and any >= 1 is the population.
data Cell = Cell
{ cellLoc :: (Int, Int)
, cellpop :: Int -- 0 sea, >= 1 population of land
}
startingCellList :: [Cell]
startingCellList =
[(Cell (1,0) 0)
,(Cell (1,-1) 0)
,(Cell (0,-1) 0)
,(Cell (-1,-1) 4)
]
The cellLoc gives me coordinates of cell in an X Y plane with (0,0) being at the centre of the grid. Am I right in thinking I can use the those coordinates to run my BSF?
Or do I need to rethink the use of coordinates to achieving my grid?
I've also found this great example but I'm not grasping it's use of vertexes and how or if I can relate it to using coordinates.
You can convert the list [(Int,Int)] into a Data.Set (Int,Int). Then you can quickly compute adjacency for your graph in the following way. Using this you can build your graph algorithm that finds components (in the complement of the graph, whatever).
import Data.Set
-- compute all possible neighbours as difference vectors
let adjDiff = [(dx,dy) | dx <- [-1..1], dy <- [-1..1], (dx,dy) /= (0,0)]
-- given a cell, compute all potential neighbouring cells
let adjFull (x,y) = [(x',y') | (dx,dy) <- adjDiff, let x'=x+dx, let y'=y+dy]
-- given a set of valid cells and a cell, compute all valid neighbours of this cell
let adj validCells cell = [n | n <- adjFull cell, member ValidCells n]

TI-BASIC (TI-84) Solving for the Sides of a Triangle

Could someone tell me if I've coded this correctly? This is my code for solving for the sides of a triangle given its perimeter, altitude, and angle (for the algebra see http://www.analyzemath.com/Geometry/challenge/triangle_per_alt_angle.html)
Prompt P
Prompt H
Prompt L [the angle]
(HP^2)/(2H(1+cos(L))+2Psin(L))→Y
(-P^2-2(1+cos(L))Y/(-2P)→Z
(Z+sqrt(Z^2-4Y))/2→N
[The same as above but Z-sqrt...]→R
If N>0
N→U
If R>0
R→U
Y/U→V
sqrt(U^2+V^2-2UVcos(L))→W
Disp U
Disp V
Disp W
Also, how would I fix this so that I can input angle = 90?
Also, in this code does it matter if the altitude is the one between b and c (refer to the website again)?
Thanks in advance
The code already works with L=90°.
Yes, the altitude must be the distance from point A to the base a between points B and C, forming a right-angle with that base. The derivation made that assumption, specifically with respect to the way it used h and a in the second area formula 1/2 h a. That exact formula would not apply if h was drawn differently.
The reason your second set of inputs resulted in a non-real answer is that sometimes a set of mathematical parameters can be inconsistent with each other and describe an impossible construct, and your P, h, and L values do exactly that. Specifically, they describe an impossible triangle.
Given an altitude h and angle L, the smallest perimeter P that can be achieved is an isosceles triangle split down the middle by h. With L=30, this would have perimeter P = a + b + c = 2h tan15 + h/cos15 + h/cos15, which, plugging in your h=3, results in P=7.819. You instead tried to use P=3+sqrt(3)=4.732. Try using various numbers less than 7.819 (plus a little; I've rounded here) and you'll see they all result in imaginary results. That's math telling you you're calculating something that cannot exist in reality.
If you fill in the missing close parenthesis between the Y and the / in line 5, then your code works perfectly.
I wrote the code slightly differently from you, here's what I did:
Prompt P
Prompt H
Prompt L
HP²/(2H(1+cos(L))+2Psin(L))→Y
(HP-Ysin(L))/H→Z
Z²-4Y→D
If D<0:Then
Disp "IMAGINARY"
Stop
End
(Z+√(D))/2→C
Y/C→B
P-(B+C)→A
Disp A
Disp B
Disp C
Edit: #Gabriel, there's nothing special (with respect to this question) about the angles 30-60-90; there is an infinite number of sets of P, h, and L inputs that describe such triangles. However, if you actually want to arrive at such triangles in the answer, you've actually changed the question; instead of just knowing one angle L plus P and h, you now know three angles (30-60-90) plus P and h. You've now over-specified the triangle, so that it is pretty well certain that a randomly generated set of inputs will describe an impossible triangle. As a contrived example, if you specified h as 0.0001 and P as 99999, then that's clearly impossible, because a triangle with a tiny altitude and fairly unextreme angles (which 30-60-90 are) cannot possibly achieve a perimeter many times its altitude.
If you want to start with just one of P or h, then you can derive equations to calculate all parameters of the triangle from the known P or h plus the knowledge of the 30-60-90 angles.
To give one example of this, if we assume that side a forms the base of the triangle between the 90° and 60° angles, then we have L=30 and (labelling the 60° angle as B) we have h=b, and you can get simple equations for all parameters:
P = a + h + c
sin60 = h/c
cos60 = a/c
=> P = c cos60 + c sin60 + c
P = c(cos60 + sin60 + 1)
c = P/(cos60 + sin60 + 1)
b = h = c sin60
a = c cos60
Plugging in P=100 we have
c = 100/(cos60 + sin60 + 1) = 42.265
b = h = 36.603
a = 21.132
If you plug in P=100, h=36.603, and L=30 into the code, you'll see you get these exact results.
Always optimize for speed, then size.
Further optimizing bgoldst's code:
Prompt P,H,L
HP²/(2H(1+cos(L))+2Psin(L
.5(Z+√((HP-sin(L)Ans)/H)²-4Ans
{Y/C→B,P-B-Ans,Ans

Separating State for a Model and GUI IO ( Wx) : Stack or FRP?

For my diagramming tool, I'd like to keep the code of the core model isolated from the GUI.
In the following example, the "state " is passed around with vDiag, which is a Tvar. This is a design decision in wx. Now, For my diagramming tool, I 'd like the core model to be "stored" in a fgl Graph, (with complex types in it), and wx will be given only a view on it; say in this example, a list of points for read access when painting, and some functions to write when clicking, dragging, etc.. . I thought first to some Monad stack, but even combining a StateT and the IO from wx does not look trivial , because the io actions are spread all over in the code of the callback (on click , on paint…etc ). It feels like having IO at the bottom of the stack does not fit well anymore.
so how to you pass a STate around, or is it not the way to go ? ( I intuition this is a classic. is this how RFP started ? )
(In the code, which paints red circle when there is a click , the list of points are passed around in a Tvar vDiag. I have tagged "--fgl" where equivalent state accessor would go. and set up a basic fgl test graph accessors to illustrate . I would like to put in a State)
(I originally tried to give it a go without FRP - reactive banana, to understand the problem, but I think I may have already hit it ;-)
module Main where
import Graphics.UI.WX hiding (empty)
import Data.Graph.Inductive
main
= start ballsFrame
ballsFrame
= do
vDiag <- varCreate []
--gDiag <- initg -- fgl
frame <- frame [text := "Demo"]
p <- panel frame []
file <- menuPane [text := "&File"]
quit <- menuQuit file [on command := close frame]
set frame [text:= "testing", menuBar := [file] ]
set p [on click := drawBins vDiag p , on paint := paintDiag vDiag ]
-- fgl pass the var around
return ()
where
drawBins d ppanel pt =
do varUpdate d (pt:)
-- addpoint f g -- fgl : insert a point
repaint ppanel
-- paint the balls
paintDiag vdiag dc view
= do balls <- varGet vdiag -- getPointsFromGraph
-- fgl : change to get the list of points
set dc [brushColor := red, brushKind := BrushSolid]
mapM_ (drawDiag dc) balls
drawDiag dc pt
= circle dc pt 10 []
-- basic fgl test graph accessors I would like to put in a State and replace vDiag
initg:: Gr Point String
initg = mkGraph [(1,pt 10 10),(2,pt 30 30)] [(1,2,"truc"), (2,1,"revtruc")]
getPointsFromGraph :: Graph gr => gr b b1 -> [b]
getPointsFromGraph g = map snd $ labNodes g
-- getPointsFromGraph initg = [Point {pointX = 10, pointY = 10},Point {pointX = 30, pointY = 30}]
addpoint :: DynGraph gr => a -> gr a b -> gr a b
addpoint p g = -- add a point p into graph p
insNode (4,p) g

Check if coordinate in selected area

I have 4 coordinates of area: x1,y1 ... etc. And have one more position x0,y0.
How to check if my coordinate in selected area?
I will explain you how to check that (x0,y0) lies "below" the line through (x1,y1) and (x2,y2). Essentially, you want that the vector (x0-x1,y0-y1) points "to the right" of (x2-x1, y2-y1). This is equivalent to saying that the matrix
x0-x1 y0-y1
x2-x1 y2-y1
has a negative determinant. So your condition becomes
(x0-x1)(y2-y1) < (y0-y1)(x2-x1).
You get such a condition for any line bounding the area.
Let
A = {x1, y1}
B = {x2, y2}
C = {x3, x3}
D = {x4, x4}
First, make sure that points form a polynomial and are not in straight line. This can be done by comparing the direction(AB) != direction(AC) != direction(AD) where AB, AC, AD are directional vectors.
To make sure that certain point P = {x0, y0} lies within the polygon ABCD, it is sufficient to check that sign(AC X AP) == sign(CD X CP) == sign(DB X DP) == sign(BA X BP).
AC: Directional vector A -> C
AP: Directional vector A -> P
.
. so on!
.
X: Cross product
sign: sign of cross product (+ or -)
It is only required to compare the sign of direction not the magnitude.

Resources