diff --git a/src/client/containers/SemanticPortal.js b/src/client/containers/SemanticPortal.js index 8dc6cd60bf747b75f646c1b36805a3549a193302..2f892f411e927a9866e95fcfc17584f49a9332c4 100644 --- a/src/client/containers/SemanticPortal.js +++ b/src/client/containers/SemanticPortal.js @@ -49,7 +49,8 @@ import { } from '../helpers/helpers' import * as apexChartsConfig from '../library_configs/ApexCharts/ApexChartsConfig' import * as leafletConfig from '../library_configs/Leaflet/LeafletConfig' -import * as networkConfig from '../library_configs/Cytoscape.js/NetworkConfig' +import * as networkToolsGeneral from '../library_configs/Cytoscape.js/NetworkToolsGeneral' +import * as networkToolsPortalSpecific from '../library_configs/Cytoscape.js/NetworkToolsPortalSpecific' // ** Generate portal configuration based on JSON configs ** import portalConfig from '../../configs/portalConfig.json' @@ -69,6 +70,10 @@ const perspectiveConfigOnlyInfoPages = await createPerspectiveConfigOnlyInfoPage portalID, onlyInstancePagePerspectives: perspectives.onlyInstancePages }) +const networkConfig = { + ...networkToolsGeneral, + ...networkToolsPortalSpecific +} // ** portal configuration end ** // ** Import general components ** diff --git a/src/client/library_configs/Cytoscape.js/NetworkConfig.js b/src/client/library_configs/Cytoscape.js/NetworkConfig.js deleted file mode 100644 index 1223a95b788ed50e8e5e7c2ddec5949d6b3e7b4a..0000000000000000000000000000000000000000 --- a/src/client/library_configs/Cytoscape.js/NetworkConfig.js +++ /dev/null @@ -1,251 +0,0 @@ -import { has } from 'lodash' -import { constrainValue, ValueScaler, ColorScaler } from './NetworkTools' - -// preprocess by pagerank -export const preprocessPagerank = elements => { - const maxEdgeWidth = 8 - - // edges - let arr = elements.edges.map(ele => ele.data.weight) - - // edge width - let res = (new ValueScaler(1.0, maxEdgeWidth)).fitTransform(arr) - elements.edges.forEach((ele, i) => { ele.data.weight = res[i] }) - - // nodes - arr = elements.nodes.map(ele => ele.data.pagerank) - - // node size - res = (new ColorScaler('6px', '24px')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) - - // node label font size - res = (new ValueScaler(8, 12)).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.font_size = res[i] }) - - elements.nodes.forEach(ele => { - if (ele.data.distance === 0) { - ele.data.size = '16px' - ele.data.color = 'black' - ele.data.font_size = 12.0 - // console.log('Found') - } - }) -} - -export const preprocessLetterSampo = elements => { - const maxEdgeWidth = 8 - - /** - const rankSort = arr => { - const arr2 = arr.map(function (o, i) { return { idx: i, obj: o } }).sort((a, b) => a.obj - b.obj) - return arr2.map(function (o, i) { o.ord = i; return o }).sort((a, b) => a.idx - b.idx).map(o => o.ord) - } - */ - - // edges - let arr = elements.edges.map(ele => ele.data.weight || 1) - - // edge width - let res = (new ValueScaler(1.0, maxEdgeWidth)).fitTransform(arr) - elements.edges.forEach((ele, i) => { ele.data.weight = res[i] }) - - // edge color - // https://www.w3schools.com/colors/colors_hsl.asp - res = (new ColorScaler('hsl(30, 64%, 85%)', 'hsl(30, 64%, 35%)')).fitTransform(arr) - elements.edges.forEach((ele, i) => { ele.data.color = res[i] }) - - // nodes - arr = elements.nodes.map(ele => Math.sqrt(ele.data.numLetters || 0)) - - // TODO: adjust node sizes e.g. https://stackoverflow.com/questions/30167117/get-the-current-index-in-sort-function - // node size - res = (new ColorScaler('8px', '40px')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) - - // node color - res = (new ColorScaler('rgb(0,0,0)', 'rgb(255,0,0)')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.color = res[i] }) -} - -export const preprocessEgo = elements => { - const maxEdgeWidth = 8 - // edges - let arr = elements.edges.map(ele => ele.data.weight || 1) - - // edge width - let res = (new ValueScaler(1.0, maxEdgeWidth)).fitTransform(arr) - elements.edges.forEach((ele, i) => { ele.data.weight = res[i] }) - - // edge color - // https://www.w3schools.com/colors/colors_hsl.asp - res = (new ColorScaler('hsl(30, 64%, 85%)', 'hsl(30, 64%, 35%)')).fitTransform(arr) - elements.edges.forEach((ele, i) => { ele.data.color = res[i] }) - - // nodes - arr = elements.nodes.map(ele => has(ele.data, 'distance') ? ele.data.distance : 3) - // node size - res = (new ColorScaler('20px', '8px')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) - - // node color - res = (new ColorScaler('rgb(255,0,0)', 'rgb(0,0,0)')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.color = res[i] }) -} - -export const preprocessTie = elements => { - const maxEdgeWidth = 8 - // edges - let arr = elements.edges.map(ele => ele.data.weight) - - // edge width - let res = (new ValueScaler(1.0, maxEdgeWidth)).fitTransform(arr) - elements.edges.forEach((ele, i) => { ele.data.weight = res[i] }) - - // edge color - res = (new ColorScaler('hsl(30, 64%, 85%)', 'hsl(30, 64%, 35%)')).fitTransform(arr) - elements.edges.forEach((ele, i) => { ele.data.color = res[i] }) - - // nodes - arr = elements.nodes.map(ele => ele.data.pagerank) - - // node size - res = (new ColorScaler('8px', '20px')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) - - // node color - res = (new ColorScaler('rgb(0,0,0)', 'rgb(255,0,0)')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.color = res[i] }) -} - -export const preprocessRelationNetwork = elements => { - preprocessPagerank(elements) - - // nodes - const arr = elements.nodes.map(ele => ele.data.distance) - - // node size - let res = (new ColorScaler('24px', '6px')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) - - // node label font size - res = (new ValueScaler(12, 8)).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.font_size = res[i] }) -} - -// preprocess for person/connections -export const preprocessConnections = elements => { - // edges - let arr = elements.edges.map(ele => ele.data.weight) - - // edge width - let res = (new ValueScaler(1.0, 4.0)).fitTransform(arr) - elements.edges.forEach((ele, i) => { ele.data.weight = res[i] }) - - const maxlength = 60 - elements.edges.forEach(ele => { - const st = ele.data.prefLabel - ele.data.prefLabel = st.length > maxlength ? st.substring(0, maxlength - 3) + '...' : st - }) - // nodes by distance to ego - arr = elements.nodes.map(ele => ele.data.distance) - - // node size - res = (new ColorScaler('24px', '6px')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) - - // node label font size - res = (new ValueScaler(12, 8)).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.font_size = res[i] }) - - elements.nodes.forEach(ele => { ele.data.color = (ele.data.distance < 1) ? 'red' : 'blue' }) - - elements.nodes.forEach(ele => { - if (ele.data.distance === 0) { - ele.data.size = '16px' - ele.data.color = 'black' - ele.data.font_size = 12.0 - // console.log('Found') - } - }) -} - -// preprocess by ego node distance -export const preprocessDistance = elements => { - const maxEdgeWidth = 8 - - // edges - let arr = elements.edges.map(ele => ele.data.weight) - - // edge width - let res = (new ValueScaler(1.0, maxEdgeWidth)).fitTransform(arr) - elements.edges.forEach((ele, i) => { ele.data.weight = res[i] }) - - // console.log(elements.nodes) - // nodes - arr = elements.nodes.map(ele => ele.data.distance) - - // node size - res = (new ColorScaler('24px', '6px')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) - - // label size - res = (new ValueScaler(16, 8)).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.font_size = res[i] }) -} - -export const preprocessPointCloud = elements => { - const nodes = elements.nodes.map(ob => { - return { - data: ob.data, - position: { - x: 360 * parseFloat(ob.data.x), - y: 360 * parseFloat(ob.data.y) - } - } - }) - elements.nodes = nodes - elements.edges = [] -} - -export const preprocessFamilytree = elements => { - const maxEdgeWidth = 8 - - const nodes = elements.nodes.map(ob => { - if (ob.data.distance === 0) { - ob.data.size = '24px' - ob.data.color = 'black' - // console.log('Found') - } - return { - data: ob.data, - position: { - x: 800 * parseFloat(ob.data.x), - y: 600 * parseFloat(ob.data.y) - } - } - }) - elements.nodes = nodes - elements.edges.forEach(edge => { - edge.data.weight = constrainValue({ value: edge.data.weight, maxValue: maxEdgeWidth }) - }) -} - -export const preprocessParliamentSampoPeopleNetwork = elements => { - preprocessPagerank(elements) - - // nodes - const arr = elements.nodes.map(ele => ele.data.distance) - - // node size - let res = (new ColorScaler('26px', '12px')).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) - - // label size - res = (new ValueScaler(12, 8)).fitTransform(arr) - elements.nodes.forEach((ele, i) => { ele.data.font_size = res[i] }) - - // node color - // res = (new ColorScaler('rgb(255, 0, 0)', 'rgb(0, 0, 255)')).fitTransform(arr) - // elements.nodes.forEach((ele, i) => { ele.data.color = res[i] }) -} diff --git a/src/client/library_configs/Cytoscape.js/NetworkTools.js b/src/client/library_configs/Cytoscape.js/NetworkTools.js deleted file mode 100644 index ceba0d428936a5eb1591cdeb8b2a87724b7e44d5..0000000000000000000000000000000000000000 --- a/src/client/library_configs/Cytoscape.js/NetworkTools.js +++ /dev/null @@ -1,59 +0,0 @@ -export const constrainValue = ({ value, maxValue, defaultValue = 1 }) => { - return (value ? (value < maxValue ? value : maxValue) : defaultValue) -} - -export class ValueScaler { - a; - b; - constructor (low, high) { - this.low = low - this.high = high - } - - fit (vals) { - const valmin = Math.min(...vals) - const valmax = Math.max(...vals) - if (valmax === valmin) { - this.a = 0.0 - } else { - this.a = (this.high - this.low) / (valmax - valmin) - } - this.b = this.low - valmin * this.a - } - - transform (vals) { - return vals.map(x => { return x * this.a + this.b }) - } - - fitTransform (vals) { - this.fit(vals) - return this.transform(vals) - } -} - -export class ColorScaler extends ValueScaler { - col1; - col2; - constructor (low, high) { - super(0.0, 1.0) - this.col1 = low - this.col2 = high - } - - // super.fit(vals) - - _process (s0, s1, r) { - const x0 = parseInt(s0) - const x1 = parseInt(s1) - if (isNaN(x0) || isNaN(x1)) return s0 - return Math.floor(x0 + (x1 - x0) * r) - } - - transform (vals) { - const s1 = this.col1.split(/(\d+)/) - const s2 = this.col2.split(/(\d+)/) - const _vals01 = vals.map(x => { return x * this.a + this.b }) - - return _vals01.map(v => s1.map((s, i) => this._process(s, s2[i], v)).join('')) - } -} diff --git a/src/client/library_configs/Cytoscape.js/NetworkToolsGeneral.js b/src/client/library_configs/Cytoscape.js/NetworkToolsGeneral.js new file mode 100644 index 0000000000000000000000000000000000000000..52d7e3771a3f12e3ac33c5c5c0a52b3941dabcae --- /dev/null +++ b/src/client/library_configs/Cytoscape.js/NetworkToolsGeneral.js @@ -0,0 +1,143 @@ +import { has } from 'lodash' + +export const constrainValue = ({ value, maxValue, defaultValue = 1 }) => { + return (value ? (value < maxValue ? value : maxValue) : defaultValue) +} + +export class ValueScaler { + a; + b; + constructor (low, high) { + this.low = low + this.high = high + } + + fit (vals) { + const valmin = Math.min(...vals) + const valmax = Math.max(...vals) + if (valmax === valmin) { + this.a = 0.0 + } else { + this.a = (this.high - this.low) / (valmax - valmin) + } + this.b = this.low - valmin * this.a + } + + transform (vals) { + return vals.map(x => { return x * this.a + this.b }) + } + + fitTransform (vals) { + this.fit(vals) + return this.transform(vals) + } +} + +export class ColorScaler extends ValueScaler { + col1; + col2; + constructor (low, high) { + super(0.0, 1.0) + this.col1 = low + this.col2 = high + } + + // super.fit(vals) + + _process (s0, s1, r) { + const x0 = parseInt(s0) + const x1 = parseInt(s1) + if (isNaN(x0) || isNaN(x1)) return s0 + return Math.floor(x0 + (x1 - x0) * r) + } + + transform (vals) { + const s1 = this.col1.split(/(\d+)/) + const s2 = this.col2.split(/(\d+)/) + const _vals01 = vals.map(x => { return x * this.a + this.b }) + + return _vals01.map(v => s1.map((s, i) => this._process(s, s2[i], v)).join('')) + } +} + +// preprocess by pagerank +export const preprocessPagerank = elements => { + const maxEdgeWidth = 8 + + // edges + let arr = elements.edges.map(ele => ele.data.weight) + + // edge width + let res = (new ValueScaler(1.0, maxEdgeWidth)).fitTransform(arr) + elements.edges.forEach((ele, i) => { ele.data.weight = res[i] }) + + // nodes + arr = elements.nodes.map(ele => ele.data.pagerank) + + // node size + res = (new ColorScaler('6px', '24px')).fitTransform(arr) + elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) + + // node label font size + res = (new ValueScaler(8, 12)).fitTransform(arr) + elements.nodes.forEach((ele, i) => { ele.data.font_size = res[i] }) + + // highlight main node + elements.nodes.forEach(ele => { + if (ele.data.distance === 0) { + ele.data.size = '16px' + ele.data.color = 'black' + ele.data.font_size = 12.0 + } + }) +} + +export const preprocessEgo = elements => { + const maxEdgeWidth = 8 + + // edges + let arr = elements.edges.map(ele => ele.data.weight || 1) + + // edge width + let res = (new ValueScaler(1.0, maxEdgeWidth)).fitTransform(arr) + elements.edges.forEach((ele, i) => { ele.data.weight = res[i] }) + + // edge color + // https://www.w3schools.com/colors/colors_hsl.asp + res = (new ColorScaler('hsl(30, 64%, 85%)', 'hsl(30, 64%, 35%)')).fitTransform(arr) + elements.edges.forEach((ele, i) => { ele.data.color = res[i] }) + + // nodes + arr = elements.nodes.map(ele => has(ele.data, 'distance') ? ele.data.distance : 3) + + // node size + res = (new ColorScaler('20px', '8px')).fitTransform(arr) + elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) + + // node color + res = (new ColorScaler('rgb(255,0,0)', 'rgb(0,0,0)')).fitTransform(arr) + elements.nodes.forEach((ele, i) => { ele.data.color = res[i] }) +} + +// preprocess by ego node distance +export const preprocessDistance = elements => { + const maxEdgeWidth = 8 + + // edges + let arr = elements.edges.map(ele => ele.data.weight) + + // edge width + let res = (new ValueScaler(1.0, maxEdgeWidth)).fitTransform(arr) + elements.edges.forEach((ele, i) => { ele.data.weight = res[i] }) + + // nodes + arr = elements.nodes.map(ele => ele.data.distance) + + // node size + res = (new ColorScaler('24px', '6px')).fitTransform(arr) + elements.nodes.forEach((ele, i) => { ele.data.size = res[i] }) + + // label size + res = (new ValueScaler(16, 8)).fitTransform(arr) + elements.nodes.forEach((ele, i) => { ele.data.font_size = res[i] }) +} diff --git a/src/client/library_configs/Cytoscape.js/NetworkToolsPortalSpecific.js b/src/client/library_configs/Cytoscape.js/NetworkToolsPortalSpecific.js new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391