Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 48209a0

Browse filesBrowse files
authored
Merge pull request #3070 from plotly/bool-cats
Axis autotype update
2 parents b02221f + 8d446be commit 48209a0
Copy full SHA for 48209a0

File tree

Expand file treeCollapse file tree

2 files changed

+98
-14
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+98
-14
lines changed

‎src/plots/cartesian/axis_autotype.js

Copy file name to clipboardExpand all lines: src/plots/cartesian/axis_autotype.js
+24-14Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,20 @@ function linearOK(array) {
3838
// 2- or 4-digit integers can be both, so require twice as many
3939
// dates as non-dates, to exclude cases with mostly 2 & 4 digit
4040
// numbers and a few dates
41+
// as with categories, consider DISTINCT values only.
4142
function moreDates(a, calendar) {
42-
var dcnt = 0,
43-
ncnt = 0,
44-
// test at most 1000 points, evenly spaced
45-
inc = Math.max(1, (a.length - 1) / 1000),
46-
ai;
43+
// test at most 1000 points, evenly spaced
44+
var inc = Math.max(1, (a.length - 1) / 1000);
45+
var dcnt = 0;
46+
var ncnt = 0;
47+
var seen = {};
4748

4849
for(var i = 0; i < a.length; i += inc) {
49-
ai = a[Math.round(i)];
50+
var ai = a[Math.round(i)];
51+
var stri = String(ai);
52+
if(seen[stri]) continue;
53+
seen[stri] = 1;
54+
5055
if(Lib.isDateTime(ai, calendar)) dcnt += 1;
5156
if(isNumeric(ai)) ncnt += 1;
5257
}
@@ -55,18 +60,23 @@ function moreDates(a, calendar) {
5560
}
5661

5762
// are the (x,y)-values in gd.data mostly text?
58-
// require twice as many categories as numbers
63+
// require twice as many DISTINCT categories as distinct numbers
5964
function category(a) {
6065
// test at most 1000 points
61-
var inc = Math.max(1, (a.length - 1) / 1000),
62-
curvenums = 0,
63-
curvecats = 0,
64-
ai;
66+
var inc = Math.max(1, (a.length - 1) / 1000);
67+
var curvenums = 0;
68+
var curvecats = 0;
69+
var seen = {};
6570

6671
for(var i = 0; i < a.length; i += inc) {
67-
ai = a[Math.round(i)];
68-
if(Lib.cleanNumber(ai) !== BADNUM) curvenums++;
69-
else if(typeof ai === 'string' && ai !== '' && ai !== 'None') curvecats++;
72+
var ai = a[Math.round(i)];
73+
var stri = String(ai);
74+
if(seen[stri]) continue;
75+
seen[stri] = 1;
76+
77+
if(typeof ai === 'boolean') curvecats++;
78+
else if(Lib.cleanNumber(ai) !== BADNUM) curvenums++;
79+
else if(typeof ai === 'string') curvecats++;
7080
}
7181

7282
return curvecats > curvenums * 2;

‎test/jasmine/tests/axes_test.js

Copy file name to clipboardExpand all lines: test/jasmine/tests/axes_test.js
+74Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,80 @@ describe('Test axes', function() {
189189
fullData = [];
190190
});
191191

192+
describe('autotype', function() {
193+
function supplyWithTrace(trace) {
194+
var fullTrace = Lib.extendDeep(
195+
{type: 'scatter', xaxis: 'x', yaxis: 'y'},
196+
trace
197+
);
198+
layoutIn = {xaxis: {}, yaxis: {}};
199+
supplyLayoutDefaults(layoutIn, layoutOut, [fullTrace]);
200+
}
201+
202+
function checkTypes(xType, yType, msg) {
203+
expect(layoutOut.xaxis.type).toBe(xType, msg);
204+
expect(layoutOut.yaxis.type).toBe(yType, msg);
205+
}
206+
207+
it('treats booleans as categories', function() {
208+
supplyWithTrace({x: [0, 1, 2], y: [true, false, true]});
209+
checkTypes('linear', 'category');
210+
});
211+
212+
it('sees a single "None" or "" as a category', function() {
213+
supplyWithTrace({x: ['None'], y: ['']});
214+
checkTypes('category', 'category');
215+
});
216+
217+
it('lets a single number beat up to two distinct categories', function() {
218+
supplyWithTrace({
219+
x: ['2.1', 'N/A', '', 'N/A', '', 'N/A', 'N/A', '', '', ''],
220+
y: [0, 'None', true, 'None', 'None', 'None', 'None', 'None']
221+
});
222+
checkTypes('linear', 'linear');
223+
});
224+
225+
it('turns back to category with >2 per distinct number', function() {
226+
supplyWithTrace({
227+
x: [4, 4, 4, 4, 4, 4, 4, 4, 'Yes', 'No', 'Maybe'],
228+
y: [1, 2, 1, 2, 1, 2, true, false, '', 'None', 'nan']
229+
});
230+
checkTypes('category', 'category');
231+
});
232+
233+
it('works with world calendars', function() {
234+
// these are only valid dates in chinese
235+
var intercalary = ['1995-08i-01', '1995-08i-29', '1984-10i-15'];
236+
supplyWithTrace({
237+
x: intercalary, xcalendar: 'chinese',
238+
y: intercalary, ycalendar: 'gregorian'
239+
});
240+
checkTypes('date', 'category');
241+
});
242+
243+
it('requires >twice as many distinct dates as numbers', function() {
244+
supplyWithTrace({
245+
x: ['2000-01-01', '2000-01-02', '2000-01-03', 1, 1.2],
246+
y: ['2000-01', '2000-02', '2000-03', '2000-04', 1.1]
247+
});
248+
checkTypes('linear', 'date');
249+
250+
supplyWithTrace({
251+
x: ['2000-01-01', '2000-01-02', '2000-01-03', 1, 1],
252+
y: ['2000-01', '2000-01', '2000-01', '2000-01', 1.1]
253+
});
254+
checkTypes('date', 'linear');
255+
});
256+
257+
it('counts ambiguous dates as both dates and numbers', function() {
258+
supplyWithTrace({
259+
x: ['2000', '2000-01', '2000-02'], // 3 dates, 1 number
260+
y: ['2000', '2001', '2000-01'] // 3 dates, 2 numbers
261+
});
262+
checkTypes('date', 'linear');
263+
});
264+
});
265+
192266
it('should set undefined linewidth/linecolor if linewidth, linecolor or showline is not supplied', function() {
193267
layoutIn = {
194268
xaxis: {},

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.