Skip to content

Commit 997e720

Browse files
authored
Merge pull request #3362 from plotly/multicat-fixes
Multicategory sorting fixes
2 parents 874ac4c + 96edd72 commit 997e720

File tree

7 files changed

+124
-44
lines changed

7 files changed

+124
-44
lines changed

src/plots/cartesian/set_convert.js

+55-33
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var cleanNumber = Lib.cleanNumber;
1717
var ms2DateTime = Lib.ms2DateTime;
1818
var dateTime2ms = Lib.dateTime2ms;
1919
var ensureNumber = Lib.ensureNumber;
20+
var isArrayOrTypedArray = Lib.isArrayOrTypedArray;
2021

2122
var numConstants = require('../../constants/numerical');
2223
var FP_SAFE = numConstants.FP_SAFE;
@@ -148,40 +149,11 @@ module.exports = function setConvert(ax, fullLayout) {
148149

149150
function setMultiCategoryIndex(arrayIn, len) {
150151
var arrayOut = new Array(len);
151-
var i;
152152

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(Lib.isArrayOrTypedArray(arrayIn[0]) && Lib.isArrayOrTypedArray(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]);
153+
for(var i = 0; i < len; i++) {
154+
var v0 = (arrayIn[0] || [])[i];
155+
var v1 = (arrayIn[1] || [])[i];
156+
arrayOut[i] = getCategoryIndex([v0, v1]);
185157
}
186158

187159
return arrayOut;
@@ -330,6 +302,56 @@ module.exports = function setConvert(ax, fullLayout) {
330302
if(Array.isArray(v) || (typeof v === 'string' && v !== '')) return v;
331303
return ensureNumber(v);
332304
};
305+
306+
ax.setupMultiCategory = function(fullData) {
307+
var traceIndices = ax._traceIndices;
308+
var i, j;
309+
310+
// [ [cnt, {$cat: index}], for 1,2 ]
311+
var seen = ax._multicatSeen = [[0, {}], [0, {}]];
312+
// [ [arrayIn[0][i], arrayIn[1][i]], for i .. N ]
313+
var list = ax._multicatList = [];
314+
315+
for(i = 0; i < traceIndices.length; i++) {
316+
var trace = fullData[traceIndices[i]];
317+
318+
if(axLetter in trace) {
319+
var arrayIn = trace[axLetter];
320+
var len = trace._length || Lib.minRowLength(arrayIn);
321+
322+
if(isArrayOrTypedArray(arrayIn[0]) && isArrayOrTypedArray(arrayIn[1])) {
323+
for(j = 0; j < len; j++) {
324+
var v0 = arrayIn[0][j];
325+
var v1 = arrayIn[1][j];
326+
327+
if(isValidCategory(v0) && isValidCategory(v1)) {
328+
list.push([v0, v1]);
329+
330+
if(!(v0 in seen[0][1])) {
331+
seen[0][1][v0] = seen[0][0]++;
332+
}
333+
if(!(v1 in seen[1][1])) {
334+
seen[1][1][v1] = seen[1][0]++;
335+
}
336+
}
337+
}
338+
}
339+
}
340+
}
341+
342+
list.sort(function(a, b) {
343+
var ind0 = seen[0][1];
344+
var d = ind0[a[0]] - ind0[b[0]];
345+
if(d) return d;
346+
347+
var ind1 = seen[1][1];
348+
return ind1[a[1]] - ind1[b[1]];
349+
});
350+
351+
for(i = 0; i < list.length; i++) {
352+
setCategoryIndex(list[i]);
353+
}
354+
};
333355
}
334356

335357
// find the range value at the specified (linear) fraction of the axis

src/plots/plots.js

+11-7
Original file line numberDiff line numberDiff line change
@@ -2524,9 +2524,9 @@ plots.transition = function(gd, data, layout, traces, frameOpts, transitionOpts)
25242524
};
25252525

25262526
plots.doCalcdata = function(gd, traces) {
2527-
var axList = axisIDs.list(gd),
2528-
fullData = gd._fullData,
2529-
fullLayout = gd._fullLayout;
2527+
var axList = axisIDs.list(gd);
2528+
var fullData = gd._fullData;
2529+
var fullLayout = gd._fullLayout;
25302530

25312531
var trace, _module, i, j;
25322532

@@ -2579,7 +2579,7 @@ plots.doCalcdata = function(gd, traces) {
25792579
);
25802580
}
25812581

2582-
clearAxesCalc(axList);
2582+
setupAxisCategories(axList, fullData);
25832583

25842584
var hasCalcTransform = false;
25852585

@@ -2617,7 +2617,7 @@ plots.doCalcdata = function(gd, traces) {
26172617
}
26182618

26192619
// clear stuff that should recomputed in 'regular' loop
2620-
if(hasCalcTransform) clearAxesCalc(axList);
2620+
if(hasCalcTransform) setupAxisCategories(axList, fullData);
26212621

26222622
function calci(i, isContainer) {
26232623
trace = fullData[i];
@@ -2675,9 +2675,13 @@ plots.doCalcdata = function(gd, traces) {
26752675
Registry.getComponentMethod('errorbars', 'calc')(gd);
26762676
};
26772677

2678-
function clearAxesCalc(axList) {
2678+
function setupAxisCategories(axList, fullData) {
26792679
for(var i = 0; i < axList.length; i++) {
2680-
axList[i].clearCalc();
2680+
var ax = axList[i];
2681+
ax.clearCalc();
2682+
if(ax.type === 'multicategory') {
2683+
ax.setupMultiCategory(fullData);
2684+
}
26812685
}
26822686
}
26832687

45.2 KB
Loading
0 Bytes
Loading
220 Bytes
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"data": [{
3+
"x": [[1, 2, 3, 4, 5 ,6],
4+
[1, 2, 1, 2, 1 ,2]],
5+
"y": [1, 2, 3, 4, 5 ,6]
6+
},
7+
8+
{
9+
"x": [[1, 2, 3, 4, 5, 6],
10+
[1, 2, 1, 2, 1, 2]],
11+
"y": [1, 2, 3, 4, 5, 6],
12+
"xaxis": "x2",
13+
"yaxis": "y2"
14+
},
15+
{
16+
"x": [[4, 5, 6, 7, 8, 9],
17+
[1, 2, 1, 2, 1, 2]],
18+
"y": [1, 2, 3, 4, 5, 6],
19+
"xaxis": "x2",
20+
"yaxis": "y2"
21+
},
22+
23+
{
24+
"x": [[1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9],
25+
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]],
26+
"y": [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6],
27+
"xaxis": "x3",
28+
"yaxis": "y3"
29+
},
30+
31+
{
32+
"x": [[1, 2, 3, 4, 5, 6],
33+
[1, 2, 1, 2, null, 2]],
34+
"y": [1, 2, 3, 4, 5, 6],
35+
"xaxis": "x4",
36+
"yaxis": "y4"
37+
},
38+
{
39+
"x": [[4, 5, 6, 7, 8, 9],
40+
[1, null, 1, 2, 1, 2]],
41+
"y": [1, 2, 3, 4, 5, 6],
42+
"xaxis": "x4",
43+
"yaxis": "y4"
44+
}],
45+
"layout": {
46+
"grid": {"rows": 2, "columns": 2, "pattern": "independent", "xgap": 0.1, "ygap": 0.15},
47+
"width": 700,
48+
"height": 400,
49+
"margin": {"l": 20, "b": 40, "t": 20, "r": 20},
50+
"showlegend": false
51+
}
52+
}

test/jasmine/tests/axes_test.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -2723,6 +2723,8 @@ describe('Test axes', function() {
27232723
ax = {type: axType};
27242724
Axes.setConvert(ax);
27252725
ax._categories = [];
2726+
ax._traceIndices = [0];
2727+
if(axType === 'multicategory') ax.setupMultiCategory([trace]);
27262728
return ax.makeCalcdata(trace, axLetter);
27272729
}
27282730

@@ -2856,7 +2858,7 @@ describe('Test axes', function() {
28562858
x: [['1', '2', '1', '2'], ['a', 'a', 'b', 'b']]
28572859
}, 'x', 'multicategory');
28582860

2859-
expect(out).toEqual([0, 1, 2, 3]);
2861+
expect(out).toEqual([0, 2, 1, 3]);
28602862
expect(ax._categories).toEqual([['1', 'a'], ['1', 'b'], ['2', 'a'], ['2', 'b']]);
28612863
expect(ax._categoriesMap).toEqual({'1,a': 0, '1,b': 1, '2,a': 2, '2,b': 3});
28622864
});
@@ -2866,7 +2868,7 @@ describe('Test axes', function() {
28662868
x: [['1', '2', null, '2'], ['a', 'a', 'b', 'b']]
28672869
}, 'x', 'multicategory');
28682870

2869-
expect(out).toEqual([0, 1, 2, BADNUM]);
2871+
expect(out).toEqual([0, 1, BADNUM, 2]);
28702872
expect(ax._categories).toEqual([['1', 'a'], ['2', 'a'], ['2', 'b']]);
28712873
expect(ax._categoriesMap).toEqual({'1,a': 0, '2,a': 1, '2,b': 2});
28722874
});
@@ -2876,7 +2878,7 @@ describe('Test axes', function() {
28762878
x: [['1', '2', '1', '2'], ['a', 'a', null, 'b']]
28772879
}, 'x', 'multicategory');
28782880

2879-
expect(out).toEqual([0, 1, 2, BADNUM]);
2881+
expect(out).toEqual([0, 1, BADNUM, 2]);
28802882
expect(ax._categories).toEqual([['1', 'a'], ['2', 'a'], ['2', 'b']]);
28812883
expect(ax._categoriesMap).toEqual({'1,a': 0, '2,a': 1, '2,b': 2});
28822884
});
@@ -2919,7 +2921,7 @@ describe('Test axes', function() {
29192921
]
29202922
}, 'x', 'multicategory');
29212923

2922-
expect(out).toEqual([0, 1, 2, 3]);
2924+
expect(out).toEqual([0, 2, 1, 3]);
29232925
expect(ax._categories).toEqual([[1, 10], [1, 20], [2, 10], [2, 20]]);
29242926
expect(ax._categoriesMap).toEqual({'1,10': 0, '1,20': 1, '2,10': 2, '2,20': 3});
29252927
});

0 commit comments

Comments
 (0)