Bindings to Graphviz for graph visualisation. (http://projects.haskell.org/graphviz/)

#6Isn't monadic API with Haskell ids instead of strings nicer?

Hi, I have some feedback on the API of the graphviz library's monadic API (resulting form my explorations written down at http://mathoverflow.net/a/203099/13991 ).

Le jeudi 23 juin 2011 04:38:21 UTC+4, Ivan Lazar Miljenovic a écrit :

On 23 June 2011 02:48, Stephen Tetley <stephen...@gmail.com> wrote:
> Or Andy Gill&#39;s Dotgen - simple and stable:
>
> http://hackage.haskell.org/package/dotgen

Within the next month, I should hopefully finally finish the new
version of graphviz.  Various improvements include:
As such, I would greatly appreciate knowing what it is that makes you

want to use a different library (admittedly the graphviz API isn&#39;t as
stable as the others, but that&#39;s because I keep trying to improve it,
and typically state in the Changelog exactly what has changed).

### graphviz Haskell library and other ones

An alternative to "graphviz" Haskell package mentioned in haskell-cafe is dotgen.

In a follow-up to the post mentioning dotgen, the author of graphviz gives some comparison between them (and other similar Haskell libs). I assume his "plans" (about a monadic interface) have been implemented already:

> Within the next month, I should hopefully finally finish the new > version of graphviz. Various improvements include: > > ... > > * A Dot graph representation based loosely upon dotgen's monadic interface (with Andy's blessing) but with the various Attributes being > used rather than (String, String). I think I'm going to be able to > make it such that you can define a graph using the monadic interface > that will almost look identical to actual Dot code. > > ... > > I would like to stress to people considering using other bindings to > Graphviz/Dot (such as dotgen, language-dot, or their own > cobbled-together interface): be very careful about quoting, etc. I > have spent a lot of time checking how to properly escape different > values and ensuring correctness under the hood (i.e. there is no need > to pre-escape your Text/String values; graphviz will do that for you > when generating the actual Dot code). This, after all, is the point > of having existing libraries rather than rolling your own each time.

Both points are related. (So, graphviz's monadic iterface is a safer improvement upon dotgen's one.)

Considering dotgen vs graphviz closer

But looking into the examples, I see that dotgen can use "Haskell ids" to identify created nodes, whereas in graphviz's monad (see the example above) one must supply extra strings as the unique ids (by which we refer to the nodes).

I like the first approach more ("Haskell ids").

Cf. dotgen (from https://github.com/ku-fpg/dotgen/blob/master/test/DotTest.hs):

module Main (main) where
import Text.Dot
-- data Animation = Start
src, box, diamond :: String -> Dot NodeId
src label = node $ [ ("shape","none"),("label",label) ]
box label = node $ [ ("shape","box"),("style","rounded"),("label",label) ]
diamond label = node $ [("shape","diamond"),("label",label),("fontsize","10")]
main :: IO ()
main = putStrLn $ showDot $ do
attribute ("size","40,15")
attribute ("rankdir","LR")
refSpec <- src "S"
tarSpec <- src "T"
same [refSpec,tarSpec]
c1 <- box "S"
c2 <- box "C"
c3 <- box "F"
same [c1,c2,c3]
refSpec .->. c1
tarSpec .->. c2
tarSpec .->. c3
m1 <- box "x"
m2 <- box "y"
ntm <- box "z"
same [m1,m2,ntm]
c1 .->. m1
c2 .->. m2
xilinxSynthesis <- box "x"
c3 .->. xilinxSynthesis
gns <- box "G"
xilinxSynthesis .->. gns
gns .->. ntm
ecs <- sequence
[ diamond "E"
, diamond "E"
, diamond "Eq"
]
same ecs
m1 .->. (ecs !! 0)
m1 .->. (ecs !! 1)
m2 .->. (ecs !! 0)
m2 .->. (ecs !! 2)
ntm .->. (ecs !! 1)
ntm .->. (ecs !! 2)
_ <- sequence [ do evidence <- src "EE"
n .->. evidence
| n <- ecs
]
edge refSpec tarSpec [("label","Engineering\nEffort"),("style","dotted")]
() <- scope $ do v1 <- box "Hello"
v2 <- box "World"
v1 .->. v2
(x,()) <- cluster $
do v1 <- box "Hello"
v2 <- box "World"
v1 .->. v2
-- x .->. m2
-- for hpc
() <- same [x,x]
v <- box "XYZ"
v .->. v
() <- attribute ("rankdir","LR")
let n1 = userNodeId 1
let n2 = userNodeId (-1)
() <- n1 `userNode` [ ("shape","box")]
n1 .->. n2
_ <- box "XYZ"
_ <- box "(\n\\n)\"(/\\)"
netlistGraph (\ a -> [("label","X" ++ show a)])
(\ a -> [succ a `mod` 10,pred a `mod` 10])
[ (n,n) | n <- [0..9] :: [Int] ]
return ()

Cf. graphviz with string ids:

A short example of the monadic notation from the documentation:

digraph (Str "G") $ do

    cluster (Int 0) $ do
        graphAttrs [style filled, color LightGray]
        nodeAttrs [style filled, color White]
        "a0" --> "a1"
        "a1" --> "a2"
        "a2" --> "a3"
        graphAttrs [textLabel "process #1"]

    cluster (Int 1) $ do
        nodeAttrs [style filled]
        "b0" --> "b1"
        "b1" --> "b2"
        "b2" --> "b3"
        graphAttrs [textLabel "process #2", color Blue]

    "start" --> "a0"
    "start" --> "b0"
    "a1" --> "b3"
    "b2" --> "a3"
    "a3" --> "end"
    "b3" --> "end"

    node "start" [shape MDiamond]
    node "end" [shape MSquare]

Thanks for the packages, and best wishes, Ivan Z.