Skip to content

Commit 3691c5c

Browse files
authored
Merge pull request #2489 from plotly/fix-categoryorder-visible-false-bug
Make ordered category algo skip over visible false traces
2 parents da37b4f + 80c13a9 commit 3691c5c

File tree

6 files changed

+126
-102
lines changed

6 files changed

+126
-102
lines changed

src/plots/cartesian/axis_defaults.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ var handleTickLabelDefaults = require('./tick_label_defaults');
1818
var handleCategoryOrderDefaults = require('./category_order_defaults');
1919
var handleLineGridDefaults = require('./line_grid_defaults');
2020
var setConvert = require('./set_convert');
21-
var orderedCategories = require('./ordered_categories');
2221

2322
/**
2423
* options: object containing:
@@ -60,11 +59,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
6059
coerce('range');
6160
containerOut.cleanRange();
6261

63-
handleCategoryOrderDefaults(containerIn, containerOut, coerce);
64-
containerOut._initialCategories = axType === 'category' ?
65-
orderedCategories(letter, containerOut.categoryorder, containerOut.categoryarray, options.data) :
66-
[];
67-
62+
handleCategoryOrderDefaults(containerIn, containerOut, coerce, options);
6863

6964
if(axType !== 'category' && !options.noHover) coerce('hoverformat');
7065

src/plots/cartesian/category_order_defaults.js

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,85 @@
88

99
'use strict';
1010

11+
function findCategories(ax, opts) {
12+
var dataAttr = opts.dataAttr || ax._id.charAt(0);
13+
var lookup = {};
14+
var axData;
15+
var i, j;
1116

12-
module.exports = function handleCategoryOrderDefaults(containerIn, containerOut, coerce) {
13-
if(containerOut.type !== 'category') return;
17+
if(opts.axData) {
18+
// non-x/y case
19+
axData = opts.axData;
20+
} else {
21+
// x/y case
22+
axData = [];
23+
for(i = 0; i < opts.data.length; i++) {
24+
var trace = opts.data[i];
25+
if(trace[dataAttr + 'axis'] === ax._id) {
26+
axData.push(trace);
27+
}
28+
}
29+
}
30+
31+
for(i = 0; i < axData.length; i++) {
32+
var vals = axData[i][dataAttr];
33+
for(j = 0; j < vals.length; j++) {
34+
var v = vals[j];
35+
if(v !== null && v !== undefined) {
36+
lookup[v] = 1;
37+
}
38+
}
39+
}
40+
41+
return Object.keys(lookup);
42+
}
1443

15-
var arrayIn = containerIn.categoryarray,
16-
orderDefault;
44+
/**
45+
* Fills in category* default and initial categories.
46+
*
47+
* @param {object} containerIn : input axis object
48+
* @param {object} containerOut : full axis object
49+
* @param {function} coerce : Lib.coerce fn wrapper
50+
* @param {object} opts :
51+
* - data {array} : (full) data trace
52+
* OR
53+
* - axData {array} : (full) data associated with axis being coerced here
54+
* - dataAttr {string} : attribute name corresponding to coordinate array
55+
*/
56+
module.exports = function handleCategoryOrderDefaults(containerIn, containerOut, coerce, opts) {
57+
if(containerOut.type !== 'category') return;
1758

59+
var arrayIn = containerIn.categoryarray;
1860
var isValidArray = (Array.isArray(arrayIn) && arrayIn.length > 0);
1961

2062
// override default 'categoryorder' value when non-empty array is supplied
63+
var orderDefault;
2164
if(isValidArray) orderDefault = 'array';
2265

2366
var order = coerce('categoryorder', orderDefault);
67+
var array;
2468

2569
// coerce 'categoryarray' only in array order case
26-
if(order === 'array') coerce('categoryarray');
70+
if(order === 'array') {
71+
array = coerce('categoryarray');
72+
}
2773

2874
// cannot set 'categoryorder' to 'array' with an invalid 'categoryarray'
2975
if(!isValidArray && order === 'array') {
30-
containerOut.categoryorder = 'trace';
76+
order = containerOut.categoryorder = 'trace';
77+
}
78+
79+
// set up things for makeCalcdata
80+
if(order === 'trace') {
81+
containerOut._initialCategories = [];
82+
} else if(order === 'array') {
83+
containerOut._initialCategories = array.slice();
84+
} else {
85+
array = findCategories(containerOut, opts).sort();
86+
if(order === 'category ascending') {
87+
containerOut._initialCategories = array;
88+
} else if(order === 'category descending') {
89+
containerOut._initialCategories = array.reverse();
90+
}
3191
}
3292
};

src/plots/cartesian/ordered_categories.js

Lines changed: 0 additions & 77 deletions
This file was deleted.

src/plots/polar/layout_defaults.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ var handleTickLabelDefaults = require('../cartesian/tick_label_defaults');
1919
var handleCategoryOrderDefaults = require('../cartesian/category_order_defaults');
2020
var handleLineGridDefaults = require('../cartesian/line_grid_defaults');
2121
var autoType = require('../cartesian/axis_autotype');
22-
var orderedCategories = require('../cartesian/ordered_categories');
2322
var setConvert = require('../cartesian/set_convert');
2423

2524
var setConvertAngular = require('./helpers').setConvertAngular;
@@ -56,10 +55,10 @@ function handleDefaults(contIn, contOut, coerce, opts) {
5655
var dataAttr = constants.axisName2dataArray[axName];
5756
var axType = handleAxisTypeDefaults(axIn, axOut, coerceAxis, subplotData, dataAttr);
5857

59-
handleCategoryOrderDefaults(axIn, axOut, coerceAxis);
60-
axOut._initialCategories = axType === 'category' ?
61-
orderedCategories(dataAttr, axOut.categoryorder, axOut.categoryarray, subplotData) :
62-
[];
58+
handleCategoryOrderDefaults(axIn, axOut, coerceAxis, {
59+
axData: subplotData,
60+
dataAttr: dataAttr
61+
});
6362

6463
var visible = coerceAxis('visible');
6564
setConvert(axOut, layoutOut);

src/traces/carpet/axis_defaults.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@ var handleTickValueDefaults = require('../../plots/cartesian/tick_value_defaults
1717
var handleTickLabelDefaults = require('../../plots/cartesian/tick_label_defaults');
1818
var handleCategoryOrderDefaults = require('../../plots/cartesian/category_order_defaults');
1919
var setConvert = require('../../plots/cartesian/set_convert');
20-
var orderedCategories = require('../../plots/cartesian/ordered_categories');
2120
var autoType = require('../../plots/cartesian/axis_autotype');
2221

2322
/**
2423
* options: object containing:
2524
*
26-
* letter: 'x' or 'y'
25+
* letter: 'a' or 'b'
2726
* title: name of the axis (ie 'Colorbar') to go in default title
2827
* name: axis object name (ie 'xaxis') if one should be stored
2928
* font: the default font to inherit
@@ -133,7 +132,10 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, options)
133132

134133
handleTickValueDefaults(containerIn, containerOut, coerce, axType);
135134
handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options);
136-
handleCategoryOrderDefaults(containerIn, containerOut, coerce);
135+
handleCategoryOrderDefaults(containerIn, containerOut, coerce, {
136+
data: options.data,
137+
dataAttr: letter
138+
});
137139

138140
var gridColor = coerce2('gridcolor', addOpacity(dfltColor, 0.3));
139141
var gridWidth = coerce2('gridwidth');
@@ -176,11 +178,6 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, options)
176178
}
177179
}
178180

179-
// fill in categories
180-
containerOut._initialCategories = axType === 'category' ?
181-
orderedCategories(letter, containerOut.categoryorder, containerOut.categoryarray, options.data) :
182-
[];
183-
184181
if(containerOut.showticklabels === 'none') {
185182
delete containerOut.tickfont;
186183
delete containerOut.tickangle;

test/jasmine/tests/calcdata_test.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,27 @@ describe('calculated data and points', function() {
150150

151151
expect(gd._fullLayout.xaxis._categories).toEqual(['1']);
152152
});
153+
154+
it('should skip over visible-false traces', function() {
155+
Plotly.plot(gd, [{
156+
x: [1, 2, 3],
157+
y: [7, 6, 5],
158+
visible: false
159+
}, {
160+
x: [10, 9, 8],
161+
y: ['A', 'B', 'C'],
162+
yaxis: 'y2'
163+
}], {
164+
yaxis2: {
165+
categoryorder: 'category descending'
166+
}
167+
});
168+
169+
expect(gd.calcdata[1][0]).toEqual(jasmine.objectContaining({x: 10, y: 2}));
170+
expect(gd.calcdata[1][1]).toEqual(jasmine.objectContaining({x: 9, y: 1}));
171+
expect(gd.calcdata[1][2]).toEqual(jasmine.objectContaining({x: 8, y: 0}));
172+
expect(gd._fullLayout.yaxis2._categories).toEqual(['C', 'B', 'A']);
173+
});
153174
});
154175

155176
describe('explicit category ordering', function() {
@@ -862,6 +883,35 @@ describe('calculated data and points', function() {
862883
expect(gd.calcdata[2][2]).toEqual(jasmine.objectContaining({x: 0, y: 11 + 20 + 32}));
863884
});
864885
});
886+
887+
it('should order categories per axis', function() {
888+
Plotly.plot(gd, [
889+
{x: ['a', 'c', 'g', 'e']},
890+
{x: ['b', 'h', 'f', 'd'], xaxis: 'x2'}
891+
], {
892+
xaxis: {categoryorder: 'category ascending', domain: [0, 0.4]},
893+
xaxis2: {categoryorder: 'category descending', domain: [0.6, 1]}
894+
});
895+
896+
expect(gd._fullLayout.xaxis._categories).toEqual(['a', 'c', 'e', 'g']);
897+
expect(gd._fullLayout.xaxis2._categories).toEqual(['h', 'f', 'd', 'b']);
898+
});
899+
900+
it('should consider number categories and their string representation to be the same', function() {
901+
Plotly.plot(gd, [{
902+
x: ['a', 'b', 1, '1'],
903+
y: [1, 2, 3, 4]
904+
}], {
905+
xaxis: {type: 'category'}
906+
});
907+
908+
expect(gd._fullLayout.xaxis._categories).toEqual(['a', 'b', 1]);
909+
expect(gd._fullLayout.xaxis._categoriesMap).toEqual({
910+
'1': 2,
911+
'a': 0,
912+
'b': 1
913+
});
914+
});
865915
});
866916

867917
describe('customdata', function() {

0 commit comments

Comments
 (0)