Public
Edited
May 30, 2023
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
focusPoint = [133.15399233370441, -24.656909465155994]
Insert cell
invertLongLat = (longlat) => {
return [-longlat[0], -longlat[1]];
}
Insert cell
projection = d3
.geoEquirectangular()
.precision(0.1)
.rotate(invertLongLat(focusPoint))
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 = (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("out.tiff").arrayBuffer()
.then(buffer => GeoTIFF.fromArrayBuffer(buffer))
Insert cell
GeoTIFF = require("geotiff@1.0.0-beta.13")
Insert cell
d3 = require("d3@6", "d3-geo-projection@3")
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