Skip to content
Snippets Groups Projects
Commit 9b8457be authored by Xiao Gui's avatar Xiao Gui
Browse files

added tests to plotly

parent 3d3590bf
No related branches found
No related tags found
No related merge requests found
......@@ -21,4 +21,7 @@ getTestBed().initTestEnvironment(
const testContext = require.context('../src', true, /\.spec\.ts$/)
testContext.keys().map(testContext)
const workerCtx = require.context('../worker', true, /\.spec\.js$/)
workerCtx.keys().map(workerCtx)
require('../common/util.spec.js')
......@@ -9,16 +9,6 @@ module.exports = {
loaders : ['ts-loader','angular2-template-loader?keepUrl=true'],
exclude : /node_modules|[Ss]pec\.ts$/
},
{
test : /third_party|.*?worker.*?\.js$/,
exclude: /[Ss]pec\.js$/,
use : {
loader : 'file-loader',
options: {
name : '[name].[ext]'
}
}
}
]
},
plugins : [
......
(function(exports){
/**
* units in mm --> convert to nm
*/
const plotyMultiple = 1e6
const { vtkHeader } = globalThis.constants || {}
const getPerpendicularPointsForLine = (A, B, scale) => {
const lineWeight = 1e6
const lineWidth = scale * lineWeight
const lineHeight = scale * lineWeight
let u = A.map((item, index) => {
return item - B[index];
})
const uLength = Math.sqrt((u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2]))
u = u.map((item, index) => {
return item/uLength
})
const n = []
if(Math.abs(u[0]) <= Math.abs(u[1]) && Math.abs(u[0]) <= Math.abs(u[2])) {
n[0] = u[1] * u[1] + u[2] * u[2]
n[1] = -u[1] * u[0]
n[2] = -u[2] * u[0]
}
else if(Math.abs(u[1])<=Math.abs(u[0])&&Math.abs(u[1])<=Math.abs(u[2]))
{
n[0] = -u[0] * u[2]
n[1] = u[0] * u[0] + u[2] * u[2]
n[2] = -u[2] * u[1]
}
else if(Math.abs(u[2])<=Math.abs(u[0])&&Math.abs(u[2])<=Math.abs(u[1]))
{
n[0] = -u[0] * u[2]
n[1] = -u[1] * u[2]
n[2] = u[0] * u[0] + u[1] * u[1]
}
const v = [ u[1] * n[2] - u[2] * n[1], u[2] * n[0] - u[0] * n[2], u[0] * n[1] - u[1] * n[0] ]
const RMul = (k) => {
const res = []
res[0] = v[0]*k[0] + n[0]*k[1] + u[0]*k[2]
res[1] = v[1]*k[0] + n[1]*k[1] + u[1]*k[2]
res[2] = v[2]*k[0] + n[2]*k[1] + u[2]*k[2]
return res
}
const sumArrays = (a1, a2) => {
return a1.map((item, index) => {
return item + a2[index];
})
}
const a = sumArrays(A, RMul([lineWidth,lineHeight,0]))
const b = sumArrays(A, RMul([-lineWidth,lineHeight,0]))
const c = sumArrays(A, RMul([lineWidth,-lineHeight,0]))
const d = sumArrays(A, RMul([-lineWidth,-lineHeight,0]))
const e = sumArrays(B, RMul([lineWidth,lineHeight,0]))
const f = sumArrays(B, RMul([-lineWidth,lineHeight,0]))
const g = sumArrays(B, RMul([lineWidth,-lineHeight,0]))
const h = sumArrays(B, RMul([-lineWidth,-lineHeight,0]))
return `${a.join(' ')}\n ${b.join(' ')}\n ${c.join(' ')}\n ${d.join(' ')}\n ${e.join(' ')}\n ${f.join(' ')}\n ${g.join(' ')}\n ${h.join(' ')}\n `
}
const getFragmentColorString = (colors) => {
const hexToRgb = (hex) => {
const [r, g, b] = hex.match(/\w\w/g).map(x => parseInt(x, 16))
return `emitRGB(vec3(${r/255}, ${g/255}, ${b/255}))`
}
const colorsUnique = colors.filter((cf, i) => colors[i-1] !== cf)
.map((color, j) => {
return `if (label > ${j - 0.01} && label < ${j + 0.01}) { ${hexToRgb(color)}; }`
})
const fragmentColorString = `${colorsUnique.join(' else ')} else {emitRGB(vec3(1.0, 0.1, 0.12));}`
return fragmentColorString
}
const getLineDataVtkPolygonStringWithNumber = (neuronCoordinateLength) => {
let returnString = ''
for (let i = 0; i < neuronCoordinateLength; i++) {
const neuronNumber = 8*i
returnString +=
`3 ${0 + neuronNumber} ${1 + neuronNumber} ${3 + neuronNumber}\n` +
`3 ${0 + neuronNumber} ${2 + neuronNumber} ${3 + neuronNumber}\n` +
`3 ${4 + neuronNumber} ${5 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${4 + neuronNumber} ${6 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${2 + neuronNumber} ${6 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${2 + neuronNumber} ${3 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${3 + neuronNumber} ${1 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${1 + neuronNumber} ${5 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${2 + neuronNumber} ${0 + neuronNumber} ${6 + neuronNumber}\n` +
`3 ${0 + neuronNumber} ${4 + neuronNumber} ${6 + neuronNumber}\n` +
`3 ${1 + neuronNumber} ${0 + neuronNumber} ${4 + neuronNumber}\n` +
`3 ${1 + neuronNumber} ${4 + neuronNumber} ${5 + neuronNumber}\n`
}
return returnString
}
const getColorIds = (colors) => {
let returnString = ''
let colorId = 0
for (let i=0; i < colors.length; i++){
if (i > 0 && colors[i] !== colors[i-1]) {
colorId += 1
}
for (let j=0; j < 8; j++){
if (i === colors.length-1 && j === 7) {
returnString += colorId
} else {
returnString += colorId + '\n'
}
}
}
return returnString
}
const parseLineDataToVtk = (data, scale= 1, plotyMultiple) => {
const lineCoordinates = []
const colors = []
for (let i = 1; i < data.x.length; i++) {
if (data.x[i] !== null && data.x[i-1] !== null) {
lineCoordinates.push([[
data.x[i-1] * plotyMultiple,
data.y[i-1] * plotyMultiple,
data.z[i-1] * plotyMultiple,
], [
data.x[i] * plotyMultiple,
data.y[i] * plotyMultiple,
data.z[i] * plotyMultiple,
]])
colors.push(data.marker.color[i-1])
}
}
const coordinateLength = lineCoordinates.length
const lineCoordinatesArrayToString = (() => {
let returnString = ''
lineCoordinates.forEach(lc => {
returnString += getPerpendicularPointsForLine(lc[0], lc[1], scale)
})
return returnString
})()
const customFragmentColor = getFragmentColorString(colors)
const vtkString = `${vtkHeader}\n` +
`POINTS ${coordinateLength*8} float\n` +
lineCoordinatesArrayToString +
`POLYGONS ${coordinateLength*12} ${coordinateLength*48}\n` +
getLineDataVtkPolygonStringWithNumber(coordinateLength) +
`POINT_DATA ${coordinateLength*8}\n` +
'SCALARS label unsigned_char 1\n' +
'LOOKUP_TABLE none\n' +
getColorIds(colors)
return {vtkString, customFragmentColor}
}
exports.plotly = {
plotyMultiple,
convert: plotlyData => {
const { x, y, z } = plotlyData.traces[0]
const lm = []
for (const idx in x) {
if (typeof x !== 'undefined' && x !== null) {
lm.push([x[idx]*plotyMultiple, y[idx]*plotyMultiple, z[idx]*plotyMultiple])
}
}
const { vtkString, customFragmentColor } = parseLineDataToVtk(plotlyData.traces[0], 5e-3, plotyMultiple)
return {
vtkString,
customFragmentColor,
}
}
}
})(
typeof exports === 'undefined' ? module.exports : exports
)
const vtkHeader = `# vtk DataFile Version 2.0
Created by worker thread at https://github.com/HumanBrainProject/interactive-viewer
ASCII
DATASET POLYDATA`
globalThis.constants = {
vtkHeader,
}
const { plotly } = require('./worker-plotly')
const input = {
traces: [{
"type":"scatter3d",
"mode":"markers",
"name":"points",
"x":[-0.9557710289955139,null,-0.9557710289955139,-0.972806990146637,null],
"y":[4.165919780731201,null,4.165919780731201,4.160162925720215,null],
"z":[1.925400972366333,null,1.925400972366333,1.9260079860687256,null],"opacity":1,
"marker":{"size":1,"color":["#00dd00",null,"#ff0000","#ff0000",null],
"reversescale":false}
}]
}
const expectedOutput = {
customFragmentColor: "if (label > -0.01 && label < 0.01) { emitRGB(vec3(1, 0, 0)); } else {emitRGB(vec3(1.0, 0.1, 0.12));}",
vtkString: "# vtk DataFile Version 2.0\nCreated by worker thread at https://github.com/HumanBrainProject/interactive-viewer\nASCII\nDATASET POLYDATA\nPOINTS 8 float\n-954011.5298146864 4161239.595879443 1930395.281492923\n -957211.0971719137 4170707.908889603 1930395.281492923\n -954330.9608191141 4161131.6525727995 1920406.663239743\n -957530.5281763414 4170599.9655829594 1920406.663239743\n -971047.4909658094 4155482.7408684567 1931002.2951953155\n -974247.0583230368 4164951.0538786165 1931002.2951953155\n -971366.9219702372 4155374.797561813 1921013.6769421357\n -974566.4893274645 4164843.110571973 1921013.6769421357\n POLYGONS 12 48\n3 0 1 3\n3 0 2 3\n3 4 5 7\n3 4 6 7\n3 2 6 7\n3 2 3 7\n3 3 1 7\n3 1 5 7\n3 2 0 6\n3 0 4 6\n3 1 0 4\n3 1 4 5\nPOINT_DATA 8\nSCALARS label unsigned_char 1\nLOOKUP_TABLE none\n0\n0\n0\n0\n0\n0\n0\n0"
}
describe('> worker-plotly.js', () => {
it('> expect input === output', () => {
expect(
plotly.convert(input)
).toEqual(expectedOutput)
})
})
self.importScripts('./worker-second.js')
const vtkHeader = `# vtk DataFile Version 2.0
Created by worker thread at https://github.com/HumanBrainProject/interactive-viewer
ASCII
DATASET POLYDATA`
globalThis.constants = {
vtkHeader
}
if (typeof self.importScripts === 'function') self.importScripts('./worker-second.js')
/**
* TODO migrate processing functionalities to other scripts
* see worker-plotly.js
*/
const validTypes = [
'GET_LANDMARKS_VTK',
......@@ -22,11 +36,6 @@ const validOutType = [
'UPDATE_PARCELLATION_REGIONS'
]
const vtkHeader = `# vtk DataFile Version 2.0
Created by worker thread at https://github.com/HumanBrainProject/interactive-viewer
ASCII
DATASET POLYDATA`
const getVertexHeader = (numVertex) => `POINTS ${numVertex} float`
const getPolyHeader = (numPoly) => `POLYGONS ${numPoly} ${4 * numPoly}`
......@@ -294,204 +303,21 @@ const processParcRegionAttr = (payload) => {
})
}
const parseLineDataToVtk = (data, scale= 1, plotyMultiple) => {
const lineCoordinates = []
const colors = []
for (let i = 1; i < data.x.length; i++) {
if (data.x[i] !== null && data.x[i-1] !== null) {
lineCoordinates.push([[
data.x[i-1] * plotyMultiple,
data.y[i-1] * plotyMultiple,
data.z[i-1] * plotyMultiple,
], [
data.x[i] * plotyMultiple,
data.y[i] * plotyMultiple,
data.z[i] * plotyMultiple,
]])
colors.push(data.marker.color[i-1])
}
}
const coordinateLength = lineCoordinates.length
const lineCoordinatesArrayToString = (() => {
let returnString = ''
lineCoordinates.forEach(lc => {
returnString += getPerpendicularPointsForLine(lc[0], lc[1], scale)
})
return returnString
})()
const customFragmentColor = getFragmentColorString(colors)
const vtkString = `${vtkHeader}\n` +
`POINTS ${coordinateLength*8} float\n` +
lineCoordinatesArrayToString +
`POLYGONS ${coordinateLength*12} ${coordinateLength*48}\n` +
getLineDataVtkPolygonStringWithNumber(coordinateLength) +
`POINT_DATA ${coordinateLength*8}\n` +
'SCALARS label unsigned_char 1\n' +
'LOOKUP_TABLE none\n' +
getColorIds(colors)
return {vtkString, customFragmentColor}
}
const getFragmentColorString = (colors) => {
const hexToRgb = (hex) => {
const [r, g, b] = hex.match(/\w\w/g).map(x => parseInt(x, 16))
return `emitRGB(vec3(${r/255}, ${g/255}, ${b/255}))`
}
const colorsUnique = colors.filter((cf, i) => colors[i-1] !== cf)
.map((color, j) => {
return `if (label > ${j - 0.01} && label < ${j + 0.01}) { ${hexToRgb(color)}; }`
})
const fragmentColorString = `${colorsUnique.join(' else ')} else {emitRGB(vec3(1.0, 0.1, 0.12));}`
return fragmentColorString
}
const getColorIds = (colors) => {
let returnString = ''
let colorId = 0
for (let i=0; i < colors.length; i++){
if (i > 0 && colors[i] !== colors[i-1]) {
colorId += 1
}
for (let j=0; j < 8; j++){
if (i === colors.length-1 && j === 7) {
returnString += colorId
} else {
returnString += colorId + '\n'
}
}
}
return returnString
}
const getLineDataVtkPolygonStringWithNumber = (neuronCoordinateLength) => {
let returnString = ''
for (let i = 0; i < neuronCoordinateLength; i++) {
const neuronNumber = 8*i
returnString +=
`3 ${0 + neuronNumber} ${1 + neuronNumber} ${3 + neuronNumber}\n` +
`3 ${0 + neuronNumber} ${2 + neuronNumber} ${3 + neuronNumber}\n` +
`3 ${4 + neuronNumber} ${5 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${4 + neuronNumber} ${6 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${2 + neuronNumber} ${6 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${2 + neuronNumber} ${3 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${3 + neuronNumber} ${1 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${1 + neuronNumber} ${5 + neuronNumber} ${7 + neuronNumber}\n` +
`3 ${2 + neuronNumber} ${0 + neuronNumber} ${6 + neuronNumber}\n` +
`3 ${0 + neuronNumber} ${4 + neuronNumber} ${6 + neuronNumber}\n` +
`3 ${1 + neuronNumber} ${0 + neuronNumber} ${4 + neuronNumber}\n` +
`3 ${1 + neuronNumber} ${4 + neuronNumber} ${5 + neuronNumber}\n`
}
return returnString
}
const getPerpendicularPointsForLine = (A, B, scale) => {
const lineWeight = 1e6
const lineWidth = scale * lineWeight
const lineHeight = scale * lineWeight
let u = A.map((item, index) => {
return item - B[index];
})
const uLength = Math.sqrt((u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2]))
u = u.map((item, index) => {
return item/uLength
})
const n = []
if(Math.abs(u[0]) <= Math.abs(u[1]) && Math.abs(u[0]) <= Math.abs(u[2])) {
n[0] = u[1] * u[1] + u[2] * u[2]
n[1] = -u[1] * u[0]
n[2] = -u[2] * u[0]
}
else if(Math.abs(u[1])<=Math.abs(u[0])&&Math.abs(u[1])<=Math.abs(u[2]))
{
n[0] = -u[0] * u[2]
n[1] = u[0] * u[0] + u[2] * u[2]
n[2] = -u[2] * u[1]
}
else if(Math.abs(u[2])<=Math.abs(u[0])&&Math.abs(u[2])<=Math.abs(u[1]))
{
n[0] = -u[0] * u[2]
n[1] = -u[1] * u[2]
n[2] = u[0] * u[0] + u[1] * u[1]
}
const v = [ u[1] * n[2] - u[2] * n[1], u[2] * n[0] - u[0] * n[2], u[0] * n[1] - u[1] * n[0] ]
const RMul = (k) => {
const res = []
res[0] = v[0]*k[0] + n[0]*k[1] + u[0]*k[2]
res[1] = v[1]*k[0] + n[1]*k[1] + u[1]*k[2]
res[2] = v[2]*k[0] + n[2]*k[1] + u[2]*k[2]
return res
}
const sumArrays = (a1, a2) => {
return a1.map((item, index) => {
return item + a2[index];
})
}
const a = sumArrays(A, RMul([lineWidth,lineHeight,0]))
const b = sumArrays(A, RMul([-lineWidth,lineHeight,0]))
const c = sumArrays(A, RMul([lineWidth,-lineHeight,0]))
const d = sumArrays(A, RMul([-lineWidth,-lineHeight,0]))
const e = sumArrays(B, RMul([lineWidth,lineHeight,0]))
const f = sumArrays(B, RMul([-lineWidth,lineHeight,0]))
const g = sumArrays(B, RMul([lineWidth,-lineHeight,0]))
const h = sumArrays(B, RMul([-lineWidth,-lineHeight,0]))
return `${a.join(' ')}\n ${b.join(' ')}\n ${c.join(' ')}\n ${d.join(' ')}\n ${e.join(' ')}\n ${f.join(' ')}\n ${g.join(' ')}\n ${h.join(' ')}\n `
}
let plotyVtkUrl
onmessage = (message) => {
if (message.data.method === 'ping') {
return postMessage({
id: message.data.id,
result: `pong ${self.meaningOfLife}`
})
}
if (message.data.method && VALID_METHODS.indexOf(message.data.method) >= 0) {
const { id } = message.data
if (message.data.method === VALID_METHOD.PROCESS_PLOTLY) {
/**
* units in mm --> convert to nm
*/
const plotyMultiple=1e6
try {
const { data: plotlyData } = message.data.param
const { x, y, z } = plotlyData.traces[0]
const lm = []
for (const idx in x) {
if (typeof x !== 'undefined' && x !== null) {
lm.push([x[idx]*plotyMultiple, y[idx]*plotyMultiple, z[idx]*plotyMultiple])
}
}
if (plotyVtkUrl) URL.revokeObjectURL(plotyVtkUrl)
const { vtkString, customFragmentColor} = parseLineDataToVtk(plotlyData.traces[0], 5e-3, plotyMultiple)
plotyVtkUrl = URL.createObjectURL(
const { data: plotlyData } = message.data.param
const {
vtkString,
customFragmentColor
} = self.plotly.convert(plotlyData)
const plotyVtkUrl = URL.createObjectURL(
new Blob([ encoder.encode(vtkString) ], { type: 'application/octet-stream' })
)
postMessage({
......
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