Commit 2b884d76 authored by Alexandre Delanoë's avatar Alexandre Delanoë

Merge remote-tracking branch 'origin/465-dev-graph-explorer-recursion-error' into dev

parents 5ab43f24 a5758914
......@@ -58,7 +58,7 @@
"react-dom": "^17.0.2",
"react-tooltip": "^4.2.8",
"secp256k1": "^4.0.2",
"sigma": "^2.3.1",
"sigma": "^2.4.0",
"twgl.js": "^5.0.4"
},
"devDependencies": {
......
let upstream =
https://github.com/garganscript/package-sets/releases/download/v0.1.6/release.dhall sha256:443a37602d5b9353c4daf4349079a77d5dddf07a7b35219016b167404d1e1138
https://github.com/garganscript/package-sets/releases/download/v0.1.7/release.dhall sha256:52886309e1f0158a85427f80c1e3d47ce747c5f14fcec671a81fe5c2c711a6db
let overrides =
{ graphql-client =
......@@ -98,7 +98,7 @@ let overrides =
, "typelevel-prelude"
]
, repo = "https://github.com/justinwoo/purescript-record-extra"
, version = "0.15.0-starter-kit"
, version = "v5.0.1"
}
}
......
......@@ -10,10 +10,14 @@ import Gargantext.Prelude
import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
import Data.Nullable (Nullable)
import Data.Tuple (Tuple(..))
import Data.Sequence as Seq
import Data.Set as Set
import Data.Traversable (traverse_)
import Data.Tuple (Tuple(..), fst, snd)
import DOM.Simple (window)
import DOM.Simple.Types (Element)
import Effect.Class.Console as ECC
import Effect.Timer (setTimeout)
import Gargantext.Components.App.Store as AppStore
import Gargantext.Components.GraphExplorer.Store as GraphStore
import Gargantext.Components.GraphExplorer.Types as GET
......@@ -45,10 +49,10 @@ type Props sigma forceatlas2 =
drawGraph :: forall s fa2. R2.Leaf (Props s fa2)
drawGraph = R2.leaf drawGraphCpt
drawGraphCpt :: forall s fa2. R.Memo (Props s fa2)
drawGraphCpt = R.memo' $ here.component "graph" cpt where
-- drawGraphCpt :: forall s fa2. R.Component (Props s fa2)
-- drawGraphCpt = here.component "graph" cpt where
-- drawGraphCpt :: forall s fa2. R.Memo (Props s fa2)
-- drawGraphCpt = R.memo' $ here.component "drawGraph" cpt where
drawGraphCpt :: forall s fa2. R.Component (Props s fa2)
drawGraphCpt = here.component "drawGraph" cpt where
-- | Component
-- |
cpt { elRef
......@@ -75,10 +79,10 @@ drawGraphCpt = R.memo' $ here.component "graph" cpt where
showEdges' <- R2.useLive' showEdges
edgeConfluence' <- R2.useLive' edgeConfluence
edgeWeight' <- R2.useLive' edgeWeight
forceAtlasState' <- R2.useLive' forceAtlasState
forceAtlasState' <- R2.useLive' forceAtlasState
graphStage' <- R2.useLive' graphStage
startForceAtlas' <- R2.useLive' startForceAtlas
hyperdataGraph' <- R2.useLive' hyperdataGraph
--hyperdataGraph' <- R2.useLive' hyperdataGraph
-- | Hooks
-- |
......@@ -99,9 +103,10 @@ drawGraphCpt = R.memo' $ here.component "graph" cpt where
here.log "[drawGraph (Cleanup)] sigma killed"
-- Stage Init
R.useEffect2' hyperdataGraph' graphStage' $ case graphStage' of
R.useEffect1' graphStage' $ case graphStage' of
GET.Init -> do
hyperdataGraph' <- T.read hyperdataGraph
let mCamera = getter _.mCamera hyperdataGraph'
let rSigma = R.readRef sigmaRef
......@@ -193,18 +198,26 @@ drawGraphCpt = R.memo' $ here.component "graph" cpt where
let tEdgesMap = SigmaxTypes.edgesGraphMap transformedGraph
let tNodesMap = SigmaxTypes.nodesGraphMap transformedGraph
Sigmax.dependOnSigma (R.readRef sigmaRef) "[drawGraph (Ready)] no sigma" $ \sigma -> do
Sigmax.performDiff sigma transformedGraph
-- Sigmax.updateEdges sigma tEdgesMap
-- Sigmax.updateNodes sigma tNodesMap
let edgesState = not $ SigmaxTypes.edgeStateHidden showEdges'
-- here.log2 "[graphCpt] edgesState" edgesState
Sigmax.setSigmaEdgesVisibility sigma { edgeConfluence: edgeConfluence'
, edgeWeight: edgeWeight'
, showEdges: showEdges' }
let updateSigma _ = do
Sigmax.dependOnSigma (R.readRef sigmaRef) "[drawGraph (Ready)] no sigma" $ \sigma -> do
Sigmax.performDiff sigma transformedGraph
-- Sigmax.updateEdges sigma tEdgesMap
-- Sigmax.updateNodes sigma tNodesMap
let edgesState = not $ SigmaxTypes.edgeStateHidden showEdges'
-- here.log2 "[graphCpt] edgesState" edgesState
Sigmax.setSigmaEdgesVisibility sigma { edgeConfluence: edgeConfluence'
, edgeWeight: edgeWeight'
, showEdges: showEdges' }
-- TODO This is a temporary solution that seems to fix
-- blank page of graph when there are too many edges. It
-- still throws error though, just in another thread.
_ <- setTimeout 100 $ updateSigma unit
pure unit
case Tuple forceAtlasState' graphStage' of
--Tuple SigmaxTypes.InitialLoading GET.Ready -> updateGraph
Tuple SigmaxTypes.InitialRunning GET.Ready -> updateGraph
Tuple SigmaxTypes.Paused GET.Ready -> updateGraph
......
......@@ -101,7 +101,6 @@ sidebarCpt = here.component "sidebar" cpt where
sideTabLegend :: R2.Leaf Props
sideTabLegend = R2.leaf sideTabLegendCpt
sideTabLegendCpt :: R.Component Props
sideTabLegendCpt = here.component "sideTabLegend" cpt where
cpt { metaData: GET.MetaData { legend } } _ = do
......@@ -165,11 +164,9 @@ sideTabDataCpt = here.component "sideTabData" cpt where
cpt props _ = do
-- States
{ selectedNodeIds
, graph
} <- GraphStore.use
selectedNodeIds' <- R2.useLive' selectedNodeIds
graph' <- R2.useLive' graph
-- Computed
let
......@@ -186,39 +183,57 @@ sideTabDataCpt = here.component "sideTabData" cpt where
-- No result
false ->
B.caveat
{}
[
H.text "Select one or more nodes to get their informations"
]
sideTabDataNoSelection {}
-- Nodes have been selected
true ->
sideTabDataWithSelection props
]
R.fragment
[
selectedNodes $
{ nodesMap: SigmaxT.nodesGraphMap graph'
} `Record.merge` props
,
sideBarTabSeparator
,
neighborhood
{}
,
sideBarTabSeparator
,
docListWrapper
{ metaData: props.metaData
}
]
sideTabDataNoSelection :: R2.Leaf ()
sideTabDataNoSelection = R2.leaf sideTabDataNoSelectionCpt
sideTabDataNoSelectionCpt :: R.Component ()
sideTabDataNoSelectionCpt = here.component "sideTabDataNoSelection" cpt where
cpt {} _ = do
pure $ B.caveat
{}
[
H.text "Select one or more nodes to get their informations"
]
sideTabDataWithSelection :: R2.Leaf Props
sideTabDataWithSelection = R2.leaf sideTabDataWithSelectionCpt
sideTabDataWithSelectionCpt :: R.Component Props
sideTabDataWithSelectionCpt = here.component "sideTabDataWithSelection" cpt where
cpt props _ = do
-- States
{ graph
} <- GraphStore.use
graph' <- R2.useLive' graph
pure $
R.fragment [
selectedNodes $
{ nodesMap: SigmaxT.nodesGraphMap graph'
} `Record.merge` props
,
sideBarTabSeparator
,
neighborhood
{}
,
sideBarTabSeparator
,
docListWrapper
{ metaData: props.metaData
}
]
------------------------------------------------------------
sideTabCommunity :: R2.Leaf Props
sideTabCommunity = R2.leaf sideTabCommunityCpt
sideTabCommunityCpt :: R.Component Props
sideTabCommunityCpt = here.component "sideTabCommunity" cpt where
cpt props _ = do
......@@ -244,33 +259,52 @@ sideTabCommunityCpt = here.component "sideTabCommunity" cpt where
-- No result
false ->
B.caveat
{}
[
H.text "Select one or more nodes to get their informations"
]
sideTabCommunityNoSelection {}
-- Nodes have been selection
true ->
sideTabCommunityWithSelection props
]
R.fragment
[
selectedNodes $
{ nodesMap: SigmaxT.nodesGraphMap graph'
} `Record.merge` props
,
sideBarTabSeparator
,
neighborhood
{}
,
sideBarTabSeparator
,
contactListWrapper
{ metaData: props.metaData
}
]
sideTabCommunityNoSelection :: R2.Leaf ()
sideTabCommunityNoSelection = R2.leaf sideTabCommunityNoSelectionCpt
sideTabCommunityNoSelectionCpt :: R.Component ()
sideTabCommunityNoSelectionCpt = here.component "sideTabCommunityNoSelection" cpt where
cpt {} _ = do
pure $ B.caveat
{}
[
H.text "Select one or more nodes to get their informations"
]
sideTabCommunityWithSelection :: R2.Leaf Props
sideTabCommunityWithSelection = R2.leaf sideTabCommunityWithSelectionCpt
sideTabCommunityWithSelectionCpt :: R.Component Props
sideTabCommunityWithSelectionCpt = here.component "sideTabCommunityWithSelection" cpt where
cpt props _ = do
{ graph
} <- GraphStore.use
graph' <- R2.useLive' graph
pure $
R.fragment
[
selectedNodes $
{ nodesMap: SigmaxT.nodesGraphMap graph'
} `Record.merge` props
,
sideBarTabSeparator
,
neighborhood
{}
,
sideBarTabSeparator
,
contactListWrapper
{ metaData: props.metaData
}
]
-------------------------------------------
......@@ -295,7 +329,6 @@ type SelectedNodesProps =
selectedNodes :: R2.Leaf SelectedNodesProps
selectedNodes = R2.leaf selectedNodesCpt
selectedNodesCpt :: R.Component SelectedNodesProps
selectedNodesCpt = here.component "selectedNodes" cpt where
cpt props _ = do
......
......@@ -42,10 +42,12 @@ type Store =
-- Controls
, multiSelectEnabled :: T.Box Boolean
, edgeConfluence :: T.Box Range.NumberRange
, edgeConfluenceRange :: T.Box Range.NumberRange
, edgeWeight :: T.Box Range.NumberRange
, forceAtlasState :: T.Box SigmaxT.ForceAtlasState
, graphStage :: T.Box GET.Stage
, nodeSize :: T.Box Range.NumberRange
, nodeSizeRange :: T.Box Range.NumberRange
, showEdges :: T.Box SigmaxT.ShowEdgesState
, showLouvain :: T.Box Boolean
, labelSize :: T.Box Number
......@@ -73,10 +75,12 @@ type State =
-- Controls
, multiSelectEnabled :: Boolean
, edgeConfluence :: Range.NumberRange
, edgeConfluenceRange :: Range.NumberRange
, edgeWeight :: Range.NumberRange
, forceAtlasState :: SigmaxT.ForceAtlasState
, graphStage :: GET.Stage
, nodeSize :: Range.NumberRange
, nodeSizeRange :: Range.NumberRange
, showEdges :: SigmaxT.ShowEdgesState
, showLouvain :: Boolean
, labelSize :: Number
......
......@@ -205,6 +205,7 @@ pauseForceAtlasButtonCpt = here.component "pauseForceAtlasButtonButton" cpt
vrt SigmaxTypes.Running = ButtonVariant Secondary
vrt _ = OutlinedButtonVariant Secondary
--icn SigmaxTypes.InitialLoading = "pause"
icn SigmaxTypes.InitialRunning = "pause"
icn SigmaxTypes.InitialStopped = "play"
icn SigmaxTypes.Running = "pause"
......
......@@ -51,6 +51,7 @@ controlsCpt = R.memo' $ here.component "controls" cpt where
-- | States
-- |
{ edgeConfluence
, edgeConfluenceRange
, edgeWeight
, forceAtlasState
, graph
......@@ -60,6 +61,7 @@ controlsCpt = R.memo' $ here.component "controls" cpt where
, mouseSelectorSize
, multiSelectEnabled
, nodeSize
, nodeSizeRange
, selectedNodeIds
, showEdges
, showLouvain
......@@ -68,11 +70,13 @@ controlsCpt = R.memo' $ here.component "controls" cpt where
} <- GraphStore.use
forceAtlasState' <- R2.useLive' forceAtlasState
graph' <- R2.useLive' graph
graphStage' <- R2.useLive' graphStage
selectedNodeIds' <- R2.useLive' selectedNodeIds
showSidebar' <- R2.useLive' showSidebar
edgeConfluenceRange' <- R2.useLive' edgeConfluenceRange
nodeSizeRange' <- R2.useLive' nodeSizeRange
session <- useSession
-- ref to track automatic FA pausing
......@@ -116,41 +120,19 @@ controlsCpt = R.memo' $ here.component "controls" cpt where
-- Timer to turn off the initial FA. This is because FA eats up lot of
-- CPU, has memory leaks etc.
R.useEffect1' forceAtlasState' $ do
if forceAtlasState' == SigmaxT.InitialRunning then do
timeoutId <- setTimeout 9000 $ do
case forceAtlasState' of
SigmaxT.InitialRunning ->
T.write_ SigmaxT.Paused forceAtlasState
_ -> pure unit
R.setRef mFAPauseRef Nothing
R.setRef mFAPauseRef $ Just timeoutId
pure unit
else
case forceAtlasState' of
SigmaxT.InitialRunning -> do
timeoutId <- setTimeout 9000 $ do
case forceAtlasState' of
SigmaxT.InitialRunning ->
T.write_ SigmaxT.Paused forceAtlasState
_ -> pure unit
R.setRef mFAPauseRef Nothing
R.setRef mFAPauseRef $ Just timeoutId
pure unit
_ -> pure unit
-- | Computed
-- |
let edgesConfluenceSorted = A.sortWith (_.confluence) $ Seq.toUnfoldable $ SigmaxT.graphEdges graph'
let edgeConfluenceMin = maybe 0.0 _.confluence $ A.head edgesConfluenceSorted
let edgeConfluenceMax = maybe 100.0 _.confluence $ A.last edgesConfluenceSorted
let edgeConfluenceRange = Range.Closed { min: edgeConfluenceMin, max: edgeConfluenceMax }
--let edgesWeightSorted = A.sortWith (_.weight) $ Seq.toUnfoldable $ SigmaxT.graphEdges graph
--let edgeWeightMin = maybe 0.0 _.weight $ A.head edgesWeightSorted
--let edgeWeightMax = maybe 100.0 _.weight $ A.last edgesWeightSorted
--let edgeWeightRange = Range.Closed { min: edgeWeightMin, max: edgeWeightMax }
let edgeWeightRange = Range.Closed {
min: 0.0
, max: I.toNumber $ Seq.length $ SigmaxT.graphEdges graph'
}
let nodesSorted = A.sortWith (_.size) $ Seq.toUnfoldable $ SigmaxT.graphNodes graph'
let nodeSizeMin = maybe 0.0 _.size $ A.head nodesSorted
let nodeSizeMax = maybe 100.0 _.size $ A.last nodesSorted
let nodeSizeRange = Range.Closed { min: nodeSizeMin, max: nodeSizeMax }
let gap = H.span { className: "graph-toolbar__gap" } []
-- | Render
......@@ -250,7 +232,7 @@ controlsCpt = R.memo' $ here.component "controls" cpt where
[
edgeConfluenceControl
{ forceAtlasState
, range: edgeConfluenceRange
, range: edgeConfluenceRange'
, state: edgeConfluence }
{- ,
edgeWeightControl
......@@ -281,7 +263,7 @@ controlsCpt = R.memo' $ here.component "controls" cpt where
-- labels size: 1-4
nodeSizeControl
{ forceAtlasState
, range: nodeSizeRange
, range: nodeSizeRange'
, state: nodeSize }
]
......
......@@ -4,12 +4,13 @@ module Gargantext.Components.Nodes.Graph
import Gargantext.Prelude
import DOM.Simple (document, querySelector)
import Data.Array as A
import Data.Int as I
import Data.Maybe (Maybe(..), fromMaybe, isJust, maybe)
import Data.Sequence as Seq
import Data.Tuple (Tuple(..))
import Data.Tuple.Nested ((/\))
import DOM.Simple (document, querySelector)
import Gargantext.Components.App.Store as AppStore
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.GraphExplorer.API as GraphAPI
......@@ -56,7 +57,7 @@ nodeCpt = here.component "node" cpt where
-- | Computed
-- |
let errorHandler = logRESTError here "[explorerLayout]"
let errorHandler = logRESTError here "[node]"
-- | Hooks
-- |
......@@ -151,6 +152,7 @@ hydrateStoreCpt = here.component "hydrateStore" cpt where
forceAtlasState
= if startForceAtlas
--then SigmaxT.InitialLoading
then SigmaxT.InitialRunning
else SigmaxT.InitialStopped
......@@ -160,6 +162,29 @@ hydrateStoreCpt = here.component "hydrateStore" cpt where
sigmaRef <- Sigmax.initSigma >>= R.useRef
fa2Ref <- R.useRef (Nothing :: Maybe ForceAtlas.FA2Layout)
-- | Precompute some values
-- |
let edgesConfluenceSorted = A.sortWith (_.confluence) $ Seq.toUnfoldable $ SigmaxT.graphEdges graph
let edgeConfluenceMin = maybe 0.0 _.confluence $ A.head edgesConfluenceSorted
let edgeConfluenceMax = maybe 100.0 _.confluence $ A.last edgesConfluenceSorted
let edgeConfluenceRange = Range.Closed { min: edgeConfluenceMin, max: edgeConfluenceMax }
--let edgesWeightSorted = A.sortWith (_.weight) $ Seq.toUnfoldable $ SigmaxT.graphEdges graph
--let edgeWeightMin = maybe 0.0 _.weight $ A.head edgesWeightSorted
--let edgeWeightMax = maybe 100.0 _.weight $ A.last edgesWeightSorted
--let edgeWeightRange = Range.Closed { min: edgeWeightMin, max: edgeWeightMax }
let edgeWeightRange = Range.Closed {
min: 0.0
, max: I.toNumber $ Seq.length $ SigmaxT.graphEdges graph
}
let nodesSorted = A.sortWith (_.size) $ Seq.toUnfoldable $ SigmaxT.graphNodes graph
let nodeSizeMin = maybe 0.0 _.size $ A.head nodesSorted
let nodeSizeMax = maybe 100.0 _.size $ A.last nodesSorted
let nodeSizeRange = Range.Closed { min: nodeSizeMin, max: nodeSizeMax }
-- Hydrate GraphStore
(state :: Record GraphStore.State) <- pure $
-- Data
......@@ -174,6 +199,8 @@ hydrateStoreCpt = here.component "hydrateStore" cpt where
{ min: 0.0
, max: I.toNumber $ Seq.length $ SigmaxT.graphEdges graph
}
, edgeConfluenceRange
, nodeSizeRange
-- (cache options)
, expandSelection: getter _.expandSelection cacheParams
, expandNeighborhood: getter _.expandNeighborhood cacheParams
......
......@@ -249,7 +249,6 @@ performDiff sigma g = do
, update: Tuple updateEdges updateNodes } = sigmaDiff sigmaGraph g
-- | Compute a diff between current sigma graph and whatever is set via custom controls
sigmaDiff :: Graphology.Graph -> ST.SGraph -> Record ST.SigmaDiff
sigmaDiff sigmaGraph gControls = { add, remove, update }
......@@ -275,6 +274,8 @@ sigmaDiff sigmaGraph gControls = { add, remove, update }
ST.nodesFilter (\n -> not (Set.member n.id sigmaNodeIds)) gControls
addEdges = ST.graphEdges addGC
addNodes = ST.graphNodes addGC
-- addEdges = Seq.empty
-- addNodes = ST.graphNodes addGC
-- Remove nodes/edges from `sigmaGraph` which aren't in
-- `gControls`
......@@ -288,6 +289,8 @@ sigmaDiff sigmaGraph gControls = { add, remove, update }
updateEdges = Seq.filter (\e -> Just e /= Map.lookup e.id sigmaEdgeIdsMap) gcEdges
-- Find nodes for which `ST.compareNodes` returns `false`, i.e. nodes differ
updateNodes = Seq.filter (\n -> (ST.compareNodes n <$> (Map.lookup n.id sigmaNodeIdsMap)) == Just false) gcNodes
-- updateEdges = Seq.empty
-- updateNodes = Seq.empty
-- DEPRECATED
......
......@@ -25,7 +25,9 @@ newtype Graph n e = Graph { edges :: Seq.Seq {|e}, nodes :: Seq.Seq {|n} }
derive instance Generic (Graph n e) _
instance (Eq (Record n), Eq (Record e)) => Eq (Graph n e) where
eq = genericEq
--eq = genericEq
eq (Graph { edges: e1, nodes: n1 }) (Graph { edges: e2, nodes: n2 }) =
(Seq.length e1 == Seq.length e2) && (Seq.length n1 == Seq.length n2)
--instance Eq Graph where
-- eq (Graph {nodes: n1, edges: e1}) (Graph {nodes: n2, edges: e2}) = n1 == n2 && e1 == e2
......@@ -162,13 +164,14 @@ eqGraph (Graph {nodes: n1, edges: e1}) (Graph {nodes: n2, edges: e2}) = (n1 == n
-- however when graph is loaded initially, forceAtlas is running for a couple of
-- seconds and then stops (unless the user alters this by clicking the toggle
-- button).
data ForceAtlasState = InitialRunning | InitialStopped | Running | Paused | Killed
data ForceAtlasState = {- InitialLoading | -} InitialRunning | InitialStopped | Running | Paused | Killed
derive instance Generic ForceAtlasState _
instance Eq ForceAtlasState where
eq = genericEq
toggleForceAtlasState :: ForceAtlasState -> ForceAtlasState
-- toggleForceAtlasState InitialLoading = InitialRunning
toggleForceAtlasState InitialRunning = Paused
toggleForceAtlasState InitialStopped = InitialRunning
toggleForceAtlasState Running = Paused
......@@ -177,6 +180,7 @@ toggleForceAtlasState Killed = InitialRunning
forceAtlasComponentStatus :: ForceAtlasState -> ComponentStatus
-- forceAtlasComponentStatus InitialLoading = Disabled
forceAtlasComponentStatus InitialRunning = Disabled
forceAtlasComponentStatus InitialStopped = Enabled
forceAtlasComponentStatus Running = Disabled
......@@ -212,6 +216,7 @@ toggleShowEdgesState s =
-- | Return state in which showEdges should be depending on forceAtlasState
forceAtlasEdgeState :: ForceAtlasState -> ShowEdgesState -> ShowEdgesState
-- forceAtlasEdgeState InitialLoading _ = ETempHiddenThenShow
forceAtlasEdgeState InitialRunning EShow = ETempHiddenThenShow
forceAtlasEdgeState InitialRunning es = es
forceAtlasEdgeState InitialStopped es = es
......
......@@ -9471,10 +9471,10 @@ side-channel@^1.0.4:
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
sigma@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/sigma/-/sigma-2.3.1.tgz#69fd9165479fa49ed84348afcd0432215fdf935f"
integrity sha512-YfQsVZf78CeIUv8EYLqp/yvhMwwBXGrbpy+rD1N2X9IqtJ11+VfQRjWfVqHDhjM8oPfWPsaJMtpWFQ8pIflvCA==
sigma@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/sigma/-/sigma-2.4.0.tgz#efa213c82e8561138c9237c3a87cf15c0bbaee76"
integrity sha512-spi4C+c3cjlhCklT+RvAxJJcarMmjRpF6RPNvBIBYDduALq8iSNm7FwSpijQNGtI+ryeZ2EfvyBNLp36OFaZiw==
dependencies:
"@yomguithereal/helpers" "^1.1.1"
events "^3.3.0"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment