Skip to content

Commit 57225fc

Browse files
authored
fix for quantization error with fractional step (#247)
* fix for quantization error with fractional step * conditional fix for rounding error
1 parent f0ed838 commit 57225fc

5 files changed

Lines changed: 11577 additions & 3 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
},
4343
"devDependencies": {
4444
"@rollup/plugin-node-resolve": "13",
45+
"d3-dsv": "3",
4546
"d3-random": "2 - 3",
4647
"eslint": "8",
4748
"jsdom": "19",

src/bin.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ export default function bin() {
9191
} else if (step < 0) {
9292
for (i = 0; i < n; ++i) {
9393
if ((x = values[i]) != null && x0 <= x && x <= x1) {
94-
bins[Math.floor((x0 - x) * step)].push(data[i]);
94+
const j = Math.floor((x0 - x) * step);
95+
bins[j + (tz[j] <= x)].push(data[i]); // handle off-by-one due to rounding
9596
}
9697
}
9798
}

test/bin-test.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import assert from "assert";
2-
import {bin, extent, histogram, thresholdSturges} from "../src/index.js";
2+
import {csvParse} from "d3-dsv";
3+
import {readFile} from "fs/promises";
4+
import {bin, extent, histogram, thresholdSturges, ticks} from "../src/index.js";
35

46
it("histogram is a deprecated alias for bin", () => {
57
assert.strictEqual(histogram, bin);
@@ -221,6 +223,18 @@ it("bin(data) coerces values to numbers as expected", () => {
221223
]);
222224
});
223225

226+
it("bin(athletes) produces the expected result", async () => {
227+
const height = csvParse(await readFile("./test/data/athletes.csv", "utf8")).filter(d => d.height).map(d => +d.height);
228+
const bins = bin().thresholds(57)(height);
229+
assert.deepStrictEqual(bins.map(b => b.length), [1, 0, 0, 0, 0, 0, 2, 1, 2, 1, 1, 4, 11, 7, 13, 39, 78, 93, 119, 193, 354, 393, 573, 483, 651, 834, 808, 763, 627, 648, 833, 672, 578, 498, 395, 425, 278, 235, 182, 128, 91, 69, 43, 29, 21, 23, 3, 3, 1, 1, 1]);
230+
});
231+
232+
it("bin(data) assigns floating point values to the correct bins", () => {
233+
for (const n of [1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000]) {
234+
assert.ok(bin().thresholds(n)(ticks(1, 2, n)).every(d => d.length === 1));
235+
}
236+
});
237+
224238
function box(bin, x0, x1) {
225239
bin.x0 = x0;
226240
bin.x1 = x1;

0 commit comments

Comments
 (0)