Skip to content

Commit

Permalink
Merge pull request Turfjs#366 from miccferr/master
Browse files Browse the repository at this point in the history
Add turf IDW package - issue Turfjs#329
  • Loading branch information
Morgan Herlocker authored Aug 2, 2016
2 parents 309a215 + 4ee06a4 commit fd3f441
Show file tree
Hide file tree
Showing 9 changed files with 19,088 additions and 0 deletions.
60 changes: 60 additions & 0 deletions packages/turf-idw/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Inverse Distance Weighting (I.D.W.)

Inverse Distance Weighting (IDW) is a type of deterministic, nonlinear interpolation method over a set of points.

### `IDW(controlPoints, valueField, b, cellWidth, units)`

Takes a [FeatureCollection](http://geojson.org/geojson-spec.html#feature-collection-objects)<[Point](http://geojson.org/geojson-spec.html#point)> of sampled points with a property of *known value* and returns a [FeatureCollection](http://geojson.org/geojson-spec.html#feature-collection-objects)<[Polygon](http://geojson.org/geojson-spec.html#polygon)> [grid](http://turfjs.org/docs/#squaregrid) with an *interpolated value* for each grid cell, according to a distance-decay exponent and a cell depth parameter (in the specified unit of measurement).

It is based on the [Inverse Distance Weighting](https://en.wikipedia.org/wiki/Inverse_distance_weighting) interpolation algorithm as covered in the following resources: [1], [2].

It finds application when in need of creating a continuous surface (i.e. rainfall, temperature, chemical dispersion surface...) from a set of spatially scattered points.




### Parameters

| parameter | type | description |
| ----------- | -------------- | ---------------------------------------- |
| `controlPoints` | **[FeatureCollection](http://geojson.org/geojson-spec.html#feature-collection-objects)<[Point](http://geojson.org/geojson-spec.html#point)>** | Sampled points with known value |
| `valueField` | **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** | GeoJSON field containing the known value to interpolate on |
| `b` | **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** | Exponent regulating the distance-decay weighting |
| `cellWidth` |**[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** | Width of each cell |
| `units` |**[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** | Units to use for cellWidth ('miles' or 'kilometers')|

### Example

```js
// load IDW
var IDW = require('./index.js')

// load a sample of test points
var fs = require('fs');
var controlPoints = JSON.parse(fs.readFileSync('./data/data.geojson'));

// produce an interpolated surface
var IDWSurface = IDW(controlPoints,'value', 0.5, 0.1,'kilometers');

```
Returns a **[FeatureCollection](http://geojson.org/geojson-spec.html#feature-collection-objects)<[Polygon](http://geojson.org/geojson-spec.html#polygon)>** grid of polygons with a property field `IDW`


## Installation & Use

Requires [nodejs](http://nodejs.org/).

`Git clone` this repo, then `require` it

## Tests

```sh
$ npm test
```

## Resources
[1] _O’Sullivan, D., & Unwin, D. (2010). Geographic Information Analysis (2nd Edition). 432pp. Hoboken, New Jersey (USA): John Wiley & Sons, Inc._

[2] _Xiao, N. (2016). GIS Algorithms, 336pp. SAGE Publications Ltd._


90 changes: 90 additions & 0 deletions packages/turf-idw/data/data.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"marker-color": "#7e7e7e",
"marker-size": "medium",
"marker-symbol": "",
"value": 4,
"id": 4
},
"geometry": {
"type": "Point",
"coordinates": [
9.155731201171875,
45.47216977418841
]
}
},
{
"type": "Feature",
"properties": {
"marker-color": "#7e7e7e",
"marker-size": "medium",
"marker-symbol": "",
"value": 99,
"id": 2
},
"geometry": {
"type": "Point",
"coordinates": [
9.195213317871094,
45.53689620055365
]
}
},
{
"type": "Feature",
"properties": {
"marker-color": "#7e7e7e",
"marker-size": "medium",
"marker-symbol": "",
"value": 10,
"id": 1
},
"geometry": {
"type": "Point",
"coordinates": [
9.175300598144531,
45.49912810913339
]
}
},
{
"type": "Feature",
"properties": {
"marker-color": "#7e7e7e",
"marker-size": "medium",
"marker-symbol": "",
"value": 6,
"id": 3
},
"geometry": {
"type": "Point",
"coordinates": [
9.231605529785156,
45.49190839157102
]
}
},
{
"type": "Feature",
"properties": {
"marker-color": "#7e7e7e",
"marker-size": "medium",
"marker-symbol": "",
"value": 7,
"id": 5
},
"geometry": {
"type": "Point",
"coordinates": [
9.116249084472656,
45.4391764115696
]
}
}
]
}
1 change: 1 addition & 0 deletions packages/turf-idw/data/data.geojson.prj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
56 changes: 56 additions & 0 deletions packages/turf-idw/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
var filter = require('turf-filter');
var distance = require('turf-distance');
var squareGrid = require('turf-square-grid');
var centroid = require('turf-centroid');
var extent = require('turf-extent');

/**
*
* Takes a FeatureCollection of points with known value, a power parameter, a cell depth, a unit of measurement
* and returns a FeatureCollection of polygons in a square-grid with an interpolated value property "IDW" for each grid cell.
* It finds application when in need of creating a continuous surface (i.e. rainfall, temperature, chemical dispersion surface...)
* from a set of spatially scattered points.
*
* @param {FeatureCollection<Point>} controlPoints Sampled points with known value
* @param {String} valueField GeoJSON field containing the known value to interpolate on
* @param {Number} b Exponent regulating the distance-decay weighting
* @param {Number} cellWidth The distance across each cell
* @param {String} units Units to use for cellWidth ('miles' or 'kilometers')
* @return {FeatureCollection<Polygon>} grid A grid of polygons with a property field "IDW"
*/
module.exports = function (controlPoints, valueField, b, cellWidth, units) {
// check if field containing data exists..
var filtered = filter(controlPoints, valueField);
//alternative method
// console.log(controlPoints.features.map(function (feat) { return valueField in feat.properties}));
if (filtered.features.length === 0) {
// create a sample square grid
// compared to a point grid helps visualizing the output (like a raster..)
var samplingGrid = squareGrid(extent(controlPoints), cellWidth, units);
var N = samplingGrid.features.length;
// for every sampling point..
var myFun = function (point, i, zw, sw) {
var d = distance(centroid(samplingGrid.features[i]), point, units);
if (d === 0) {
zw = point.properties[valueField];
return zw;
}
var w = 1.0 / Math.pow(d, b);
sw += w;
zw += w * point.properties[valueField];
};
for (var i = 0; i < N; i++) {
var zw = 0;
var sw = 0;
// calculate the distance from each control point to cell's centroid
controlPoints.features.map(myFun);
// write IDW value for each grid cell
samplingGrid.features[i].properties.z = zw / sw;
}
return samplingGrid;

} else {
console.log('Specified Data Field is Missing');
}

};
32 changes: 32 additions & 0 deletions packages/turf-idw/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "idw-js",
"version": "1.0.0",
"description": "Today a plain IDW alg. implemented in JS. Tomorrow a Turf.js package? Maybe?",
"main": "index.js",
"directories": {
"test": "tests"
},
"dependencies": {
"turf-centroid": "^1.1.3",
"turf-distance": "^1.1.0",
"turf-extent": "^1.0.4",
"turf-filter": "^1.0.1",
"turf-square-grid": "^1.0.1"
},
"devDependencies": {
"tape": "^4.5.1"
},
"scripts": {
"test": "node test.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/miccferr/idw-js.git"
},
"author": "Michele Ferretti",
"license": "MIT",
"bugs": {
"url": "https://github.com/miccferr/idw-js/issues"
},
"homepage": "https://github.com/miccferr/idw-js#readme"
}
24 changes: 24 additions & 0 deletions packages/turf-idw/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
var test = require('tape');
var idw = require('./');
var fs = require('fs');

test('idw', function (t) {
var testPoints = JSON.parse(fs.readFileSync('./data/data.geojson'));

var idw1 = idw(testPoints,'value' , 0.5 , 1, 'kilometers');
var idw2 = idw(testPoints,'value', 0.5 ,0.5, 'kilometers');
var idw3 = idw(testPoints,'value', 2 , 1, 'miles');
var idw4 = idw(testPoints, 'WRONGDataField', 0.5, 1, 'miles');

t.ok(idw1.features.length);
t.ok(idw2.features.length);
t.ok(idw3.features.length);
t.error(idw4);

fs.writeFileSync(__dirname+'/tests/idw1.geojson', JSON.stringify(idw1,null,2));
fs.writeFileSync(__dirname+'/tests/idw2.geojson', JSON.stringify(idw2,null,2));
fs.writeFileSync(__dirname+'/tests/idw3.geojson', JSON.stringify(idw3,null,2));


t.end();
});
Loading

0 comments on commit fd3f441

Please sign in to comment.