Public
Edited
Sep 23, 2024
18 forks
26 stars
Also listed in…
Gallery
d3-contour
Insert cell
Insert cell
chart = html`<svg style="width: 100%; height: auto; display: block;" viewBox="0 0 960 500">
<g stroke="#000" stroke-width="0.5" stroke-linejoin="round" stroke-linecap="round">
${Array.from(contours(values), d => svg`<path d="${path(invert(d))}" fill="${color(d.value)}" />`)}
</g>
</svg>`
Insert cell
projection = d3.geoNaturalEarth1().precision(0.1)
Insert cell
path = d3.geoPath(projection)
Insert cell
contours = d3.contours().size([n, m])
Insert cell
color = d3.scaleSequential(d3.extent(values), d3.interpolateMagma)
Insert cell
image = tiff.getImage()
Insert cell
values = rotate((await image.readRasters())[0])
Insert cell
n = image.getWidth()
Insert cell
m = image.getHeight()
Insert cell
Insert cell
function rotate(values) {
var l = n >> 1;
for (var j = 0, k = 0; j < m; ++j, k += n) {
values.subarray(k, k + l).reverse();
values.subarray(k + l, k + n).reverse();
values.subarray(k, k + n).reverse();
}
return values;
}
Insert cell
Insert cell
function invert(d) {
const shared = {};

let p = {
type: "Polygon",
coordinates: d3.merge(d.coordinates.map(polygon => {
return polygon.map(ring => {
return ring.map(point => {
return [point[0] / n * 360 - 180, 90 - point[1] / m * 180];
}).reverse();
});
}))
};

// Record the y-intersections with the antimeridian.
p.coordinates.forEach(ring => {
ring.forEach(p => {
if (p[0] === -180) shared[p[1]] |= 1;
else if (p[0] === 180) shared[p[1]] |= 2;
});
});

// Offset any unshared antimeridian points to prevent their stitching.
p.coordinates.forEach(ring => {
ring.forEach(p => {
if ((p[0] === -180 || p[0] === 180) && shared[p[1]] !== 3) {
p[0] = p[0] === -180 ? -179.9995 : 179.9995;
}
});
});

p = d3.geoStitch(p);

// If the MultiPolygon is empty, treat it as the Sphere.
return p.coordinates.length
? {type: "Polygon", coordinates: p.coordinates}
: {type: "Sphere"};
}
Insert cell
tiff = FileAttachment("sfctmp.tiff").arrayBuffer()
.then(buffer => GeoTIFF.fromArrayBuffer(buffer))
Insert cell
GeoTIFF = require("geotiff@2.0.7")
Insert cell
d3 = require("d3@7", "d3-geo-projection@4")
Insert cell
Insert cell
Plot.plot({
projection: "equal-earth",
color: { scheme: "Magma" },
marks: [Plot.contour(values, {
x: (_, i) => i % n / 2 - 180,
y: (_, i) => 90 - Math.floor(i / n) / 2,
fill: values,
thresholds: 10,
stroke: "#000",
strokeWidth: 0.5,
clip: "sphere"
})]
})
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