Published
Edited
Mar 11, 2021
1 fork
24 stars
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const context = DOM.context2d(width, height),
path = d3
.geoPath(projection)
.context(context);

yield context.canvas;

while (animate) {
const rotate = projection.rotate();
rotate[0] += 0.3;
projection.rotate(rotate);
render(context, path);
yield context.canvas;
}

const sel = d3.select(context.canvas).style("cursor", "grab");
d3.geoInertiaDrag(sel, () => render(context, path), projection);
invalidation.then(() => sel.on(".drag", null));

render(context, path);
}
Insert cell
function render(context, path) {
// dark blue sphere
context.fillStyle = "#000";
context.fillRect(0, 0, width, height);

context.beginPath();
path({ type: "Sphere" });
context.fillStyle = "#003";
context.fill();

const clipAngle = projection.clipAngle();
context.globalAlpha = 0.3;
projection.clipAngle(180);
draw(context, path.pointRadius(0.7));

// front globe
context.globalAlpha = 1;
projection.clipAngle(clipAngle);
draw(context, path.pointRadius(1.5));
}
Insert cell
function draw(context, path) {
for (const [value, points] of groups) {
context.beginPath();
path({
type: "MultiPoint",
coordinates: points.map(p => [p.lon, p.lat])
});
context.fillStyle = value === "NA" ? "#666" : color(value);
context.fill();
}
}
Insert cell
Insert cell
Insert cell
mapped = {
var m = d3.range(-90,91).map(x => d3.range(-180,181).map(y => undefined));
for (var datum of data){m[90+(+datum.lat)][180+(+datum.lon)] = datum.change}
return m;
}
Insert cell
// See https://www.dynamicmath.xyz/sketches/sunflowerSphere/
function sphericalPhyllotaxis(n) {
const g = 1.61803398875;
const degrees = 180 / Math.PI;
return Array.from({ length: n }, (_, i) => {
const z = 1 - (2 * i + 1) / n;
const a = Math.PI * 2 * g * i;
const b = Math.sin(Math.acos(1 - (2 * i + 1) / n));
const x = Math.cos(a) * b;
const y = Math.sin(a) * b;
return [Math.atan2(y, x) * degrees, Math.asin(z) * degrees];
});
}
Insert cell
phyllo = sphericalPhyllotaxis(nPoints)
.map(([lon, lat]) => ({ lon, lat, change: mapped[Math.round(lat)+90][Math.round(lon)+180]}))
.filter(({change}) => change !== undefined)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
height = Math.min(550, width)
Insert cell
d3 = require("d3@6", "d3-inertia@0.2", "d3-geo-projection@2")
Insert cell
import { Toggle, Range } from "@observablehq/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