Published
Edited
Dec 23, 2019
1 star
Also listed in…
Graphs
Algorithms
Insert cell
Insert cell
Insert cell
N = 500
Insert cell
Insert cell
Insert cell
viewof similarities = pt(
new Matrix(points.map(i => points.map(j => similarity(i, j))))
)
Insert cell
similarity = {
await Promises.delay(300); // cheap debounce of the sigma slider value
return (i, j) => Math.exp(-(distance(i, j) / sigma));
}
Insert cell
Insert cell
function distance(i, j) {
return Math.hypot(i[0] - j[0], i[1] - j[1]) / deviation;
}
Insert cell
Insert cell
I = mlMatrix.inverse(similarities)
Insert cell
weights = I.mmul(Matrix.ones(points.length, 1))
.flatMap(d => Math.log(1 + Math.abs(d)))
Insert cell
Insert cell
magnitude = new Matrix([weights])
.mmul(similarities)
.mmul(new Matrix([weights]).transpose())
.get(0, 0)
Insert cell
Insert cell
Insert cell
Insert cell
{
const width = 600,
height = 600,
context = DOM.context2d(width, height);

yield context.canvas;

context.clearRect(0, 0, width, height);
for (let i = 0; i < points.length; i++) {
const p = points[i];
context.beginPath();
context.arc(x(p[0]), y(p[1]), radius(weights[i]), 0, tau);
context.strokeStyle = context.fillStyle = color(weights[i]);
context.fill();
}

yield context.canvas;

const min = extent[1] - (extent[1] - extent[0]) * 0.75;
for (let i = 0; i < points.length; i++) {
if (weights[i] > min) {
const p = points[i];
context.beginPath();
context.arc(x(p[0]), y(p[1]), 4, 0, tau);
context.strokeStyle = context.fillStyle = "#ff88bb";
context.fill();
}
}
yield context.canvas;
}
Insert cell
x = d3
.scaleLinear()
.domain(d3.extent(points, d => d[0]))
.range([50, 550])
Insert cell
y = d3
.scaleLinear()
.domain(d3.extent(points, d => d[1]))
.range([50, 550])
Insert cell
deviation = +Math.sqrt(
d3.deviation(points, d => d[0]) * d3.deviation(points, d => d[1])
).toFixed(1)
Insert cell
radius = d3
.scaleLinear()
.domain(extent)
.range([1.5, 25])
Insert cell
extent = d3.extent(weights)
Insert cell
color = d3.scaleSequential(d3.interpolateInferno).domain(extent)
Insert cell
Insert cell
square = Array.from({ length: N }, () => {
return [Math.random(), Math.random()];
})
Insert cell
circle = Array.from({ length: N }, () => {
const r = Math.random() + 1,
alpha = Math.random() * tau;
return [r * Math.cos(alpha), r * Math.sin(alpha)];
})
Insert cell
lunes = Array.from({ length: N }, (_, i) => {
const r = Math.random() + 1,
alpha = Math.random() * Math.PI;
return i % 2
? [r * Math.cos(alpha), r * Math.sin(alpha)]
: [1.5 + r * Math.cos(alpha), -r * Math.sin(alpha)];
})
Insert cell
blobs = Array.from({ length: N }, (_, i) => {
const center = [[0, 0], [5, 5], [6, -2]][i % 3];
return center.map(d => d + d3.randomNormal()());
})
Insert cell
d3 = require("d3@5")
Insert cell
tau = 2 * Math.PI
Insert cell
// adapted from https://beta.observablehq.com/@chitacan/handling-matrices#pt
function pt(matrix, MAXROWS = 13) {
const values =
typeof matrix[0] === "object" ? matrix : Array.from(matrix).map(d => [d]);
const data = values
//.toArray()
.slice(0, MAXROWS)
.map(row =>
row
.slice(0, MAXROWS)
.map(format)
.map((d, i) => (i === MAXROWS - 1 ? "…" : d))
.join(" & ")
)
.map(
(d, i) =>
i === MAXROWS - 1
? values[0]
.slice(0, MAXROWS)
.map(d => "…")
.join(" & ")
: d
)
.join(" \\\\ ");
const el = tex`
\left(\begin{matrix}
${data}
\end{matrix}\right)
`;
el.value = matrix;
return el;
}
Insert cell
mlMatrix = require(await FileAttachment("ml-matrix-6.4.1.js").url()) //("https://recifs.neocities.org/browserify/ml-matrix@6.4.1.js")
// require("https://bundle.run/ml-matrix@6.4.1")
// hosted version built with: browserify matrix.js --standalone ml-matrix -o ml-matrix-6.4.1.js
Insert cell
Insert cell
Insert cell
import {select, 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