Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
clinicaltrials
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
david Chavalarias
clinicaltrials
Commits
4f2ad358
Commit
4f2ad358
authored
Sep 25, 2017
by
Romain Loth
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' (bipartite colors)
parents
3bdfe991
4c1a7550
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
678 additions
and
531 deletions
+678
-531
old_heatmapColors_with_binning.js
...OCUMENTATION/C-advanced/old_heatmapColors_with_binning.js
+0
-152
explorerjs.html
explorerjs.html
+5
-5
settings_explorerjs.js
settings_explorerjs.js
+3
-3
selection-panels-mobile.css
twlibs/css/selection-panels-mobile.css
+9
-6
selection-panels.css
twlibs/css/selection-panels.css
+29
-18
twjs.css
twlibs/css/twjs.css
+7
-0
Tinaweb.js
twmain/Tinaweb.js
+1
-1
enviroment.js
twmain/enviroment.js
+61
-10
extras_explorerjs.js
twmain/extras_explorerjs.js
+253
-149
globalUtils.js
twmain/globalUtils.js
+4
-2
main.js
twmain/main.js
+3
-0
methods.js
twmain/methods.js
+4
-2
sigma.parseCustom.js
twmain/sigma.parseCustom.js
+97
-42
sigmaUtils.js
twmain/sigmaUtils.js
+199
-138
settings_explorerjs.comex.js
twpresets/settings_explorerjs.comex.js
+2
-2
settings_explorerjs.devdefault.js
twpresets/settings_explorerjs.devdefault.js
+1
-1
No files found.
00.DOCUMENTATION/C-advanced/old_heatmapColors_with_binning.js
deleted
100644 → 0
View file @
3bdfe991
// KEPT FOR REFERENCE, BINNING NOW PRECOMPUTED in parseCustom
// rewrite of gradientColors with binning and for attributes that can have negative float values
// /!\ age and growth_rate attributes referred to by name
function
colorsRelByBins_old
(
daclass
)
{
cancelSelection
(
false
);
var
binColors
var
doModifyLabel
=
false
TW
.
handpickedcolor
=
true
// for debug of heatmapColoring
var
totalsPerBinMin
=
{}
// should be = binColors.length
var
nTicksParam
=
(
daclass
==
'age'
)
?
8
:
12
// do first loop entirely to get percentiles => bins, then modify alt_color
// estimating ticks
let
tickThresholds
=
[]
let
valArray
=
[]
for
(
var
j
=
0
;
j
<
TW
.
nNodes
;
j
++
)
{
let
n
=
TW
.
partialGraph
.
graph
.
nodes
(
TW
.
nodeIds
[
j
])
if
(
!
n
.
hidden
&&
n
.
attributes
&&
n
.
attributes
.
category
==
'terms'
&&
n
.
attributes
[
daclass
]
!=
undefined
)
{
valArray
.
push
(
Number
(
n
.
attributes
[
daclass
]))
}
}
var
len
=
valArray
.
length
valArray
.
sort
(
function
(
a
,
b
)
{
return
a
-
b
;})
// important :)
for
(
var
l
=
0
;
l
<
nTicksParam
;
l
++
)
{
let
nthVal
=
Math
.
floor
(
len
*
l
/
nTicksParam
)
tickThresholds
.
push
(
valArray
[
nthVal
])
}
// also always add the max+1 as last tick (excluded upper bound of last bin)
tickThresholds
.
push
((
valArray
[
len
-
1
])
+
1
)
console
.
info
(
`[|===|===
${
nTicksParam
}
color ticks ===|===|]\n`
,
tickThresholds
)
cancelSelection
(
false
);
if
(
daclass
==
'age'
)
{
// 9 colors
binColors
=
TW
.
gui
.
getHeatmapColors
(
9
)
}
else
if
(
daclass
==
'growth_rate'
)
{
doModifyLabel
=
true
// 12 colors
binColors
=
TW
.
gui
.
getHeatmapColors
(
12
)
}
// verification
if
(
nTicksParam
!=
binColors
.
length
)
{
console
.
warn
(
`heatmapColoring setup mismatch: nTicksParam
${
nTicksParam
}
should == nColors
${
binColors
.
length
}
`
)
}
// get the nodes
for
(
var
j
=
0
;
j
<
TW
.
nNodes
;
j
++
)
{
let
n
=
TW
.
partialGraph
.
graph
.
nodes
(
TW
.
nodeIds
[
j
])
if
(
!
n
.
hidden
&&
n
.
attributes
&&
n
.
attributes
.
category
==
'terms'
&&
!
isUndef
(
n
.
attributes
[
daclass
])
)
{
var
valSt
=
n
.
attributes
[
daclass
]
var
originalLabel
=
TW
.
Nodes
[
n
.
id
].
label
if
(
doModifyLabel
)
{
n
.
label
=
`(
${
valSt
}
)
${
originalLabel
}
`
}
else
{
n
.
label
=
originalLabel
}
var
theVal
=
parseFloat
(
valSt
)
var
foundBin
=
false
// console.log('theVal:',theVal)
if
(
!
isNaN
(
theVal
)
)
{
//is float
// iterate over bins
for
(
var
k
=
0
;
k
<
tickThresholds
.
length
-
1
;
k
++
)
{
var
binMin
=
tickThresholds
[
k
]
var
binMax
=
tickThresholds
[(
k
+
1
)]
if
((
theVal
>=
binMin
)
&&
(
theVal
<
binMax
))
{
// TW.partialGraph._core.graph.nodesIndex[n.id].binMin = binMin
// TW.partialGraph._core.graph.nodesIndex[n.id].color = binColors[j]
n
.
binMin
=
binMin
n
.
color
=
binColors
[
k
]
n
.
customAttrs
.
alt_color
=
binColors
[
k
]
n
.
customAttrs
.
altgrey_color
=
false
foundBin
=
true
// console.log(`theVal ${theVal} => found its bin ${binMin} ... ${binColors[k]}`)
if
(
!
totalsPerBinMin
[
binMin
])
{
totalsPerBinMin
[
binMin
]
=
1
}
else
{
totalsPerBinMin
[
binMin
]
++
}
break
}
}
// case no bin after loop (perhaps more ticks than colors-1 ??)
if
(
!
foundBin
)
{
console
.
warn
(
'no bin for theVal'
,
theVal
,
n
.
id
)
n
.
binMin
=
null
n
.
color
=
'#000'
n
.
customAttrs
.
alt_color
=
'#000'
}
}
else
{
// case no val
// console.log('no val for', n.id)
n
.
binMin
=
null
n
.
color
=
'#555'
n
.
customAttrs
.
alt_color
=
'#555'
}
}
}
// console.debug(valArray)
console
.
info
(
'coloring distribution per tick thresholds'
,
totalsPerBinMin
)
// Edge precompute alt_rgb by new source-target nodes-colours combination
repaintEdges
()
// set_ClustersLegend ( daclass )
TW
.
partialGraph
.
render
();
}
explorerjs.html
View file @
4f2ad358
...
@@ -159,8 +159,8 @@
...
@@ -159,8 +159,8 @@
<li>
<li>
<a>
<a>
<select id="aselector" onchange="console.log('salut monde')" class="selectpicker" data-style="btn btn-success btn-sm" data-width="auto">
<select id="aselector" onchange="console.log('salut monde')" class="selectpicker" data-style="btn btn-success btn-sm" data-width="auto">
<option value="
Document
" selected>Scholars</option>
<option value="
Scholars
" selected>Scholars</option>
<option value="
NGram
">Keywords</option>
<option value="
Keywords
">Keywords</option>
</select>
</select>
</a>
</a>
</li>
</li>
...
@@ -430,9 +430,9 @@
...
@@ -430,9 +430,9 @@
</div>
<!-- /row -->
</div>
<!-- /row -->
</div>
</div>
<!-- attributes' legends (absolute position bottom left)
<!-- class="my-legend" (absolute position bottom left
) -->
(contains one div of class "my-legend" per colored nodetype
) -->
<div
id=
"legend-for-
cluster
s"
class=
"over-panels"
></div>
<div
id=
"legend-for-
facet
s"
class=
"over-panels"
></div>
<!-- to reopen the panel -->
<!-- to reopen the panel -->
<div
id=
"sideunfold"
>
<div
id=
"sideunfold"
>
...
...
settings_explorerjs.js
View file @
4f2ad358
...
@@ -21,7 +21,7 @@ TW.conf = (function(TW){
...
@@ -21,7 +21,7 @@ TW.conf = (function(TW){
// ...or remote bridge to default source api ajax queries
// ...or remote bridge to default source api ajax queries
TWConf
.
sourceAPI
=
{}
TWConf
.
sourceAPI
=
{}
TWConf
.
sourceAPI
[
"nodetypes"
]
=
{
"node0"
:
"
NGram"
,
"node1"
:
"Document
"
}
TWConf
.
sourceAPI
[
"nodetypes"
]
=
{
"node0"
:
"
Keywords"
,
"node1"
:
"Scholars
"
}
TWConf
.
sourceAPI
[
"forNormalQuery"
]
=
"services/api/graph"
TWConf
.
sourceAPI
[
"forNormalQuery"
]
=
"services/api/graph"
TWConf
.
sourceAPI
[
"forFilteredQuery"
]
=
"services/api/graph"
TWConf
.
sourceAPI
[
"forFilteredQuery"
]
=
"services/api/graph"
...
@@ -114,8 +114,8 @@ TW.conf = (function(TW){
...
@@ -114,8 +114,8 @@ TW.conf = (function(TW){
// =============
// =============
// Node typology: categories (resp. 0 and 1) will get these default labels
// Node typology: categories (resp. 0 and 1) will get these default labels
TWConf
.
catSem
=
"
NGram
"
;
TWConf
.
catSem
=
"
Keywords
"
;
TWConf
.
catSoc
=
"
Document
"
;
TWConf
.
catSoc
=
"
Scholars
"
;
// NB: these labels may be superseded by:
// NB: these labels may be superseded by:
// - the input data's node types values cf. sortNodeTypes()
// - the input data's node types values cf. sortNodeTypes()
// - in servermenu mode, by the node0 & node1 properties
// - in servermenu mode, by the node0 & node1 properties
...
...
twlibs/css/selection-panels-mobile.css
View file @
4f2ad358
...
@@ -49,8 +49,8 @@
...
@@ -49,8 +49,8 @@
}
}
/* legend re-positioned */
/* legend re-positioned */
.my-legend
{
#legend-for-facets
{
bottom
:
calc
(
40%
-
10
5
px
);
bottom
:
calc
(
40%
-
10
0
px
);
/* bot just above #sidebar which has top at calc(105px + 60%); */
/* bot just above #sidebar which has top at calc(105px + 60%); */
}
}
...
@@ -97,17 +97,20 @@
...
@@ -97,17 +97,20 @@
}
}
/* legend reduction */
/* legend reduction */
#legend-for-facets
{
max-width
:
25%
;
}
.my-legend
{
.my-legend
{
max-width
:
27%
;
max-height
:
25%
;
max-height
:
25%
;
padding
:
0
2px
;
font-size
:
85%
;
font-size
:
85%
;
margin
:
0
0
5px
0
;
margin
:
0
;
padding
:
0
1px
3px
1px
;
}
}
.my-legend
.legend-title
{
.my-legend
.legend-title
{
margin-bottom
:
0
;
margin-bottom
:
0
;
font-size
:
90
%
;
font-size
:
85
%
;
}
}
.my-legend
.legend-scale
ul
{
.my-legend
.legend-scale
ul
{
margin-bottom
:
0
;
margin-bottom
:
0
;
...
...
twlibs/css/selection-panels.css
View file @
4f2ad358
...
@@ -33,44 +33,55 @@
...
@@ -33,44 +33,55 @@
}
}
/* LEGEND PANEL */
/* LEGEND PANEL */
#legend-for-facets
{
bottom
:
10px
;
left
:
0
;
position
:
fixed
;
/* width: we set it a bit more than #lefttopbox width */
max-width
:
20%
;
max-height
:
40%
;
font-size
:
120%
;
cursor
:
default
;
overflow-y
:
auto
;
overflow-x
:
hidden
;
}
.my-legend
{
.my-legend
{
position
:
fixed
;
position
:
relative
;
/* width: we set it equal or smaller than #lefttopbox width */
height
:
100%
;
max-width
:
20%
;
width
:
100%
;
max-height
:
30%
;
margin
:
0
;
padding
:
0
5px
;
padding
:
0
5px
5px
5px
;
overflow-y
:
scroll
;
opacity
:
1
;
bottom
:
18px
;
background-color
:
white
;
left
:
0
;
border
:
solid
1px
black
;
background-color
:
white
;
opacity
:
0.8
;
color
:
#250587
;
color
:
#250587
;
margin
:
7px
;
overflow
:
hidden
;
font-size
:
120%
;
z-index
:
5
;
cursor
:
default
;
}
}
.my-legend
.legend-title
{
.my-legend
.legend-title
{
text-align
:
left
;
text-align
:
left
;
margin-bottom
:
5px
;
margin-bottom
:
5px
;
font-weight
:
bold
;
font-weight
:
bold
;
font-size
:
90%
;
font-size
:
75%
;
}
}
.my-legend
.legend-scale
ul
{
.my-legend
.legend-scale
ul
{
margin
:
0
;
margin
:
0
;
margin-bottom
:
5px
;
margin-bottom
:
5px
;
padding
:
0
;
padding
:
0
;
float
:
left
;
float
:
left
;
list-style
:
none
;
list-style
:
none
;
}
}
.my-legend
.legend-scale
ul
li
{
.my-legend
.legend-scale
ul
li
{
font-size
:
80%
;
font-size
:
80%
;
list-style
:
none
;
list-style
:
none
;
margin-left
:
0
;
margin-left
:
0
;
line-height
:
16px
;
line-height
:
16px
;
margin-bottom
:
2px
;
margin-bottom
:
2px
;
}
}
.my-legend
ul
.legend-labels
li
span
.lgdcol
{
.my-legend
ul
.legend-labels
li
span
.lgdcol
{
display
:
block
;
display
:
block
;
float
:
left
;
float
:
left
;
...
...
twlibs/css/twjs.css
View file @
4f2ad358
...
@@ -165,6 +165,13 @@ html.waiting {
...
@@ -165,6 +165,13 @@ html.waiting {
display
:
none
;
/* initial display off but turned on if bipartite */
display
:
none
;
/* initial display off but turned on if bipartite */
}
}
.pseudo-optgroup
{
color
:
#555
;
text-align
:
center
;
font-size
:
90%
;
padding
:
1.5em
0
.5em
0
;
}
.tagcloud-item
{
.tagcloud-item
{
display
:
inline-block
;
display
:
inline-block
;
border
:
solid
1px
;
border
:
solid
1px
;
...
...
twmain/Tinaweb.js
View file @
4f2ad358
...
@@ -1161,7 +1161,7 @@ var TinaWebJS = function ( sigmacanvas ) {
...
@@ -1161,7 +1161,7 @@ var TinaWebJS = function ( sigmacanvas ) {
}
}
// otherwise, set the default legend
// otherwise, set the default legend
if
(
!
madeDefaultColor
)
{
if
(
!
madeDefaultColor
)
{
set_Cluste
rsLegend
(
"clust_default"
)
updateColo
rsLegend
(
"clust_default"
)
}
}
// select currently active sliders
// select currently active sliders
...
...
twmain/enviroment.js
View file @
4f2ad358
...
@@ -23,11 +23,20 @@ TW.gui.checkBox=false;
...
@@ -23,11 +23,20 @@ TW.gui.checkBox=false;
TW
.
gui
.
shiftKey
=
false
;
TW
.
gui
.
shiftKey
=
false
;
TW
.
gui
.
foldedSide
=
false
;
TW
.
gui
.
foldedSide
=
false
;
TW
.
gui
.
manuallyChecked
=
false
;
TW
.
gui
.
manuallyChecked
=
false
;
TW
.
gui
.
handpickedcolor
=
false
;
// <= changes edge rendering strategy
TW
.
gui
.
lastFilters
=
{}
// <= last values, by slider id
TW
.
gui
.
lastFilters
=
{}
TW
.
gui
.
reldocTabs
=
[{},
{}]
// <= by nodetype and then dbtype
TW
.
gui
.
reldocTabs
=
[{},
{}]
// <= by nodetype and then dbtype
TW
.
gui
.
sizeRatios
=
[
1
,
1
]
// sizeRatios per nodetype
TW
.
gui
.
sizeRatios
=
[
1
,
1
]
// sizeRatios per nodetype
TW
.
gui
.
handpickedcolors
=
{};
// <= changes rendering, by nodetype
TW
.
gui
.
handpickedcolorsReset
=
function
(
forTypes
=
TW
.
categories
)
{
TW
.
gui
.
handpickedcolors
=
{}
for
(
var
k
in
forTypes
)
{
TW
.
gui
.
handpickedcolors
[
forTypes
[
k
]]
=
{
'alton'
:
false
,
'altattr'
:
null
}
}
}
TW
.
gui
.
noverlapConf
=
{
TW
.
gui
.
noverlapConf
=
{
nodeMargin
:
.
4
,
nodeMargin
:
.
4
,
...
@@ -517,15 +526,37 @@ function changeType(optionaltypeFlag) {
...
@@ -517,15 +526,37 @@ function changeType(optionaltypeFlag) {
updateSearchLabels
(
nid
,
allNodes
[
nid
].
label
,
allNodes
[
nid
].
type
);
updateSearchLabels
(
nid
,
allNodes
[
nid
].
label
,
allNodes
[
nid
].
type
);
}
}
// update the gui (TODO handle by TW.pushGUIState) =========================
// update the gui (POSS could be handled by TW.pushGUIState)
TW
.
gui
.
handpickedcolor
=
false
updateDynamicFacets
()
updateDynamicFacets
()
// console.log("outgoing.activetypes", outgoing.activetypes)
// console.log("newActivetypes", newActivetypes)
changeGraphAppearanceByFacets
(
getActivetypesNames
()
)
changeGraphAppearanceByFacets
(
getActivetypesNames
()
)
if
(
typeFlag
!=
'all'
)
{
// turn off the altcolors for outgoing types
graphResetLabelsAndSizes
()
for
(
var
tyId
in
TW
.
categories
)
{
let
ty
=
TW
.
categories
[
tyId
]
if
(
outgoing
.
activetypes
[
tyId
]
&&
!
newActivetypes
[
tyId
])
{
if
(
TW
.
gui
.
handpickedcolors
[
ty
].
alton
)
{
clearColorLegend
([
ty
])
TW
.
gui
.
handpickedcolors
[
ty
].
alton
=
false
}
}
else
if
(
!
outgoing
.
activetypes
[
tyId
]
&&
newActivetypes
[
tyId
])
{
if
(
TW
.
gui
.
handpickedcolors
[
ty
].
altattr
)
{
TW
.
gui
.
handpickedcolors
[
ty
].
alton
=
true
// this re-coloring can be avoided if "hidden" was used in changeLevel and sliders
let
recolorMethod
=
getColorFunction
(
TW
.
gui
.
handpickedcolors
[
ty
].
altattr
)
window
[
recolorMethod
](
TW
.
gui
.
handpickedcolors
[
ty
].
altattr
)
// without re-coloring step, we would only need to recreate legend box
// updateColorsLegend(TW.gui.handpickedcolors[ty].altattr, [ty])
}
}
}
}
TW
.
partialGraph
.
settings
(
'labelThreshold'
,
getSizeFactor
())
TW
.
partialGraph
.
settings
(
'labelThreshold'
,
getSizeFactor
())
fillAttrsInForm
(
'choose-attr'
)
fillAttrsInForm
(
'choose-attr'
)
fillAttrsInForm
(
'attr-titling-metric'
,
'num'
)
fillAttrsInForm
(
'attr-titling-metric'
,
'num'
)
...
@@ -537,6 +568,8 @@ function changeType(optionaltypeFlag) {
...
@@ -537,6 +568,8 @@ function changeType(optionaltypeFlag) {
sigma_utils
.
smartForceAtlas
()
sigma_utils
.
smartForceAtlas
()
}
}
})
})
// end update the gui ======================================================
}
}
...
@@ -623,6 +656,13 @@ function changeLevel(optionalTgtState) {
...
@@ -623,6 +656,13 @@ function changeLevel(optionalTgtState) {
activereltypes
=
present
.
activereltypes
;
activereltypes
=
present
.
activereltypes
;
}
}
let
activetypesDict
=
{}
for
(
var
i
in
activetypes
)
{
if
(
activetypes
[
i
])
{
activetypesDict
[
TW
.
categories
[
i
]]
=
true
}
}
TW
.
partialGraph
.
graph
.
clear
();
TW
.
partialGraph
.
graph
.
clear
();
var
voisinage
=
{}
var
voisinage
=
{}
...
@@ -683,9 +723,10 @@ function changeLevel(optionalTgtState) {
...
@@ -683,9 +723,10 @@ function changeLevel(optionalTgtState) {
// var t0 = performance.now()
// var t0 = performance.now()
for
(
var
nid
in
TW
.
Nodes
)
{
for
(
var
nid
in
TW
.
Nodes
)
{
if
(
activetypes
[
TW
.
catDict
[
TW
.
Nodes
[
nid
].
type
]])
if
(
activetypesDict
[
TW
.
Nodes
[
nid
].
type
])
{
// we add 1 by 1
// we add 1 by 1 (POSS: use hidden instead)
add1Elem
(
nid
)
add1Elem
(
nid
)
}
}
}
for
(
var
eid
in
TW
.
Edges
)
{
for
(
var
eid
in
TW
.
Edges
)
{
for
(
var
k
in
activereltypes
)
{
for
(
var
k
in
activereltypes
)
{
...
@@ -715,6 +756,16 @@ function changeLevel(optionalTgtState) {
...
@@ -715,6 +756,16 @@ function changeLevel(optionalTgtState) {
updateDynamicFacets
()
updateDynamicFacets
()
changeGraphAppearanceByFacets
(
getActivetypesNames
()
)
changeGraphAppearanceByFacets
(
getActivetypesNames
()
)
// going back to global: recolor nodes that were out of scope
if
(
futurelevel
)
{
for
(
var
ty
in
activetypesDict
)
{
if
(
TW
.
gui
.
handpickedcolors
[
ty
].
alton
)
{
let
recolorMethod
=
getColorFunction
(
TW
.
gui
.
handpickedcolors
[
ty
].
altattr
)
window
[
recolorMethod
](
TW
.
gui
.
handpickedcolors
[
ty
].
altattr
)
}
}
}
// recreate FA2 nodes array after you change the nodes
// recreate FA2 nodes array after you change the nodes
reInitFa2
({
reInitFa2
({
useSoftMethod
:
false
,
useSoftMethod
:
false
,
...
...
twmain/extras_explorerjs.js
View file @
4f2ad358
...
@@ -68,77 +68,125 @@ function changeGraphAppearanceByFacets(actypes) {
...
@@ -68,77 +68,125 @@ function changeGraphAppearanceByFacets(actypes) {
if
(
!
actypes
)
actypes
=
getActivetypesNames
()
if
(
!
actypes
)
actypes
=
getActivetypesNames
()
let
currentNbNodes
=
TW
.
partialGraph
.
graph
.
nNodes
()
let
colorsMeta
=
{}
let
allNbNodes
=
TW
.
partialGraph
.
graph
.
nNodes
()
// create colormenu and 1st default entry
var
color_menu_info
=
'<li><a href="#" onclick="TW.gui.handpickedcolor = false ; graphResetLabelsAndSizes() ; TW.partialGraph.refresh()">By Default</a></li>'
;
let
gotPreviousLouvain
=
false
let
gotPreviousLouvain
=
false
if
(
$
(
"#colorgraph-menu"
).
length
>
0
)
{
for
(
var
tid
in
actypes
)
{
let
ty
=
actypes
[
tid
]
let
currentNbNodes
=
{}
for
(
var
k
in
actypes
)
{
currentNbNodes
[
actypes
[
k
]]
=
TW
.
partialGraph
.
graph
.
getNodesByType
(
TW
.
catDict
[
actypes
[
k
]]).
length
}
// each facet family or clustering type was already prepared
// 1st loop: census on [colors <=> types] and involved nb Nodes
for
(
var
attTitle
in
TW
.
Facets
[
ty
]
)
{
for
(
var
k
in
actypes
)
{
let
ty
=
actypes
[
k
]
// console.warn('changeGraphAppearanceByFacets:', ty, attTitle)
let
attNbNodes
=
currentNbNodes
[
ty
]
// note any previous louvains
// each facet family or clustering type was already prepared
if
(
attTitle
==
'clust_louvain'
)
gotPreviousLouvain
=
true
for
(
var
attTitle
in
TW
.
Facets
[
ty
])
{
if
(
!
colorsMeta
[
attTitle
])
{
colorsMeta
[
attTitle
]
=
[]
}
// attribute counts: nb of classes
// attribute counts: nb of classes
// POSS here distinguish [ty][attTitle].classes.length and ranges.length
// POSS here distinguish [ty][attTitle].classes.length and ranges.length
var
attNbClasses
=
TW
.
Facets
[
ty
][
attTitle
].
invIdx
.
length
let
attNbClasses
=
TW
.
Facets
[
ty
][
attTitle
].
invIdx
.
length
var
attNbNodes
=
currentNbNodes
if
(
attNbClasses
)
{
if
(
attNbClasses
)
{
let
lastClass
=
TW
.
Facets
[
ty
][
attTitle
].
invIdx
[
attNbClasses
-
1
]
let
lastClass
=
TW
.
Facets
[
ty
][
attTitle
].
invIdx
[
attNbClasses
-
1
]
if
(
lastClass
.
labl
&&
/^_non_numeric_/
.
test
(
lastClass
.
labl
)
&&
lastClass
.
nids
)
{
if
(
lastClass
.
labl
&&
/^_non_numeric_/
.
test
(
lastClass
.
labl
)
&&
lastClass
.
nids
)
{
if
(
lastClass
.
nids
.
length
)
{
if
(
lastClass
.
nids
.
length
)
{
attNbNodes
-=
lastClass
.
nids
.
length
attNbNodes
-=
lastClass
.
nids
.
length
}
}
else
{
else
{
attNbClasses
-=
1
attNbClasses
-=
1
}
}
}
}
}
}
// coloringFunction
// note any previous louvains
var
colMethod
if
(
attTitle
==
'clust_louvain'
)
gotPreviousLouvain
=
true
// read from user settings
// save relevant info
if
(
TW
.
facetOptions
[
attTitle
]
&&
TW
.
facetOptions
[
attTitle
][
'col'
])
{
colorsMeta
[
attTitle
].
push
({
colMethod
=
TW
.
gui
.
colorFuns
[
TW
.
facetOptions
[
attTitle
][
'col'
]]
'type'
:
ty
,
'nbDomain'
:
attNbNodes
,
'nbOutput'
:
attNbClasses
})
}
}
console
.
log
(
colorsMeta
)
// sorted by type and how many types (one type x by alpha, one type y by alpha, two types xy by alpha)
let
colorsList
=
Object
.
keys
(
colorsMeta
)
colorsList
.
sort
(
function
(
a
,
b
)
{
let
cmp
=
colorsMeta
[
a
].
length
-
colorsMeta
[
b
].
length
if
(
cmp
==
0
)
{
cmp
=
(
a
in
TW
.
sigmaAttributes
)
-
(
b
in
TW
.
sigmaAttributes
)
if
(
cmp
==
0
)
{
if
(
colorsMeta
[
a
][
0
].
type
<
colorsMeta
[
b
][
0
].
type
)
cmp
=
-
1
else
if
(
colorsMeta
[
a
][
0
].
type
>
colorsMeta
[
b
][
0
].
type
)
cmp
=
1
else
{
if
(
a
<
b
)
cmp
=
-
1
else
if
(
a
>
b
)
cmp
=
1
}
}
}
}
return
cmp
})
// fallback guess-values
// 2nd loop: create colormenu and 1st default entry
if
(
!
colMethod
)
{
var
color_menu_info
=
'<li><a href="#" onclick="graphResetAllColors() ; TW.partialGraph.refresh()">By Default</a></li>'
;
if
(
attTitle
.
indexOf
(
"clust"
)
>-
1
||
attTitle
.
indexOf
(
"class"
)
>-
1
)
{
// for classes and clusters
colMethod
=
"clusterColoring"
}
else
{
colMethod
=
"gradientColoring"
}
}
// family label :)
let
lastGroup
=
null
var
attLabel
;
if
(
$
(
"#colorgraph-menu"
).
length
>
0
)
{
if
(
TW
.
facetOptions
[
attTitle
]
&&
TW
.
facetOptions
[
attTitle
][
'legend'
])
{
attLabel
=
TW
.
facetOptions
[
attTitle
][
'legend'
]
}
else
attLabel
=
attTitle
color_menu_info
+=
`<li><a href="#" onclick='
${
colMethod
}
("
${
attTitle
}
")'>By
${
attLabel
}
(
${
attNbClasses
}
|
${
attNbNodes
}
)</a></li>`
for
(
var
l
in
colorsList
)
{
var
attTitle
=
colorsList
[
l
]
// which concerned types and how many concerned nodes and output classes
let
attNbNodes
=
0
let
forTypes
=
[]
for
(
var
i
in
colorsMeta
[
attTitle
])
{
forTypes
.
push
(
colorsMeta
[
attTitle
][
i
].
type
)
attNbNodes
+=
colorsMeta
[
attTitle
][
i
].
nbDomain
}
}
let
attNbClasses
=
colorsMeta
[
attTitle
][
0
].
nbOutput
// coloring function
let
colMethod
=
getColorFunction
(
attTitle
)
// POSS add cumulated degree via TW.partialGraph.graph.degree(nid)
// family label :)
var
attLabel
;
if
(
TW
.
facetOptions
[
attTitle
]
&&
TW
.
facetOptions
[
attTitle
][
'legend'
])
{
attLabel
=
TW
.
facetOptions
[
attTitle
][
'legend'
]
}
else
attLabel
=
attTitle
if
(
actypes
.
length
==
1
)
{
color_menu_info
+=
`
<li><a href="#" onclick='
${
colMethod
}
("
${
attTitle
}
")'>
By
${
attLabel
}
(
${
attNbClasses
}
|
${
attNbNodes
}
)
</a></li>
`
}
else
{
groupName
=
`
${
forTypes
}
`
if
(
groupName
!=
lastGroup
)
{
color_menu_info
+=
`<li class="pseudo-optgroup">
${
groupName
}
</li>`
}
color_menu_info
+=
`
<li><a href="#" onclick='
${
colMethod
}
("
${
attTitle
}
",
${
JSON
.
stringify
(
forTypes
)}
)'>
By
${
attLabel
}
(
${
attNbClasses
}
|
${
attNbNodes
}
)
</a></li>
`
lastGroup
=
groupName
}
}
}
// we also add clust_louvain if not already there
// we also add clust_louvain if not already there
if
(
!
gotPreviousLouvain
)
{
if
(
!
gotPreviousLouvain
)
{
color_menu_info
+=
`<li><a href="#" onclick='clusterColoring("clust_louvain")'>By Louvain clustering ( <span id="louvainN">?</span> |
${
current
NbNodes
}
)</a></li>`
color_menu_info
+=
`<li><a href="#" onclick='clusterColoring("clust_louvain")'>By Louvain clustering ( <span id="louvainN">?</span> |
${
all
NbNodes
}
)</a></li>`
}
}
// for debug
// for debug
...
@@ -148,11 +196,33 @@ function changeGraphAppearanceByFacets(actypes) {
...
@@ -148,11 +196,33 @@ function changeGraphAppearanceByFacets(actypes) {
}
}
// Legend slots were prepared in TW.Facets
// Legend slots were prepared in TW.Facets
}
}
function
getColorFunction
(
attTitle
)
{
// coloringFunction name as str
var
colMethod
// read from user settings
if
(
TW
.
facetOptions
[
attTitle
]
&&
TW
.
facetOptions
[
attTitle
][
'col'
])
{
colMethod
=
TW
.
gui
.
colorFuns
[
TW
.
facetOptions
[
attTitle
][
'col'
]]
}
// fallback guess-values
if
(
!
colMethod
)
{
if
(
attTitle
.
indexOf
(
"clust"
)
>-
1
||
attTitle
.
indexOf
(
"class"
)
>-
1
)
{
// for classes and clusters
colMethod
=
"clusterColoring"
}
else
{
colMethod
=
"gradientColoring"
}
}
return
colMethod
}
function
RunLouvain
()
{
// @cb: optional callback
function
RunLouvain
(
cb
)
{
var
node_realdata
=
[]
var
node_realdata
=
[]
var
nodesV
=
getVisibleNodes
()
var
nodesV
=
getVisibleNodes
()
...
@@ -216,6 +286,11 @@ function RunLouvain() {
...
@@ -216,6 +286,11 @@ function RunLouvain() {
TW
.
facetOptions
[
'clust_louvain'
]
=
{
'col'
:
'cluster'
}
TW
.
facetOptions
[
'clust_louvain'
]
=
{
'col'
:
'cluster'
}
}
}
// NB the LouvainFait flag is updated by caller fun
// NB the LouvainFait flag is updated by caller fun
// callback
if
(
cb
&&
typeof
cb
==
'function'
)
{
cb
()
}
}
}
...
@@ -269,139 +344,168 @@ function graphResetLabelsAndSizes(){
...
@@ -269,139 +344,168 @@ function graphResetLabelsAndSizes(){
n
.
size
=
TW
.
Nodes
[
n
.
id
].
size
n
.
size
=
TW
.
Nodes
[
n
.
id
].
size
}
}
}
}
set_ClustersLegend
()
}
}
// @daclass: the name of a numeric/categorical attribute from node.attributes
function
graphResetAllColors
()
{
// @groupingTicks: an optional threshold's array expressing ranges with their low/up bounds label and ref to matchin nodeIds
graphResetLabelsAndSizes
()
function
set_ClustersLegend
(
daclass
,
groupedByTicks
)
{
TW
.
gui
.
handpickedcolorsReset
()
$
(
"#legend-for-clusters"
).
removeClass
(
"my-legend"
)
updateColorsLegend
()
$
(
"#legend-for-clusters"
).
html
(
""
)
}
if
(
daclass
==
null
)
return
;
// removes selectively for an array of nodetypes
function
clearColorLegend
(
forTypes
)
{
// console.log('clearColorLegend', forTypes)
for
(
var
ty
of
forTypes
)
{
let
legTy
=
document
.
getElementById
(
"legend-for-"
+
ty
)
if
(
legTy
)
legTy
.
remove
()
}
}
var
actypes
=
getActivetypesNames
()
// TODO test more for multiple types
// @daclass: the name of a numeric/categorical attribute from node.attributes
// we have no specifications yet for colors (and legends) on multiple types
// @forTypes: array of which typenames are concerned
if
(
actypes
.
length
>
1
)
{
// @groupingTicks: an optional threshold's array expressing ranges with their low/up bounds label and ref to matchin nodeIds
console
.
warn
(
"colors by bins will only color nodes of type 0"
)
function
updateColorsLegend
(
daclass
,
forTypes
,
groupedByTicks
)
{
// shortcut to erase legends for all types
if
(
daclass
==
null
)
{
clearColorLegend
(
TW
.
categories
)
$
(
"#legend-for-facets"
).
html
(
""
)
};
// current display among TW.categories (ex: ['terms'])
if
(
typeof
forTypes
!=
'array'
||
!
forTypes
.
length
)
{
forTypes
=
getActivetypesNames
().
filter
(
function
(
ty
){
return
daclass
in
TW
.
Facets
[
ty
]
})
}
}
// current display among TW.categories (ex: 'terms')
// (we ignore other types: their color legends remain the same by default)
var
curType
=
actypes
[
0
]
// all infos in a bin array
for
(
var
k
in
forTypes
)
{
var
legendInfo
=
[]
let
curType
=
forTypes
[
k
]
var
LegendDiv
=
"<div id=legend-for-"
+
curType
+
" class=
\"
over-panels my-legend
\"
>"
// sample node color
// all infos in a bin array
var
ClustNB_CurrentColor
=
{}
var
legendInfo
=
[]
// passed as arg or prepared in parseCustom
// sample node color
if
(
!
groupedByTicks
&&
(
!
TW
.
Facets
[
curType
]
||
!
TW
.
Facets
[
curType
][
daclass
]))
{
var
ClustNB_CurrentColor
=
{}
console
.
warn
(
`no class bins for
${
daclass
}
, displaying no legend`
)
$
(
"#legend-for-clusters"
).
hide
()
// passed as arg or prepared in parseCustom
}
if
(
!
groupedByTicks
&&
(
!
TW
.
Facets
[
curType
]
||
!
TW
.
Facets
[
curType
][
daclass
]))
{
else
{
console
.
warn
(
`no class bins for
${
curType
}
${
daclass
}
`
)
let
daclassLabel
=
daclass
if
(
TW
.
facetOptions
&&
TW
.
facetOptions
[
daclass
]
&&
TW
.
facetOptions
[
daclass
].
legend
)
{
daclassLabel
=
TW
.
facetOptions
[
daclass
].
legend
}
}
var
LegendDiv
=
""
else
{
LegendDiv
+=
` <div class="legend-title">
${
daclassLabel
}
</div>`
let
daclassLabel
=
daclass
LegendDiv
+=
' <div class="legend-scale">'
if
(
TW
.
facetOptions
LegendDiv
+=
' <ul class="legend-labels">'
&&
TW
.
facetOptions
[
daclass
]
&&
TW
.
facetOptions
[
daclass
].
legend
)
{
daclassLabel
=
TW
.
facetOptions
[
daclass
].
legend
}
var
legendInfo
=
groupedByTicks
||
TW
.
Facets
[
curType
][
daclass
].
invIdx
LegendDiv
+=
` <div class="legend-title"><small>
${
curType
}
:</small>
${
daclassLabel
}
</div>`
LegendDiv
+=
' <div class="legend-scale">'
LegendDiv
+=
' <ul class="legend-labels">'
// valueclasses (values or intervals or classes) are already sorted in TW.Facets
var
legendInfo
=
groupedByTicks
||
TW
.
Facets
[
curType
][
daclass
].
invIdx
for
(
var
l
in
legendInfo
)
{
var
nMatchedNodes
=
legendInfo
[
l
][
'nids'
].
length
// get a sample node color for each bin/class
// valueclasses (values or intervals or classes) are already sorted in TW.Facets
let
theColor
=
legendInfo
[
l
].
col
||
"#777"
// grey if empty
for
(
var
l
in
legendInfo
)
{
var
nMatchedNodes
=
legendInfo
[
l
][
'nids'
].
length
// create the legend item
// get a sample node color for each bin/class
var
preparedLabel
=
legendInfo
[
l
][
'labl'
]
let
theColor
=
legendInfo
[
l
].
col
||
"#777"
// grey if empty
if
(
/^_non_numeric_/
.
test
(
preparedLabel
))
{
// create the legend item
if
(
!
nMatchedNodes
)
{
var
preparedLabel
=
legendInfo
[
l
][
'labl'
]
continue
// we skip "trash" category if empty
}
if
(
/^_non_numeric_/
.
test
(
preparedLabel
))
{
else
{
if
(
!
nMatchedNodes
)
{
preparedLabel
=
"not numeric"
continue
// we skip "trash" category if empty
}
else
{
preparedLabel
=
"not numeric"
}
}
}
}
// we add a title to cluster classes by ranking their nodes and taking k best labels, except if type is "social"
// we add a title to cluster classes by ranking their nodes and taking k best labels, except if type is "social"
if
(
TW
.
facetOptions
[
daclass
]
&&
TW
.
facetOptions
[
daclass
].
col
==
'cluster'
&&
curType
!=
TW
.
categories
[
1
])
{
if
(
TW
.
facetOptions
[
daclass
]
&&
TW
.
facetOptions
[
daclass
].
col
==
'cluster'
&&
curType
!=
TW
.
categories
[
1
])
{
// let t0 = performance.now()
// let t0 = performance.now()
let
titles
=
[]
let
titles
=
[]
let
theRankingAttr
=
TW
.
facetOptions
[
daclass
].
titlingMetric
let
theRankingAttr
=
TW
.
facetOptions
[
daclass
].
titlingMetric
let
maxLen
=
TW
.
facetOptions
[
daclass
].
titlingNTerms
||
2
let
maxLen
=
TW
.
facetOptions
[
daclass
].
titlingNTerms
||
2
// custom accessor (sigma auto attr or user settings or by default)
// custom accessor (sigma auto attr or user settings or by default)
let
getVal
let
getVal
if
(
theRankingAttr
)
{
if
(
theRankingAttr
)
{
// one of the 3 sigma dynamic attributes 'degree', etc
// one of the 3 sigma dynamic attributes 'degree', etc
if
(
theRankingAttr
in
TW
.
sigmaAttributes
)
{
if
(
theRankingAttr
in
TW
.
sigmaAttributes
)
{
getVal
=
TW
.
sigmaAttributes
[
theRankingAttr
](
TW
.
partialGraph
)
getVal
=
TW
.
sigmaAttributes
[
theRankingAttr
](
TW
.
partialGraph
)
}
// a user setting for a source data attribute
else
{
getVal
=
function
(
node
)
{
return
node
.
attributes
[
theRankingAttr
]}
}
}
}
//
a user setting for a source data attribut
e
//
default ranking: by siz
e
else
{
else
{
getVal
=
function
(
node
)
{
return
node
.
attributes
[
theRankingAttr
]
}
getVal
=
function
(
node
)
{
return
node
.
size
}
}
}
}
// default ranking: by size
else
{
getVal
=
function
(
node
)
{
return
node
.
size
}
}
for
(
let
j
in
legendInfo
[
l
][
'nids'
])
{
for
(
let
j
in
legendInfo
[
l
][
'nids'
])
{
let
n
=
TW
.
partialGraph
.
graph
.
nodes
(
legendInfo
[
l
][
'nids'
][
j
])
let
n
=
TW
.
partialGraph
.
graph
.
nodes
(
legendInfo
[
l
][
'nids'
][
j
])
let
theRankingVal
=
getVal
(
n
)
let
theRankingVal
=
getVal
(
n
)
if
(
titles
.
length
<
maxLen
)
{
if
(
titles
.
length
<
maxLen
)
{
titles
.
push
({
'key'
:
n
.
label
,
'val'
:
theRankingVal
})
}
else
{
// we keep titles sorted for this
let
lastMax
=
titles
.
slice
(
-
1
)[
0
].
val
if
(
theRankingVal
>
lastMax
)
{
titles
.
push
({
'key'
:
n
.
label
,
'val'
:
theRankingVal
})
titles
.
push
({
'key'
:
n
.
label
,
'val'
:
theRankingVal
})
}
}
else
{
// we keep titles sorted for this
let
lastMax
=
titles
.
slice
(
-
1
)[
0
].
val
if
(
theRankingVal
>
lastMax
)
{
titles
.
push
({
'key'
:
n
.
label
,
'val'
:
theRankingVal
})
}
}
titles
.
sort
(
function
(
a
,
b
)
{
return
b
.
val
-
a
.
val
})
titles
=
titles
.
slice
(
0
,
maxLen
)
}
}
titles
.
sort
(
function
(
a
,
b
)
{
return
b
.
val
-
a
.
val
})
// replacing the cluster numbers by those k best titles in the legend
titles
=
titles
.
slice
(
0
,
maxLen
)
preparedLabel
=
"["
+
titles
.
map
(
function
(
x
){
return
x
.
key
}).
join
(
' / '
)
+
"...]"
+
` (
${
nMatchedNodes
}
)`
}
// replacing the cluster numbers by those k best titles in the legend
// console.log("finding title perf", performance.now() - t0, titles)
preparedLabel
=
"["
+
titles
.
map
(
function
(
x
){
return
x
.
key
}).
join
(
' / '
)
+
"...]"
+
` (
${
nMatchedNodes
}
)`
}
//
console.log("finding title perf", performance.now() - t0, titles)
//
all-in-one argument for SomeEffect
}
var
valueclassId
=
`
${
curType
}
::
${
daclass
}
::
${
l
}
`
// all-in-one argument for SomeEffect
var
colorBg
=
`<span class="lgdcol" style="background:
${
theColor
}
;"></span>`
var
valueclassId
=
`
${
curType
}
::
${
daclass
}
::
${
l
}
`
var
colorBg
=
`<span class="lgdcol" style="background:
${
theColor
}
;"></span>`
LegendDiv
+=
`<li onclick='SomeEffect("
${
valueclassId
}
")'>`
LegendDiv
+=
colorBg
+
preparedLabel
LegendDiv
+=
"</li>
\n
"
}
LegendDiv
+=
' </ul>'
LegendDiv
+=
' </div>'
LegendDiv
+=
' </div>'
LegendDiv
+=
`<li onclick='SomeEffect("
${
valueclassId
}
")'>`
let
perhapsPreviousLegend
=
document
.
getElementById
(
"legend-for-"
+
curType
)
LegendDiv
+=
colorBg
+
preparedLabel
if
(
perhapsPreviousLegend
)
{
LegendDiv
+=
"</li>
\n
"
perhapsPreviousLegend
.
outerHTML
=
LegendDiv
}
else
{
let
newLegend
=
document
.
createElement
(
'div'
)
$
(
"#legend-for-facets"
).
prepend
(
newLegend
)
newLegend
.
outerHTML
=
LegendDiv
}
}
}
LegendDiv
+=
' </ul>'
LegendDiv
+=
' </div>'
$
(
"#legend-for-clusters"
).
addClass
(
"my-legend"
);
$
(
"#legend-for-clusters"
).
html
(
LegendDiv
)
$
(
"#legend-for-clusters"
).
show
()
}
}
$
(
"#legend-for-facets"
).
show
()
}
}
// = = = = = = = = = = = [ / Clusters Plugin ] = = = = = = = = = = = //
// = = = = = = = = = = = [ / Clusters Plugin ] = = = = = = = = = = = //
...
...
twmain/globalUtils.js
View file @
4f2ad358
...
@@ -96,8 +96,10 @@ function isUndef(variable){
...
@@ -96,8 +96,10 @@ function isUndef(variable){
function
stringToSomeInt
(
anyString
)
{
function
stringToSomeInt
(
anyString
)
{
let
charCodeSum
=
0
let
charCodeSum
=
0
for
(
let
i
=
0
;
i
<
anyString
.
length
;
i
++
)
{
if
(
anyString
&&
anyString
.
length
)
{
charCodeSum
+=
anyString
.
charCodeAt
(
i
)
for
(
let
i
=
0
;
i
<
anyString
.
length
;
i
++
)
{
charCodeSum
+=
anyString
.
charCodeAt
(
i
)
}
}
}
return
charCodeSum
return
charCodeSum
}
}
...
...
twmain/main.js
View file @
4f2ad358
...
@@ -413,6 +413,9 @@ function mainStartGraph(inFormat, inData, twInstance) {
...
@@ -413,6 +413,9 @@ function mainStartGraph(inFormat, inData, twInstance) {
TW
.
ByType
=
dicts
.
byType
// useful for loops
TW
.
ByType
=
dicts
.
byType
// useful for loops
// init the rendering flags (after we got types, before we first render)
TW
.
gui
.
handpickedcolorsReset
(
TW
.
categories
)
// in-place: pre-compute all color/unselected color/size properties
// in-place: pre-compute all color/unselected color/size properties
prepareNodesRenderingProperties
(
TW
.
Nodes
)
prepareNodesRenderingProperties
(
TW
.
Nodes
)
prepareEdgesRenderingProperties
(
TW
.
Edges
,
TW
.
Nodes
)
prepareEdgesRenderingProperties
(
TW
.
Edges
,
TW
.
Nodes
)
...
...
twmain/methods.js
View file @
4f2ad358
...
@@ -97,7 +97,6 @@ TW.resetGraph = function() {
...
@@ -97,7 +97,6 @@ TW.resetGraph = function() {
// reset rendering gui flags
// reset rendering gui flags
TW
.
gui
.
selectionActive
=
false
TW
.
gui
.
selectionActive
=
false
TW
.
gui
.
handpickedcolor
=
false
// reset circle size and cursor
// reset circle size and cursor
TW
.
gui
.
circleSize
=
0
TW
.
gui
.
circleSize
=
0
...
@@ -107,6 +106,9 @@ TW.resetGraph = function() {
...
@@ -107,6 +106,9 @@ TW.resetGraph = function() {
TW
.
gui
.
checkBox
=
false
TW
.
gui
.
checkBox
=
false
TW
.
gui
.
lastFilters
=
{}
TW
.
gui
.
lastFilters
=
{}
// reset colors legends
updateColorsLegend
()
// forget the states
// forget the states
TW
.
states
=
[
TW
.
initialSystemState
]
TW
.
states
=
[
TW
.
initialSystemState
]
...
@@ -734,7 +736,7 @@ function prepareNodesRenderingProperties(nodesDict) {
...
@@ -734,7 +736,7 @@ function prepareNodesRenderingProperties(nodesDict) {
// default unselected color
// default unselected color
defgrey_color
:
"rgba("
+
rgbStr
+
","
+
TW
.
conf
.
sigmaJsDrawingProperties
.
twNodesGreyOpacity
+
")"
,
defgrey_color
:
"rgba("
+
rgbStr
+
","
+
TW
.
conf
.
sigmaJsDrawingProperties
.
twNodesGreyOpacity
+
")"
,
// will be used for repainting (read when TW.gui.handpickedcolor
flag
)
// will be used for repainting (read when TW.gui.handpickedcolor
s flags
)
alt_color
:
null
,
alt_color
:
null
,
altgrey_color
:
null
,
altgrey_color
:
null
,
}
}
...
...
twmain/sigma.parseCustom.js
View file @
4f2ad358
...
@@ -211,8 +211,8 @@ function scanGexf(gexfContent) {
...
@@ -211,8 +211,8 @@ function scanGexf(gexfContent) {
// ex: terms
// ex: terms
// ex: ISItermsriskV2_140 & ISItermsriskV2_140
// ex: ISItermsriskV2_140 & ISItermsriskV2_140
// optional arg optionalNodeConf should contain keys of the form:
// optional arg optionalNodeConf should contain keys of the form:
// "node0": "
NGram
",
// "node0": "
Keywords
",
// "node1": "
Document
"
// "node1": "
Scholars
"
// etc.
// etc.
// (it's read from project_conf.json)
// (it's read from project_conf.json)
function
sortNodeTypes
(
observedTypesDict
,
optionalNodeConf
)
{
function
sortNodeTypes
(
observedTypesDict
,
optionalNodeConf
)
{
...
@@ -220,6 +220,14 @@ function sortNodeTypes(observedTypesDict, optionalNodeConf) {
...
@@ -220,6 +220,14 @@ function sortNodeTypes(observedTypesDict, optionalNodeConf) {
observedTypes
.
sort
(
function
(
a
,
b
)
{
return
observedTypesDict
[
b
]
-
observedTypesDict
[
a
]})
observedTypes
.
sort
(
function
(
a
,
b
)
{
return
observedTypesDict
[
b
]
-
observedTypesDict
[
a
]})
let
nbNodeTypes
=
2
let
nbNodeTypes
=
2
if
(
observedTypes
.
length
>
nbNodeTypes
)
{
console
.
warn
(
`The graph source data has more different node types than
supported. Less frequent node types will be ignored.
Max allowed types:
${
nbNodeTypes
}
,
Found:
${
observedTypes
.
length
}
(namely:
${
observedTypes
}
)`
)
}
var
declaredTypes
=
[]
var
declaredTypes
=
[]
for
(
var
i
=
0
;
i
<
nbNodeTypes
;
i
++
)
{
for
(
var
i
=
0
;
i
<
nbNodeTypes
;
i
++
)
{
if
(
optionalNodeConf
&&
optionalNodeConf
[
"node"
+
i
])
{
if
(
optionalNodeConf
&&
optionalNodeConf
[
"node"
+
i
])
{
...
@@ -234,10 +242,14 @@ function sortNodeTypes(observedTypesDict, optionalNodeConf) {
...
@@ -234,10 +242,14 @@ function sortNodeTypes(observedTypesDict, optionalNodeConf) {
}
}
}
}
var
newcats
=
[]
// console.log("observedTypes", observedTypes)
var
catDict
=
{}
// console.log("declaredTypes", declaredTypes)
var
newcats
=
[]
// will become TW.categories
var
catDict
=
{}
// will become TW.catDict
var
nTypes
=
observedTypes
.
length
var
nTypes
=
observedTypes
.
length
if
(
nTypes
==
0
)
{
if
(
nTypes
==
0
)
{
newcats
[
0
]
=
"Terms"
;
newcats
[
0
]
=
"Terms"
;
catDict
[
"Terms"
]
=
0
;
catDict
[
"Terms"
]
=
0
;
...
@@ -251,43 +263,72 @@ function sortNodeTypes(observedTypesDict, optionalNodeConf) {
...
@@ -251,43 +263,72 @@ function sortNodeTypes(observedTypesDict, optionalNodeConf) {
console
.
log
(
`cat unique (
${
observedTypes
[
0
]}
) =>0`
)
console
.
log
(
`cat unique (
${
observedTypes
[
0
]}
) =>0`
)
}
}
if
(
nTypes
>
1
)
{
if
(
nTypes
>
1
)
{
// allows multiple node types, with an "all the rest" node1
// allows multiple node types even if not well declared
// ----------------------------------------------------
// try stipulated cats, then fallbacks
// POSSIBLE: an "all the rest" last nodeType ?
// possible: loop
if
(
observedTypesDict
[
declaredTypes
[
0
]])
{
let
alreadyUsed
=
{}
newcats
[
0
]
=
declaredTypes
[
0
];
catDict
[
declaredTypes
[
0
]]
=
0
;
// try declared cats in declared position, independantly from each other
}
for
(
var
i
=
0
;
i
<
nbNodeTypes
;
i
++
)
{
if
(
observedTypesDict
[
declaredTypes
[
1
]])
{
if
(
observedTypesDict
[
declaredTypes
[
i
]])
{
newcats
[
1
]
=
declaredTypes
[
1
];
let
validatedType
=
declaredTypes
[
i
]
catDict
[
declaredTypes
[
1
]]
=
1
;
newcats
[
i
]
=
validatedType
;
alreadyUsed
[
validatedType
]
=
true
}
}
}
// NB: type for nodes0 will be the majoritary by default, unless taken
// console.log("found stipulated cats", newcats, catDict)
if
(
!
newcats
[
0
])
{
if
(
observedTypes
[
0
]
!=
newcats
[
1
])
{
// fallbacks: if some or all stipulated cats are not found
newcats
[
0
]
=
observedTypes
[
0
]
// 0 is the most frequent here
// ---------
catDict
[
observedTypes
[
0
]]
=
0
;
}
// heuristic A: fill missing ones, by frequence
else
{
// (eg if nodes0 was not found, then type for nodes0 will be the
newcats
[
0
]
=
observedTypes
[
1
]
// 1 is second most frequent
// majoritary observed one, unless taken where we move one up)
catDict
[
observedTypes
[
1
]]
=
0
;
for
(
var
i
=
0
;
i
<
nbNodeTypes
;
i
++
)
{
if
(
typeof
newcats
[
i
]
==
"undefined"
)
{
for
(
var
j
=
0
;
j
<
nTypes
;
j
++
)
{
if
(
!
alreadyUsed
[
observedTypes
[
j
]])
{
newcats
[
i
]
=
observedTypes
[
j
]
alreadyUsed
[
observedTypes
[
j
]]
=
true
break
}
}
}
}
}
}
// console.log("after filling majority cats", newcats, catDict)
// all the rest
for
(
var
i
in
observedTypes
)
{
// all the rest (heuristic B)
let
c
=
observedTypes
[
i
]
if
(
!
newcats
[
nbNodeTypes
-
1
])
{
// or c is in "all the rest" group
for
(
var
i
in
observedTypes
)
{
// (POSS extend to multitypes)
// without a group others: if there is more than two cats altogether,
if
(
c
!=
newcats
[
0
]
&&
c
!=
newcats
[
1
])
{
// only the last cat counts as node1 cat
if
(
!
newcats
[
1
])
newcats
[
1
]
=
c
;
let
c
=
observedTypes
[
i
]
else
newcats
[
1
]
+=
'/'
+
c
catDict
[
c
]
=
1
;
// -------------------------------------------- for a group "others"
// with a group "others": if there is more than two cats altogether,
// all the non majoritary or non-stipulated
// are grouped here as node1 cat
// but problem: it break the symetry b/w TW.categories and TW.catDict
//
// // c is in "all the rest" group (POSS extend to multitypes)
// if (c != newcats[0] && c != newcats[1]) {
// if (!newcats[1]) newcats[1] = c;
// else newcats[1] += '/'+c
// catDict[c] = 1;
// }
// -------------------------------------------/ for a group "others"
}
}
}
}
}
}
// reverse lookup
for
(
var
i
in
newcats
)
{
catDict
[
newcats
[
i
]]
=
i
}
return
{
'categories'
:
newcats
,
'lookup_dict'
:
catDict
}
return
{
'categories'
:
newcats
,
'lookup_dict'
:
catDict
}
}
}
...
@@ -650,10 +691,18 @@ function dictfyGexf( gexf , categories ){
...
@@ -650,10 +691,18 @@ function dictfyGexf( gexf , categories ){
for
(
var
i
in
categories
)
{
for
(
var
i
in
categories
)
{
nodesByType
[
i
]
=
[]
nodesByType
[
i
]
=
[]
let
subCats
=
categories
[
i
].
split
(
/
\/
/g
)
for
(
var
j
in
subCats
)
{
// without a group "others" -------------------
catDict
[
subCats
[
j
]]
=
i
catDict
[
categories
[
i
]]
=
i
}
// POSS subCats for cat "others" if open types mapped to n types
//
// ----------------------- with a group "others"
// let subCats = categories[i].split(/\//g)
// for (var j in subCats) {
// catDict[subCats[j]] = i
// }
// ---------------------- /with a group "others"
}
}
...
@@ -1077,11 +1126,17 @@ function dictfyJSON( data , categories ) {
...
@@ -1077,11 +1126,17 @@ function dictfyJSON( data , categories ) {
for
(
var
i
in
categories
)
{
for
(
var
i
in
categories
)
{
nodesByType
[
i
]
=
[]
nodesByType
[
i
]
=
[]
let
subCats
=
categories
[
i
].
split
(
/
\/
/g
)
// without a group "others" -------------------
for
(
var
j
in
subCats
)
{
catDict
[
categories
[
i
]]
=
i
catDict
[
subCats
[
j
]]
=
i
}
// POSS subCats for cat "others" if open types mapped to n types
//
// ----------------------- with a group "others"
// let subCats = categories[i].split(/\//g)
// for (var j in subCats) {
// catDict[subCats[j]] = i
// }
// ---------------------- /with a group "others"
}
}
// normalization, same as parseGexf
// normalization, same as parseGexf
...
...
twmain/sigmaUtils.js
View file @
4f2ad358
...
@@ -118,7 +118,7 @@ var SigmaUtils = function () {
...
@@ -118,7 +118,7 @@ var SigmaUtils = function () {
context
.
beginPath
();
context
.
beginPath
();
if
(
settings
(
'twSelectedColor'
)
==
"node"
)
if
(
settings
(
'twSelectedColor'
)
==
"node"
)
context
.
fillStyle
=
TW
.
gui
.
handpickedcolor
?
node
.
customAttrs
.
alt_color
:
node
.
color
;
// node's
context
.
fillStyle
=
TW
.
gui
.
handpickedcolor
s
[
node
.
type
].
alton
?
node
.
customAttrs
.
alt_color
:
node
.
color
;
// node's
else
else
context
.
fillStyle
=
"#fff"
;
// default
context
.
fillStyle
=
"#fff"
;
// default
...
@@ -180,7 +180,6 @@ var SigmaUtils = function () {
...
@@ -180,7 +180,6 @@ var SigmaUtils = function () {
var
color
,
size
,
var
color
,
size
,
prefix
=
settings
(
'prefix'
)
||
''
prefix
=
settings
(
'prefix'
)
||
''
//debug
//debug
// console.warn("rendering edge", edge)
// console.warn("rendering edge", edge)
...
@@ -188,7 +187,7 @@ var SigmaUtils = function () {
...
@@ -188,7 +187,7 @@ var SigmaUtils = function () {
// precomputed color with no opacity
// precomputed color with no opacity
// cf. sigmaTools.edgeRGB
// cf. sigmaTools.edgeRGB
var
baseRGB
=
TW
.
gui
.
handpickedc
olor
?
edge
.
customAttrs
.
alt_rgb
:
edge
.
customAttrs
.
rgb
var
baseRGB
=
edge
.
customAttrs
.
useAltC
olor
?
edge
.
customAttrs
.
alt_rgb
:
edge
.
customAttrs
.
rgb
if
(
edge
.
customAttrs
.
activeEdge
)
{
if
(
edge
.
customAttrs
.
activeEdge
)
{
size
=
(
defSize
*
2
)
+
1
size
=
(
defSize
*
2
)
+
1
...
@@ -291,7 +290,7 @@ var SigmaUtils = function () {
...
@@ -291,7 +290,7 @@ var SigmaUtils = function () {
// mode variants 1: if a coloringFunction is active
// mode variants 1: if a coloringFunction is active
if
(
!
TW
.
gui
.
handpickedcolor
)
{
if
(
!
TW
.
gui
.
handpickedcolor
s
[
node
.
type
].
alton
)
{
nodeColor
=
node
.
color
nodeColor
=
node
.
color
}
}
else
{
else
{
...
@@ -301,7 +300,6 @@ var SigmaUtils = function () {
...
@@ -301,7 +300,6 @@ var SigmaUtils = function () {
// mode variants 2: if node is selected, highlighted or unselected
// mode variants 2: if node is selected, highlighted or unselected
if
(
TW
.
gui
.
selectionActive
)
{
if
(
TW
.
gui
.
selectionActive
)
{
// the selected node(s)
// the selected node(s)
if
(
node
.
customAttrs
.
active
)
{
if
(
node
.
customAttrs
.
active
)
{
// called by label+background overlay cf. "subcall"
// called by label+background overlay cf. "subcall"
...
@@ -317,7 +315,7 @@ var SigmaUtils = function () {
...
@@ -317,7 +315,7 @@ var SigmaUtils = function () {
// passive nodes should blend in the grey of twEdgeGreyColor
// passive nodes should blend in the grey of twEdgeGreyColor
// cf settings_explorerjs, defgrey_color and deselectNodes()
// cf settings_explorerjs, defgrey_color and deselectNodes()
else
{
else
{
if
(
!
TW
.
gui
.
handpickedcolor
)
{
if
(
!
TW
.
gui
.
handpickedcolor
s
[
node
.
type
].
alton
)
{
nodeColor
=
node
.
customAttrs
.
defgrey_color
nodeColor
=
node
.
customAttrs
.
defgrey_color
}
}
else
{
else
{
...
@@ -442,7 +440,7 @@ var SigmaUtils = function () {
...
@@ -442,7 +440,7 @@ var SigmaUtils = function () {
x
=
Math
.
round
(
node
[
prefix
+
'x'
]
-
fontSize
/
2
-
2
);
x
=
Math
.
round
(
node
[
prefix
+
'x'
]
-
fontSize
/
2
-
2
);
y
=
Math
.
round
(
node
[
prefix
+
'y'
]
-
fontSize
/
2
-
2
);
y
=
Math
.
round
(
node
[
prefix
+
'y'
]
-
fontSize
/
2
-
2
);
w
=
Math
.
round
(
w
=
Math
.
round
(
context
.
measureText
(
node
.
label
).
width
+
fontSize
/
2
+
size
+
7
context
.
measureText
(
node
.
label
).
width
+
fontSize
/
2
+
size
+
12
);
);
h
=
Math
.
round
(
fontSize
+
4
);
h
=
Math
.
round
(
fontSize
+
4
);
e
=
Math
.
round
(
fontSize
/
2
+
4
);
e
=
Math
.
round
(
fontSize
/
2
+
4
);
...
@@ -656,11 +654,17 @@ function edgeInfos(anEdge) {
...
@@ -656,11 +654,17 @@ function edgeInfos(anEdge) {
}
}
function
gradientColoring
(
daclass
)
{
// FIXME this function could be optimized
function
gradientColoring
(
daclass
,
forTypes
)
{
graphResetLabelsAndSizes
()
// full loop
graphResetLabelsAndSizes
()
// full loop
TW
.
gui
.
handpickedcolor
=
true
if
(
typeof
forTypes
!=
'array'
||
!
forTypes
.
length
)
{
// default strategy on multiple types: color all types that have the attr
forTypes
=
getActivetypesNames
().
filter
(
function
(
ty
){
return
daclass
in
TW
.
Facets
[
ty
]
})
}
// value getter
// value getter
let
getVal
let
getVal
...
@@ -672,18 +676,20 @@ function gradientColoring(daclass) {
...
@@ -672,18 +676,20 @@ function gradientColoring(daclass) {
}
}
var
min_pow
=
0
;
var
min_pow
=
0
;
for
(
var
nid
in
TW
.
Nodes
)
{
for
(
var
k
in
forTypes
)
{
var
the_node
=
TW
.
Nodes
[
nid
]
let
nids
=
TW
.
ByType
[
TW
.
catDict
[
forTypes
[
k
]]]
var
attval
=
getVal
(
the_node
);
for
(
var
j
in
nids
)
{
let
attval
=
getVal
(
TW
.
Nodes
[
nids
[
j
]
]);
if
(
!
isNaN
(
parseFloat
(
attval
))
)
{
//is float
if
(
!
isNaN
(
parseFloat
(
attval
))
)
{
//is float
while
(
true
)
{
while
(
true
)
{
var
themult
=
Math
.
pow
(
10
,
min_pow
);
var
themult
=
Math
.
pow
(
10
,
min_pow
);
if
(
parseFloat
(
attval
)
==
0.0
)
break
;
if
(
parseFloat
(
attval
)
==
0.0
)
break
;
if
(
(
parseFloat
(
attval
)
*
themult
)
<
1.0
)
{
if
(
(
parseFloat
(
attval
)
*
themult
)
<
1.0
)
{
min_pow
++
;
min_pow
++
;
}
else
break
;
}
else
break
;
}
}
}
}
}
}
}
var
NodeID_Val
=
{}
var
NodeID_Val
=
{}
...
@@ -692,9 +698,13 @@ function gradientColoring(daclass) {
...
@@ -692,9 +698,13 @@ function gradientColoring(daclass) {
var
themult
=
Math
.
pow
(
10
,
min_pow
);
var
themult
=
Math
.
pow
(
10
,
min_pow
);
// console.log('themult', themult)
// console.log('themult', themult)
for
(
var
nid
in
TW
.
Nodes
)
{
for
(
var
k
in
forTypes
)
{
var
the_node
=
TW
.
Nodes
[
nid
]
let
nids
=
TW
.
partialGraph
.
graph
.
getNodesByType
(
var
attval
=
getVal
(
the_node
)
TW
.
catDict
[
forTypes
[
k
]]
// unordered type names to type id
)
for
(
var
j
in
nids
)
{
let
nid
=
nids
[
j
]
var
attval
=
getVal
(
TW
.
Nodes
[
nid
])
var
attnumber
=
Number
(
attval
);
var
attnumber
=
Number
(
attval
);
if
(
isNaN
(
attnumber
))
{
if
(
isNaN
(
attnumber
))
{
...
@@ -707,6 +717,7 @@ function gradientColoring(daclass) {
...
@@ -707,6 +717,7 @@ function gradientColoring(daclass) {
if
(
round_number
<
real_min
)
real_min
=
round_number
;
if
(
round_number
<
real_min
)
real_min
=
round_number
;
if
(
round_number
>
real_max
)
real_max
=
round_number
;
if
(
round_number
>
real_max
)
real_max
=
round_number
;
}
}
}
// console.log("NodeID_Val", NodeID_Val)
// console.log("NodeID_Val", NodeID_Val)
...
@@ -718,14 +729,21 @@ function gradientColoring(daclass) {
...
@@ -718,14 +729,21 @@ function gradientColoring(daclass) {
// console.log("the mult: "+themult)
// console.log("the mult: "+themult)
// console.log(" - - - - - - - - -- - - ")
// console.log(" - - - - - - - - -- - - ")
// [ Scaling node colours(0-255) and sizes(2-7) ]
// [ Scaling node colours(0-255) and sizes(2-7) ]
var
Min_color
=
0
;
var
Min_color
=
0
;
var
Max_color
=
255
;
var
Max_color
=
255
;
var
Min_size
=
1
;
var
Min_size
=
1
;
var
Max_size
=
8
;
var
Max_size
=
8
;
var
setSize
=
(
TW
.
facetOptions
[
daclass
]
&&
TW
.
facetOptions
[
daclass
].
setsize
)
for
(
var
nid
in
NodeID_Val
)
{
for
(
var
nid
in
NodeID_Val
)
{
var
newval_color
=
Math
.
round
(
(
Min_color
+
(
NodeID_Val
[
nid
][
"round"
]
-
real_min
)
*
((
Max_color
-
Min_color
)
/
(
real_max
-
real_min
))
)
);
var
newval_color
// special case: all nodes have the same size
if
(
real_min
==
real_max
)
{
newval_color
=
0
}
else
{
newval_color
=
Math
.
round
(
(
Min_color
+
(
NodeID_Val
[
nid
][
"round"
]
-
real_min
)
*
((
Max_color
-
Min_color
)
/
(
real_max
-
real_min
))
)
);
}
var
hex_color
=
rgbToHex
(
255
,
(
255
-
newval_color
)
,
0
)
var
hex_color
=
rgbToHex
(
255
,
(
255
-
newval_color
)
,
0
)
let
n
=
TW
.
partialGraph
.
graph
.
nodes
(
nid
)
let
n
=
TW
.
partialGraph
.
graph
.
nodes
(
nid
)
...
@@ -736,7 +754,7 @@ function gradientColoring(daclass) {
...
@@ -736,7 +754,7 @@ function gradientColoring(daclass) {
n
.
customAttrs
.
altgrey_color
=
"rgba("
+
(
hex2rgba
(
hex_color
).
slice
(
0
,
3
).
join
(
','
))
+
",0.4)"
n
.
customAttrs
.
altgrey_color
=
"rgba("
+
(
hex2rgba
(
hex_color
).
slice
(
0
,
3
).
join
(
','
))
+
",0.4)"
// optionally changing size
// optionally changing size
if
(
TW
.
facetOptions
[
daclass
]
&&
TW
.
facetOptions
[
daclass
].
sets
ize
)
{
if
(
setS
ize
)
{
var
newval_size
=
Math
.
round
(
(
Min_size
+
(
NodeID_Val
[
nid
][
"round"
]
-
real_min
)
*
((
Max_size
-
Min_size
)
/
(
real_max
-
real_min
))
)
);
var
newval_size
=
Math
.
round
(
(
Min_size
+
(
NodeID_Val
[
nid
][
"round"
]
-
real_min
)
*
((
Max_size
-
Min_size
)
/
(
real_max
-
real_min
))
)
);
n
.
size
=
newval_size
;
n
.
size
=
newval_size
;
}
}
...
@@ -752,36 +770,43 @@ function gradientColoring(daclass) {
...
@@ -752,36 +770,43 @@ function gradientColoring(daclass) {
// Edge precompute alt_rgb by new source-target nodes-colours combination
// Edge precompute alt_rgb by new source-target nodes-colours combination
repaintEdges
()
repaintEdges
()
// remember in clusters
// remember in clusters of each requested type
let
bins
=
TW
.
Facets
[
getActivetypesNames
()[
0
]][
daclass
]
for
(
var
k
in
forTypes
)
{
if
(
bins
&&
bins
.
invIdx
)
{
let
ty
=
forTypes
[
k
]
for
(
var
i
in
bins
.
invIdx
)
{
TW
.
gui
.
handpickedcolors
[
ty
]
=
{
if
(
bins
.
invIdx
[
i
].
labl
!=
'_non_numeric_'
)
{
'alton'
:
true
,
let
nidList
=
bins
.
invIdx
[
i
][
'nids'
]
'altattr'
:
daclass
,
if
(
nidList
.
length
)
{
}
// we take first non null exemplar from last in the range
let
bins
=
TW
.
Facets
[
ty
][
daclass
]
// (possible skip due to changeLevel or filters)
if
(
bins
&&
bins
.
invIdx
)
{
for
(
var
k
=
nidList
.
length
-
1
;
k
>=
0
;
k
--
)
{
for
(
var
i
in
bins
.
invIdx
)
{
let
nd
=
TW
.
partialGraph
.
graph
.
nodes
(
nidList
[
k
])
if
(
bins
.
invIdx
[
i
].
labl
!=
'_non_numeric_'
)
{
if
(
nd
)
{
let
nidList
=
bins
.
invIdx
[
i
][
'nids'
]
bins
.
invIdx
[
i
].
col
=
nd
.
customAttrs
.
alt_color
if
(
nidList
.
length
)
{
break
// we take first non null exemplar from last in the range
// (possible skip due to changeLevel or filters)
for
(
var
k
=
nidList
.
length
-
1
;
k
>=
0
;
k
--
)
{
let
nd
=
TW
.
partialGraph
.
graph
.
nodes
(
nidList
[
k
])
if
(
nd
)
{
bins
.
invIdx
[
i
].
col
=
nd
.
customAttrs
.
alt_color
break
}
}
}
}
}
else
{
bins
.
invIdx
[
i
].
col
=
"#777"
// empty bin
}
}
}
else
{
else
{
bins
.
invIdx
[
i
].
col
=
"#
777"
// empty
bin
bins
.
invIdx
[
i
].
col
=
"#
bbb"
// non numeric values
bin
}
}
}
}
else
{
bins
.
invIdx
[
i
].
col
=
"#bbb"
// non numeric values bin
}
}
}
}
}
// NB legend will group different possible values using
// NB legend will group different possible values using
// precomputed ticks from TW.Facets
.terms
[daclass]
// precomputed ticks from TW.Facets
[type]
[daclass]
set_ClustersLegend
(
daclas
s
)
updateColorsLegend
(
daclass
,
forType
s
)
TW
.
partialGraph
.
render
();
TW
.
partialGraph
.
render
();
}
}
...
@@ -808,15 +833,27 @@ function repaintEdges() {
...
@@ -808,15 +833,27 @@ function repaintEdges() {
if
(
src
&&
tgt
)
{
if
(
src
&&
tgt
)
{
let
src_color
let
src_color
let
tgt_color
let
tgt_color
if
(
TW
.
gui
.
handpickedcolor
)
{
// handpickedcolors on multiple types may or may not affect
// a given edge so we need the useAltColor individual flag
let
useAlt
=
false
if
(
TW
.
gui
.
handpickedcolors
[
src
.
type
].
alton
)
{
src_color
=
src
.
customAttrs
.
alt_color
||
'#555'
src_color
=
src
.
customAttrs
.
alt_color
||
'#555'
tgt_color
=
tgt
.
customAttrs
.
alt_color
||
'#555'
useAlt
=
true
}
}
else
{
else
src_color
=
src
.
color
||
'#555'
src_color
=
src
.
color
||
'#555'
tgt_color
=
tgt
.
color
||
'#555'
if
(
TW
.
gui
.
handpickedcolors
[
tgt
.
type
].
alton
)
{
tgt_color
=
tgt
.
customAttrs
.
alt_color
||
'#555'
useAlt
=
true
}
}
else
tgt_color
=
tgt
.
color
||
'#555'
e
.
customAttrs
.
alt_rgb
=
sigmaTools
.
edgeRGB
(
src_color
,
tgt_color
)
e
.
customAttrs
.
alt_rgb
=
sigmaTools
.
edgeRGB
(
src_color
,
tgt_color
)
e
.
customAttrs
.
useAltColor
=
useAlt
// we don't set e.color because opacity may vary if selected or not
// we don't set e.color because opacity may vary if selected or not
}
}
}
}
...
@@ -830,10 +867,12 @@ function repaintEdges() {
...
@@ -830,10 +867,12 @@ function repaintEdges() {
// (good for values centered around a neutral zone)
// (good for values centered around a neutral zone)
// NB - binning is done at parseCustom (cf. TW.Facets)
// NB - binning is done at parseCustom (cf. TW.Facets)
// - number of bins can be specified by attribute name in TW.facetOptions[daclass]["n"]
// - number of bins can be specified by attribute name in TW.facetOptions[daclass]["n"]
function
heatmapColoring
(
daclass
)
{
function
heatmapColoring
(
daclass
,
forTypes
)
{
var
binColors
var
binColors
var
doModifyLabel
=
false
var
doModifyLabel
=
false
var
actypes
=
getActivetypesNames
()
// let's go
graphResetLabelsAndSizes
()
// full loop
// default value
// default value
let
nColors
=
TW
.
conf
.
legendsBins
||
5
let
nColors
=
TW
.
conf
.
legendsBins
||
5
...
@@ -848,94 +887,109 @@ function heatmapColoring(daclass) {
...
@@ -848,94 +887,109 @@ function heatmapColoring(daclass) {
}
}
}
}
// we have no specifications yet for colors and legends on multiple types
if
(
typeof
forTypes
!=
'array'
||
!
forTypes
.
length
)
{
if
(
actypes
.
length
>
1
)
{
// default strategy on multiple types: color all types that have the attr
console
.
warn
(
"colors by bins will only color nodes of type 0"
)
forTypes
=
getActivetypesNames
().
filter
(
function
(
ty
){
return
daclass
in
TW
.
Facets
[
ty
]
})
}
}
var
ty
=
actypes
[
0
]
for
(
var
k
in
forTypes
)
{
// our binning
var
ty
=
forTypes
[
k
]
var
tickThresholds
=
TW
.
Facets
[
ty
][
daclass
].
invIdx
// verifications
// global flag
if
(
tickThresholds
.
length
-
1
!=
nColors
)
{
TW
.
gui
.
handpickedcolors
[
ty
]
=
{
console
.
warn
(
`heatmapColoring setup mismatch: TW.Facets ticks
${
tickThresholds
.
length
}
- 1 non_numeric from scanAttributes should == nColors
${
nColors
}
`
)
'alton'
:
true
,
nColors
=
tickThresholds
.
length
-
1
'altattr'
:
daclass
,
}
}
binColors
=
getHeatmapColors
(
nColors
)
// our binning
var
tickThresholds
=
TW
.
Facets
[
ty
][
daclass
].
invIdx
// let's go
// verifications
graphResetLabelsAndSizes
()
// full loop
if
(
tickThresholds
.
length
-
1
!=
nColors
)
{
console
.
log
(
`heatmapColoring setup mismatch: TW.Facets ticks
${
tickThresholds
.
length
}
- 1 non_numeric from scanAttributes should == nColors
${
nColors
}
`
)
nColors
=
tickThresholds
.
length
-
1
}
// global flag
binColors
=
getHeatmapColors
(
nColors
)
TW
.
gui
.
handpickedcolor
=
true
// use our valueclass => ids mapping
// use our valueclass => ids mapping
for
(
var
k
in
tickThresholds
)
{
for
(
var
k
in
tickThresholds
)
{
// console.debug('tick infos', tickThresholds[k])
// console.debug('tick infos', tickThresholds[k])
// ex: {labl: "terms||growth_rate||[0 ; 0.583]", nids: Array(99), range: [0 ; 0.583210]}
// ex: {labl: "terms||growth_rate||[0 ; 0.583]", nids: Array(99), range: [0 ; 0.583210]}
let
theColor
let
theColor
// skip grouped NaN values case => grey
// skip grouped NaN values case => grey
if
(
tickThresholds
[
k
].
labl
==
'_non_numeric_'
)
{
if
(
tickThresholds
[
k
].
labl
==
'_non_numeric_'
)
{
theColor
=
'#bbb'
theColor
=
'#bbb'
}
}
else
{
else
{
theColor
=
binColors
[
k
]
theColor
=
binColors
[
k
]
}
}
if
(
tickThresholds
[
k
].
nids
.
length
)
{
if
(
tickThresholds
[
k
].
nids
.
length
)
{
let
rgbColStr
=
hex2rgba
(
binColors
[
k
]).
slice
(
0
,
3
).
join
(
','
)
let
rgbColStr
=
hex2rgba
(
binColors
[
k
]).
slice
(
0
,
3
).
join
(
','
)
// color the referred nodes
// color the referred nodes
for
(
var
j
in
tickThresholds
[
k
].
nids
)
{
for
(
var
j
in
tickThresholds
[
k
].
nids
)
{
let
n
=
TW
.
partialGraph
.
graph
.
nodes
(
tickThresholds
[
k
].
nids
[
j
])
let
n
=
TW
.
partialGraph
.
graph
.
nodes
(
tickThresholds
[
k
].
nids
[
j
])
if
(
n
)
{
if
(
n
)
{
n
.
customAttrs
.
alt_color
=
binColors
[
k
]
n
.
customAttrs
.
alt_color
=
binColors
[
k
]
n
.
customAttrs
.
altgrey_color
=
"rgba("
+
rgbColStr
+
",0.4)"
n
.
customAttrs
.
altgrey_color
=
"rgba("
+
rgbColStr
+
",0.4)"
var
originalLabel
=
TW
.
Nodes
[
n
.
id
].
label
var
originalLabel
=
TW
.
Nodes
[
n
.
id
].
label
if
(
doModifyLabel
)
{
if
(
doModifyLabel
)
{
var
valSt
=
n
.
attributes
[
daclass
]
var
valSt
=
n
.
attributes
[
daclass
]
n
.
label
=
`(
${
valSt
}
)
${
originalLabel
}
`
n
.
label
=
`(
${
valSt
}
)
${
originalLabel
}
`
}
}
}
}
}
}
}
}
// remember
// remember
tickThresholds
[
k
].
col
=
theColor
tickThresholds
[
k
].
col
=
theColor
}
}
}
// Edge precompute alt_rgb by new source-target nodes-colours combination
// Edge precompute alt_rgb by new source-target nodes-colours combination
repaintEdges
()
repaintEdges
()
set_ClustersLegend
(
daclas
s
)
updateColorsLegend
(
daclass
,
forType
s
)
TW
.
partialGraph
.
render
();
TW
.
partialGraph
.
render
();
}
}
function
clusterColoring
(
daclass
)
{
function
clusterColoring
(
daclass
,
forTypes
)
{
graphResetLabelsAndSizes
()
// full loop
graphResetLabelsAndSizes
()
// full loop (could be avoided most times if flag in sstate)
if
(
typeof
forTypes
!=
'array'
||
!
forTypes
.
length
)
{
// default strategy on multiple types: color all types that have the attr
forTypes
=
getActivetypesNames
().
filter
(
function
(
ty
){
return
daclass
in
TW
.
Facets
[
ty
]
})
}
// louvain needs preparation
// louvain needs preparation
if
(
daclass
==
"clust_louvain"
)
{
if
(
daclass
==
"clust_louvain"
)
{
if
(
!
TW
.
SystemState
().
LouvainFait
)
{
if
(
!
TW
.
SystemState
().
LouvainFait
)
{
try
{
try
{
RunLouvain
()
RunLouvain
(
function
()
{
TW
.
SystemState
().
LouvainFait
=
true
TW
.
SystemState
().
LouvainFait
=
true
clusterColoring
(
"clust_louvain"
)
})
}
}
catch
(
e
)
{
catch
(
e
)
{
TW
.
SystemState
().
LouvainFait
=
false
TW
.
SystemState
().
LouvainFait
=
false
console
.
warn
(
"skipped error on louvain, falling back to default colors"
)
console
.
warn
(
"skipped error on louvain, falling back to default colors"
)
daclass
==
'clust_default'
daclass
==
'clust_default'
}
}
return
}
}
}
}
...
@@ -949,10 +1003,10 @@ function clusterColoring(daclass) {
...
@@ -949,10 +1003,10 @@ function clusterColoring(daclass) {
}
}
// reset the global state
// reset the global state
TW
.
gui
.
handpickedcolor
=
false
TW
.
gui
.
handpickedcolorsReset
()
}
}
else
{
else
{
let
colList
=
[]
let
colList
=
[]
if
(
TW
.
conf
.
randomizeClusterColors
)
{
if
(
TW
.
conf
.
randomizeClusterColors
)
{
// shuffle on entire array is better than random sorting function on each element
// shuffle on entire array is better than random sorting function on each element
...
@@ -964,52 +1018,56 @@ function clusterColoring(daclass) {
...
@@ -964,52 +1018,56 @@ function clusterColoring(daclass) {
let
nColors
=
TW
.
gui
.
colorList
.
length
let
nColors
=
TW
.
gui
.
colorList
.
length
for
(
var
k
in
forTypes
)
{
let
typeName
=
forTypes
[
k
]
let
facets
=
TW
.
Facets
[
typeName
][
daclass
]
let
facets
=
TW
.
Facets
[
getActivetypesNames
()[
0
]][
daclass
]
if
(
facets
&&
facets
.
invIdx
)
{
if
(
facets
&&
facets
.
invIdx
)
{
for
(
var
i
in
facets
.
invIdx
)
{
for
(
var
i
in
facets
.
invIdx
)
{
let
valGroup
=
facets
.
invIdx
[
i
]
let
valGroup
=
facets
.
invIdx
[
i
]
let
theColor
let
theColor
if
(
valGroup
.
labl
==
"_non_numeric_"
)
{
if
(
valGroup
.
labl
==
"_non_numeric_"
)
{
theColor
==
'#bbb'
theColor
==
'#bbb'
}
else
{
let
val
=
valGroup
.
val
||
valGroup
.
range
// use the int as an index between 0 and nColors
if
(
parseInt
(
val
)
==
val
)
{
theColor
=
colList
[
val
%
nColors
]
}
}
// or create a representative int on the same range
else
{
else
{
let
someRepresentativeInt
=
stringToSomeInt
(
val
)
%
nColors
let
val
=
valGroup
.
val
||
valGroup
.
range
theColor
=
colList
[
someRepresentativeInt
]
// use the int as an index between 0 and nColors
if
(
parseInt
(
val
)
==
val
)
{
theColor
=
colList
[
val
%
nColors
]
}
// or create a representative int on the same range
else
{
let
someRepresentativeInt
=
stringToSomeInt
(
val
)
%
nColors
theColor
=
colList
[
someRepresentativeInt
]
}
}
}
}
if
(
valGroup
.
nids
.
length
)
{
if
(
valGroup
.
nids
.
length
)
{
let
rgbColStr
=
hex2rgba
(
theColor
).
slice
(
0
,
3
).
join
(
','
)
let
rgbColStr
=
hex2rgba
(
theColor
).
slice
(
0
,
3
).
join
(
','
)
for
(
let
j
in
valGroup
.
nids
)
{
for
(
let
j
in
valGroup
.
nids
)
{
let
theNode
=
TW
.
partialGraph
.
graph
.
nodes
(
valGroup
.
nids
[
j
])
let
theNode
=
TW
.
partialGraph
.
graph
.
nodes
(
valGroup
.
nids
[
j
])
if
(
theNode
)
{
if
(
theNode
)
{
theNode
.
customAttrs
.
alt_color
=
theColor
theNode
.
customAttrs
.
alt_color
=
theColor
theNode
.
customAttrs
.
altgrey_color
=
"rgba("
+
rgbColStr
+
",0.4)"
theNode
.
customAttrs
.
altgrey_color
=
"rgba("
+
rgbColStr
+
","
+
TW
.
conf
.
sigmaJsDrawingProperties
.
twNodesGreyOpacity
+
")"
}
}
}
}
}
}
// remember in TW.Facets
// remember in TW.Facets
valGroup
.
col
=
theColor
valGroup
.
col
=
theColor
}
}
}
}
// fallback on old, slower strategy if scanAttributes inactive
// fallback on old, slower strategy if scanAttributes inactive
else
{
else
{
let
nids
=
TW
.
ByType
[
TW
.
catDict
[
typeName
]]
for
(
var
nid
in
TW
.
Nodes
)
{
for
(
var
j
in
nids
)
{
var
the_node
=
TW
.
partialGraph
.
graph
.
nodes
(
nid
)
let
nid
=
nids
[
j
]
let
the_node
=
TW
.
partialGraph
.
graph
.
nodes
(
nid
)
if
(
the_node
)
{
if
(
the_node
)
{
// POSS: use "hidden" in filters instead of remove/readd
// POSS: use "hidden" in filters instead of remove/readd
// then this condition would be more useful here
//
typeName
then this condition would be more useful here
if
(
!
the_node
.
hidden
)
{
if
(
!
the_node
.
hidden
)
{
var
attval
=
(
!
isUndef
(
the_node
.
attributes
)
&&
!
isUndef
(
the_node
.
attributes
[
daclass
])
)?
the_node
.
attributes
[
daclass
]
:
TW
.
partialGraph
.
graph
.
nodes
(
nid
)[
daclass
];
var
attval
=
(
!
isUndef
(
the_node
.
attributes
)
&&
!
isUndef
(
the_node
.
attributes
[
daclass
])
)?
the_node
.
attributes
[
daclass
]
:
TW
.
partialGraph
.
graph
.
nodes
(
nid
)[
daclass
];
...
@@ -1031,17 +1089,20 @@ function clusterColoring(daclass) {
...
@@ -1031,17 +1089,20 @@ function clusterColoring(daclass) {
the_node
.
customAttrs
.
altgrey_color
=
"rgba("
+
(
hex2rgba
(
theColor
).
slice
(
0
,
3
).
join
(
','
))
+
",0.4)"
the_node
.
customAttrs
.
altgrey_color
=
"rgba("
+
(
hex2rgba
(
theColor
).
slice
(
0
,
3
).
join
(
','
))
+
",0.4)"
}
}
}
}
}
}
// set the global state
TW
.
gui
.
handpickedcolors
[
typeName
]
=
{
'alton'
:
true
,
'altattr'
:
daclass
,
}
}
}
}
// set the global state
TW
.
gui
.
handpickedcolor
=
true
}
}
// Edge precompute alt_rgb by new source-target nodes-colours combination
// Edge precompute alt_rgb by new source-target nodes-colours combination
repaintEdges
()
repaintEdges
()
set_ClustersLegend
(
daclas
s
)
updateColorsLegend
(
daclass
,
forType
s
)
TW
.
partialGraph
.
render
();
TW
.
partialGraph
.
render
();
}
}
...
...
twpresets/settings_explorerjs.comex.js
View file @
4f2ad358
...
@@ -21,7 +21,7 @@ TW.conf = (function(TW){
...
@@ -21,7 +21,7 @@ TW.conf = (function(TW){
// ...or remote bridge to default source api ajax queries
// ...or remote bridge to default source api ajax queries
TWConf
.
sourceAPI
=
{}
TWConf
.
sourceAPI
=
{}
TWConf
.
sourceAPI
[
"nodetypes"
]
=
{
"node0"
:
"
NGram"
,
"node1"
:
"Document
"
}
TWConf
.
sourceAPI
[
"nodetypes"
]
=
{
"node0"
:
"
Keywords"
,
"node1"
:
"Scholars
"
}
TWConf
.
sourceAPI
[
"forNormalQuery"
]
=
"services/api/graph"
TWConf
.
sourceAPI
[
"forNormalQuery"
]
=
"services/api/graph"
TWConf
.
sourceAPI
[
"forFilteredQuery"
]
=
"services/api/graph"
TWConf
.
sourceAPI
[
"forFilteredQuery"
]
=
"services/api/graph"
...
@@ -251,7 +251,7 @@ TW.conf = (function(TW){
...
@@ -251,7 +251,7 @@ TW.conf = (function(TW){
// "default" for white background
// "default" for white background
// not selected <=> (1-greyness)
// not selected <=> (1-greyness)
twNodesGreyOpacity
:
.
4
,
// smaller value: more grey
twNodesGreyOpacity
:
.
5
,
// smaller value: more grey
twBorderGreyColor
:
"rgba(100, 100, 100, 0.5)"
,
twBorderGreyColor
:
"rgba(100, 100, 100, 0.5)"
,
twEdgeGreyColor
:
"rgba(100, 100, 100, 0.25)"
,
twEdgeGreyColor
:
"rgba(100, 100, 100, 0.25)"
,
};
};
...
...
twpresets/settings_explorerjs.devdefault.js
View file @
4f2ad358
...
@@ -21,7 +21,7 @@ TW.conf = (function(TW){
...
@@ -21,7 +21,7 @@ TW.conf = (function(TW){
// ...or remote bridge to default source api ajax queries
// ...or remote bridge to default source api ajax queries
TWConf
.
sourceAPI
=
{}
TWConf
.
sourceAPI
=
{}
TWConf
.
sourceAPI
[
"nodetypes"
]
=
{
"node0"
:
"
NGram"
,
"node1"
:
"Document
"
}
TWConf
.
sourceAPI
[
"nodetypes"
]
=
{
"node0"
:
"
Keywords"
,
"node1"
:
"Scholars
"
}
TWConf
.
sourceAPI
[
"forNormalQuery"
]
=
"services/api/graph"
TWConf
.
sourceAPI
[
"forNormalQuery"
]
=
"services/api/graph"
TWConf
.
sourceAPI
[
"forFilteredQuery"
]
=
"services/api/graph"
TWConf
.
sourceAPI
[
"forFilteredQuery"
]
=
"services/api/graph"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment