rveciana - isobands-from-a-geotiff-with-d3

Isobands from a geotiff with d3

Open raw page in new tab

This example shows how to use the d3-marching-squares library.

The gist reads a GeoTIFF file, gets its data, calculates the zones for each interval and draws it on an html5 canvas element.

The data is an output of the GFS meteorological model (surface temperature), transformed using the grib api tools

The d3-marching-squares library is based on the MarchingSquares.js library.

The GeoTIFF file is read using the npm geotiff library

<!DOCTYPE html>
<meta charset="utf-8">

.states {
  fill: #ccc;
  stroke: #fff;
  <div id="map"></div>

<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script src="https://d3js.org/d3-format.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://d3js.org/d3-time.v1.min.js"></script>
<script src="https://d3js.org/d3-time-format.v2.min.js"></script>
<script src="https://d3js.org/d3-scale.v1.min.js"></script>

<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-geo.v1.min.js"></script>
<script src="https://d3js.org/d3-selection.v1.min.js"></script>
<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="https://d3js.org/d3-request.v1.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>

<script src="geotiff.js"></script>
<script src="https://npmcdn.com/d3-marching-squares@0.0.4"></script>

var width = 960,
    height = 500;

var canvas = d3.select("#map").append("canvas")
        .attr("width", width)
        .attr("height", height);
var context = canvas.node().getContext("2d");

var projection = d3.geoEquirectangular();
var path = d3.geoPath()

  .get(function(error, tiffData){

d3.json("world-110m.json", function(error, topojsonData) {
    var tiff = GeoTIFF.parse(tiffData.response);
    var image = tiff.getImage(); 
    var rasters = image.readRasters();
    var data = new Array(image.getHeight());
    for (var j = 0; j<image.getHeight(); j++){ 
        data[j] = new Array(image.getWidth());
        for (var i = 0; i<image.getWidth(); i++){
            data[j][i] = rasters[0][i + j*image.getWidth()];

    var maxVal = 70.0;
    var minVal = -75.0;

    var intervals = d3.range(minVal, maxVal+(maxVal-minVal)/20, (maxVal-minVal)/20);
    var colors = d3.ticks(0, 1, intervals.length).map(function(d){return d3.interpolatePlasma(d);});
    geoTransform = [0, 0.500695, 0, 90, 0, -0.5]; //x-interval corrected to match borders

    var bands = d3marchingsquares.isobands(data, geoTransform, intervals);

    bands.features.forEach(function(d, i) {
      context.fillStyle = colors[i];

    var countries = topojson.feature(topojsonData, topojsonData.objects.countries);

    context.strokeStyle = "#000";