Published
Edited
Aug 31, 2022
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
path = d3.geoPath(magnifiedAzimuthal)
Insert cell
Insert cell
centerpoint = [-120.61108655801085, -23.685162485477473, 0]
Insert cell
Insert cell
Insert cell
Insert cell
magnifiedAzimuthalEquidistant = function () {
return magnifiedAzimuthalMutator(magnifiedAzimuthalEquidistantRaw);
}
Insert cell
magnifiedAzimuthalEqualArea = function () {
return magnifiedAzimuthalMutator(magnifiedAzimuthalEqualAreaRaw);
}
Insert cell
function taperedAzimuthalEquidistant() {
return magnifiedAzimuthalMutator(taperedAzimuthalEquidistantRaw);
}
Insert cell
function taperedAzimuthalEqualArea() {
return magnifiedAzimuthalMutator(taperedAzimuthalEqualAreaRaw);
}
Insert cell
function taperedStereographic() {
return magnifiedAzimuthalMutator(taperedStereographicRaw);
}
Insert cell
function taperedGnomic() {
return magnifiedAzimuthalMutator(taperedGnomicRaw);
}
Insert cell
function magnifiedAzimuthalEquidistantRaw(b1, b2, n) {
const g = b1 * (1 - n) / (n * (b2 - b1)),
q = b1 * (1 - g);
function pSinZ(z) {
return z <= b1
? z / Math.sin(z)
: (q + g * z) / Math.sin(z);
}
return magnifiedAzimuthalFactory(pSinZ);
}
Insert cell
function magnifiedAzimuthalEqualAreaRaw(b1, b2, n) {
const g = (1 - n * n) * (1 - Math.cos(b1)) / (n * n * (Math.cos(b1) - Math.cos(b2))),
q = 1 - (1 - g) * Math.cos(b1);
function pSinZ(z) {
return z <= b1
? Math.SQRT2 * Math.sqrt(1 - Math.cos(z)) / Math.sin(z)
: Math.SQRT2 * Math.sqrt(q - g * Math.cos(z)) / Math.sin(z);
}
return magnifiedAzimuthalFactory(pSinZ);
}
Insert cell
function taperedAzimuthalEquidistantRaw(b1, b2, n) {
const dB = b2 - b1,
n0 = b1 / b2;
if (n >= 1) n = 1 - 0.0001;
if (n <= n0) n = n0 + 0.0001;
const g = dB / (b2 - b1 / n);
function pSinZ(z) {
return z <= b1
? z / Math.sin(z)
: (z - dB * Math.pow((z - b1) / dB, g) / g) / Math.sin(z);
}
return magnifiedAzimuthalFactory(pSinZ);
}
Insert cell
function taperedAzimuthalEqualAreaRaw(b1, b2, n) {

const G = 2 * Math.tan(b1 / 2),
dB = b2 - b1,
n0 = G / (G + dB);
if (n >= 1) n = 1 - 0.0001;
if (n <= n0) n = n0 + 0.0001;
const g = dB / (dB + (1 - 1 / n) * G),
C = G + dB * (1 - 1 / g),
R = C * Math.cos(b1 / 2),
RC = R / C;
function pSinZ(z) {
return z <= b1
? 2 * Math.sin(z / 2) / Math.sin(z)
: RC * (G + z -b1 - dB * Math.pow((z - b1) / dB, g) / g) / Math.sin(z);
}
return magnifiedAzimuthalFactory(pSinZ);
}
Insert cell
function taperedStereographicRaw(b1, b2, n) {
const {sin, cos, acos, pow, tan} = Math;
const G = sin(b1),
dB = b2 - b1,
n0 = G / (G + dB);
if (n >= 1) n = 1 - 0.0001;
if (n <= n0) n = n0 + 0.0001;
const g = dB / (dB + (1 - 1 / n) * G),
C = G + dB * (1 - 1 / g),
R = C / (cos(b1 / 2) * cos(b1 / 2)),
RC = R / C;
function pSinZ(z) {
return pSinZ = z <= b1
? 2 * tan(z / 2) / sin(z)
: RC * (G + z -b1 - dB * pow((z - b1) / dB, g) / g) / sin(z);
}
return magnifiedAzimuthalFactory(pSinZ);
}
Insert cell
taperedGnomicRaw = (b1, b2, n) => {

const G = Math.sin(b1) * Math.cos(b1),
dB = b2 - b1,
n0 = G / (G + dB);
if (n >= 1) n = 1 - 0.0001;
if (n <= n0) n = n0 + 0.0001;
const g = dB / (dB + (1 - 1 / n) * G),
C = G + dB * (1 - 1 / g),
R = C / (Math.cos(b1) * Math.cos(b1)),
RC = R / C;
function pSinZ(z) {
return z <= b1
? Math.tan(z) / Math.sin(z)
: RC * (G + z -b1 - dB * Math.pow((z - b1) / dB, g) / g) / Math.sin(z);
}
return magnifiedAzimuthalFactory(pSinZ);
}
Insert cell
function magnifiedAzimuthalMutator(raw) {
const rad = Math.PI / 180,
deg = 180 / Math.PI,
epsilon = 1e-4;
let b1 = 30 * rad,
b2 = 120 * rad,
n = 0.5;
const mutate = d3.geoProjectionMutator(raw);
const projection = mutate(b1, b2, n);
projection.innerRadius = function(inner) {
if (!arguments.length) return b1 * deg;
b1 = Math.max(epsilon, Math.min(90 - epsilon, inner)) * rad;
if (b1 > b2) { let tmp = b1; b1 = b2, b2 = tmp; }
if (b1 === b2) b2 += epsilon;
mutate(b1, b2, n);
return projection.clipAngle(b2 * deg);
}
projection.outerRadius = function(outer) {
if (!arguments.length) return b1 * deg;
b2 = Math.max(epsilon, Math.min(180 - epsilon, outer)) * rad;
if (b1 > b2) { let tmp = b1; b1 = b2, b2 = tmp; }
if (b1 === b2) b2 += epsilon;
mutate(b1, b2, n);
return projection.clipAngle(b2 * deg);
}
projection.ratio = function(ratio) {
if (!arguments.length) return ratio;
n = Math.max(0, Math.min(1, ratio));
mutate(b1, b2, n);
return projection;
}
return projection.clipAngle(b2 * deg);
}
Insert cell
function magnifiedAzimuthalFactory(cb) {
let cosPhi, z, cosZ, pSinZ;
return function(lambda, phi) {
cosPhi = Math.cos(phi), cosZ = cosPhi * Math.cos(lambda), z = Math.acos(cosZ);
if (z === 0) return [0, 0];
if (z === Math.PI) return [Math.cos(lambda), Math.sin(phi)]; // I think
pSinZ = cb(z);
return [
pSinZ * cosPhi * Math.sin(lambda),
pSinZ * Math.sin(phi)
];
}
}
Insert cell
Insert cell
magnifiedAzimuthal = projections[projection]()
.innerRadius(inner)
.outerRadius(outer)
.ratio(ratio)
.rotate(centerpoint)
.translate([width / 2, height / 2])
.fitExtent(
[
[padding, padding],
[width - padding, height - padding]
],
sphere
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { world10m_wound } from "@lifewinning/comtrade-commodity-flow-sketches/2"
Insert cell
Insert cell
import { toc } from "@mbostock/toc"
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