Skip to content

Commit c709f63

Browse files
authored
Merge pull request #651 from plotly/heatmap-1-xy
Fix heatmap brick generation edge cases
2 parents 7810d7a + f9b5ebd commit c709f63

File tree

4 files changed

+561
-284
lines changed

4 files changed

+561
-284
lines changed

src/traces/heatmap/calc.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -173,36 +173,43 @@ function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) {
173173
dv,
174174
i;
175175

176-
if(Array.isArray(arrayIn) && !isHist && (ax.type !== 'category')) {
176+
var isArrayOfTwoItemsOrMore = Array.isArray(arrayIn) && arrayIn.length > 1;
177+
178+
if(isArrayOfTwoItemsOrMore && !isHist && (ax.type !== 'category')) {
177179
arrayIn = arrayIn.map(ax.d2c);
178180
var len = arrayIn.length;
179181

180182
// given vals are brick centers
181-
// hopefully length==numbricks, but use this method even if too few are supplied
183+
// hopefully length === numbricks, but use this method even if too few are supplied
182184
// and extend it linearly based on the last two points
183185
if(len <= numbricks) {
184186
// contour plots only want the centers
185187
if(isContour || isGL2D) arrayOut = arrayIn.slice(0, numbricks);
186-
else if(numbricks === 1) arrayOut = [arrayIn[0] - 0.5, arrayIn[0] + 0.5];
188+
else if(numbricks === 1) {
189+
arrayOut = [arrayIn[0] - 0.5, arrayIn[0] + 0.5];
190+
}
187191
else {
188192
arrayOut = [1.5 * arrayIn[0] - 0.5 * arrayIn[1]];
193+
189194
for(i = 1; i < len; i++) {
190195
arrayOut.push((arrayIn[i - 1] + arrayIn[i]) * 0.5);
191196
}
197+
192198
arrayOut.push(1.5 * arrayIn[len - 1] - 0.5 * arrayIn[len - 2]);
193199
}
194200

195201
if(len < numbricks) {
196202
var lastPt = arrayOut[arrayOut.length - 1],
197203
delta = lastPt - arrayOut[arrayOut.length - 2];
204+
198205
for(i = len; i < numbricks; i++) {
199206
lastPt += delta;
200207
arrayOut.push(lastPt);
201208
}
202209
}
203210
}
204211
else {
205-
// hopefully length==numbricks+1, but do something regardless:
212+
// hopefully length === numbricks+1, but do something regardless:
206213
// given vals are brick boundaries
207214
return isContour ?
208215
arrayIn.slice(0, numbricks) : // we must be strict for contours
@@ -211,14 +218,17 @@ function makeBoundArray(trace, arrayIn, v0In, dvIn, numbricks, ax) {
211218
}
212219
else {
213220
dv = dvIn || 1;
214-
if(v0In === undefined) v0 = 0;
221+
222+
if(Array.isArray(arrayIn) && arrayIn.length === 1) v0 = arrayIn[0];
223+
else if(v0In === undefined) v0 = 0;
215224
else if(isHist || ax.type === 'category') v0 = v0In;
216225
else v0 = ax.d2c(v0In);
217226

218227
for(i = (isContour || isGL2D) ? 0 : -0.5; i < numbricks; i++) {
219228
arrayOut.push(v0 + dv * i);
220229
}
221230
}
231+
222232
return arrayOut;
223233
}
224234

test/jasmine/assets/custom_matchers.js

+59-4
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,76 @@ module.exports = {
44
toBeCloseToArray: function() {
55
return {
66
compare: function(actual, expected, precision) {
7-
if(precision !== 0) {
8-
precision = Math.pow(10, -precision) / 2 || 0.005;
9-
}
7+
precision = coercePosition(precision);
108

119
var tested = actual.map(function(element, i) {
1210
return Math.abs(expected[i] - element) < precision;
1311
});
1412

15-
var passed = tested.indexOf(false) < 0;
13+
var passed = (
14+
expected.length === actual.length &&
15+
tested.indexOf(false) < 0
16+
);
1617

1718
return {
1819
pass: passed,
1920
message: 'Expected ' + actual + ' to be close to ' + expected + '.'
2021
};
2122
}
2223
};
24+
},
25+
26+
// toBeCloseTo... but for 2D arrays
27+
toBeCloseTo2DArray: function() {
28+
return {
29+
compare: function(actual, expected, precision) {
30+
precision = coercePosition(precision);
31+
32+
var passed = true;
33+
34+
if(expected.length !== actual.length) passed = false;
35+
else {
36+
for(var i = 0; i < expected.length; ++i) {
37+
if(expected[i].length !== actual[i].length) {
38+
passed = false;
39+
break;
40+
}
41+
42+
for(var j = 0; j < expected[i].length; ++j) {
43+
var isClose = Math.abs(expected[i][j] - actual[i][j]) < precision;
44+
45+
if(!isClose) {
46+
passed = false;
47+
break;
48+
}
49+
}
50+
}
51+
}
52+
53+
var message = [
54+
'Expected',
55+
arrayToStr(actual.map(arrayToStr)),
56+
'to be close to',
57+
arrayToStr(expected.map(arrayToStr))
58+
].join(' ');
59+
60+
return {
61+
pass: passed,
62+
message: message
63+
};
64+
}
65+
};
2366
}
2467
};
68+
69+
function coercePosition(precision) {
70+
if(precision !== 0) {
71+
precision = Math.pow(10, -precision) / 2 || 0.005;
72+
}
73+
74+
return precision;
75+
}
76+
77+
function arrayToStr(array) {
78+
return '[ ' + array.join(', ') + ' ]';
79+
}

0 commit comments

Comments
 (0)