Public
Edited
May 9, 2023
Paused
3 forks
Importers
36 stars
Insert cell
Insert cell
Insert cell
Insert cell
Plot.plot({
width,
height: width * 0.7,
inset: 20,
marks: [
Plot.frame(),
showVoronoi
? Plot.voronoiMesh(airports, { x: "longitude", y: "latitude" })
: null,
Plot.arrow(
airports,
maybeVoronoiCentroids({
x1: "longitude",
y1: "latitude",
x2: "longitude",
y2: "latitude",
stroke: "black",
strokeWidth: 0.7,
bend: true,
headLength: 0
})
),
Plot.dot(airports, {
x: "longitude",
y: "latitude",
r: 1.5,
fill: "black"
}),
Plot.text(
airports,
maybeVoronoiCentroids({
x: "longitude",
y: "latitude",
text: (d) => d.name.split(/ /)[0],
stroke: "white",
strokeWidth: 7,
fill: "black"
})
)
]
})
Insert cell
Insert cell
voronoiCentroids = (options) =>
Plot.initializer(
options,
function (
data,
facets,
{ x: X0, y: Y0, x2: X2, y2: Y2 },
{ x, y },
{ width, height, marginLeft, marginRight, marginTop, marginBottom },
context
) {
const X = X2 ?? X0;
const Y = Y2 ?? Y0;
if (X.scale !== "x") x = (x) => x;
if (Y.scale !== "y") y = (y) => y;

for (const I of facets) {
const v = d3.Delaunay.from(
I,
(i) => x(X.value[i]),
(i) => y(Y.value[i])
).voronoi([
marginLeft,
marginTop,
width - marginRight,
height - marginBottom
]);
let cell;
for (const [i, k] of I.entries()) {
if ((cell = v.cellPolygon(k))) {
const [x, y] = d3.polygonCentroid(cell);
X.value[i] = x;
Y.value[i] = y;
}
}
}
delete X.scale;
delete Y.scale;
return { data, facets };
}
)
Insert cell
maybeVoronoiCentroids = activate ? voronoiCentroids : (options) => options
Insert cell
Insert cell
airports = FileAttachment("airports.csv")
.csv({ typed: true })
.then((data) => data.filter((d, i) => i % 20 === 0))
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