Published
Edited
Jul 6, 2022
13 stars
Insert cell
Insert cell
Insert cell
Insert cell
Plot.plot({
marks: [
Plot.ruleX([0]),
Plot.ruleY([0]),
Plot.image(data, {
x: "pearson",
y: "chatterjee",
src: (d) =>
`data:image/svg+xml,${
d3
.select(plot(d.data, plotSize, false))
.attr("xmlns", d3.namespaces.svg)
.node().outerHTML
}`,
width: plotSize,
height: plotSize,
opacity: 0.8
})
],
x: { nice: true },
y: { nice: true },
width,
height: width
})
Insert cell
Insert cell
funcs = [
["sine", (x) => Math.sin(9 * x)],
["linear", (x) => x],
["circle", (x, i) => (i % 2 ? -1 : 1) * Math.sqrt(1 - (2 * x - 1) ** 2)],
["parabola", (x) => (2 * (x - 0.5)) ** 2]
// add your own!
]
Insert cell
plot = (data, size = 300, axis = true) => Plot.plot({
marks: [
Plot.frame({fill: "rgba(250,250,250,0.8)", stroke: "black"}),
Plot.dot(data, {
r: 1.5,
opacity: 0.9
})
],
inset: size / 15,
x: { axis },
y: { axis },
nice: true,
width: size,
height: size
})
Insert cell
function* noise(data, rnd) {
for (const [x, y] of data) yield [x + rnd(), y + rnd()];
}
Insert cell
function* sample(fn, N = 40) {
for (let i = 0; i < N + 1; i++) yield [i / N, fn(i / N, i)];
}
Insert cell
data = d3.cross(funcs, [0, 0.06, 0.12], (func, sigma) => {
const data = [...noise(sample(func[1]), d3.randomNormal(0, sigma))];
return {
func,
noise: sigma,
data,
pearson: pearson(data),
chatterjee: chatterjee(data)
};
})
Insert cell
htl.html`<div style=${{display: "flex", flexWrap: "wrap"}}>${data.map(d => plot(d.data))}</div>`
Insert cell
// pearson
x = d3.scaleLinear([-0.4, 1], [margin.left, width - margin.right])
Insert cell
// chatterjee
y = d3.scaleLinear([-0.6, 1], [height - margin.bottom, margin.top])
Insert cell
height = width
Insert cell
margin = ({top: 60, right: 60, bottom: 60, left: 60})
Insert cell
plotSize = 80
Insert cell
Insert cell
Insert cell
chatterjee = (data, { x = (d) => d[0], y = (d) => d[1] } = {}) => {
// 0. Extract values
const X = d3.map(data, x);
const Y = d3.map(data, y);
const N = X.length;

// 1. rearrange along X
const I = d3.sort(d3.range(N), (i) => X[i]);

// 2. rank Y
const rank = d3.rank(Y);

// 3. compute ξ (simple formula with no ties)
return (
1 -
(3 / (N * N - 1)) *
d3.sum(d3.pairs(I), ([a, b]) => Math.abs(rank[a] - rank[b]))
);
}
Insert cell
Insert cell
Insert cell
pearson = (data, { x = (d) => d[0], y = (d) => d[1] } = {}) => {
// 0. Extract values
const X = d3.map(data, x);
const Y = d3.map(data, y);
const N = X.length;

// 1. Calculate covariance
const cov =
(1 / (X.length - 1)) *
d3.sum(X.map((_, i) => (X[i] - d3.mean(X)) * (Y[i] - d3.mean(Y))));

// 2. Divide covariance by product of standard deviations
return cov / (d3.deviation(X) * d3.deviation(Y));
}
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