Skip to content

Commit 5c60dbe

Browse files
committed
Merge pull request #427 from plotly/gl-heatmap2d
Add heatmapgl trace module
2 parents 688639f + 46ceca9 commit 5c60dbe

File tree

8 files changed

+203
-19
lines changed

8 files changed

+203
-19
lines changed

lib/heatmapgl.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
module.exports = require('../src/traces/heatmapgl');

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"fs-extra": "^0.26.2",
5656
"gl-error2d": "^1.0.0",
5757
"gl-error3d": "^1.0.0",
58+
"gl-heatmap2d": "^1.0.2",
5859
"gl-line2d": "^1.2.1",
5960
"gl-line3d": "^1.1.0",
6061
"gl-mat4": "^1.1.2",

src/plots/gl2d/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ exports.plot = function plotGl2d(gd) {
6262
subplotObj._scene2d = scene;
6363
}
6464

65-
scene.plot(fullSubplotData, fullLayout, gd.layout);
65+
scene.plot(fullSubplotData, gd.calcdata, fullLayout, gd.layout);
6666
}
6767
};
6868

src/plots/gl2d/scene2d.js

+13-16
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
'use strict';
1111

12-
var Plots = require('../../plots/plots');
1312
var Axes = require('../../plots/cartesian/axes');
1413
var Fx = require('../../plots/cartesian/graph_interact');
1514

@@ -19,7 +18,6 @@ var createSelectBox = require('gl-select-box');
1918

2019
var createOptions = require('./convert');
2120
var createCamera = require('./camera');
22-
2321
var htmlToUnicode = require('../../lib/html2unicode');
2422
var showNoWebGlMsg = require('../../lib/show_no_webgl_msg');
2523

@@ -301,11 +299,11 @@ proto.destroy = function() {
301299
this.stopped = true;
302300
};
303301

304-
proto.plot = function(fullData, fullLayout) {
302+
proto.plot = function(fullData, calcData, fullLayout) {
305303
var glplot = this.glplot,
306304
pixelRatio = this.pixelRatio;
307305

308-
var i, j;
306+
var i, j, trace;
309307

310308
this.fullLayout = fullLayout;
311309
this.updateAxes(fullLayout);
@@ -322,30 +320,27 @@ proto.plot = function(fullData, fullLayout) {
322320
canvas.height = pixelHeight;
323321
}
324322

325-
if(!fullData) fullData = [];
326-
else if(!Array.isArray(fullData)) fullData = [fullData];
327-
328323
// update traces
329-
var traceData, trace;
330324
for(i = 0; i < fullData.length; ++i) {
331-
traceData = fullData[i];
332-
trace = this.traces[traceData.uid];
325+
var fullTrace = fullData[i],
326+
calcTrace = calcData[i];
327+
trace = this.traces[fullTrace.uid];
333328

334-
if(trace) trace.update(traceData);
329+
if(trace) trace.update(fullTrace, calcTrace);
335330
else {
336-
var traceModule = Plots.getModule(traceData.type);
337-
trace = traceModule.plot(this, traceData);
331+
trace = fullTrace._module.plot(this, fullTrace, calcTrace);
338332
}
339-
this.traces[traceData.uid] = trace;
333+
334+
this.traces[fullTrace.uid] = trace;
340335
}
341336

342337
// remove empty traces
343338
var traceIds = Object.keys(this.traces);
344339

345340
trace_id_loop:
346341
for(i = 0; i < traceIds.length; ++i) {
347-
for(j = 0; j < fullData.length; ++j) {
348-
if(fullData[j].uid === traceIds[i]) continue trace_id_loop;
342+
for(j = 0; j < calcData.length; ++j) {
343+
if(calcData[j][0].trace.uid === traceIds[i]) continue trace_id_loop;
349344
}
350345

351346
trace = this.traces[traceIds[i]];
@@ -480,6 +475,7 @@ proto.draw = function() {
480475
var parts = hoverinfo.split('+');
481476
if(parts.indexOf('x') === -1) selection.traceCoord[0] = undefined;
482477
if(parts.indexOf('y') === -1) selection.traceCoord[1] = undefined;
478+
if(parts.indexOf('z') === -1) selection.traceCoord[2] = undefined;
483479
if(parts.indexOf('text') === -1) selection.textLabel = undefined;
484480
if(parts.indexOf('name') === -1) selection.name = undefined;
485481
}
@@ -489,6 +485,7 @@ proto.draw = function() {
489485
y: selection.screenCoord[1],
490486
xLabel: this.hoverFormatter('xaxis', selection.traceCoord[0]),
491487
yLabel: this.hoverFormatter('yaxis', selection.traceCoord[1]),
488+
zLabel: selection.traceCoord[2],
492489
text: selection.textLabel,
493490
name: selection.name,
494491
color: selection.color

src/traces/heatmap/calc.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,11 @@ function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) {
172172
var arrayOut = [],
173173
isContour = Plots.traceIs(trace, 'contour'),
174174
isHist = Plots.traceIs(trace, 'histogram'),
175+
isGL2D = Plots.traceIs(trace, 'gl2d'),
175176
v0,
176177
dv,
177178
i;
179+
178180
if(Array.isArray(arrayIn) && !isHist && (ax.type!=='category')) {
179181
arrayIn = arrayIn.map(ax.d2c);
180182
var len = arrayIn.length;
@@ -184,7 +186,7 @@ function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) {
184186
// and extend it linearly based on the last two points
185187
if(len <= numbricks) {
186188
// contour plots only want the centers
187-
if(isContour) arrayOut = arrayIn.slice(0, numbricks);
189+
if(isContour || isGL2D) arrayOut = arrayIn.slice(0, numbricks);
188190
else if(numbricks === 1) arrayOut = [arrayIn[0]-0.5,arrayIn[0]+0.5];
189191
else {
190192
arrayOut = [1.5*arrayIn[0]-0.5*arrayIn[1]];
@@ -217,7 +219,9 @@ function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) {
217219
else if(isHist || ax.type==='category') v0 = v0In;
218220
else v0 = ax.d2c(v0In);
219221

220-
for(i = isContour ? 0 : -0.5; i < numbricks; i++) arrayOut.push(v0 + dv * i);
222+
for(i = (isContour || isGL2D) ? 0 : -0.5; i < numbricks; i++) {
223+
arrayOut.push(v0 + dv * i);
224+
}
221225
}
222226
return arrayOut;
223227
}

src/traces/heatmapgl/attributes.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
12+
var heatmapAttrs = require('../scatter/attributes');
13+
14+
module.exports = heatmapAttrs;

src/traces/heatmapgl/convert.js

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var createHeatmap2D = require('gl-heatmap2d');
13+
14+
var str2RGBArray = require('../../lib/str2rgbarray');
15+
16+
17+
function Heatmap(scene, uid) {
18+
this.scene = scene;
19+
this.uid = uid;
20+
21+
this.name = '';
22+
this.hoverinfo = 'all';
23+
24+
this.xData = [];
25+
this.yData = [];
26+
this.zData = [];
27+
this.textLabels = [];
28+
29+
this.idToIndex = [];
30+
this.bounds = [0, 0, 0, 0];
31+
32+
this.options = {
33+
z: [],
34+
x: [],
35+
y: [],
36+
shape: [0, 0],
37+
colorLevels: [0],
38+
colorValues: [0, 0, 0, 1]
39+
};
40+
41+
this.heatmap = createHeatmap2D(scene.glplot, this.options);
42+
this.heatmap._trace = this;
43+
}
44+
45+
var proto = Heatmap.prototype;
46+
47+
proto.handlePick = function(pickResult) {
48+
var index = pickResult.pointId,
49+
shape = this.options.shape;
50+
51+
return {
52+
trace: this,
53+
dataCoord: pickResult.dataCoord,
54+
traceCoord: [
55+
this.options.x[index % shape[0]],
56+
this.options.y[Math.floor(index / shape[0])],
57+
this.options.z[index]
58+
],
59+
textLabel: this.textLabels[index],
60+
name: this.name,
61+
hoverinfo: this.hoverinfo
62+
};
63+
};
64+
65+
proto.update = function(fullTrace, calcTrace) {
66+
var calcPt = calcTrace[0];
67+
68+
this.name = fullTrace.name;
69+
this.hoverinfo = fullTrace.hoverinfo;
70+
71+
// convert z from 2D -> 1D
72+
var z = calcPt.z;
73+
this.options.z = [].concat.apply([], z);
74+
75+
var rowLen = z[0].length,
76+
colLen = z.length;
77+
this.options.shape = [rowLen, colLen];
78+
79+
this.options.x = calcPt.x;
80+
this.options.y = calcPt.y;
81+
82+
var colorOptions = convertColorscale(fullTrace);
83+
this.options.colorLevels = colorOptions.colorLevels;
84+
this.options.colorValues = colorOptions.colorValues;
85+
86+
// convert text from 2D -> 1D
87+
this.textLabels = [].concat.apply([], fullTrace.text);
88+
89+
this.heatmap.update(this.options);
90+
};
91+
92+
proto.dispose = function() {
93+
this.heatmap.dispose();
94+
};
95+
96+
function convertColorscale(fullTrace) {
97+
var scl = fullTrace.colorscale,
98+
zmin = fullTrace.zmin,
99+
zmax = fullTrace.zmax;
100+
101+
var N = scl.length,
102+
domain = new Array(N),
103+
range = new Array(4 * N);
104+
105+
for(var i = 0; i < N; i++) {
106+
var si = scl[i];
107+
var color = str2RGBArray(si[1]);
108+
109+
domain[i] = zmin + si[0] * (zmax - zmin);
110+
111+
for(var j = 0; j < 4; j++) {
112+
range[(4 * i) + j] = color[j];
113+
}
114+
}
115+
116+
return {
117+
colorLevels: domain,
118+
colorValues: range
119+
};
120+
}
121+
122+
function createHeatmap(scene, fullTrace, calcTrace) {
123+
var plot = new Heatmap(scene, fullTrace.uid);
124+
plot.update(fullTrace, calcTrace);
125+
return plot;
126+
}
127+
128+
module.exports = createHeatmap;

src/traces/heatmapgl/index.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var HeatmapGl = {};
13+
14+
HeatmapGl.attributes = require('./attributes');
15+
HeatmapGl.supplyDefaults = require('../heatmap/defaults');
16+
HeatmapGl.colorbar = require('../heatmap/colorbar');
17+
18+
HeatmapGl.calc = require('../heatmap/calc');
19+
HeatmapGl.plot = require('./convert');
20+
21+
HeatmapGl.moduleType = 'trace';
22+
HeatmapGl.name = 'heatmapgl';
23+
HeatmapGl.basePlotModule = require('../../plots/gl2d');
24+
HeatmapGl.categories = ['gl2d', '2dMap'];
25+
HeatmapGl.meta = {
26+
description: [
27+
'WebGL heatmap (beta)'
28+
].join(' ')
29+
};
30+
31+
module.exports = HeatmapGl;

0 commit comments

Comments
 (0)