function make_bins(data, xAccessor, weightAccessor, valueAccessor, options)
{
options = {binCount: 10, xMax: +Infinity, ...options};
var xMin = Infinity;
var xMax = -Infinity;
data.forEach(e => {
var x = +xAccessor(e);
if (x == x) {
xMin = Math.min(x, xMin);
xMax = Math.max(x, xMax);
}
});
xMax = Math.min(options.xMax, xMax);
var xStep = (xMax - xMin) / options.binCount;
xStep = Math.pow(10, Math.ceil(Math.log10(xStep)));
if (xStep * options.binCount * 0.3 > xMax - xMin) xStep *= .2;
if (xStep * options.binCount * 0.75 > xMax - xMin) xStep *= .5;
var xInvStep = 1 / xStep;
var xBinMinIx = Math.floor(xMin * xInvStep);
var xBinMaxIx = Math.ceil(xMax * xInvStep);
var bins = Array(xBinMaxIx - xBinMinIx).fill().map((_, i) => ({
x: (i + xBinMinIx) * xStep,
n: 0,
_aggr: new meanAggregator(valueAccessor, weightAccessor)
}));
data.forEach(e => {
var x = xAccessor(e);
var x_bin = Math.floor((x - xMin) * xInvStep);
if (x < options.xMax)
{
var bin = bins[x_bin];
bin.n += 1;
bin._aggr.add(e);
}
});
bins.forEach(bin => {
bin.value = bin._aggr.value();
bin.weight = bin._aggr.w;
});
return bins;
}