diff --git a/.gitignore b/.gitignore index b4a852f..7198f37 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,3 @@ results npm-debug.log node_modules/* package-lock.json -*.DS_Store -gh-pages diff --git a/README.md b/README.md index 7de884f..05154c7 100644 --- a/README.md +++ b/README.md @@ -2,5 +2,11 @@ gl-heatmap2d ============ 2D heatmaps +This version of gl-heatmap2d modifies Mikola Lysenko's original code to optionally produce a discretised heatmap instead of an interpolated one. The discretised heatmap modifications were made by Louise Ord (@ordiology). + +An option, zsmooth, is introduced that defaults to the smoothed heatmap. If zsmooth: false is passed to createHeatmap2D, the discretised heatmap will be rendered. + +Scientific data is often discretised and this option allows the data to be represented as measured rather than smoothing between observations. + # License (c) 2015 Mikola Lysenko. MIT License diff --git a/heatmap.js b/heatmap.js index 7795a17..5190940 100644 --- a/heatmap.js +++ b/heatmap.js @@ -182,6 +182,8 @@ proto.update = function (options) { var y = options.y || iota(shape[1]) var z = options.z || new Float32Array(shape[0] * shape[1]) + var isSmooth = options.zsmooth !== false + this.xData = x this.yData = y @@ -190,11 +192,23 @@ proto.update = function (options) { 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 lox, loy, hix, hiy + if (isSmooth) { + lox = bounds[0] = x[0] + loy = bounds[1] = y[0] + hix = bounds[2] = x[x.length - 1] + hiy = bounds[3] = y[y.length - 1] + } else { + /* To get squares to centre on data values */ + lox = bounds[0] = x[0] + (x[1] - x[0]) / 2 /* starting x value */ + loy = bounds[1] = y[0] + (y[1] - y[0]) / 2 /* starting y value */ + + /* Bounds needs to add half a square on each end */ + hix = bounds[2] = x[x.length - 1] + (x[x.length - 1] - x[x.length - 2]) / 2 + hiy = bounds[3] = y[y.length - 1] + (y[y.length - 1] - y[y.length - 2]) / 2 + + // N.B. Resolution = 1 / range + } var xs = 1.0 / (hix - lox) var ys = 1.0 / (hiy - loy) @@ -203,7 +217,9 @@ proto.update = function (options) { this.shape = [numX, numY] - var numVerts = (numX - 1) * (numY - 1) * (WEIGHTS.length >>> 1) + var numVerts = ( + isSmooth ? (numX - 1) * (numY - 1) : numX * numY + ) * (WEIGHTS.length >>> 1) this.numVertices = numVerts @@ -214,17 +230,35 @@ proto.update = function (options) { 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) + var ni = isSmooth ? numX - 1 : numX + var nj = isSmooth ? numY - 1 : numY + + for (var j = 0; j < nj; ++j) { + var yc0, yc1 + + if (isSmooth) { + yc0 = ys * (y[j] - loy) + yc1 = ys * (y[j + 1] - loy) + } else { + yc0 = j < numY - 1 ? ys * (y[j] - (y[j + 1] - y[j])/2 - loy) : ys * (y[j] - (y[j] - y[j - 1])/2 - loy) + yc1 = j < numY - 1 ? ys * (y[j] + (y[j + 1] - y[j])/2 - loy) : ys * (y[j] + (y[j] - y[j - 1])/2 - loy) + } + + for (var i = 0; i < ni; ++i) { + var xc0, xc1 + + if (isSmooth) { + xc0 = xs * (x[i] - lox) + xc1 = xs * (x[i + 1] - lox) + } else { + xc0 = i < numX - 1 ? xs * (x[i] - (x[i + 1] - x[i])/2 - lox) : xs * (x[i] - (x[i] - x[i - 1])/2 - lox) + xc1 = i < numX - 1 ? xs * (x[i] + (x[i + 1] - x[i])/2 - lox) : xs * (x[i] + (x[i] - x[i - 1])/2 - 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 offset = isSmooth ? (j + dy) * numX + (i + dx) : j * numX + i var zc = z[offset] var colorIdx = bsearch.le(colorLevels, zc) var r, g, b, a diff --git a/package.json b/package.json index 5a1b4d0..0798fe2 100644 --- a/package.json +++ b/package.json @@ -36,14 +36,14 @@ "gl-shader": "^4.2.1", "glslify": "^7.0.0", "iota-array": "^1.0.0", - "typedarray-pool": "^1.1.0" + "typedarray-pool": "^1.2.0" }, "devDependencies": { "canvas-fit": "^1.5.0", "chttps": "^1.0.6", "enable-mobile": "^1.0.7", "fps-indicator": "^1.3.0", - "gl-plot2d": "^1.4.3", + "gl-plot2d": "^1.4.5", "gl-select-box": "^1.0.4", "gl-spikes2d": "^1.0.2", "mouse-change": "^1.4.0",