Skip to content

Instantly share code, notes, and snippets.

Last active February 7, 2017 08:30
Show Gist options
  • Save phil-pedruco/9999984 to your computer and use it in GitHub Desktop.
Save phil-pedruco/9999984 to your computer and use it in GitHub Desktop.
Contours of Nepal using topojson and d3.js

This is an answer to this Stackoverflow question which asks how to render topographic contour lines. The second part of the question looks into animating parts of the visualisation which isn't covered here.

To demonstrate this a visualisation of topographic contours of Nepal (and Tibet) was created. The visualisation here is based on ETOPO1 1 minute resolution dataset from the NOAA National Geophysical Data Centre. It was downloaded as an ArcGIS ASCII grid and processed in QGIS where the resulting DEM was contoured into 500m contours.

The resulting contours were then converted to topojson using the command line version. This was necessary to preserve the properties of the topojson as I wanted to colour code the contours based on elevation. On-line topojson tools typically don't allow this as the default in topojson to to remove properties.

The contours are then rendered using the typical pattern for geo-objects. The stroke property for the paths set based on the elevation property using the interpolateLab function.

Well, there is a little bit of interaction when you mouse over a contour just to give a bit of a demo of what's possible.

<!DOCTYPE html>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Nepal Topographic Contours</title>
<script type="text/javascript" src=""></script>
<script type="text/javascript" src=""></script>
<script type="text/javascript">
var h = 500,
w = 960;
// set-up unit projection and path
var projection = d3.geo.mercator()
.translate([0, 0]);
var path = d3.geo.path()
// set-up svg canvas
var svg ="body").append("svg")
.attr("height", h)
.attr("width", w);
// set-up scale for colour coding contours
var cScale = d3.scale.linear()
.domain([0, 1]);
// read in topojson of Nepal
d3.json("z_contours_500_clipped.json", function(error, nepal) {
// first variable is used to centre and scale map to viewport
// could have used the bbox feature (see
var bTopo = topojson.feature(nepal, nepal.objects.contours_500_clipped),
topo = bTopo.features;
// calculate range for colours based on ELVE property
// Note when converting to topojon the default is to REMOVE all properties
// from the input file, you need to use the -p switch.
var hRange = d3.extent(topo, function(d, i) {
// calculate bounds, scale and transform
// see
var b = path.bounds(bTopo),
s = .95 / Math.max((b[1][0] - b[0][0]) / w, (b[1][1] - b[0][1]) / h),
t = [(w - s * (b[1][0] + b[0][0])) / 2, (h - s * (b[1][1] + b[0][1])) / 2];
.style("fill", "none")
.style("stroke", function(d, i) {
return interp(cScale(;
.attr("d", path)
.on("mouseover", highlight) // just a little example of what's available in terms of interaction
.on("mouseout", function (d,i) {unhighlight(this,d);
// function to interpolate between to colours
// see
function interp(x) {
var ans = d3.interpolateLab("#ffffe5", "#004529")(x);
return ans
// A simple highlight example
function highlight(x) {
var s =;"stroke", "red");
function unhighlight(x,y) {
var old =;
var u =;"stroke", function(d, i) {
return interp(cScale(old));
Display the source blob
Display the rendered blob
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment