Skip to content

Commit

Permalink
apply linear binning (#46)
Browse files Browse the repository at this point in the history
* apply linear binning
closes #8

* a test for contourDensity & linear binning

* style

Co-authored-by: Mike Bostock <mbostock@gmail.com>
  • Loading branch information
Fil and mbostock committed Jun 5, 2021
1 parent 29d1447 commit 14e21c2
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 4 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -36,6 +36,7 @@
"d3-array": "2 - 3"
},
"devDependencies": {
"d3-polygon": "1 - 2",
"eslint": "7",
"mocha": "8",
"rollup": "2",
Expand Down
16 changes: 12 additions & 4 deletions src/density.js
Expand Up @@ -31,14 +31,22 @@ export default function() {

function density(data) {
var values0 = new Float32Array(n * m),
values1 = new Float32Array(n * m);
values1 = new Float32Array(n * m),
pow2k = Math.pow(2, -k);

data.forEach(function(d, i, data) {
var xi = (+x(d, i, data) + o) >> k,
yi = (+y(d, i, data) + o) >> k,
var xi = (x(d, i, data) + o) * pow2k,
yi = (y(d, i, data) + o) * pow2k,
wi = +weight(d, i, data);
if (xi >= 0 && xi < n && yi >= 0 && yi < m) {
values0[xi + yi * n] += wi;
var x0 = Math.floor(xi),
y0 = Math.floor(yi),
xt = xi - x0 - 0.5,
yt = yi - y0 - 0.5;
values0[x0 + y0 * n] += (1 - xt) * (1 - yt) * wi;
values0[x0 + 1 + y0 * n] += xt * (1 - yt) * wi;
values0[x0 + 1 + (y0 + 1) * n] += xt * yt * wi;
values0[x0 + (y0 + 1) * n] += (1 - xt) * yt * wi;
}
});

Expand Down
20 changes: 20 additions & 0 deletions test/asserts.js
@@ -0,0 +1,20 @@
import assert from "assert";

export function assertInDelta(actual, expected, delta = 1e-6) {
assert(inDelta(actual, expected, delta));
}

function inDelta(actual, expected, delta) {
return (Array.isArray(expected) ? inDeltaArray : inDeltaNumber)(actual, expected, delta);
}

function inDeltaArray(actual, expected, delta) {
const n = expected.length;
if (actual.length !== n) return false;
for (let i = 0; i < n; ++i) if (!inDelta(actual[i], expected[i], delta)) return false;
return true;
}

function inDeltaNumber(actual, expected, delta) {
return actual >= expected - delta && actual <= expected + delta;
}
20 changes: 20 additions & 0 deletions test/density-test.js
@@ -1,9 +1,29 @@
import assert from "assert";
import {polygonCentroid} from "d3-polygon";
import {contourDensity} from "../src/index.js";
import {assertInDelta} from "./asserts.js";

it("density.size(…) validates the specified size", () => {
assert.deepStrictEqual(contourDensity().size([1, 2]).size(), [1, 2]);
assert.deepStrictEqual(contourDensity().size([0, 0]).size(), [0, 0]);
assert.deepStrictEqual(contourDensity().size([1.5, 2.5]).size(), [1.5, 2.5]);
assert.throws(() => void contourDensity().size([0, -1]), /invalid size/);
});

it("contourDensity(data) returns the expected result for empty data", () => {
const c = contourDensity();
assert.deepStrictEqual(c([]), []);
});

it("contourDensity(data) returns contours centered on a point", () => {
const c = contourDensity().thresholds([0.0001, 0.001]);
for (const p of [[100, 100], [100.5, 102]]) {
const contour = c([p]);
assert.strictEqual(contour.length, 2);
for (const b of contour) {
const a = polygonCentroid(b.coordinates[0][0]);
assertInDelta(a[0], p[0], 0.1);
assertInDelta(a[1], p[1], 0.1);
}
}
});
5 changes: 5 additions & 0 deletions yarn.lock
Expand Up @@ -275,6 +275,11 @@ cross-spawn@^7.0.2:
dependencies:
internmap "1 - 2"

"d3-polygon@1 - 2":
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-2.0.0.tgz#13608ef042fbec625ba1598327564f03c0396d8e"
integrity sha512-MsexrCK38cTGermELs0cO1d79DcTsQRN7IWMJKczD/2kBjzNXxLUWP33qRF6VDpiLV/4EI4r6Gs0DAWQkE8pSQ==

debug@4.3.1, debug@^4.0.1, debug@^4.1.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
Expand Down

0 comments on commit 14e21c2

Please sign in to comment.