Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 016846a

Browse files
committed
improve multicategory ax.makeCalcdata
- make sure calc'ed arrays are sorted properly - handle null and undefined item correctly - handle non-2d-array input correctly - test 2d-array input on non-multicategory axes
1 parent 701f793 commit 016846a

File tree

2 files changed

+147
-21
lines changed

2 files changed

+147
-21
lines changed

src/plots/cartesian/set_convert.js

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ function fromLog(v) {
3030
return Math.pow(10, v);
3131
}
3232

33+
function isValidCategory(v) {
34+
return v !== null && v !== undefined;
35+
}
36+
3337
/**
3438
* Define the conversion functions for an axis data is used in 5 ways:
3539
*
@@ -123,7 +127,7 @@ module.exports = function setConvert(ax, fullLayout) {
123127
* a disconnect between the array and the index returned
124128
*/
125129
function setCategoryIndex(v) {
126-
if(v !== null && v !== undefined) {
130+
if(isValidCategory(v)) {
127131
if(ax._categoriesMap === undefined) {
128132
ax._categoriesMap = {};
129133
}
@@ -142,6 +146,47 @@ module.exports = function setConvert(ax, fullLayout) {
142146
return BADNUM;
143147
}
144148

149+
function setMultiCategoryIndex(arrayIn, len) {
150+
var arrayOut = new Array(len);
151+
var i;
152+
153+
// [ [arrayIn[0][i], arrayIn[1][i]], for i .. len ]
154+
var tmp = new Array(len);
155+
// [ [cnt, {$cat: index}], for j .. arrayIn.length ]
156+
var seen = [[0, {}], [0, {}]];
157+
158+
if(Array.isArray(arrayIn[0]) && Array.isArray(arrayIn[1])) {
159+
for(i = 0; i < len; i++) {
160+
var v0 = arrayIn[0][i];
161+
var v1 = arrayIn[1][i];
162+
if(isValidCategory(v0) && isValidCategory(v1)) {
163+
tmp[i] = [v0, v1];
164+
if(!(v0 in seen[0][1])) {
165+
seen[0][1][v0] = seen[0][0]++;
166+
}
167+
if(!(v1 in seen[1][1])) {
168+
seen[1][1][v1] = seen[1][0]++;
169+
}
170+
}
171+
}
172+
173+
tmp.sort(function(a, b) {
174+
var ind0 = seen[0][1];
175+
var d = ind0[a[0]] - ind0[b[0]];
176+
if(d) return d;
177+
178+
var ind1 = seen[1][1];
179+
return ind1[a[1]] - ind1[b[1]];
180+
});
181+
}
182+
183+
for(i = 0; i < len; i++) {
184+
arrayOut[i] = setCategoryIndex(tmp[i]);
185+
}
186+
187+
return arrayOut;
188+
}
189+
145190
function getCategoryIndex(v) {
146191
// d2l/d2c variant that that won't add categories but will also
147192
// allow numbers to be mapped to the linearized axis positions
@@ -423,14 +468,14 @@ module.exports = function setConvert(ax, fullLayout) {
423468
// in case the expected data isn't there, make a list of
424469
// integers based on the opposite data
425470
ax.makeCalcdata = function(trace, axLetter) {
426-
var arrayIn, arrayOut, i, j, len;
471+
var arrayIn, arrayOut, i, len;
427472

428473
var axType = ax.type;
429474
var cal = axType === 'date' && trace[axLetter + 'calendar'];
430475

431476
if(axLetter in trace) {
432477
arrayIn = trace[axLetter];
433-
len = trace._length || arrayIn.length;
478+
len = trace._length || Lib.minRowLength(arrayIn);
434479

435480
if(Lib.isTypedArray(arrayIn) && (axType === 'linear' || axType === 'log')) {
436481
if(len === arrayIn.length) {
@@ -440,25 +485,13 @@ module.exports = function setConvert(ax, fullLayout) {
440485
}
441486
}
442487

443-
arrayOut = new Array(len);
444488
if(axType === 'multicategory') {
445-
var tmp = new Array(len);
446-
for(j = 0; j < arrayIn.length; j++) {
447-
if(Array.isArray(arrayIn[j])) {
448-
for(i = 0; i < len; i++) {
449-
var v = arrayIn[j][i];
450-
if(j) tmp[i].push(v);
451-
else tmp[i] = [v];
452-
}
453-
}
454-
}
455-
for(i = 0; i < len; i++) {
456-
arrayOut[i] = setCategoryIndex(tmp[i]);
457-
}
458-
} else {
459-
for(i = 0; i < len; i++) {
460-
arrayOut[i] = ax.d2c(arrayIn[i], 0, cal);
461-
}
489+
return setMultiCategoryIndex(arrayIn, len);
490+
}
491+
492+
arrayOut = new Array(len);
493+
for(i = 0; i < len; i++) {
494+
arrayOut[i] = ax.d2c(arrayIn[i], 0, cal);
462495
}
463496
}
464497
else {

test/jasmine/tests/axes_test.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,6 +2777,99 @@ describe('Test axes', function() {
27772777
expect(out).toEqual([946684800000, 978307200000, 1009843200000]);
27782778
});
27792779
});
2780+
2781+
describe('should set up category maps correctly for multicategory axes', function() {
2782+
it('case 1', function() {
2783+
var out = _makeCalcdata({
2784+
x: [['1', '1', '2', '2'], ['a', 'b', 'a', 'b']]
2785+
}, 'x', 'multicategory');
2786+
2787+
expect(out).toEqual([0, 1, 2, 3]);
2788+
expect(ax._categories).toEqual([['1', 'a'], ['1', 'b'], ['2', 'a'], ['2', 'b']]);
2789+
expect(ax._categoriesMap).toEqual({'1,a': 0, '1,b': 1, '2,a': 2, '2,b': 3});
2790+
});
2791+
2792+
it('case 2', function() {
2793+
var out = _makeCalcdata({
2794+
x: [['1', '2', '1', '2'], ['a', 'a', 'b', 'b']]
2795+
}, 'x', 'multicategory');
2796+
2797+
expect(out).toEqual([0, 1, 2, 3]);
2798+
expect(ax._categories).toEqual([['1', 'a'], ['1', 'b'], ['2', 'a'], ['2', 'b']]);
2799+
expect(ax._categoriesMap).toEqual({'1,a': 0, '1,b': 1, '2,a': 2, '2,b': 3});
2800+
});
2801+
2802+
it('case invalid in x[0]', function() {
2803+
var out = _makeCalcdata({
2804+
x: [['1', '2', null, '2'], ['a', 'a', 'b', 'b']]
2805+
}, 'x', 'multicategory');
2806+
2807+
expect(out).toEqual([0, 1, 2, BADNUM]);
2808+
expect(ax._categories).toEqual([['1', 'a'], ['2', 'a'], ['2', 'b']]);
2809+
expect(ax._categoriesMap).toEqual({'1,a': 0, '2,a': 1, '2,b': 2});
2810+
});
2811+
2812+
it('case invalid in x[1]', function() {
2813+
var out = _makeCalcdata({
2814+
x: [['1', '2', '1', '2'], ['a', 'a', null, 'b']]
2815+
}, 'x', 'multicategory');
2816+
2817+
expect(out).toEqual([0, 1, 2, BADNUM]);
2818+
expect(ax._categories).toEqual([['1', 'a'], ['2', 'a'], ['2', 'b']]);
2819+
expect(ax._categoriesMap).toEqual({'1,a': 0, '2,a': 1, '2,b': 2});
2820+
});
2821+
2822+
it('case 1D coordinate array', function() {
2823+
var out = _makeCalcdata({
2824+
x: ['a', 'b', 'c']
2825+
}, 'x', 'multicategory');
2826+
2827+
expect(out).toEqual([BADNUM, BADNUM, BADNUM]);
2828+
expect(ax._categories).toEqual([]);
2829+
expect(ax._categoriesMap).toEqual(undefined);
2830+
});
2831+
2832+
it('case 2D 1-row coordinate array', function() {
2833+
var out = _makeCalcdata({
2834+
x: [['a', 'b', 'c']]
2835+
}, 'x', 'multicategory');
2836+
2837+
expect(out).toEqual([BADNUM, BADNUM, BADNUM]);
2838+
expect(ax._categories).toEqual([]);
2839+
expect(ax._categoriesMap).toEqual(undefined);
2840+
});
2841+
2842+
it('case 2D with empty x[0] row coordinate array', function() {
2843+
var out = _makeCalcdata({
2844+
x: [null, ['a', 'b', 'c']]
2845+
}, 'x', 'multicategory');
2846+
2847+
expect(out).toEqual([BADNUM, BADNUM]);
2848+
expect(ax._categories).toEqual([]);
2849+
expect(ax._categoriesMap).toEqual(undefined);
2850+
});
2851+
});
2852+
2853+
describe('2d coordinate array on non-multicategory axes should return BADNUMs', function() {
2854+
var axTypes = ['linear', 'log', 'date'];
2855+
2856+
axTypes.forEach(function(t) {
2857+
it('- case ' + t, function() {
2858+
var out = _makeCalcdata({
2859+
x: [['1', '1', '2', '2'], ['a', 'b', 'a', 'b']]
2860+
}, 'x', t);
2861+
expect(out).toEqual([BADNUM, BADNUM, BADNUM, BADNUM]);
2862+
});
2863+
});
2864+
2865+
it('- case category', function() {
2866+
var out = _makeCalcdata({
2867+
x: [['1', '1', '2', '2'], ['a', 'b', 'a', 'b']]
2868+
}, 'x', 'category');
2869+
// picks out length=4
2870+
expect(out).toEqual([0, 1, undefined, undefined]);
2871+
});
2872+
});
27802873
});
27812874

27822875
describe('automargin', function() {

0 commit comments

Comments
 (0)