Published
Edited
May 6, 2020
Importers
18 stars
Insert cell
Insert cell
Insert cell
Insert cell
// Definition of d3.geoModifiedStereographicGs50
// as in d3-geo-projection
// The polynomial is written as a list of complex numbers [re, im]
projection = d3
.geoProjection(
d3.geoModifiedStereographicRaw([
[0.984299, 0], // a X [ general scale (+ rotate) ]
[0.0211642, 0.0037608], // b X^2 [ right-left ; bottom-top ]
[-0.1036018, -0.0575102], // c X^3
[-0.0329095, -0.0320119], // d X^4
[0.0499471, 0.1223335], // …
[0.026046, 0.0899805],
[0.0007388, -0.1435792],
[0.0075848, -0.1334108],
[-0.0216473, 0.0776645],
[-0.0225161, 0.0853673]
])
)
.rotate([120, -45])
.clipAngle(55)
.scale(490)
.translate([width / 2, height * 0.55])
.precision(0.1)

// added to make sure the graticule does not fold on itself around the singularities
.preclip(
d3.geoClipPolygon({
type: "Polygon",
coordinates: [
outline.coordinates[0].map(d3.geoRotation([120, -45, 0.0001]))
]
})
)
Insert cell
// Outline from https://www.jasondavies.com/maps/modified-stereographic/gs50/
outline = {
return {
type: "Polygon",
coordinates: [
[[-180, 30]]
.concat(parallel(75, -180, -60))
.concat([
[-60, 70],
[-50, 70],
[-50, 40],
[-60, 40],
[-60, 30],
[-65, 30]
])
.concat(parallel(15, -65, -165))
.concat([[-165, 30], [-180, 30]])
]
};

function parallel(y, x0, x1) {
var dx = x0 < x1 ? 5 : -5;
return d3.range(x0, x1 + dx / 2, dx).map(function(x) {
return [x, y];
});
}
}
Insert cell
Insert cell
/*
* other projections to try:
*

d3.geoModifiedStereographicAlaska()
d3.geoModifiedStereographicGs48()

d3.geoModifiedStereographicGs50().preclip(
d3.geoClipPolygon({
type: "Polygon",
coordinates: [outlineGs50.map(d3.geoRotation([120, -45, 0.0001]))]
})
) ||

d3.geoModifiedStereographicLee()

d3.geoModifiedStereographicMiller()
*/
Insert cell
color = {
const div = d3
.scaleDiverging()
.domain([-0.5, 0, 0.5])
.interpolator(d3.interpolateBrBG);

return function(e) {
if (Math.abs(e) < 0.005) return div(0); //"white";
e += Math.sign(e) * 0.05;
// if (Math.abs(e) < 0.02) return div(Math.sign(e) * 0.1);
return div(0.05 * ((e * 20) | 0));
};
}
Insert cell
// area of the projection of a circle of radius epsilon; as the projection is conformal
// we need just one direction (North) to evaluate the distortion; no need for Tissot ellipse!
function area(p) {
const eps = 1e-6;
const p0 = projection(p),
// p1 = projection([p[0] + eps / Math.cos(p[1] * radians), p[1]]),
p2 = projection([p[0], p[1] + eps]),
// a = [p1[0] - p0[0], p1[1] - p0[1]],
b = [p2[0] - p0[0], p2[1] - p0[1]];
return b[0]**2+b[1]**2 //a[1] * b[0] - a[0] * b[1];
}
Insert cell
world = d3.json(
"https://unpkg.com/visionscarto-world-atlas@0.0.6/world/110m_countries.geojson"
)
Insert cell
d3 = require("d3@5", "d3-geo-projection@2", "d3-geo-polygon@1")
Insert cell
height = (width * 0.7) | 0
Insert cell
width = 975
Insert cell
import {radians} from "@fil/math"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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