Turf.js for Inverse distance weighted interpolation (IDW) of Potsdam´s base rents. Web mapping playground part IV

Introduction

In this blog post I’ll show how an inverse distance weighted interpolator (IDW) can be applied with Turf.js. My blog post can serve as a tutorial for you, to try yourself  to interpolate own data sets with Turf.js  (e.g. temperature data).

The example uses a set of geocoded rental data of 3-room, apartments located in the city of Potsdam (fetched on the 19th of March).

From an analytical viewpoint, the resulting map isn’t that useful and just shows a spatial trend of the rental offers rental costs in € without service costs. Absolute prices had to be interpolated, as the apartment sizes in the fetched data were missing.

IDW actually is one of the least applicable spatial interpolators for rental data, due to known effects as bull eyes;  but Turf.js´s client side processing is in heavy development and for sure other interpolation algorithms will be integrated soon. So far Turf.js is capable to interpolate isolines, plane points, triangulated irregular networks and IDW. If you are interested how IDW works, I can recommend the interpolation tutorial on Gitta Info: http://www.gitta.info/ContiSpatVar/de/html/Interpolatio_learningObject2.xhtml

The map

Click on the map to get a price estimation per grid cell.

A full screen map can be accessed via:

http://hatschit.alkaid.uberspace.de/IDW_TURF_Choropletes/Potsdam_example.html

Turf.js IDW example

The resulting map is styled as choropleth map, using the leaflet.js choroplet plugin. The example geoprocesses the GeoJson data with the turf.js´s IDW plugin by Michele Ferreti. His turf-inverse-distance-weighting module was accepted as part of the turf.js library. He also hosts an example of a Leaflet.js, Turf.js IDW vizualisation, which served as basis for my tutorial.

Relevant code blocks

In the body of the document, several JavaScript libraries have to be integrated. That’s first leaflet.js for the map canvas and the functions of the slippy map, second turf.js,for the interpolation and choropleth.js, that styles the resulting map as choropleth map and creates the map legend.

 <script src="leaflet/leaflet.js"></script>
  <script src="choropleth.js"></script>
  <script src='https://npmcdn.com/@turf/turf@3.13.2/turf.min.js'></script>

After setting the parameters for the leaflet.js map canvas and after integrating the TileMapService for the base map,
the GeoJson file with the points for the interpolation has to be integrated to the script. Unlikely external referencing
via Ajax can’t pass the points to the interpolator. Therefore, the script soon can get quite long, which can be confusing.

<script>// <![CDATA[
var map = L.map('map').setView([52.39, 13.06], 12)
 
    // Add basemap
    L.tileLayer('http://{s}.tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
    }).addTo(map)
 
    // Add Sampled Point with known 'value'
    var sampledPoints = {
      "type": "FeatureCollection",
      "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
      "features": [
      { "type": "Feature", "properties": { "field_1": 3, "latitude": 52.395768, "longitude": 13.065812, "price_high": 1480.0, "room_numbe": "3" }, "geometry": { "type": "Point", "coordinates": [ 13.065812, 52.395768 ] } },
      { "type": "Feature", "properties": { "field_1": 5, "latitude": 52.42388, "longitude": 13.057468, "price_high": 1145.0, "room_numbe": "3" }, "geometry": { "type": "Point", "coordinates": [ 13.057468, 52.42388 ] } },

In the next section, the actual interpolation is realized by the turf.idw function. The attribute of the GeoJson to be interpolated, the power of the interpolation, the cell size of the resulting grid and the measurement units have to be defined.

 
var Grid = turf.idw(sampledPoints,'price_high', 0.3, 0.5,'kilometers');
 
    L.geoJson(sampledPoints.features, {
      onEachFeature: function(feature, layer) {
        layer.bindPopup("Estimated base rent for a three room apartment " + feature.properties.value)
      }
    })

Finally, the settings of the choropleth map have to be defined. The legend automatically is created from the interpolated values. As in my last example, the legend has to be improved.

var legend = L.control({
      position: 'bottomright'
    })
    legend.onAdd = function(map) {
      var div = L.DomUtil.create('div', 'info legend')
      var limits = choroplethLayer.options.limits
      var colors = choroplethLayer.options.colors
      var labels = []
      // Add min & max
      div.innerHTML = '<div class="labels"><div class="min">' + limits[0] + '</div> \
			<div class="max">' + limits[limits.length - 1] + '</div></div>'
      limits.forEach(function(limit, index) {
        labels.push('<li style="background-color: ' + colors[index] + '"></li>')
      })
      div.innerHTML += '<ul>' + labels.join('') + '</ul>'
      return div
    }
    legend.addTo(map)

To try IDW with turf.js with own data, the script and the data packed to a zip file can be downloaded here:
hatschit.alkaid.uberspace.de/IDW_TURF_Choropletes.zip

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.