@@ -486,22 +486,19 @@ axes.expand = function(ax, data, options) {
486486} ;
487487
488488axes . autoBin = function ( data , ax , nbins , is2d ) {
489- var datamin = Lib . aggNums ( Math . min , null , data ) ,
490- datamax = Lib . aggNums ( Math . max , null , data ) ,
491- blankcount = 0 ,
492- datacount ,
493- i ;
489+ var dataMin = Lib . aggNums ( Math . min , null , data ) ,
490+ dataMax = Lib . aggNums ( Math . max , null , data ) ;
494491
495492 if ( ax . type === 'category' ) {
496493 return {
497- start : datamin - 0.5 ,
498- end : datamax + 0.5 ,
494+ start : dataMin - 0.5 ,
495+ end : dataMax + 0.5 ,
499496 size : 1
500497 } ;
501498 }
502499
503500 var size0 ;
504- if ( nbins ) size0 = ( ( datamax - datamin ) / nbins ) ;
501+ if ( nbins ) size0 = ( ( dataMax - dataMin ) / nbins ) ;
505502 else {
506503 // totally auto: scale off std deviation so the highest bin is
507504 // somewhat taller than the total number of bins, but don't let
@@ -518,100 +515,106 @@ axes.autoBin = function(data, ax, nbins, is2d) {
518515 }
519516
520517 // piggyback off autotick code to make "nice" bin sizes
521- var dummyax ;
518+ var dummyAx ;
522519 if ( ax . type === 'log' ) {
523- dummyax = {
520+ dummyAx = {
524521 type : 'linear' ,
525- range : [ datamin , datamax ] ,
522+ range : [ dataMin , dataMax ] ,
526523 r2l : Number
527524 } ;
528525 }
529526 else {
530- dummyax = {
527+ dummyAx = {
531528 type : ax . type ,
532529 // conversion below would be ax.c2r but that's only different from l2r
533530 // for log, and this is the only place (so far?) we would want c2r.
534- range : [ datamin , datamax ] . map ( ax . l2r ) ,
531+ range : [ dataMin , dataMax ] . map ( ax . l2r ) ,
535532 r2l : ax . r2l
536533 } ;
537534 }
538535
539- axes . autoTicks ( dummyax , size0 ) ;
540- var binstart = axes . tickIncrement (
541- axes . tickFirst ( dummyax ) , dummyax . dtick , 'reverse' ) ,
542- binend ;
543-
544- function nearEdge ( v ) {
545- // is a value within 1% of a bin edge?
546- return ( 1 + ( v - binstart ) * 100 / dummyax . dtick ) % 100 < 2 ;
547- }
536+ axes . autoTicks ( dummyAx , size0 ) ;
537+ var binStart = axes . tickIncrement (
538+ axes . tickFirst ( dummyAx ) , dummyAx . dtick , 'reverse' ) ,
539+ binEnd ;
548540
549541 // check for too many data points right at the edges of bins
550542 // (>50% within 1% of bin edges) or all data points integral
551543 // and offset the bins accordingly
552- if ( typeof dummyax . dtick === 'number' ) {
553- var edgecount = 0 ,
554- midcount = 0 ,
555- intcount = 0 ;
556-
557- for ( i = 0 ; i < data . length ; i ++ ) {
558- if ( data [ i ] % 1 === 0 ) intcount ++ ;
559- else if ( ! isNumeric ( data [ i ] ) ) blankcount ++ ;
560-
561- if ( nearEdge ( data [ i ] ) ) edgecount ++ ;
562- if ( nearEdge ( data [ i ] + dummyax . dtick / 2 ) ) midcount ++ ;
563- }
564- datacount = data . length - blankcount ;
565-
566- if ( intcount === datacount && ax . type !== 'date' ) {
567- // all integers: if bin size is <1, it's because
568- // that was specifically requested (large nbins)
569- // so respect that... but center the bins containing
570- // integers on those integers
571- if ( dummyax . dtick < 1 ) {
572- binstart = datamin - 0.5 * dummyax . dtick ;
573- }
574- // otherwise start half an integer down regardless of
575- // the bin size, just enough to clear up endpoint
576- // ambiguity about which integers are in which bins.
577- else binstart -= 0.5 ;
578- }
579- else if ( midcount < datacount * 0.1 ) {
580- if ( edgecount > datacount * 0.3 ||
581- nearEdge ( datamin ) || nearEdge ( datamax ) ) {
582- // lots of points at the edge, not many in the middle
583- // shift half a bin
584- var binshift = dummyax . dtick / 2 ;
585- binstart += ( binstart + binshift < datamin ) ? binshift : - binshift ;
586- }
587- }
544+ if ( typeof dummyAx . dtick === 'number' ) {
545+ binStart = autoShiftNumericBins ( binStart , data , dummyAx , dataMin , dataMax ) ;
588546
589- var bincount = 1 + Math . floor ( ( datamax - binstart ) / dummyax . dtick ) ;
590- binend = binstart + bincount * dummyax . dtick ;
547+ var bincount = 1 + Math . floor ( ( dataMax - binStart ) / dummyAx . dtick ) ;
548+ binEnd = binStart + bincount * dummyAx . dtick ;
591549 }
592550 else {
593- // month ticks - should be the only nonlinear kind we have
594- // at this point.
595- if ( dummyax . dtick . charAt ( 0 ) === 'M' ) {
596- binstart = autoShiftMonthBins ( binstart , data , dummyax . dtick , datamin ) ;
551+ // month ticks - should be the only nonlinear kind we have at this point.
552+ if ( dummyAx . dtick . charAt ( 0 ) === 'M' ) {
553+ binStart = autoShiftMonthBins ( binStart , data , dummyAx . dtick , dataMin ) ;
597554 }
598555
599556 // calculate the endpoint for nonlinear ticks - you have to
600557 // just increment until you're done
601- binend = binstart ;
602- while ( binend <= datamax ) {
603- binend = axes . tickIncrement ( binend , dummyax . dtick ) ;
558+ binEnd = binStart ;
559+ while ( binEnd <= dataMax ) {
560+ binEnd = axes . tickIncrement ( binEnd , dummyAx . dtick ) ;
604561 }
605562 }
606563
607564 return {
608- start : ax . c2r ( binstart ) ,
609- end : ax . c2r ( binend ) ,
610- size : dummyax . dtick
565+ start : ax . c2r ( binStart ) ,
566+ end : ax . c2r ( binEnd ) ,
567+ size : dummyAx . dtick
611568 } ;
612569} ;
613570
614571
572+ function autoShiftNumericBins ( binStart , data , ax , dataMin , dataMax ) {
573+ var edgecount = 0 ,
574+ midcount = 0 ,
575+ intcount = 0 ,
576+ blankCount = 0 ;
577+
578+ function nearEdge ( v ) {
579+ // is a value within 1% of a bin edge?
580+ return ( 1 + ( v - binStart ) * 100 / ax . dtick ) % 100 < 2 ;
581+ }
582+
583+ for ( var i = 0 ; i < data . length ; i ++ ) {
584+ if ( data [ i ] % 1 === 0 ) intcount ++ ;
585+ else if ( ! isNumeric ( data [ i ] ) ) blankCount ++ ;
586+
587+ if ( nearEdge ( data [ i ] ) ) edgecount ++ ;
588+ if ( nearEdge ( data [ i ] + ax . dtick / 2 ) ) midcount ++ ;
589+ }
590+ var dataCount = data . length - blankCount ;
591+
592+ if ( intcount === dataCount && ax . type !== 'date' ) {
593+ // all integers: if bin size is <1, it's because
594+ // that was specifically requested (large nbins)
595+ // so respect that... but center the bins containing
596+ // integers on those integers
597+ if ( ax . dtick < 1 ) {
598+ binStart = dataMin - 0.5 * ax . dtick ;
599+ }
600+ // otherwise start half an integer down regardless of
601+ // the bin size, just enough to clear up endpoint
602+ // ambiguity about which integers are in which bins.
603+ else binStart -= 0.5 ;
604+ }
605+ else if ( midcount < dataCount * 0.1 ) {
606+ if ( edgecount > dataCount * 0.3 ||
607+ nearEdge ( dataMin ) || nearEdge ( dataMax ) ) {
608+ // lots of points at the edge, not many in the middle
609+ // shift half a bin
610+ var binshift = ax . dtick / 2 ;
611+ binStart += ( binStart + binshift < dataMin ) ? binshift : - binshift ;
612+ }
613+ }
614+ return binStart ;
615+ }
616+
617+
615618function autoShiftMonthBins ( binStart , data , dtick , dataMin ) {
616619 var exactYears = 0 ,
617620 exactMonths = 0 ,
0 commit comments