From 6e2742b7604a9a2ec4a7bae246292b07a1350a68 Mon Sep 17 00:00:00 2001 From: etpinard Date: Tue, 15 Dec 2015 16:13:57 -0500 Subject: [PATCH 1/6] add gl-heatmap2d@1.0.2 --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 3d50e8afbf5..c692aa632cf 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "fs-extra": "^0.26.2", "gl-error2d": "^1.0.0", "gl-error3d": "^1.0.0", + "gl-heatmap2d": "^1.0.2", "gl-line2d": "^1.2.1", "gl-line3d": "^1.1.0", "gl-mat4": "^1.1.2", From d091f13824cabe3ef0a8ae5c0e418ee3798d788f Mon Sep 17 00:00:00 2001 From: etpinard Date: Fri, 18 Dec 2015 13:33:36 -0500 Subject: [PATCH 2/6] wip heatmapgl (got a plot to show up) --- src/plots/gl2d/index.js | 2 +- src/plots/gl2d/scene2d.js | 30 +++--- src/traces/heatmapgl/attributes.js | 14 +++ src/traces/heatmapgl/convert.js | 157 +++++++++++++++++++++++++++++ src/traces/heatmapgl/index.js | 31 ++++++ 5 files changed, 217 insertions(+), 17 deletions(-) create mode 100644 src/traces/heatmapgl/attributes.js create mode 100644 src/traces/heatmapgl/convert.js create mode 100644 src/traces/heatmapgl/index.js diff --git a/src/plots/gl2d/index.js b/src/plots/gl2d/index.js index d8bb69580b9..d446972fe7f 100644 --- a/src/plots/gl2d/index.js +++ b/src/plots/gl2d/index.js @@ -62,7 +62,7 @@ exports.plot = function plotGl2d(gd) { subplotObj._scene2d = scene; } - scene.plot(fullSubplotData, fullLayout, gd.layout); + scene.plot(fullSubplotData, gd.calcdata, fullLayout, gd.layout); } }; diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index fb16dffb638..b4fef9436e6 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -9,7 +9,6 @@ 'use strict'; -var Plots = require('../../plots/plots'); var Axes = require('../../plots/cartesian/axes'); var Fx = require('../../plots/cartesian/graph_interact'); @@ -19,7 +18,6 @@ var createSelectBox = require('gl-select-box'); var createOptions = require('./convert'); var createCamera = require('./camera'); - var htmlToUnicode = require('../../lib/html2unicode'); var showNoWebGlMsg = require('../../lib/show_no_webgl_msg'); @@ -301,11 +299,11 @@ proto.destroy = function() { this.stopped = true; }; -proto.plot = function(fullData, fullLayout) { +proto.plot = function(fullData, calcData, fullLayout) { var glplot = this.glplot, pixelRatio = this.pixelRatio; - var i, j; + var i, j, trace; this.fullLayout = fullLayout; this.updateAxes(fullLayout); @@ -322,21 +320,18 @@ proto.plot = function(fullData, fullLayout) { canvas.height = pixelHeight; } - if(!fullData) fullData = []; - else if(!Array.isArray(fullData)) fullData = [fullData]; - // update traces - var traceData, trace; for(i = 0; i < fullData.length; ++i) { - traceData = fullData[i]; - trace = this.traces[traceData.uid]; + var fullTrace = fullData[i], + calcTrace = calcData[i]; + trace = this.traces[fullTrace.uid]; - if(trace) trace.update(traceData); + if(trace) trace.update(fullTrace, calcTrace); else { - var traceModule = Plots.getModule(traceData.type); - trace = traceModule.plot(this, traceData); + trace = fullTrace._module.plot(this, fullTrace, calcTrace); } - this.traces[traceData.uid] = trace; + + this.traces[fullTrace.uid] = trace; } // remove empty traces @@ -344,8 +339,8 @@ proto.plot = function(fullData, fullLayout) { trace_id_loop: for(i = 0; i < traceIds.length; ++i) { - for(j = 0; j < fullData.length; ++j) { - if(fullData[j].uid === traceIds[i]) continue trace_id_loop; + for(j = 0; j < calcData.length; ++j) { + if(calcData[j][0].trace.uid === traceIds[i]) continue trace_id_loop; } trace = this.traces[traceIds[i]]; @@ -452,9 +447,12 @@ proto.draw = function() { (y / glplot.pixelRatio) - (size.t + (1-domainY[1]) * size.h) ); + if(result && fullLayout.hovermode) { var nextSelection = result.object._trace.handlePick(result); + console.log(result.dataCoord, result.pointId) + if(nextSelection && ( !this.lastPickResult || this.lastPickResult.trace !== nextSelection.trace || diff --git a/src/traces/heatmapgl/attributes.js b/src/traces/heatmapgl/attributes.js new file mode 100644 index 00000000000..e00fd49a1ab --- /dev/null +++ b/src/traces/heatmapgl/attributes.js @@ -0,0 +1,14 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +'use strict'; + + +var heatmapAttrs = require('../scatter/attributes'); + +module.exports = heatmapAttrs; diff --git a/src/traces/heatmapgl/convert.js b/src/traces/heatmapgl/convert.js new file mode 100644 index 00000000000..653c4b93eae --- /dev/null +++ b/src/traces/heatmapgl/convert.js @@ -0,0 +1,157 @@ +/** +* Copyright 2012-2015, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + + +'use strict'; + +var createHeatmap2D = require('gl-heatmap2d'); + +var maxRowLength = require('../heatmap/max_row_length'); +var str2RGBArray = require('../../lib/str2rgbarray'); + +var AXES = ['xaxis', 'yaxis']; + + +function Heatmap(scene, uid) { + this.scene = scene; + this.uid = uid; + + this.name = ''; + this.hoverinfo = 'all'; + + this.xData = []; + this.yData = []; + this.zData = []; + this.textLabels = []; + + this.idToIndex = []; + this.bounds = [0, 0, 0, 0]; + + this.options = { + z: [], + x: [], + y: [], + shape: [0, 0], + colorLevels: [0], + colorValues: [0, 0, 0, 1] + }; + + this.heatmap = createHeatmap2D(scene.glplot, this.options); + this.heatmap._trace = this; +} + +var proto = Heatmap.prototype; + +proto.handlePick = function(pickResult) { + var index = this.idToIndex[pickResult.pointId]; + +// console.log(pickResult.pointId) + + return { + trace: this, + dataCoord: pickResult.dataCoord, + traceCoord: [ + this.xData[index], + this.yData[index] + ], + textLabel: Array.isArray(this.textLabels) ? + this.textLabels[index] : + this.textLabels, + color: Array.isArray(this.color) ? + this.color[index] : + this.color, + name: this.name, + hoverinfo: this.hoverinfo + }; +}; + +proto.update = function(fullTrace, calcTrace) { + var calcPt = calcTrace[0]; + + this.textLabels = fullTrace.text; + this.name = fullTrace.name; + this.hoverinfo = fullTrace.hoverinfo; + + // convert z from 2D -> 1D + var z = calcPt.z; + this.options.z = [].concat.apply([], z); + + var rowLen = z[0].length, + colLen = z.length; + this.options.shape = [rowLen, colLen]; + + // don't use calc'ed bricks + // maybe use xa.makeCalcdata() ??? + var x = fullTrace.x; + if(x) { + this.options.x = x; + this.bounds[0] = x[0]; + this.bounds[2] = x[rowLen - 1]; + } + else { + this.options.x = null; + this.bounds[0] = 0; + this.bounds[2] = rowLen + } + + var y = fullTrace.y; + if(y) { + this.options.y = y; + this.bounds[1] = y[0]; + this.bounds[3] = y[colLen - 1]; + } + else { + this.options.y = null; + this.bounds[1] = 0; + this.bounds[3] = colLen + } + + var colorOptions = convertColorscale(fullTrace); + this.options.colorLevels = colorOptions.colorLevels; + this.options.colorValues = colorOptions.colorValues; + + this.heatmap.update(this.options); +}; + +proto.dispose = function() { + this.heatmap.dispose(); +}; + +function convertColorscale(fullTrace) { + var scl = fullTrace.colorscale, + zmin = fullTrace.zmin, + zmax = fullTrace.zmax; + + var N = scl.length, + domain = new Array(N), + range = new Array(4 * N); + + for(var i = 0; i < N; i++) { + var si = scl[i]; + var color = str2RGBArray(si[1]); + + domain[i] = zmin + si[0] * (zmax - zmin); + + for(var j = 0; j < 4; j++) { + range[(4 * i) + j] = color[j]; + } + } + + return { + colorLevels: domain, + colorValues: range + }; +} + +function createHeatmap(scene, fullTrace, calcTrace) { + var plot = new Heatmap(scene, fullTrace.uid); + plot.update(fullTrace, calcTrace); + return plot; +} + +module.exports = createHeatmap; diff --git a/src/traces/heatmapgl/index.js b/src/traces/heatmapgl/index.js new file mode 100644 index 00000000000..fcd5124f031 --- /dev/null +++ b/src/traces/heatmapgl/index.js @@ -0,0 +1,31 @@ +/** +* Copyright 2012-2015, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + + +'use strict'; + +var HeatmapGl = {}; + +HeatmapGl.attributes = require('./attributes'); +HeatmapGl.supplyDefaults = require('../heatmap/defaults'); +HeatmapGl.colorbar = require('../heatmap/colorbar'); + +HeatmapGl.calc = require('../heatmap/calc'); +HeatmapGl.plot = require('./convert'); + +HeatmapGl.moduleType = 'trace'; +HeatmapGl.name = 'heatmapgl'; +HeatmapGl.basePlotModule = require('../../plots/gl2d'); +HeatmapGl.categories = ['gl2d', '2dMap']; +HeatmapGl.meta = { + description: [ + 'HIGH PERFORMANCE HEATMAPS BABY !!!' + ].join(' ') +}; + +module.exports = HeatmapGl; From f0af183056fab2f9822176f951b357b127cfcb59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Fri, 22 Jan 2016 16:07:54 -0500 Subject: [PATCH 3/6] more wip heatmap gl --- lib/index.js | 3 +- src/plots/gl2d/scene2d.js | 5 ++-- src/traces/heatmap/calc.js | 7 +++-- src/traces/heatmapgl/convert.js | 51 +++++++-------------------------- 4 files changed, 20 insertions(+), 46 deletions(-) diff --git a/lib/index.js b/lib/index.js index 631fed56656..4dd97c941a9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -30,7 +30,8 @@ Core.register([ require('./scattergeo'), require('./choropleth'), require('./scattergl'), - require('./scatterternary') + require('./scatterternary'), + require('../src/traces/heatmapgl') ]); module.exports = Core; diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index b4fef9436e6..cc0ed3df658 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -447,12 +447,9 @@ proto.draw = function() { (y / glplot.pixelRatio) - (size.t + (1-domainY[1]) * size.h) ); - if(result && fullLayout.hovermode) { var nextSelection = result.object._trace.handlePick(result); - console.log(result.dataCoord, result.pointId) - if(nextSelection && ( !this.lastPickResult || this.lastPickResult.trace !== nextSelection.trace || @@ -478,6 +475,7 @@ proto.draw = function() { var parts = hoverinfo.split('+'); if(parts.indexOf('x') === -1) selection.traceCoord[0] = undefined; if(parts.indexOf('y') === -1) selection.traceCoord[1] = undefined; + if(parts.indexOf('z') === -1) selection.traceCoord[2] = undefined; if(parts.indexOf('text') === -1) selection.textLabel = undefined; if(parts.indexOf('name') === -1) selection.name = undefined; } @@ -487,6 +485,7 @@ proto.draw = function() { y: selection.screenCoord[1], xLabel: this.hoverFormatter('xaxis', selection.traceCoord[0]), yLabel: this.hoverFormatter('yaxis', selection.traceCoord[1]), + zLabel: selection.traceCoord[2], text: selection.textLabel, name: selection.name, color: selection.color diff --git a/src/traces/heatmap/calc.js b/src/traces/heatmap/calc.js index 57ee556cd0b..7535ea5dce7 100644 --- a/src/traces/heatmap/calc.js +++ b/src/traces/heatmap/calc.js @@ -175,6 +175,7 @@ function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) { v0, dv, i; + if(Array.isArray(arrayIn) && !isHist && (ax.type!=='category')) { arrayIn = arrayIn.map(ax.d2c); var len = arrayIn.length; @@ -184,7 +185,7 @@ function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) { // and extend it linearly based on the last two points if(len <= numbricks) { // contour plots only want the centers - if(isContour) arrayOut = arrayIn.slice(0, numbricks); + if(isContour || isGL2D) arrayOut = arrayIn.slice(0, numbricks); else if(numbricks === 1) arrayOut = [arrayIn[0]-0.5,arrayIn[0]+0.5]; else { arrayOut = [1.5*arrayIn[0]-0.5*arrayIn[1]]; @@ -217,7 +218,9 @@ function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) { else if(isHist || ax.type==='category') v0 = v0In; else v0 = ax.d2c(v0In); - for(i = isContour ? 0 : -0.5; i < numbricks; i++) arrayOut.push(v0 + dv * i); + for(i = (isContour || isGL2D) ? 0 : -0.5; i < numbricks; i++) { + arrayOut.push(v0 + dv * i); + } } return arrayOut; } diff --git a/src/traces/heatmapgl/convert.js b/src/traces/heatmapgl/convert.js index 653c4b93eae..60db614ac45 100644 --- a/src/traces/heatmapgl/convert.js +++ b/src/traces/heatmapgl/convert.js @@ -11,11 +11,8 @@ var createHeatmap2D = require('gl-heatmap2d'); -var maxRowLength = require('../heatmap/max_row_length'); var str2RGBArray = require('../../lib/str2rgbarray'); -var AXES = ['xaxis', 'yaxis']; - function Heatmap(scene, uid) { this.scene = scene; @@ -48,23 +45,18 @@ function Heatmap(scene, uid) { var proto = Heatmap.prototype; proto.handlePick = function(pickResult) { - var index = this.idToIndex[pickResult.pointId]; - -// console.log(pickResult.pointId) + var index = pickResult.pointId, + shape = this.options.shape; return { trace: this, dataCoord: pickResult.dataCoord, traceCoord: [ - this.xData[index], - this.yData[index] + this.options.x[index % shape[0]], + this.options.y[Math.floor(index / shape[0])], + this.options.z[index] ], - textLabel: Array.isArray(this.textLabels) ? - this.textLabels[index] : - this.textLabels, - color: Array.isArray(this.color) ? - this.color[index] : - this.color, + textLabel: this.textLabels[index], name: this.name, hoverinfo: this.hoverinfo }; @@ -73,7 +65,6 @@ proto.handlePick = function(pickResult) { proto.update = function(fullTrace, calcTrace) { var calcPt = calcTrace[0]; - this.textLabels = fullTrace.text; this.name = fullTrace.name; this.hoverinfo = fullTrace.hoverinfo; @@ -85,36 +76,16 @@ proto.update = function(fullTrace, calcTrace) { colLen = z.length; this.options.shape = [rowLen, colLen]; - // don't use calc'ed bricks - // maybe use xa.makeCalcdata() ??? - var x = fullTrace.x; - if(x) { - this.options.x = x; - this.bounds[0] = x[0]; - this.bounds[2] = x[rowLen - 1]; - } - else { - this.options.x = null; - this.bounds[0] = 0; - this.bounds[2] = rowLen - } - - var y = fullTrace.y; - if(y) { - this.options.y = y; - this.bounds[1] = y[0]; - this.bounds[3] = y[colLen - 1]; - } - else { - this.options.y = null; - this.bounds[1] = 0; - this.bounds[3] = colLen - } + this.options.x = calcPt.x; + this.options.y = calcPt.y; var colorOptions = convertColorscale(fullTrace); this.options.colorLevels = colorOptions.colorLevels; this.options.colorValues = colorOptions.colorValues; + // convert text from 2D -> 1D + this.textLabels = [].concat.apply([], fullTrace.text); + this.heatmap.update(this.options); }; From 1b5459f79009cd87d90b1398cfa873116f8d668f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 26 Jan 2016 14:17:04 -0500 Subject: [PATCH 4/6] fix header and meta description --- src/traces/heatmapgl/convert.js | 2 +- src/traces/heatmapgl/index.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/traces/heatmapgl/convert.js b/src/traces/heatmapgl/convert.js index 60db614ac45..1509f916d51 100644 --- a/src/traces/heatmapgl/convert.js +++ b/src/traces/heatmapgl/convert.js @@ -1,5 +1,5 @@ /** -* Copyright 2012-2015, Plotly, Inc. +* Copyright 2012-2016, Plotly, Inc. * All rights reserved. * * This source code is licensed under the MIT license found in the diff --git a/src/traces/heatmapgl/index.js b/src/traces/heatmapgl/index.js index fcd5124f031..f8789310196 100644 --- a/src/traces/heatmapgl/index.js +++ b/src/traces/heatmapgl/index.js @@ -1,5 +1,5 @@ /** -* Copyright 2012-2015, Plotly, Inc. +* Copyright 2012-2016, Plotly, Inc. * All rights reserved. * * This source code is licensed under the MIT license found in the @@ -24,7 +24,7 @@ HeatmapGl.basePlotModule = require('../../plots/gl2d'); HeatmapGl.categories = ['gl2d', '2dMap']; HeatmapGl.meta = { description: [ - 'HIGH PERFORMANCE HEATMAPS BABY !!!' + 'WebGL heatmap (beta)' ].join(' ') }; From 0242ff0b695b89571481cfc80a085d861d779626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Tue, 29 Mar 2016 14:17:03 -0400 Subject: [PATCH 5/6] fixup (add isGL2D in heatmap calc) --- src/traces/heatmap/calc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/traces/heatmap/calc.js b/src/traces/heatmap/calc.js index 7535ea5dce7..a48af753fe6 100644 --- a/src/traces/heatmap/calc.js +++ b/src/traces/heatmap/calc.js @@ -172,6 +172,7 @@ function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) { var arrayOut = [], isContour = Plots.traceIs(trace, 'contour'), isHist = Plots.traceIs(trace, 'histogram'), + isGL2D = Plots.traceIs(trace, 'gl2d'), v0, dv, i; From 46ceca9d68042dd3740af09601a98958ddd14860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20T=C3=A9treault-Pinard?= Date: Thu, 14 Apr 2016 14:49:23 -0400 Subject: [PATCH 6/6] rm heatmapgl from lib/index.js : - 'heatmagl' is only available through custom bundling by require('plotly.js/lib/heatmapgl'); --- lib/heatmapgl.js | 9 +++++++++ lib/index.js | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 lib/heatmapgl.js diff --git a/lib/heatmapgl.js b/lib/heatmapgl.js new file mode 100644 index 00000000000..f00dcd51551 --- /dev/null +++ b/lib/heatmapgl.js @@ -0,0 +1,9 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +module.exports = require('../src/traces/heatmapgl'); diff --git a/lib/index.js b/lib/index.js index 4dd97c941a9..631fed56656 100644 --- a/lib/index.js +++ b/lib/index.js @@ -30,8 +30,7 @@ Core.register([ require('./scattergeo'), require('./choropleth'), require('./scattergl'), - require('./scatterternary'), - require('../src/traces/heatmapgl') + require('./scatterternary') ]); module.exports = Core;