module Gargantext.Components.GraphExplorer.Utils ( stEdgeToGET, stNodeToGET , normalizeNodes , normalizeNodeSizeDefault , normalizeNodeSize , takeGreatestNodeByCluster, countNodeByCluster ) where import Data.Array as A import Data.Foldable (maximum, minimum) import Data.Lens (Lens', lens, over, traversed, (^.)) import Data.Maybe (Maybe(..), fromMaybe, maybe) import Data.Newtype (wrap) import Data.Number as DN import Data.Traversable (class Traversable) import Gargantext.Components.GraphExplorer.GraphTypes as GEGT import Gargantext.Components.GraphExplorer.Types as GET import Gargantext.Hooks.Sigmax.Types as ST import Gargantext.Prelude import Gargantext.Utils (getter) import Gargantext.Utils.Lens as GUL stEdgeToGET :: Record ST.Edge -> GEGT.Edge stEdgeToGET { _original: GEGT.Edge original, hidden } = GEGT.Edge $ original { hidden = Just hidden } stNodeToGET :: Record ST.Node -> GEGT.Node stNodeToGET { id, label, x, y, _original: GEGT.Node { attributes, size, type_ } } = GEGT.Node { attributes , children: [] , id_: id , label , size , type_ , x , y } ----------------------------------------------------------------------- -- | Normalize nodes, i.e. set their {x, y} values so that they are in -- | range [0, 1]. normalizeNodes :: forall t. Traversable t => t GEGT.Node -> t GEGT.Node normalizeNodes ns = GUL.normalizeLens xLens $ GUL.normalizeLens yLens ns where xLens :: Lens' GEGT.Node Number xLens = lens (\(GEGT.Node { x }) -> x) $ (\(GEGT.Node n) val -> GEGT.Node (n { x = val })) yLens :: Lens' GEGT.Node Number yLens = lens (\(GEGT.Node { y }) -> y) $ (\(GEGT.Node n) val -> GEGT.Node (n { y = val })) type NodeSize r = { size :: Number | r } normalizeNodeSizeDefault :: forall t r. Traversable t => t (NodeSize r) -> t (NodeSize r) normalizeNodeSizeDefault ns = logSize <$> normalizeNodeSize 50.0 100000.0 ns where logSize (n@{ size }) = n { size = DN.log (size + 1.0) } normalizeNodeSize :: forall t r. Traversable t => Number -> Number -> t (NodeSize r) -> t (NodeSize r) normalizeNodeSize minSize maxSize ns = over traversed (over sizeLens (\s -> minSize + (s - sizeMin') * quotient)) ns where sizes = over traversed (_ ^. sizeLens) ns sizeMin = minimum sizes sizeMax = maximum sizes range = do sMin <- sizeMin sMax <- sizeMax pure $ sMax - sMin sizeMin' = fromMaybe 0.0 sizeMin divisor = maybe 1.0 (\r -> 1.0 / r) range quotient :: Number quotient = (maxSize - minSize) * divisor --quotient = (toNumber $ maxSize - minSize) * divisor --sizeLens :: Lens' GEGT.Node Number --sizeLens = lens (\(GEGT.Node { size }) -> size) $ (\(GEGT.Node n) val -> GEGT.Node (n { size = val })) sizeLens :: Lens' { size :: Number | r } Number sizeLens = lens (\{ size } -> size) $ \n val -> (n { size = val }) ------------------------------------------------------------------------ takeGreatestNodeByCluster :: GET.HyperdataGraph -> Int -> Int -> Array GEGT.Node takeGreatestNodeByCluster graphData take clusterId = graphData # getter _.graph >>> getter _.nodes >>> A.filter ( getter _.attributes >>> getter _.clustDefault >>> eq clusterId ) >>> A.sortWith ( getter _.size ) >>> A.takeEnd take >>> A.reverse countNodeByCluster :: GET.HyperdataGraph -> Int -> GEGT.ClusterCount countNodeByCluster graphData clusterId = graphData # getter _.graph >>> getter _.nodes >>> A.filter ( getter _.attributes >>> getter _.clustDefault >>> eq clusterId ) >>> A.length >>> { id: clusterId , count: _ } >>> wrap