Published
Edited
Sep 28, 2021
3 stars
Also listed in…
Plot
Insert cell
Insert cell
Plot.plot({
facet: { data, x: "island" },
marks: [
Plot.frame(),
hull(data, {
x: "body_mass",
y: "bill_length",
fill: "sex",
fillOpacity: 0.2,
curve: "catmull-rom",
alpha: 0.8,
stroke: "black"
}),
Plot.dot(data, { x: "body_mass", y: "bill_length", fill: "sex" })
],
width
})
Insert cell
function hull(data, { curve, tension, alpha, ...options }) {
const L = Plot.line(data, options);
const render = L.render;
const line = d3.line().curve(maybeClosedCurve(curve, { tension, alpha }));

L.render = function () {
const g = render.apply(this, arguments);
d3.select(g)
.selectAll("path")
.each(function () {
const points = this.getAttribute("d")
.replace(/[MZ]/g, "L") // NaN data creates M in the lines (gaps)
.split("L")
.map((d) => d.split(",").map(Number))
.filter((d) => d.length === 2);
if (points.length > 3) {
const hull = d3.polygonHull(points);
this.setAttribute("d", line(hull));
} else this.setAttribute("d", null);
});
return g;
};
return L;
}
Insert cell
function maybeClosedCurve(curve, { tension = 0, alpha = 0.5 }) {
switch (curve) {
case "linear":
case undefined:
case null:
curve = d3.curveLinearClosed;
break;
case "basis":
case "basis-closed":
curve = d3.curveBasisClosed;
break;
case "cardinal":
case "cardinal-closed":
curve = d3.curveCardinalClosed.tension(tension);
break;
case "catmull-rom":
case "catmull-rom-closed":
curve = d3.curveCatmullRomClosed.alpha(alpha);
break;
}
if (typeof curve === "function") return curve;
else throw new Error("unknow curve");
}
Insert cell
import { data } from "@observablehq/plot-exploration-penguins"
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