Skip to content

Commit e966030

Browse files
committed
categorical heatmap: handle missing categories, 1D data and hover
1 parent 5160948 commit e966030

File tree

8 files changed

+109
-9
lines changed

8 files changed

+109
-9
lines changed

src/traces/heatmap/clean_2d_array.js

+16-8
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,29 @@ module.exports = function clean2dArray(zOld, trace, xa, ya) {
3131
old2new = function(zOld, i, j) { return zOld[i][j]; };
3232
}
3333

34-
var xMap = Lib.identity;
35-
var yMap = Lib.identity;
36-
if(trace && trace.type !== 'carpet' && trace.type !== 'contourcarpet') {
37-
if(ya && ya.type === 'category' && trace._y.length) {
38-
yMap = function(i) {return trace._y[i];};
39-
}
40-
if(xa && xa.type === 'category' && trace._x.length) {
41-
xMap = function(i) {return trace._x[i];};
34+
function axisMapping(ax) {
35+
if(trace && trace.type !== 'carpet' && trace.type !== 'contourcarpet' &&
36+
ax && ax.type === 'category' && trace['_' + ax._id.charAt(0)].length) {
37+
var axMapping = [];
38+
for(i = 0; i < ax._categories.length; i++) {
39+
axMapping.push((trace['_' + ax._id.charAt(0) + 'Map'] || trace[ax._id.charAt(0)]).indexOf(ax._categories[i]));
40+
}
41+
console.log('axMapping', axMapping);
42+
return function(i) {return axMapping[i] === -1 ? undefined : axMapping[i];};
43+
} else {
44+
return Lib.identity;
4245
}
4346
}
4447

48+
var xMap = axisMapping(xa);
49+
var yMap = axisMapping(ya);
50+
4551
var zNew = new Array(rowlen);
4652

53+
if(ya && ya.type === 'category') rowlen = ya._categories.length;
4754
for(i = 0; i < rowlen; i++) {
4855
collen = getCollen(zOld, i);
56+
if(xa && xa.type === 'category') collen = xa._categories.length;
4957
zNew[i] = new Array(collen);
5058
for(j = 0; j < collen; j++) zNew[i][j] = cleanZvalue(old2new(zOld, yMap(i), xMap(j)));
5159
}

src/traces/heatmap/convert_column_xyz.js

+8
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,12 @@ module.exports = function convertColumnData(trace, ax1, ax2, var1Name, var2Name,
6565
}
6666
if(hasColumnText) trace._text = text;
6767
if(hasColumnHoverText) trace._hovertext = hovertext;
68+
69+
if(ax1 && ax1.type === 'category') {
70+
trace['_' + var1Name + 'Map'] = col1vals.map(function(v) { return ax1._categories[v];});
71+
}
72+
73+
if(ax2 && ax2.type === 'category') {
74+
trace['_' + var2Name + 'Map'] = col2vals.map(function(v) { return ax2._categories[v];});
75+
}
6876
};

src/traces/heatmap/hover.js

+4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay
7878
} else {
7979
xl = xc ? xc[nx] : ((x[nx] + x[nx + 1]) / 2);
8080
yl = yc ? yc[ny] : ((y[ny] + y[ny + 1]) / 2);
81+
82+
if(xa && xa.type === 'category') xl = x[nx];
83+
if(ya && ya.type === 'category') yl = y[ny];
84+
8185
if(trace.zsmooth) {
8286
x0 = x1 = xa.c2p(xl);
8387
y0 = y1 = ya.c2p(yl);
21.1 KB
Loading
Loading
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"data": [{
3+
"type": "heatmap",
4+
"x": ["a", "a", "a", "b", "b", "b", "c", "c", "c"],
5+
"y": ["A", "B", "C", "A", "B", "C", "A", "B", "C"],
6+
"z": [0, 50, 100, 50, 0, 255, 100, 510, 1010]
7+
}],
8+
"layout": {
9+
"xaxis": {
10+
"categoryorder": "category descending"
11+
}
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"data": [{
3+
"type": "heatmap",
4+
"x": ["Team A", "Team B", "Team C"],
5+
"xaxis": "x",
6+
"y": ["Game Three", "Game Two", "Game One"],
7+
"z": [
8+
[0.1, 0.3, 0.5],
9+
[1, 0.8, 0.6],
10+
[0.6, 0.4, 0.2]
11+
],
12+
"yaxis": "y"
13+
}, {
14+
"type": "heatmap",
15+
"x": ["Team B", "Team C"],
16+
"xaxis": "x",
17+
"y": ["Game Three", "Game Two", "Game One"],
18+
"z": [
19+
[0.3, 0.5],
20+
[0.8, 0.6],
21+
[0.4, 0.2]
22+
],
23+
"yaxis": "y2"
24+
}],
25+
"layout": {
26+
"xaxis": {
27+
"anchor": "y2",
28+
"domain": [0, 1],
29+
"type": "category",
30+
"range": [-0.5, 2.5],
31+
"autorange": true
32+
},
33+
"yaxis": {
34+
"anchor": "free",
35+
"domain": [0.575, 1],
36+
"position": 0,
37+
"type": "category",
38+
"range": [-0.5, 2.5],
39+
"autorange": true
40+
},
41+
"yaxis2": {
42+
"anchor": "x",
43+
"domain": [0, 0.425],
44+
"type": "category",
45+
"range": [-0.5, 2.5],
46+
"autorange": true
47+
}
48+
}
49+
}

test/jasmine/tests/heatmap_test.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ describe('heatmap calc', function() {
539539

540540
expect(out._xcategories).toEqual(layout.xaxis.categoryarray, 'xaxis should reorder');
541541
expect(out._ycategories).toEqual(layout.yaxis.categoryarray, 'yaxis should reorder');
542-
expect(out.z[0][0]).toEqual(65);
542+
expect(out.z[0][0]).toEqual(0);
543543
});
544544
});
545545
});
@@ -781,6 +781,24 @@ describe('heatmap hover', function() {
781781
});
782782
});
783783

784+
describe('with sorted categories', function() {
785+
beforeAll(function(done) {
786+
gd = createGraphDiv();
787+
788+
var mock = require('@mocks/heatmap_categoryorder.json');
789+
var mockCopy = Lib.extendDeep({}, mock);
790+
791+
Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done);
792+
});
793+
afterAll(destroyGraphDiv);
794+
795+
it('should find closest point (case 1) and should', function() {
796+
var pt = _hover(gd, 3, 1)[0];
797+
expect(pt.index).toEqual([1, 3], 'have correct index');
798+
assertLabels(pt, 2.5, 0.5, 0);
799+
});
800+
});
801+
784802
describe('for xyz-column traces', function() {
785803
beforeAll(function(done) {
786804
gd = createGraphDiv();

0 commit comments

Comments
 (0)