haskell-igraph-0.3.0: src/IGraph/Exporter/GEXF.hs
module IGraph.Exporter.GEXF
( NodeAttr(..)
, defaultNodeAttributes
, EdgeAttr(..)
, defaultEdgeAttributes
, genXMLTree
, writeGEXF
) where
import Data.Hashable
import Data.Colour (AlphaColour, black, over, alphaChannel, opaque)
import Data.Colour.SRGB (toSRGB24, channelRed, channelBlue, channelGreen)
import Text.XML.HXT.Core
import Data.Tree.NTree.TypeDefs
import Text.XML.HXT.DOM.TypeDefs
import IGraph
data NodeAttr = NodeAttr
{ _size :: Double
, _nodeColour :: AlphaColour Double
, _nodeLabel :: String
, _positionX :: Double
, _positionY :: Double
, _nodeZindex :: Int
} deriving (Show, Read, Eq)
instance Hashable NodeAttr where
hashWithSalt salt at = hashWithSalt salt $ _nodeLabel at
defaultNodeAttributes :: NodeAttr
defaultNodeAttributes = NodeAttr
{ _size = 0.15
, _nodeColour = opaque black
, _nodeLabel = ""
, _positionX = 0
, _positionY = 0
, _nodeZindex = 1
}
data EdgeAttr = EdgeAttr
{ _edgeLabel :: String
, _edgeColour :: AlphaColour Double
, _edgeWeight :: Double
, _edgeArrowLength :: Double
, _edgeZindex :: Int
} deriving (Show, Read, Eq)
instance Hashable EdgeAttr where
hashWithSalt salt at = hashWithSalt salt $ _edgeLabel at
defaultEdgeAttributes :: EdgeAttr
defaultEdgeAttributes = EdgeAttr
{ _edgeLabel = ""
, _edgeColour = opaque black
, _edgeWeight = 1.0
, _edgeArrowLength = 10
, _edgeZindex = 2
}
genXMLTree :: (ArrowXml a, Graph d) => LGraph d NodeAttr EdgeAttr -> a XmlTree XmlTree
genXMLTree gr = root [] [gexf]
where
gexf = mkelem "gexf" [ attr "version" $ txt "1.2"
, attr "xmlns" $ txt "http://www.gexf.net/1.2draft"
, attr "xmlns:viz" $ txt "http://www.gexf.net/1.2draft/viz"
, attr "xmlns:xsi" $ txt "http://www.w3.org/2001/XMLSchema-instance"
, attr "xsi:schemaLocation" $ txt "http://www.gexf.net/1.2draft http://www.gexf.net/1.2draft/gexf.xsd"
] [graph]
directed | isDirected gr = "directed"
| otherwise = "undirected"
graph = mkelem "graph" [ attr "mode" $ txt "static"
, attr "defaultedgetype" $ txt directed
] [ns, es]
ns = mkelem "nodes" [] $ map mkNode $ nodes gr
es = mkelem "edges" [] $ map mkEdge $ edges gr
mkNode i =
mkelem "node" [ attr "id" $ txt $ show i
, attr "label" $ txt $ _nodeLabel at ]
[ aelem "viz:position" [ attr "x" $ txt $ show $ _positionX at
, attr "y" $ txt $ show $ _positionY at ]
, aelem "viz:color" [ attr "r" $ txt r
, attr "g" $ txt g
, attr "b" $ txt b
, attr "a" $ txt a ]
, aelem "viz:size" [attr "value" $ txt $ show $ _size at]
]
where
at = nodeLab gr i
rgb = toSRGB24 $ _nodeColour at `over` black
r = show (fromIntegral $ channelRed rgb :: Int)
b = show (fromIntegral $ channelBlue rgb :: Int)
g = show (fromIntegral $ channelGreen rgb :: Int)
a = show $ alphaChannel $ _nodeColour at
mkEdge (fr,to) =
mkelem "edge" [ attr "source" $ txt $ show fr
, attr "target" $ txt $ show to
, attr "weight" $ txt $ show $ _edgeWeight at ]
[ aelem "viz:color" [ attr "r" $ txt r
, attr "g" $ txt g
, attr "b" $ txt b
, attr "a" $ txt a ]
]
where
at = edgeLab gr (fr,to)
rgb = toSRGB24 $ _edgeColour at `over` black
r = show (fromIntegral $ channelRed rgb :: Int)
b = show (fromIntegral $ channelBlue rgb :: Int)
g = show (fromIntegral $ channelGreen rgb :: Int)
a = show $ alphaChannel $ _edgeColour at
{-# INLINE genXMLTree #-}
writeGEXF :: Graph d => FilePath -> LGraph d NodeAttr EdgeAttr -> IO ()
writeGEXF fl gr = runX (genXMLTree gr >>> writeDocument config fl) >> return ()
where
config = [withIndent yes]