Skip to main content

Creating contour lines with GDAL and Mapnik

Credits: Wikipedia
So far we’ve used our Digital Elevation Model (DEM) to create hillshade and color relief. Contours is another common cartographic method used to show the shape of the terrain. If contour lines are placed close to each other, it means that the terrain is steep. Let’s add some contours for our terrain map of Jotunheimen.

We can use a GDAL command, gdal_contour, to create vector contour lines from a DEM:

gdal_contour -a height jotunheimen.tif jotunheimen_contour_25m.shp -i 25.0

The resulting shapefile has an attribute named “height” (-a) containing the elevation of each contour line. The contour interval, the difference in elevation between successive contour lines, is 25 meters (-i).

Let's render the contour lines with Mapnik (jotunheimen_contours.xml):


We can use Nik2Img to create an image from the Mapnik XML file:

nik2img.py jotunheimen_contours.xml jotunheimen_contours.png -d 4096 4096 --projected-extent 460000 6810000 470000 6820000

Contour lines for Besseggen mountain ridge

I want to render the contour lines differently for various zoom levels. The contours should be more visible at higher zoom levels, and we should add numbers showing the actual elevation for some of the contours. I also want to make the contour lines for every 100 meters thicker. To achieve this we need to know the map scale at different zoom levels. In the last blog post, we calculated the resolution (meters per pixel) for each zoom level. You get the map scale by dividing this number by 0.00028 (234.375 / 0.00028 = 837053.571).

Zoom
Resolution
Scale
0
234.375
837054
1
117.1875
418527
2
58.59375
209263
3
29.296875
104632
4
14.6484375
52316

For zoom level 4, the map scale is about 1:50,000. Read more about map scale on this excellent Mapnik page

Let’s create a style rule that will display the elevation on a contour line on zoom level 3:

If you look at the table above, the only scale number between the max and min scale denominator is 104632, which corresponds to zoom level 3. jotunheimen_contours2.xml includes all the style rules to render the contour lines differently for five zoom levels. You’ll also see that I’ve created contour shapefiles with contour intervals of 25, 100, 200 and 500 meters, - to be able to render these differently.

Finally, I've used TileCache to render transparent tiles with contours, and added them as a separate layer to Leaflet map:


Fullscreen map

Comments

Lars Johansson said…
Very nice tutorial Bjørn!
I am trying adding labels based on the datasets form kartverket, "Stedsnavn SSR, WGS84, geoJSON".
Trying a shapefle conversion using
ogr2ogr -skipfailures -f "ESRI Shapefile" shapefiles/myshape.shp kildefiler/kartverket/stedsnavn.geojson -s_srs EPSG:4326 -t_srs EPSG:32633
but obviously there is some projection errors (my guess) as the layers won't align.

Considering an example perhaps? :)
Unknown said…
Thank you for the tutorial Bjørn!
Two questions; Does creating 5m contour lines from 30m (SRTMGL1) data give you any extra precision?
Have you ever tried to, or know a way to create a path over contour lines which would be the easiest/safest to walk? ie software or algorithm that picks a line down a hill, descending at the lowest rate.

Popular posts from this blog

Creating a WebGL Earth with three.js

This blog post will show you how to create a WebGL Earth with three.js , a great JavaScript library which helps you to go 3D in the browser. I was surprised how easy it seemed when reading a blog post  by Jerome Etienne . So I decided to give it a try using earth textures  from one of my favourite cartographers, Tom Patterson . WebGL is a JavaScript API for rendering interactive 3D graphics in modern web browsers without the use of plug-ins. Three.js is built on top of WebGL, and allows you to create complex 3D scenes with a few lines of JavaScript. If your browser supports WebGL you should see a rotating Earth below: [ Fullscreen ] To be able to display something with three.js, you need three things: a scene, a camera and a renderer. var width  = window.innerWidth,     height = window.innerHeight; var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 1000); camera.position.z = 1.5; var rende...

Terrain building with three.js

In my last blog post , we converted a digital elevation model (DEM) to a WebGL-friendly format ( i.e. easy to transfer and parse by JavaScript in the browser). In this blog post, we'll use the elevation data to build a terrain mesh with three.js .  First we need to transfer the terrain data to the browser. The elevation values are stored in a binary file as 16-bit unsigned integers. This page explains how you can send and receive binary data using JavaScript typed arrays. I've created a TerrainLoader by adapting the  XHRLoader . You can also use this function: function loadTerrain(file, callback) {   var xhr = new XMLHttpRequest();   xhr.responseType = 'arraybuffer';   xhr.open('GET', file, true);   xhr.onload = function(evt) {         if (xhr.response) {       callback(new Uint16Array(xhr.response));     }   };     xhr.send(null); } Loading elevation data with the Terrai...

Thematic Mapping Engine

It's time to introduce the Thematic Mapping Engine (TME). In my previous blog posts, I've shown various techniques of how geobrowsers can be used for thematic mapping. The goal has been to explore the possibilites and to make these techniques available to a wider audience. The Tematic Mapping Engine provides an easy-to-use web interface where you can create visually appealing maps on-the-fly. So far only prism maps are supported, but other thematic mapping techniques will be added in the upcoming weeks. The engine returns a KMZ file that you can open in Google Earth or download to your computer. My primary data source is UNdata . The above visualisation is generated by TME ( download KMZ ) and shows child mortaility in the world ( UNdata ). The Thematic Mapping Engine is also an example of what you can achieve with open source tools and datasets in the public domain: A world border dataset is loaded into a MySQL database . The same database contains tables with statistics ...