From 1a7bf6d721da46e4460bfb2aa872e72b44ea9ced Mon Sep 17 00:00:00 2001 From: Rich Gwozdz Date: Wed, 29 May 2024 13:57:17 -0700 Subject: [PATCH 1/2] fix: break count must >= features.length - 1 --- .changeset/strange-avocados-guess.md | 5 + packages/winnow/coverage-unit.svg | 8 +- .../src/calculate-class-breaks/index.js | 16 ++- .../src/calculate-class-breaks/index.spec.js | 98 +++++++++++++++++++ 4 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 .changeset/strange-avocados-guess.md diff --git a/.changeset/strange-avocados-guess.md b/.changeset/strange-avocados-guess.md new file mode 100644 index 000000000..410b59978 --- /dev/null +++ b/.changeset/strange-avocados-guess.md @@ -0,0 +1,5 @@ +--- +"@koopjs/winnow": patch +--- + +- breakCount needs to >= features.length - 1 diff --git a/packages/winnow/coverage-unit.svg b/packages/winnow/coverage-unit.svg index fb3d4915b..cfceaa374 100644 --- a/packages/winnow/coverage-unit.svg +++ b/packages/winnow/coverage-unit.svg @@ -1,5 +1,5 @@ - - coverage: 96.89% + + coverage: 97.16% @@ -13,8 +13,8 @@ \ No newline at end of file diff --git a/packages/winnow/src/calculate-class-breaks/index.js b/packages/winnow/src/calculate-class-breaks/index.js index b7c8dfc74..673cf4da9 100644 --- a/packages/winnow/src/calculate-class-breaks/index.js +++ b/packages/winnow/src/calculate-class-breaks/index.js @@ -5,14 +5,22 @@ const transformClassBreaksToRanges = require('./transform-class-breaks-to-ranges const filterAndValidateClassificationFeatures = require('./filter-and-validate-classification-features'); // eslint-disable-line function calculateClassBreaks(features, classification) { - if (!classification.method) throw new Error('must supply classification.method'); - if (!classification.breakCount) throw new Error('must supply classification.breakCount'); + if (!classification.method) { + throw new Error('must supply classification.method'); + } + + if (!classification.breakCount) { + throw new Error('must supply classification.breakCount'); + } const values = classification.normType ? normalizeClassificationValues(features, classification) : getFieldValues(features, classification.field); - // limit break count to num values - if (classification.breakCount > values.length) classification.breakCount = values.length; + + // limit break count to num values - 1; [1, 2, 3, 4, 5, 6] => [1-2, 2-3, 3-4, 4-5, 5-6] + if (classification.breakCount > values.length) { + classification.breakCount = values.length - 1; + } // calculate break ranges [ [a-b], [b-c], ...] from input values const classBreakArray = transformValuesToClassBreaksArray(values, classification); diff --git a/packages/winnow/src/calculate-class-breaks/index.spec.js b/packages/winnow/src/calculate-class-breaks/index.spec.js index fed1ccefd..4911689f9 100644 --- a/packages/winnow/src/calculate-class-breaks/index.spec.js +++ b/packages/winnow/src/calculate-class-breaks/index.spec.js @@ -24,6 +24,31 @@ test('calculateClassBreaks: no breakCount', (t) => { } }); +test('calculateClassBreaks: breakCount > values', (t) => { + t.plan(1); + const features = [ + { properties: { Trunk_Diameter: 13 } }, + { properties: { Trunk_Diameter: 7 } }, + { properties: { Trunk_Diameter: 17 } }, + { properties: { Trunk_Diameter: 25 } }, + { properties: { Trunk_Diameter: 3 } }, + ]; + const classification = { + type: 'classes', + field: 'Trunk_Diameter', + method: 'equalInterval', + breakCount: 6, + }; + + const result = calculateClassBreaks(features, classification); + t.deepEquals(result, [ + [3, 8.5], + [8.6, 14], + [15, 19.5], + [19.6, 25], + ]); +}); + test('calculateClassBreaks: no method', (t) => { t.plan(1); const features = [ @@ -171,6 +196,54 @@ test('calculateClassBreaks: quantile', (t) => { ]); }); +test('calculateClassBreaks: geomInterval not supported', (t) => { + t.plan(1); + const features = [ + { properties: { Trunk_Diameter: 13 } }, + { properties: { Trunk_Diameter: 7 } }, + { properties: { Trunk_Diameter: 17 } }, + { properties: { Trunk_Diameter: 25 } }, + { properties: { Trunk_Diameter: 3 } }, + ]; + const classification = { + type: 'classes', + field: 'Trunk_Diameter', + method: 'geomInterval', + breakCount: 4, + }; + + try { + calculateClassBreaks(features, classification); + t.fail('should have thrown'); + } catch (error) { + t.equals(error.message, 'Classification method not yet supported'); + } +}); + +test('calculateClassBreaks: unknown method not supported', (t) => { + t.plan(1); + const features = [ + { properties: { Trunk_Diameter: 13 } }, + { properties: { Trunk_Diameter: 7 } }, + { properties: { Trunk_Diameter: 17 } }, + { properties: { Trunk_Diameter: 25 } }, + { properties: { Trunk_Diameter: 3 } }, + ]; + const classification = { + type: 'classes', + field: 'Trunk_Diameter', + method: 'geomIntervalz', + breakCount: 4, + }; + + try { + calculateClassBreaks(features, classification); + t.fail('should have thrown'); + } catch (error) { + t.equals(error.message, 'invalid classificationMethod: geomIntervalz'); + } +}); + test('calculateClassBreaks: normalize by field', (t) => { t.plan(1); const features = [ @@ -271,3 +344,28 @@ test('calculateClassBreaks: null values not used in breaks calculation', (t) => [17.666666666666664, 25], ]); }); + +test('calculateClassBreaks: zero negative values', (t) => { + t.plan(1); + const features = [ + { properties: { Trunk_Diameter: 13 } }, + { properties: { Trunk_Diameter: -10 } }, + { properties: { Trunk_Diameter: 7 } }, + { properties: { Trunk_Diameter: 17 } }, + { properties: { Trunk_Diameter: 25 } }, + { properties: { Trunk_Diameter: 3 } }, + ]; + const classification = { + type: 'classes', + field: 'Trunk_Diameter', + method: 'equalInterval', + breakCount: 3, + }; + + const result = calculateClassBreaks(features, classification); + t.deepEquals(result, [ + [0, 8.333333333333334], + [8.333333333333336, 16.666666666666668], + [16.666666666666668, 25], + ]); +}); From c7f72c2ae9664ab4d3e57ed15d9277aa73c1a6d2 Mon Sep 17 00:00:00 2001 From: Rich Gwozdz Date: Wed, 29 May 2024 14:05:59 -0700 Subject: [PATCH 2/2] chore: e2e test --- test/geoservice-generate-renderer.spec.js | 25 ++++------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/test/geoservice-generate-renderer.spec.js b/test/geoservice-generate-renderer.spec.js index e91a1e7e9..381d68b04 100644 --- a/test/geoservice-generate-renderer.spec.js +++ b/test/geoservice-generate-renderer.spec.js @@ -40,8 +40,8 @@ describe('Feature Server Output - /generateRenderer', () => { classBreakInfos: [ { classMinValue: 900, - classMaxValue: 900, - label: '900-900', + classMaxValue: 985, + label: '900-985', description: '', symbol: { color: [0, 255, 0], @@ -57,26 +57,9 @@ describe('Feature Server Output - /generateRenderer', () => { }, }, { - classMinValue: 901, classMaxValue: 1103, - label: '901-1103', - description: '', - symbol: { - color: [0, 255, 255], - outline: { - color: [190, 190, 190, 105], - width: 0.5, - type: 'esriSLS', - style: 'esriSLSSolid', - }, - size: 7.5, - type: 'esriSMS', - style: 'esriSMSCircle', - }, - }, - { - classMinValue: 1104, - label: '1104-undefined', + classMinValue: 986, + label: '986-1103', description: '', symbol: { color: [0, 0, 255],