Skip to content

Commit 1b9b122

Browse files
committed
refactor numeric bin shift for consistency, and lint
1 parent f6b902c commit 1b9b122

File tree

1 file changed

+73
-70
lines changed

1 file changed

+73
-70
lines changed

src/plots/cartesian/axes.js

Lines changed: 73 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -486,22 +486,19 @@ axes.expand = function(ax, data, options) {
486486
};
487487

488488
axes.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+
615618
function autoShiftMonthBins(binStart, data, dtick, dataMin) {
616619
var exactYears = 0,
617620
exactMonths = 0,

0 commit comments

Comments
 (0)