Skip to content
  • PHP-Proxy

    PHP-Proxy

    Error accessing resource: 429 - Too Many Requests

  • Notifications You must be signed in to change notification settings
  • Fork 1.9k

Multicategory sorting fixes #3362

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 21, 2018
PHP-Proxy

PHP-Proxy

Error accessing resource: 429 - Too Many Requests

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 55 additions & 33 deletions src/plots/cartesian/set_convert.js
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ var cleanNumber = Lib.cleanNumber;
var ms2DateTime = Lib.ms2DateTime;
var dateTime2ms = Lib.dateTime2ms;
var ensureNumber = Lib.ensureNumber;
var isArrayOrTypedArray = Lib.isArrayOrTypedArray;

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

function setMultiCategoryIndex(arrayIn, len) {
var arrayOut = new Array(len);
var i;

// [ [arrayIn[0][i], arrayIn[1][i]], for i .. len ]
var tmp = new Array(len);
// [ [cnt, {$cat: index}], for j .. arrayIn.length ]
var seen = [[0, {}], [0, {}]];

if(Lib.isArrayOrTypedArray(arrayIn[0]) && Lib.isArrayOrTypedArray(arrayIn[1])) {
for(i = 0; i < len; i++) {
var v0 = arrayIn[0][i];
var v1 = arrayIn[1][i];
if(isValidCategory(v0) && isValidCategory(v1)) {
tmp[i] = [v0, v1];
if(!(v0 in seen[0][1])) {
seen[0][1][v0] = seen[0][0]++;
}
if(!(v1 in seen[1][1])) {
seen[1][1][v1] = seen[1][0]++;
}
}
}

tmp.sort(function(a, b) {
var ind0 = seen[0][1];
var d = ind0[a[0]] - ind0[b[0]];
if(d) return d;

var ind1 = seen[1][1];
return ind1[a[1]] - ind1[b[1]];
});
}

for(i = 0; i < len; i++) {
arrayOut[i] = setCategoryIndex(tmp[i]);
for(var i = 0; i < len; i++) {
var v0 = (arrayIn[0] || [])[i];
var v1 = (arrayIn[1] || [])[i];
arrayOut[i] = getCategoryIndex([v0, v1]);
}

return arrayOut;
@@ -330,6 +302,56 @@ module.exports = function setConvert(ax, fullLayout) {
if(Array.isArray(v) || (typeof v === 'string' && v !== '')) return v;
return ensureNumber(v);
};

ax.setupMultiCategory = function(fullData) {
var traceIndices = ax._traceIndices;
var i, j;

// [ [cnt, {$cat: index}], for 1,2 ]
var seen = ax._multicatSeen = [[0, {}], [0, {}]];
// [ [arrayIn[0][i], arrayIn[1][i]], for i .. N ]
var list = ax._multicatList = [];

for(i = 0; i < traceIndices.length; i++) {
var trace = fullData[traceIndices[i]];

if(axLetter in trace) {
var arrayIn = trace[axLetter];
var len = trace._length || Lib.minRowLength(arrayIn);

if(isArrayOrTypedArray(arrayIn[0]) && isArrayOrTypedArray(arrayIn[1])) {
for(j = 0; j < len; j++) {
var v0 = arrayIn[0][j];
var v1 = arrayIn[1][j];

if(isValidCategory(v0) && isValidCategory(v1)) {
list.push([v0, v1]);

if(!(v0 in seen[0][1])) {
seen[0][1][v0] = seen[0][0]++;
}
if(!(v1 in seen[1][1])) {
seen[1][1][v1] = seen[1][0]++;
}
}
}
}
}
}

list.sort(function(a, b) {
var ind0 = seen[0][1];
var d = ind0[a[0]] - ind0[b[0]];
if(d) return d;

var ind1 = seen[1][1];
return ind1[a[1]] - ind1[b[1]];
});

for(i = 0; i < list.length; i++) {
setCategoryIndex(list[i]);
}
};
}

// find the range value at the specified (linear) fraction of the axis
18 changes: 11 additions & 7 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
@@ -2524,9 +2524,9 @@ plots.transition = function(gd, data, layout, traces, frameOpts, transitionOpts)
};

plots.doCalcdata = function(gd, traces) {
var axList = axisIDs.list(gd),
fullData = gd._fullData,
fullLayout = gd._fullLayout;
var axList = axisIDs.list(gd);
var fullData = gd._fullData;
var fullLayout = gd._fullLayout;

var trace, _module, i, j;

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

clearAxesCalc(axList);
setupAxisCategories(axList, fullData);

var hasCalcTransform = false;

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

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

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

function clearAxesCalc(axList) {
function setupAxisCategories(axList, fullData) {
for(var i = 0; i < axList.length; i++) {
axList[i].clearCalc();
var ax = axList[i];
ax.clearCalc();
if(ax.type === 'multicategory') {
ax.setupMultiCategory(fullData);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clearCalc is also used in rangeslider.draw and gl2d/scene2d - do these need setupMultiCategory? Should that just be part of clearCalc for multicategory axes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clearCalc is also used in rangeslider.draw and gl2d/scene2d - do these need setupMultiCategory?

setupMultiCategory only needs to be called once (here in doCalcdata, to fill in ax._muticatList), so rangeslider don't need it, that's why I didn't put the setupMultiCategory logic in clearCalc. As for gl2d/scene2d, gl2d subplots don't support multicategory axes, so I think we're 👌

}
}

Binary file added test/image/baselines/multicategory-sorting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/multicategory-y.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/multicategory2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions test/image/mocks/multicategory-sorting.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"data": [{
"x": [[1, 2, 3, 4, 5 ,6],
[1, 2, 1, 2, 1 ,2]],
"y": [1, 2, 3, 4, 5 ,6]
},

{
"x": [[1, 2, 3, 4, 5, 6],
[1, 2, 1, 2, 1, 2]],
"y": [1, 2, 3, 4, 5, 6],
"xaxis": "x2",
"yaxis": "y2"
},
{
"x": [[4, 5, 6, 7, 8, 9],
[1, 2, 1, 2, 1, 2]],
"y": [1, 2, 3, 4, 5, 6],
"xaxis": "x2",
"yaxis": "y2"
},

{
"x": [[1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9],
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]],
"y": [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6],
"xaxis": "x3",
"yaxis": "y3"
},

{
"x": [[1, 2, 3, 4, 5, 6],
[1, 2, 1, 2, null, 2]],
"y": [1, 2, 3, 4, 5, 6],
"xaxis": "x4",
"yaxis": "y4"
},
{
"x": [[4, 5, 6, 7, 8, 9],
[1, null, 1, 2, 1, 2]],
"y": [1, 2, 3, 4, 5, 6],
"xaxis": "x4",
"yaxis": "y4"
}],
"layout": {
"grid": {"rows": 2, "columns": 2, "pattern": "independent", "xgap": 0.1, "ygap": 0.15},
"width": 700,
"height": 400,
"margin": {"l": 20, "b": 40, "t": 20, "r": 20},
"showlegend": false
}
}
10 changes: 6 additions & 4 deletions test/jasmine/tests/axes_test.js
Original file line number Diff line number Diff line change
@@ -2723,6 +2723,8 @@ describe('Test axes', function() {
ax = {type: axType};
Axes.setConvert(ax);
ax._categories = [];
ax._traceIndices = [0];
if(axType === 'multicategory') ax.setupMultiCategory([trace]);
return ax.makeCalcdata(trace, axLetter);
}

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

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

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

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

expect(out).toEqual([0, 1, 2, 3]);
expect(out).toEqual([0, 2, 1, 3]);
expect(ax._categories).toEqual([[1, 10], [1, 20], [2, 10], [2, 20]]);
expect(ax._categoriesMap).toEqual({'1,10': 0, '1,20': 1, '2,10': 2, '2,20': 3});
});