StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
StackGenVis/frontend/node_modules/gl-heatmap2d/heatmap.js

316 lines
7.5 KiB

'use strict'
module.exports = createHeatmap2D
var bsearch = require('binary-search-bounds')
var iota = require('iota-array')
var pool = require('typedarray-pool')
var createShader = require('gl-shader')
var createBuffer = require('gl-buffer')
var shaders = require('./lib/shaders')
function GLHeatmap2D (
plot,
shader,
pickShader,
positionBuffer,
weightBuffer,
colorBuffer,
idBuffer) {
this.plot = plot
this.shader = shader
this.pickShader = pickShader
this.positionBuffer = positionBuffer
this.weightBuffer = weightBuffer
this.colorBuffer = colorBuffer
this.idBuffer = idBuffer
this.xData = []
this.yData = []
this.shape = [0, 0]
this.bounds = [Infinity, Infinity, -Infinity, -Infinity]
this.pickOffset = 0
}
var proto = GLHeatmap2D.prototype
var WEIGHTS = [
0, 0,
1, 0,
0, 1,
1, 0,
1, 1,
0, 1
]
proto.draw = (function () {
var MATRIX = [
1, 0, 0,
0, 1, 0,
0, 0, 1
]
return function () {
var plot = this.plot
var shader = this.shader
var bounds = this.bounds
var numVertices = this.numVertices
if (numVertices <= 0) {
return
}
var gl = plot.gl
var dataBox = plot.dataBox
var boundX = bounds[2] - bounds[0]
var boundY = bounds[3] - bounds[1]
var dataX = dataBox[2] - dataBox[0]
var dataY = dataBox[3] - dataBox[1]
MATRIX[0] = 2.0 * boundX / dataX
MATRIX[4] = 2.0 * boundY / dataY
MATRIX[6] = 2.0 * (bounds[0] - dataBox[0]) / dataX - 1.0
MATRIX[7] = 2.0 * (bounds[1] - dataBox[1]) / dataY - 1.0
shader.bind()
var uniforms = shader.uniforms
uniforms.viewTransform = MATRIX
uniforms.shape = this.shape
var attributes = shader.attributes
this.positionBuffer.bind()
attributes.position.pointer()
this.weightBuffer.bind()
attributes.weight.pointer(gl.UNSIGNED_BYTE, false)
this.colorBuffer.bind()
attributes.color.pointer(gl.UNSIGNED_BYTE, true)
gl.drawArrays(gl.TRIANGLES, 0, numVertices)
}
})()
proto.drawPick = (function () {
var MATRIX = [
1, 0, 0,
0, 1, 0,
0, 0, 1
]
var PICK_VECTOR = [0, 0, 0, 0]
return function (pickOffset) {
var plot = this.plot
var shader = this.pickShader
var bounds = this.bounds
var numVertices = this.numVertices
if (numVertices <= 0) {
return
}
var gl = plot.gl
var dataBox = plot.dataBox
var boundX = bounds[2] - bounds[0]
var boundY = bounds[3] - bounds[1]
var dataX = dataBox[2] - dataBox[0]
var dataY = dataBox[3] - dataBox[1]
MATRIX[0] = 2.0 * boundX / dataX
MATRIX[4] = 2.0 * boundY / dataY
MATRIX[6] = 2.0 * (bounds[0] - dataBox[0]) / dataX - 1.0
MATRIX[7] = 2.0 * (bounds[1] - dataBox[1]) / dataY - 1.0
for (var i = 0; i < 4; ++i) {
PICK_VECTOR[i] = (pickOffset >> (i * 8)) & 0xff
}
this.pickOffset = pickOffset
shader.bind()
var uniforms = shader.uniforms
uniforms.viewTransform = MATRIX
uniforms.pickOffset = PICK_VECTOR
uniforms.shape = this.shape
var attributes = shader.attributes
this.positionBuffer.bind()
attributes.position.pointer()
this.weightBuffer.bind()
attributes.weight.pointer(gl.UNSIGNED_BYTE, false)
this.idBuffer.bind()
attributes.pickId.pointer(gl.UNSIGNED_BYTE, false)
gl.drawArrays(gl.TRIANGLES, 0, numVertices)
return pickOffset + this.shape[0] * this.shape[1]
}
})()
proto.pick = function (x, y, value) {
var pickOffset = this.pickOffset
var pointCount = this.shape[0] * this.shape[1]
if (value < pickOffset || value >= pickOffset + pointCount) {
return null
}
var pointId = value - pickOffset
var xData = this.xData
var yData = this.yData
return {
object: this,
pointId: pointId,
dataCoord: [
xData[pointId % this.shape[0]],
yData[(pointId / this.shape[0]) | 0]]
}
}
proto.update = function (options) {
options = options || {}
var shape = options.shape || [0, 0]
var x = options.x || iota(shape[0])
var y = options.y || iota(shape[1])
var z = options.z || new Float32Array(shape[0] * shape[1])
this.xData = x
this.yData = y
var colorLevels = options.colorLevels || [0]
var colorValues = options.colorValues || [0, 0, 0, 1]
var colorCount = colorLevels.length
var bounds = this.bounds
var lox = bounds[0] = x[0]
var loy = bounds[1] = y[0]
var hix = bounds[2] = x[x.length - 1]
var hiy = bounds[3] = y[y.length - 1]
var xs = 1.0 / (hix - lox)
var ys = 1.0 / (hiy - loy)
var numX = shape[0]
var numY = shape[1]
this.shape = [numX, numY]
var numVerts = (numX - 1) * (numY - 1) * (WEIGHTS.length >>> 1)
this.numVertices = numVerts
var colors = pool.mallocUint8(numVerts * 4)
var positions = pool.mallocFloat32(numVerts * 2)
var weights = pool.mallocUint8 (numVerts * 2)
var ids = pool.mallocUint32(numVerts)
var ptr = 0
for (var j = 0; j < numY - 1; ++j) {
var yc0 = ys * (y[j] - loy)
var yc1 = ys * (y[j + 1] - loy)
for (var i = 0; i < numX - 1; ++i) {
var xc0 = xs * (x[i] - lox)
var xc1 = xs * (x[i + 1] - lox)
for (var dd = 0; dd < WEIGHTS.length; dd += 2) {
var dx = WEIGHTS[dd]
var dy = WEIGHTS[dd + 1]
var offset = (j + dy) * numX + (i + dx)
var zc = z[offset]
var colorIdx = bsearch.le(colorLevels, zc)
var r, g, b, a
if (colorIdx < 0) {
r = colorValues[0]
g = colorValues[1]
b = colorValues[2]
a = colorValues[3]
} else if (colorIdx === colorCount - 1) {
r = colorValues[4 * colorCount - 4]
g = colorValues[4 * colorCount - 3]
b = colorValues[4 * colorCount - 2]
a = colorValues[4 * colorCount - 1]
} else {
var t = (zc - colorLevels[colorIdx]) /
(colorLevels[colorIdx + 1] - colorLevels[colorIdx])
var ti = 1.0 - t
var i0 = 4 * colorIdx
var i1 = 4 * (colorIdx + 1)
r = ti * colorValues[i0] + t * colorValues[i1]
g = ti * colorValues[i0 + 1] + t * colorValues[i1 + 1]
b = ti * colorValues[i0 + 2] + t * colorValues[i1 + 2]
a = ti * colorValues[i0 + 3] + t * colorValues[i1 + 3]
}
colors[4 * ptr] = 255 * r
colors[4 * ptr + 1] = 255 * g
colors[4 * ptr + 2] = 255 * b
colors[4 * ptr + 3] = 255 * a
positions[2*ptr] = xc0*.5 + xc1*.5;
positions[2*ptr+1] = yc0*.5 + yc1*.5;
weights[2*ptr] = dx;
weights[2*ptr+1] = dy;
ids[ptr] = j * numX + i
ptr += 1
}
}
}
this.positionBuffer.update(positions)
this.weightBuffer.update(weights)
this.colorBuffer.update(colors)
this.idBuffer.update(ids)
pool.free(positions)
pool.free(colors)
pool.free(weights)
pool.free(ids)
}
proto.dispose = function () {
this.shader.dispose()
this.pickShader.dispose()
this.positionBuffer.dispose()
this.weightBuffer.dispose()
this.colorBuffer.dispose()
this.idBuffer.dispose()
this.plot.removeObject(this)
}
function createHeatmap2D (plot, options) {
var gl = plot.gl
var shader = createShader(gl, shaders.vertex, shaders.fragment)
var pickShader = createShader(gl, shaders.pickVertex, shaders.pickFragment)
var positionBuffer = createBuffer(gl)
var weightBuffer = createBuffer(gl)
var colorBuffer = createBuffer(gl)
var idBuffer = createBuffer(gl)
var heatmap = new GLHeatmap2D(
plot,
shader,
pickShader,
positionBuffer,
weightBuffer,
colorBuffer,
idBuffer)
heatmap.update(options)
plot.addObject(heatmap)
return heatmap
}