@@ -14,23 +14,49 @@ var isNumeric = require('fast-isnumeric');
1414var Lib = require ( '../../lib' ) ;
1515var BADNUM = require ( '../../constants/numerical' ) . BADNUM ;
1616
17+ var isArrayOrTypedArray = Lib . isArrayOrTypedArray ;
18+ var isDateTime = Lib . isDateTime ;
19+ var cleanNumber = Lib . cleanNumber ;
20+ var round = Math . round ;
21+
1722module . exports = function autoType ( array , calendar , opts ) {
18- opts = opts || { } ;
23+ var a = array ;
24+
25+ var noMultiCategory = opts . noMultiCategory ;
26+ if ( isArrayOrTypedArray ( a ) && ! a . length ) return '-' ;
27+ if ( ! noMultiCategory && multiCategory ( a ) ) return 'multicategory' ;
28+ if ( noMultiCategory && Array . isArray ( a [ 0 ] ) ) { // no need to flat typed arrays here
29+ var b = [ ] ;
30+ for ( var i = 0 ; i < a . length ; i ++ ) {
31+ if ( isArrayOrTypedArray ( a [ i ] ) ) {
32+ for ( var j = 0 ; j < a [ i ] . length ; j ++ ) {
33+ b . push ( a [ i ] [ j ] ) ;
34+ }
35+ }
36+ }
37+ a = b ;
38+ }
39+
40+ if ( moreDates ( a , calendar ) ) return 'date' ;
1941
20- if ( ! opts . noMultiCategory && multiCategory ( array ) ) return 'multicategory' ;
21- if ( moreDates ( array , calendar ) ) return 'date ' ;
22- if ( category ( array ) ) return 'category ' ;
23- if ( linearOK ( array ) ) return 'linear' ;
24- else return '-' ;
42+ var convertNumeric = opts . autotypenumbers !== 'strict' ; // compare against strict, just in case autotypenumbers was not provided in opts
43+ if ( category ( a , convertNumeric ) ) return 'category ' ;
44+ if ( linearOK ( a , convertNumeric ) ) return 'linear ' ;
45+
46+ return '-' ;
2547} ;
2648
49+ function hasTypeNumber ( v , convertNumeric ) {
50+ return convertNumeric ? isNumeric ( v ) : typeof v === 'number' ;
51+ }
52+
2753// is there at least one number in array? If not, we should leave
2854// ax.type empty so it can be autoset later
29- function linearOK ( array ) {
30- if ( ! array ) return false ;
55+ function linearOK ( a , convertNumeric ) {
56+ var len = a . length ;
3157
32- for ( var i = 0 ; i < array . length ; i ++ ) {
33- if ( isNumeric ( array [ i ] ) ) return true ;
58+ for ( var i = 0 ; i < len ; i ++ ) {
59+ if ( hasTypeNumber ( a [ i ] , convertNumeric ) ) return true ;
3460 }
3561
3662 return false ;
@@ -43,51 +69,61 @@ function linearOK(array) {
4369// numbers and a few dates
4470// as with categories, consider DISTINCT values only.
4571function moreDates ( a , calendar ) {
46- // test at most 1000 points, evenly spaced
47- var inc = Math . max ( 1 , ( a . length - 1 ) / 1000 ) ;
48- var dcnt = 0 ;
49- var ncnt = 0 ;
72+ var len = a . length ;
73+
74+ var inc = getIncrement ( len ) ;
75+ var dats = 0 ;
76+ var nums = 0 ;
5077 var seen = { } ;
5178
52- for ( var i = 0 ; i < a . length ; i += inc ) {
53- var ai = a [ Math . round ( i ) ] ;
79+ for ( var f = 0 ; f < len ; f += inc ) {
80+ var i = round ( f ) ;
81+ var ai = a [ i ] ;
5482 var stri = String ( ai ) ;
5583 if ( seen [ stri ] ) continue ;
5684 seen [ stri ] = 1 ;
5785
58- if ( Lib . isDateTime ( ai , calendar ) ) dcnt += 1 ;
59- if ( isNumeric ( ai ) ) ncnt += 1 ;
86+ if ( isDateTime ( ai , calendar ) ) dats ++ ;
87+ if ( isNumeric ( ai ) ) nums ++ ;
6088 }
6189
62- return ( dcnt > ncnt * 2 ) ;
90+ return dats > nums * 2 ;
91+ }
92+
93+ // return increment to test at most 1000 points, evenly spaced
94+ function getIncrement ( len ) {
95+ return Math . max ( 1 , ( len - 1 ) / 1000 ) ;
6396}
6497
6598// are the (x,y)-values in gd.data mostly text?
6699// require twice as many DISTINCT categories as distinct numbers
67- function category ( a ) {
68- // test at most 1000 points
69- var inc = Math . max ( 1 , ( a . length - 1 ) / 1000 ) ;
70- var curvenums = 0 ;
71- var curvecats = 0 ;
100+ function category ( a , convertNumeric ) {
101+ var len = a . length ;
102+
103+ var inc = getIncrement ( len ) ;
104+ var nums = 0 ;
105+ var cats = 0 ;
72106 var seen = { } ;
73107
74- for ( var i = 0 ; i < a . length ; i += inc ) {
75- var ai = a [ Math . round ( i ) ] ;
108+ for ( var f = 0 ; f < len ; f += inc ) {
109+ var i = round ( f ) ;
110+ var ai = a [ i ] ;
76111 var stri = String ( ai ) ;
77112 if ( seen [ stri ] ) continue ;
78113 seen [ stri ] = 1 ;
79114
80- if ( typeof ai === 'boolean' ) curvecats ++ ;
81- else if ( Lib . cleanNumber ( ai ) !== BADNUM ) curvenums ++ ;
82- else if ( typeof ai === 'string' ) curvecats ++ ;
115+ var t = typeof ai ;
116+ if ( t === 'boolean' ) cats ++ ;
117+ else if ( convertNumeric ? cleanNumber ( ai ) !== BADNUM : t === 'number' ) nums ++ ;
118+ else if ( t === 'string' ) cats ++ ;
83119 }
84120
85- return curvecats > curvenums * 2 ;
121+ return cats > nums * 2 ;
86122}
87123
88124// very-loose requirements for multicategory,
89125// trace modules that should never auto-type to multicategory
90126// should be declared with 'noMultiCategory'
91127function multiCategory ( a ) {
92- return Lib . isArrayOrTypedArray ( a [ 0 ] ) && Lib . isArrayOrTypedArray ( a [ 1 ] ) ;
128+ return isArrayOrTypedArray ( a [ 0 ] ) && isArrayOrTypedArray ( a [ 1 ] ) ;
93129}
0 commit comments