Skip to content

Commit abf63e2

Browse files
committedOct 4, 2021
modernized sum
1 parent d0f3607 commit abf63e2

File tree

3 files changed

+200
-87
lines changed

3 files changed

+200
-87
lines changed
 

‎src/sum/index.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import sum from './sum.module';
1+
/**
2+
* @prettier
3+
*/
4+
import sum from "./sum.module";
25

36
/**
47
* The sum function takes a raster as an input and an optional geometry.
@@ -10,7 +13,7 @@ import sum from './sum.module';
1013
* @param {Object} geometry - geometry can be an [xmin, ymin, xmax, ymax] array for a bounding box, [[[x00,y00],...,[x0n,y0n],[x00,y00]]...] for a polygon, a GeoJSON polygon object, or a string representation of a GeoJSON polygon object.
1114
* @returns {Object} array of sums for each band
1215
* @example
13-
* const sums = geoblaze.sum(georaster, geometry);
16+
* const sums = await geoblaze.sum(georaster, geometry);
1417
*/
1518

1619
export default sum;

‎src/sum/sum.module.js

+33-34
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,39 @@
1-
import get from '../get';
2-
import utils from '../utils';
3-
import convertGeometry from '../convert-geometry';
4-
import intersectPolygon from '../intersect-polygon';
5-
6-
const sum = (georaster, geom, test, debug=false) => {
1+
/**
2+
* @prettier
3+
*/
4+
import get from "../get";
5+
import utils from "../utils";
6+
import wrap from "../wrap-func";
7+
import convertGeometry from "../convert-geometry";
8+
import intersectPolygon from "../intersect-polygon";
9+
10+
const sum = (georaster, geom, test, debug = false) => {
711
try {
8-
if (geom === null || geom === undefined) {
12+
const { noDataValue } = georaster;
913

10-
const { noDataValue } = georaster;
11-
return georaster.values.map(band => { // iterate over each band which include rows of pixels
12-
return band.reduce((sumOfBand, row) => { // reduce all the rows into one sum
13-
return sumOfBand + row.reduce((sumOfRow, cellValue) => { // reduce each row to a sum of its pixel values
14-
return cellValue !== noDataValue && (test === undefined || test(cellValue)) ? sumOfRow + cellValue : sumOfRow;
15-
}, 0);
14+
const calcSumByBand = bands => {
15+
return bands.map(band => {
16+
return band.reduce((sumOfBand, cellValue) => {
17+
return cellValue !== noDataValue && (test === undefined || test(cellValue)) ? sumOfBand + cellValue : sumOfBand;
1618
}, 0);
1719
});
18-
} else if (utils.isBbox(geom)) {
19-
geom = convertGeometry('bbox', geom);
20+
};
2021

21-
const values = get(georaster, geom);
22-
const { noDataValue } = georaster;
23-
24-
// sum values
25-
return values.map(band => { // iterate over each band which include rows of pixels
26-
return band.reduce((sumOfBand, row) => { // reduce all the rows into one sum
27-
return sumOfBand + row.reduce((sumOfRow, cellValue) => { // reduce each row to a sum of its pixel values
28-
return cellValue !== noDataValue && (test === undefined || test(cellValue)) ? sumOfRow + cellValue : sumOfRow;
29-
}, 0);
30-
}, 0);
31-
});
22+
const flat = true;
23+
if (geom === null || geom === undefined) {
24+
const values = get(georaster, undefined, flat);
25+
return utils.callAfterResolveArgs(calcSumByBand, values);
26+
} else if (utils.isBbox(geom)) {
27+
geom = convertGeometry("bbox", geom);
28+
const values = get(georaster, geom, flat);
29+
return utils.callAfterResolveArgs(calcSumByBand, values);
3230
} else if (utils.isPolygon(geom, debug)) {
33-
geom = convertGeometry('polygon', geom);
31+
geom = convertGeometry("polygon", geom);
3432
const sums = [];
3533

3634
// the third argument of intersectPolygon is a function which
3735
// is run on every value, we use it to increment the sum
38-
intersectPolygon(georaster, geom, (value, bandIndex) => {
36+
const done = intersectPolygon(georaster, geom, (value, bandIndex) => {
3937
if (test === undefined || test(value)) {
4038
if (sums[bandIndex]) {
4139
sums[bandIndex] += value;
@@ -45,16 +43,17 @@ const sum = (georaster, geom, test, debug=false) => {
4543
}
4644
});
4745

48-
if (sums.length > 0) return sums;
49-
else return [0];
50-
46+
return utils.callAfterResolveArgs(() => {
47+
if (sums.length > 0) return sums;
48+
else return [0];
49+
}, done);
5150
} else {
52-
throw 'Sum couldn\'t identify geometry';
51+
throw "[geoblaze] sum couldn't identify geometry";
5352
}
54-
} catch(e) {
53+
} catch (e) {
5554
console.error(e);
5655
throw e;
5756
}
5857
};
5958

60-
export default sum;
59+
export default wrap(sum);

‎src/sum/sum.test.js

+162-51
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,47 @@
1-
import utils from '../utils';
2-
import test from 'flug';
3-
import load from '../load';
4-
import sum from './sum.module';
5-
import { polygon as turfPolygon } from '@turf/helpers';
1+
/**
2+
* @prettier
3+
*/
4+
import test from "flug";
5+
import { serve } from "srvd";
6+
7+
import utils from "../utils";
8+
import load from "../load";
9+
import parse from "../parse";
10+
import sum from "./sum.module";
11+
import { polygon as turfPolygon } from "@turf/helpers";
612

713
const { fetchJson, fetchJsons } = utils;
814

9-
const urlRwanda = 'http://localhost:3000/data/RWA_MNH_ANC.tif';
10-
const bboxRwanda = require('../../data/RwandaBufferedBoundingBox.json');
15+
if (require.main === module) serve({ debug: true, port: 3000, wait: 60 });
1116

12-
const urlToData = 'http://localhost:3000/data/';
13-
const urlToGeojsons = urlToData + 'gadm/geojsons/';
14-
const urlToArcgisJsons = urlToData + 'gadm/arcgis/';
17+
const urlRwanda = "http://localhost:3000/data/RWA_MNH_ANC.tif";
18+
const bboxRwanda = require("../../data/RwandaBufferedBoundingBox.json");
1519

16-
const url = 'http://localhost:3000/data/test.tiff';
17-
const bbox = [80.63, 7.42, 84.21, 10.10];
18-
const expectedBboxValue = 262516.50;
20+
const urlToData = "http://localhost:3000/data/";
21+
const urlToGeojsons = urlToData + "gadm/geojsons/";
22+
const urlToArcgisJsons = urlToData + "gadm/arcgis/";
1923

20-
const polygon = [[
21-
[83.12255859375, 22.49225722008518], [82.96875, 21.57571893245848], [81.58447265624999, 1.207458730482642],
22-
[83.07861328125, 20.34462694382967], [83.8037109375, 19.497664168139053], [84.814453125, 19.766703551716976],
23-
[85.078125, 21.166483858206583], [86.044921875, 20.838277806058933], [86.98974609375, 22.49225722008518],
24-
[85.58349609375, 24.54712317973075], [84.6826171875, 23.36242859340884], [83.12255859375, 22.49225722008518]
25-
]];
26-
const expectedPolygonValue = 3165731.9;
24+
const url = "http://localhost:3000/data/test.tiff";
25+
const bbox = [80.63, 7.42, 84.21, 10.1];
26+
const expectedBboxValue = 262516.5;
2727

28+
const polygon = [
29+
[
30+
[83.12255859375, 22.49225722008518],
31+
[82.96875, 21.57571893245848],
32+
[81.58447265624999, 1.207458730482642],
33+
[83.07861328125, 20.34462694382967],
34+
[83.8037109375, 19.497664168139053],
35+
[84.814453125, 19.766703551716976],
36+
[85.078125, 21.166483858206583],
37+
[86.044921875, 20.838277806058933],
38+
[86.98974609375, 22.49225722008518],
39+
[85.58349609375, 24.54712317973075],
40+
[84.6826171875, 23.36242859340884],
41+
[83.12255859375, 22.49225722008518]
42+
]
43+
];
44+
const expectedPolygonValue = 3165731.9;
2845

2946
const polygonGeojson1 = `{
3047
"type": "FeatureCollection",
@@ -204,46 +221,47 @@ const polygonGeojsonCollection = `{
204221

205222
const expectedPolygonGeojsonCollectionValue = expectedPolygonGeojsonValue1 + expectedPolygonGeojsonValue2;
206223

207-
test('Get Sum from Veneto Geonode', async ({ eq }) => {
208-
const values = [
209-
await load('https://s3.amazonaws.com/geoblaze/geonode_atlanteil.tif'),
210-
await fetchJson('https://s3.amazonaws.com/geoblaze/veneto.geojson')
211-
];
224+
test("(Legacy) Get Sum from Veneto Geonode", async ({ eq }) => {
225+
const values = [await load("http://localhost:3000/data/veneto/geonode_atlanteil.tif"), await fetchJson("http://localhost:3000/data/veneto/veneto.geojson")];
212226
const [georaster, geojson] = values;
213-
const actualValue = Number(sum(georaster, geojson)[0].toFixed(2));
227+
const results = sum(georaster, geojson);
228+
const actualValue = Number(results[0].toFixed(2));
214229
const expectedValue = 25323.11;
215230
eq(actualValue, expectedValue);
216231
});
217232

218-
test('Get Sum', async ({ eq }) => {
233+
test("(Legacy) Get Sum", async ({ eq }) => {
219234
const georaster = await load(url);
220-
const actualValue = Number(sum(georaster)[0].toFixed(2));
235+
const results = sum(georaster);
236+
const actualValue = Number(results[0].toFixed(2));
221237
const expectedValue = 108343045.4;
222238
eq(actualValue, expectedValue);
223239
});
224240

225-
test('Get Sum from Bounding Box', async ({ eq }) => {
241+
test("(Legacy) Get Sum from Bounding Box", async ({ eq }) => {
226242
const georaster = await load(url);
227-
const value = Number(sum(georaster, bbox)[0].toFixed(2));
243+
const results = sum(georaster, bbox);
244+
const value = Number(results[0].toFixed(2));
228245
eq(value, expectedBboxValue);
229246
});
230247

231-
test('Get Sum from Bounding Box Greater Then Raster', async ({ eq }) => {
248+
test("(Legacy) Get Sum from Bounding Box Greater Then Raster", async ({ eq }) => {
232249
const georaster = await load(urlRwanda);
233-
const valueWithBufferedBbox = Number(sum(georaster, bboxRwanda)[0].toFixed(2));
250+
const results = sum(georaster, bboxRwanda);
251+
const valueWithBufferedBbox = Number(results[0].toFixed(2));
234252
const valueWithoutBbox = Number(sum(georaster)[0].toFixed(2));
235253
eq(valueWithBufferedBbox, 104848.45);
236254
eq(valueWithoutBbox, 104848.45);
237255
eq(valueWithBufferedBbox, valueWithoutBbox);
238256
});
239257

240-
test('Get Same Sum from GeoJSON and ESRI JSON', async ({ eq }) => {
241-
const urlToRaster = urlToData + 'mapspam/spam2005v3r2_harvested-area_wheat_total.tiff';
258+
test("(Legacy) Get Same Sum from GeoJSON and ESRI JSON", async ({ eq }) => {
259+
const urlToRaster = urlToData + "mapspam/spam2005v3r2_harvested-area_wheat_total.tiff";
242260
const georaster = await load(urlToRaster);
243-
const countryNames = ['Afghanistan', 'Ukraine'];
261+
const countryNames = ["Afghanistan", "Ukraine"];
244262
for (let i = 0; i < countryNames.length; i++) {
245263
const name = countryNames[i];
246-
const jsons = await fetchJsons([urlToGeojsons + name + '.geojson', urlToArcgisJsons + name + '.json'], true);
264+
const jsons = await fetchJsons([urlToGeojsons + name + ".geojson", urlToArcgisJsons + name + ".json"], true);
247265
const [geojson, arcgisJson] = jsons;
248266
const valueViaGeojson = Number(sum(georaster, geojson)[0].toFixed(2));
249267
const valueViaArcgisJson = Number(sum(georaster, arcgisJson)[0].toFixed(2));
@@ -253,51 +271,48 @@ test('Get Same Sum from GeoJSON and ESRI JSON', async ({ eq }) => {
253271
}
254272
});
255273

256-
test('Get Sum from Polygon', async ({ eq }) => {
274+
test("(Legacy) Get Sum from Polygon", async ({ eq }) => {
257275
const georaster = await load(url);
258276
const value = Number(sum(georaster, polygon)[0].toFixed(2));
259277
eq(value, expectedPolygonValue);
260278
});
261279

262-
263-
test('Get Sum from Polygon (GeoJSON) 1', async ({ eq }) => {
280+
test("(Legacy) Get Sum from Polygon (GeoJSON) 1", async ({ eq }) => {
264281
const georaster = await load(url);
265282
const value = Number(sum(georaster, polygonGeojson1)[0].toFixed(2));
266283
eq(value, expectedPolygonGeojsonValue1);
267284
});
268285

269-
test('Get Sum from Polygon (GeoJSON) 2', async ({ eq }) => {
286+
test("(Legacy) Get Sum from Polygon (GeoJSON) 2", async ({ eq }) => {
270287
const georaster = await load(url);
271288
const value = Number(sum(georaster, polygonGeojson2)[0].toFixed(2));
272289
eq(value, expectedPolygonGeojsonValue2);
273290
});
274291

275-
test('Get Sum from Polygon (Multi-Polygon GeoJSON, 1 + 2)', async ({ eq }) => {
292+
test("(Legacy) Get Sum from Polygon (Multi-Polygon GeoJSON, 1 + 2)", async ({ eq }) => {
276293
const georaster = await load(url);
277294
const value = Number(sum(georaster, polygonGeojsonCollection)[0].toFixed(2));
278295
eq(value, expectedPolygonGeojsonCollectionValue);
279296
});
280297

281-
test('Test sum for Country with Multiple Rings', async ({ eq }) => {
298+
test("(Legacy) Test sum for Country with Multiple Rings", async ({ eq }) => {
282299
const georaster = await load(url);
283-
const country = await utils.fetchJson(urlToGeojsons + 'Akrotiri and Dhekelia.geojson');
300+
const country = await utils.fetchJson(urlToGeojsons + "Akrotiri and Dhekelia.geojson");
284301
const result = sum(georaster, country);
285302
// eq(result, [123]);
286303
});
287304

288-
test('Get Sum from Polygon Above X Value', async ({ eq }) => {
305+
test("(Legacy) Get Sum from Polygon Above X Value", async ({ eq }) => {
289306
const georaster = await load(url);
290307
const value = Number(sum(georaster, polygon, v => v > 3000)[0].toFixed(2));
291308
eq(value, 1501820.8);
292309
});
293310

294-
295-
296-
test('Test Super Simplified Albanian Polygon', async ({ eq }) => {
297-
const feature = await utils.fetchJson(urlToData + 'gadm/derived/super-simplified-albanian-polygon.geojson');
298-
const georaster = await load(urlToData + 'ghsl/tiles/GHS_POP_GPW42015_GLOBE_R2015A_54009_1k_v1_0_4326_60_40.tif');
299-
const result = sum(georaster, turfPolygon(polygon))[0];
300-
eq(result, 0);
311+
test("(Legacy) Test Super Simplified Albanian Polygon", async ({ eq }) => {
312+
const feature = await utils.fetchJson(urlToData + "gadm/derived/super-simplified-albanian-polygon.geojson");
313+
const georaster = await load(urlToData + "ghsl/tiles/GHS_POP_GPW42015_GLOBE_R2015A_54009_1k_v1_0_4326_60_40.tif");
314+
const result = sum(georaster, turfPolygon(polygon));
315+
eq(result, [0]);
301316
});
302317

303318
// describe('Get Populations', function () {
@@ -367,3 +382,99 @@ test('Test Super Simplified Albanian Polygon', async ({ eq }) => {
367382
// return Promise.all(promises);
368383
// });
369384
// });
385+
386+
// modern
387+
388+
test("(Modern) Get Sum from Veneto Geonode", async ({ eq }) => {
389+
const values = [await load("http://localhost:3000/data/veneto/geonode_atlanteil.tif"), await fetchJson("http://localhost:3000/data/veneto/veneto.geojson")];
390+
const [georaster, geojson] = values;
391+
const results = await sum(georaster, geojson);
392+
const actualValue = Number(results[0].toFixed(2));
393+
const expectedValue = 25323.11;
394+
eq(actualValue, expectedValue);
395+
});
396+
397+
test("(Modern) Get Sum", async ({ eq }) => {
398+
const georaster = await parse(url);
399+
const results = await sum(georaster);
400+
const actualValue = Number(results[0].toFixed(2));
401+
const expectedValue = 108343045.4;
402+
eq(actualValue, expectedValue);
403+
});
404+
405+
test("(Modern) Get Sum from Bounding Box", async ({ eq }) => {
406+
const georaster = await parse(url);
407+
const results = await sum(georaster, bbox);
408+
const value = Number(results[0].toFixed(2));
409+
eq(value, expectedBboxValue);
410+
});
411+
412+
test("(Modern) Get Sum from Bounding Box Greater Then Raster", async ({ eq }) => {
413+
const georaster = await parse(urlRwanda);
414+
const results = await sum(georaster, bboxRwanda);
415+
const valueWithBufferedBbox = Number(results[0].toFixed(2));
416+
const valueWithoutBbox = Number(sum(georaster)[0].toFixed(2));
417+
eq(valueWithBufferedBbox, 104848.45);
418+
eq(valueWithoutBbox, 104848.45);
419+
eq(valueWithBufferedBbox, valueWithoutBbox);
420+
});
421+
422+
test("(Modern) Get Same Sum from GeoJSON and ESRI JSON", async ({ eq }) => {
423+
const urlToRaster = urlToData + "mapspam/spam2005v3r2_harvested-area_wheat_total.tiff";
424+
const georaster = await parse(urlToRaster);
425+
const countryNames = ["Afghanistan", "Ukraine"];
426+
for (let i = 0; i < countryNames.length; i++) {
427+
const name = countryNames[i];
428+
const jsons = await fetchJsons([urlToGeojsons + name + ".geojson", urlToArcgisJsons + name + ".json"], true);
429+
const [geojson, arcgisJson] = jsons;
430+
const valueViaGeojson = Number(sum(georaster, geojson)[0].toFixed(2));
431+
const valueViaArcgisJson = Number(sum(georaster, arcgisJson)[0].toFixed(2));
432+
const valueViaArcgisJsonPolygon = Number(sum(georaster, arcgisJson.geometry)[0].toFixed(2));
433+
eq(valueViaGeojson, valueViaArcgisJson);
434+
eq(valueViaGeojson, valueViaArcgisJsonPolygon);
435+
}
436+
});
437+
438+
test("(Modern) Get Sum from Polygon", async ({ eq }) => {
439+
const georaster = await parse(url);
440+
const value = Number(sum(georaster, polygon)[0].toFixed(2));
441+
eq(value, expectedPolygonValue);
442+
});
443+
444+
test("(Modern) Get Sum from Polygon (GeoJSON) 1", async ({ eq }) => {
445+
const georaster = await parse(url);
446+
const value = Number(sum(georaster, polygonGeojson1)[0].toFixed(2));
447+
eq(value, expectedPolygonGeojsonValue1);
448+
});
449+
450+
test("(Modern) Get Sum from Polygon (GeoJSON) 2", async ({ eq }) => {
451+
const georaster = await parse(url);
452+
const value = Number(sum(georaster, polygonGeojson2)[0].toFixed(2));
453+
eq(value, expectedPolygonGeojsonValue2);
454+
});
455+
456+
test("(Modern) Get Sum from Polygon (Multi-Polygon GeoJSON, 1 + 2)", async ({ eq }) => {
457+
const georaster = await parse(url);
458+
const value = Number(sum(georaster, polygonGeojsonCollection)[0].toFixed(2));
459+
eq(value, expectedPolygonGeojsonCollectionValue);
460+
});
461+
462+
test("(Modern) Test sum for Country with Multiple Rings", async ({ eq }) => {
463+
const georaster = await parse(url);
464+
const country = await utils.fetchJson(urlToGeojsons + "Akrotiri and Dhekelia.geojson");
465+
const result = await sum(georaster, country);
466+
// eq(result, [123]);
467+
});
468+
469+
test("(Modern) Get Sum from Polygon Above X Value", async ({ eq }) => {
470+
const georaster = await parse(url);
471+
const value = Number(sum(georaster, polygon, v => v > 3000)[0].toFixed(2));
472+
eq(value, 1501820.8);
473+
});
474+
475+
test("(Modern) Test Super Simplified Albanian Polygon", async ({ eq }) => {
476+
const feature = await utils.fetchJson(urlToData + "gadm/derived/super-simplified-albanian-polygon.geojson");
477+
const georaster = await parse(urlToData + "ghsl/tiles/GHS_POP_GPW42015_GLOBE_R2015A_54009_1k_v1_0_4326_60_40.tif");
478+
const result = await sum(georaster, turfPolygon(polygon));
479+
eq(result, [0]);
480+
});

0 commit comments

Comments
 (0)
Please sign in to comment.