Published
Edited
Dec 5, 2020
1 fork
11 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
geometricMedian(points, P)
Insert cell
[
...geometricMedianIterator(points, {
P,
alpha: 0.5
})
]
Insert cell
paths = points.map(p0 => [
p0,
...geometricMedianIterator(points, {
P,
alpha: .2 / P,
precision: .03,
x: p0[0],
y: p0[1]
})
])
Insert cell
// as a function
geometricMedian = (points, options = {}) => {
for (var m of geometricMedianIterator(points, options));
return m;
}
Insert cell
function* geometricMedianIterator(
points,
{ P = 1, alpha = 1, precision = 1e-6, x = 0, y = 0 } = {}
) {
// starting point
let delta,
i = 0;

if (x === undefined) x = y = 0;

do {
let sx = 0;
let sy = 0;
let s = 0;
for (const p of points) {
const d = [x - p[0], y - p[1]];
const n = norm(d);
if (n) {
const np = pow(n, P - 2);
s += np;
sx += p[0] * np;
sy += p[1] * np;
}
}
yield [x, y];
const x_ = x,
y_ = y;
x += alpha * (sx / s - x);
y += alpha * (sy / s - y);
delta = abs(x - x_) + abs(y - y_);
} while (delta > precision && i++ < 1000);

return yield [x, y];
}
Insert cell
function norm(X) {
return Math.hypot(...X);
}
Insert cell
points = (replay,
Array.from({ length: 50 }, () => [random(), random()])
.map(d => [d[0] - 300, d[1] - 50])
.concat(
Array.from({ length: 30 + 40 * Math.random() }, () => [random(), random()])
))
Insert cell
random = d3.randomNormal(0, width / 20)
Insert cell
d3 = require("d3@6")
Insert cell
height = 500
Insert cell
import { abs, pow, tau } from "@fil/math"
Insert cell
import { slider } from "@jashkenas/inputs"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more