Create a gist now

Instantly share code, notes, and snippets.

@hugolpz /README.md forked from mbostock/.block
Last active Aug 29, 2015

Topography via D3js image processing

Proof of concept of grayscale image recolored directly via D3js color scale. Wikimaps colors used.

Source: The source image is a global heightmap from the Shuttle Radar Topography Mission, released as part of NASA’s Blue Marble collection at 8km resolution. The topography data is stored in a simple 130KB black&white, 8-bit PNG. In it, darker values represent lower elevations (sea floor), lighter values represent higher elevations (mountains).

Colors are read out of the image using the Canvas API.

Data properties:

Formerly, Mike Bostock used the 5th, 50th and 95th percentiles for land elevation as 15, 35 and 132 respectively; quantiles being an effective way to maximize contrast while remapping colors, similar to auto-tone features popular in image editors.

The percentiles are used as the domain of a diverging linear scale; red values are below the median elevation, and blue values are above. Interpolating in HCL colorspace improves perception.

Stylesheet: this dataviz follow the Wikipedia Maps Conventions for Topographic maps.

var color = d3.scale.linear()
   .domain([0,14,15,40,100,200])
   .range([
        "#71ABD8", //-10000m dark blue
        "#D8F2FE", //     0m light-blue
        "#94BF8B", //     1m green
        "#EFEBC0", //   300m yellow
        "#AA8753", //  3000m brown
        "#FFFFFF"]) //~6000m white
   .interpolate(d3.interpolateHcl);

Binary images can store lots of data efficiently. Also, see Mike Bostock's :

Note: Semantically, traditional rainbow color scale are to avoid since rainbow color scales are harmful. To do better, let's use perceptually-optimized scales.

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="../js/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500;
var color = d3.scale.linear()
.domain([0,14,15,40,100,200])
.range(["#71ABD8", "#D8F2FE", "#94BF8B", "#EFEBC0", "#AA8753", "#FFFFFF"])
.interpolate(d3.interpolateHcl);
var canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height);
var context = canvas.node().getContext("2d");
getImage("readme.png", function(image) {
context.drawImage(image, 0, 0, width, height);
image = context.getImageData(0, 0, width, height);
// Rescale the colors.
for (var c, i = 0, n = width * height * 4, d = image.data; i < n; i += 4) {
c = d3.rgb(color(d[i]));
d[i + 0] = c.r;
d[i + 1] = c.g;
d[i + 2] = c.b;
}
context.putImageData(image, 0, 0);
});
function getImage(path, callback) {
var image = new Image;
image.onload = function() { callback(image); };
image.src = path;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment