@turf/quadrat-analysis 7.0.0-alpha.2 → 7.1.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -93,26 +93,21 @@ Type: [Object][3]
93
93
 
94
94
  [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
95
95
 
96
- <!-- This file is automatically generated. Please don't edit it directly:
97
- if you find an error, edit the source file (likely index.js), and re-run
98
- ./scripts/generate-readmes in the turf project. -->
96
+ <!-- This file is automatically generated. Please don't edit it directly. If you find an error, edit the source file of the module in question (likely index.js or index.ts), and re-run "yarn docs" from the root of the turf project. -->
99
97
 
100
98
  ---
101
99
 
102
- This module is part of the [Turfjs project](http://turfjs.org/), an open source
103
- module collection dedicated to geographic algorithms. It is maintained in the
104
- [Turfjs/turf](https://github.com/Turfjs/turf) repository, where you can create
105
- PRs and issues.
100
+ This module is part of the [Turfjs project](https://turfjs.org/), an open source module collection dedicated to geographic algorithms. It is maintained in the [Turfjs/turf](https://github.com/Turfjs/turf) repository, where you can create PRs and issues.
106
101
 
107
102
  ### Installation
108
103
 
109
- Install this module individually:
104
+ Install this single module individually:
110
105
 
111
106
  ```sh
112
107
  $ npm install @turf/quadrat-analysis
113
108
  ```
114
109
 
115
- Or install the Turf module that includes it as a function:
110
+ Or install the all-encompassing @turf/turf module that includes all modules as functions:
116
111
 
117
112
  ```sh
118
113
  $ npm install @turf/turf
@@ -0,0 +1,114 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});// index.ts
2
+ var _area = require('@turf/area');
3
+ var _bbox = require('@turf/bbox');
4
+ var _bboxpolygon = require('@turf/bbox-polygon');
5
+ var _invariant = require('@turf/invariant');
6
+ var _squaregrid = require('@turf/square-grid');
7
+ function quadratAnalysis(pointFeatureSet, options) {
8
+ options = options || {};
9
+ const studyBbox = options.studyBbox || _bbox.bbox.call(void 0, pointFeatureSet);
10
+ const confidenceLevel = options.confidenceLevel || 20;
11
+ const points = pointFeatureSet.features;
12
+ const numOfPoints = points.length;
13
+ const sizeOfArea = _area.area.call(void 0, _bboxpolygon.bboxPolygon.call(void 0, studyBbox));
14
+ const lengthOfSide = Math.sqrt(sizeOfArea / numOfPoints * 2);
15
+ const grid = _squaregrid.squareGrid.call(void 0, studyBbox, lengthOfSide, {
16
+ units: "meters"
17
+ });
18
+ const quadrats = grid.features;
19
+ const quadratIdDict = {};
20
+ for (let i = 0; i < quadrats.length; i++) {
21
+ quadratIdDict[i] = {
22
+ box: _bbox.bbox.call(void 0, quadrats[i]),
23
+ cnt: 0
24
+ };
25
+ }
26
+ let sumOfPoint = 0;
27
+ for (const pt of points) {
28
+ for (const key of Object.keys(quadratIdDict)) {
29
+ const box = quadratIdDict[key].box;
30
+ if (inBBox(_invariant.getCoord.call(void 0, pt), box)) {
31
+ quadratIdDict[key].cnt += 1;
32
+ sumOfPoint += 1;
33
+ break;
34
+ }
35
+ }
36
+ }
37
+ let maxCnt = 0;
38
+ for (const key of Object.keys(quadratIdDict)) {
39
+ const cnt = quadratIdDict[key].cnt;
40
+ if (cnt > maxCnt) {
41
+ maxCnt = cnt;
42
+ }
43
+ }
44
+ const expectedDistribution = [];
45
+ const numOfQuadrat = Object.keys(quadratIdDict).length;
46
+ const lambda = sumOfPoint / numOfQuadrat;
47
+ let cumulativeProbility = 0;
48
+ for (let x = 0; x < maxCnt + 1; x++) {
49
+ cumulativeProbility += Math.exp(-lambda) * Math.pow(lambda, x) / factorial(x);
50
+ expectedDistribution.push(cumulativeProbility);
51
+ }
52
+ const observedDistribution = [];
53
+ let cumulativeObservedQuads = 0;
54
+ for (let x = 0; x < maxCnt + 1; x++) {
55
+ for (const key of Object.keys(quadratIdDict)) {
56
+ if (quadratIdDict[key].cnt === x) {
57
+ cumulativeObservedQuads += 1;
58
+ }
59
+ }
60
+ const p = cumulativeObservedQuads / numOfQuadrat;
61
+ observedDistribution.push(p);
62
+ }
63
+ let maxDifference = 0;
64
+ for (let x = 0; x < maxCnt + 1; x++) {
65
+ const difference = Math.abs(
66
+ expectedDistribution[x] - observedDistribution[x]
67
+ );
68
+ if (difference > maxDifference) {
69
+ maxDifference = difference;
70
+ }
71
+ }
72
+ const k = K_TABLE[confidenceLevel];
73
+ const criticalValue = k / Math.sqrt(numOfQuadrat);
74
+ const result = {
75
+ criticalValue,
76
+ isRandom: true,
77
+ maxAbsoluteDifference: maxDifference,
78
+ observedDistribution
79
+ };
80
+ if (maxDifference > criticalValue) {
81
+ result.isRandom = false;
82
+ }
83
+ return result;
84
+ }
85
+ var K_TABLE = {
86
+ 20: 1.07275,
87
+ 15: 1.13795,
88
+ 10: 1.22385,
89
+ 5: 1.3581,
90
+ 2: 1.51743,
91
+ 1: 1.62762
92
+ };
93
+ function inBBox(pt, bbox) {
94
+ return bbox[0] <= pt[0] && bbox[1] <= pt[1] && bbox[2] >= pt[0] && bbox[3] >= pt[1];
95
+ }
96
+ function factorial(num) {
97
+ const f = [];
98
+ function inner(n) {
99
+ if (n === 0 || n === 1) {
100
+ return 1;
101
+ }
102
+ if (f[n] > 0) {
103
+ return f[n];
104
+ }
105
+ return f[n] = inner(n - 1) * n;
106
+ }
107
+ return inner(num);
108
+ }
109
+ var turf_quadrat_analysis_default = quadratAnalysis;
110
+
111
+
112
+
113
+ exports.default = turf_quadrat_analysis_default; exports.quadratAnalysis = quadratAnalysis;
114
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../index.ts"],"names":[],"mappings":"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","sourcesContent":["import { BBox, FeatureCollection, Point } from \"geojson\";\nimport { area } from \"@turf/area\";\nimport { bbox as turfBBox } from \"@turf/bbox\";\nimport { bboxPolygon } from \"@turf/bbox-polygon\";\nimport { getCoord } from \"@turf/invariant\";\nimport { squareGrid } from \"@turf/square-grid\";\n\ninterface QuadratAnalysisResult {\n criticalValue: number;\n maxAbsoluteDifference: number;\n isRandom: boolean;\n observedDistribution: number[];\n}\n\n/**\n * Quadrat analysis lays a set of equal-size areas(quadrat) over the study area and counts\n * the number of features in each quadrat and creates a frequency table.\n * The table lists the number of quadrats containing no features,\n * the number containing one feature, two features, and so on,\n * all the way up to the quadrat containing the most features.\n * The method then creates the frequency table for the random distribution, usually based on a Poisson distribution.\n * The method uses the distribution to calculate the probability for 0 feature occuring,\n * 1 feature occuring, 2 features, and so on,\n * and lists these probabilities in the frequency table.\n * By comparing the two frequency tables, you can see whether the features create a pattern.\n * If the table for the observed distribution has more quadrats containing many features than the\n * table for the random distribution dose, then the features create a clustered pattern.\n *\n * It is hard to judge the frequency tables are similar or different just by looking at them.\n * So, we can use serval statistical tests to find out how much the frequency tables differ.\n * We use Kolmogorov-Smirnov test.This method calculates cumulative probabilities for both distributions,\n * and then compares the cumulative probabilities at each class level and selects the largest absolute difference D.\n * Then, the test compares D to the critical value for a confidence level you specify.\n * If D is greater than the critical value, the difference between the observed distribution and\n * the random distribution is significant. The greater the value the bigger the difference.\n *\n * Traditionally, squares are used for the shape of the quadrats, in a regular grid(square-grid).\n * Some researchers suggest that the quadrat size equal twice the size of mean area per feature,\n * which is simply the area of the study area divided by the number of features.\n *\n *\n * @name quadratAnalysis\n * @param {FeatureCollection<Point>} pointFeatureSet point set to study\n * @param {Object} [options={}] optional parameters\n * @param {bbox} [options.studyBbox] bbox representing the study area\n * @param {number} [options.confidenceLevel=20] a confidence level.\n * The unit is percentage . 5 means 95%, value must be in {@link K_TABLE}\n * @returns {Object} result {@link QuadratAnalysisResult}\n * @example\n *\n * var bbox = [-65, 40, -63, 42];\n * var dataset = turf.randomPoint(100, { bbox: bbox });\n * var result = turf.quadratAnalysis(dataset);\n *\n */\nfunction quadratAnalysis(\n pointFeatureSet: FeatureCollection<Point>,\n options: {\n studyBbox?: [number, number, number, number];\n confidenceLevel?: 20 | 15 | 10 | 5 | 2 | 1;\n }\n): QuadratAnalysisResult {\n options = options || {};\n const studyBbox = options.studyBbox || turfBBox(pointFeatureSet);\n const confidenceLevel = options.confidenceLevel || 20;\n const points = pointFeatureSet.features;\n\n // create square-grid\n const numOfPoints = points.length;\n const sizeOfArea = area(bboxPolygon(studyBbox));\n const lengthOfSide = Math.sqrt((sizeOfArea / numOfPoints) * 2);\n const grid = squareGrid(studyBbox, lengthOfSide, {\n units: \"meters\",\n });\n const quadrats = grid.features;\n\n // count the number of features in each quadrat\n const quadratIdDict: { [key: string]: { box: BBox; cnt: number } } = {};\n for (let i = 0; i < quadrats.length; i++) {\n quadratIdDict[i] = {\n box: turfBBox(quadrats[i]),\n cnt: 0,\n };\n }\n\n let sumOfPoint = 0;\n for (const pt of points) {\n for (const key of Object.keys(quadratIdDict)) {\n const box = quadratIdDict[key].box;\n if (inBBox(getCoord(pt), box)) {\n quadratIdDict[key].cnt += 1;\n sumOfPoint += 1;\n break;\n }\n }\n }\n\n // the most amount of features in quadrat\n let maxCnt = 0;\n for (const key of Object.keys(quadratIdDict)) {\n const cnt = quadratIdDict[key].cnt;\n if (cnt > maxCnt) {\n maxCnt = cnt;\n }\n }\n\n const expectedDistribution = [];\n const numOfQuadrat = Object.keys(quadratIdDict).length;\n const lambda = sumOfPoint / numOfQuadrat;\n\n // get the cumulative probability of the random distribution\n let cumulativeProbility = 0.0;\n for (let x = 0; x < maxCnt + 1; x++) {\n cumulativeProbility +=\n (Math.exp(-lambda) * Math.pow(lambda, x)) / factorial(x);\n expectedDistribution.push(cumulativeProbility);\n }\n\n // get the cumulative probability of the observed distribution\n const observedDistribution = [];\n let cumulativeObservedQuads = 0;\n for (let x = 0; x < maxCnt + 1; x++) {\n for (const key of Object.keys(quadratIdDict)) {\n if (quadratIdDict[key].cnt === x) {\n cumulativeObservedQuads += 1;\n }\n }\n const p = cumulativeObservedQuads / numOfQuadrat;\n observedDistribution.push(p);\n }\n\n // get the largest absolute difference between two distributions\n let maxDifference = 0;\n for (let x = 0; x < maxCnt + 1; x++) {\n const difference = Math.abs(\n expectedDistribution[x] - observedDistribution[x]\n );\n if (difference > maxDifference) {\n maxDifference = difference;\n }\n }\n\n const k = K_TABLE[confidenceLevel];\n\n // statistical test\n const criticalValue = k / Math.sqrt(numOfQuadrat);\n const result: QuadratAnalysisResult = {\n criticalValue,\n isRandom: true,\n maxAbsoluteDifference: maxDifference,\n observedDistribution,\n };\n\n if (maxDifference > criticalValue) {\n result.isRandom = false;\n }\n\n return result;\n}\n\n/**\n * the confidence level\n * @type {Object} K_TABLE\n * @property {number} 20\n * @property {number} 15\n * @property {number} 10\n * @property {number} 5\n * @property {number} 2\n * @property {number} 1\n */\nconst K_TABLE = {\n 20: 1.07275,\n 15: 1.13795,\n 10: 1.22385,\n 5: 1.3581,\n 2: 1.51743,\n 1: 1.62762,\n};\n\n/**\n * the return type of the quadratAnalysis\n * @typedef {Object} QuadratAnalysisResult\n * @property {number} criticalValue\n * @property {number} maxAbsoluteDifference\n * @property {boolean} isRandom\n * @property {Array.<number>} observedDistribution the cumulative distribution of observed features,\n * the index represents the number of features in the quadrat.\n */\n\n/**\n * inBBox from @turf/boolean-point-in-polygon\n *\n * @private\n * @param {Array<number>} pt point [x,y]\n * @param {BBox} bbox BBox [west, south, east, north]\n * @returns {boolean} true/false if point is inside BBox\n */\nfunction inBBox(pt: number[], bbox: BBox) {\n return (\n bbox[0] <= pt[0] && bbox[1] <= pt[1] && bbox[2] >= pt[0] && bbox[3] >= pt[1]\n );\n}\n\n/**\n * https://stackoverflow.com/questions/3959211/fast-factorial-function-in-javascript\n * @private\n * @param {number} num Number\n * @returns {number} the factorial of num\n */\nfunction factorial(num: number) {\n const f: number[] = [];\n function inner(n: number): number {\n if (n === 0 || n === 1) {\n return 1;\n }\n if (f[n] > 0) {\n return f[n];\n }\n return (f[n] = inner(n - 1) * n);\n }\n return inner(num);\n}\n\nexport { QuadratAnalysisResult, quadratAnalysis };\nexport default quadratAnalysis;\n"]}
@@ -0,0 +1,55 @@
1
+ import { FeatureCollection, Point } from 'geojson';
2
+
3
+ interface QuadratAnalysisResult {
4
+ criticalValue: number;
5
+ maxAbsoluteDifference: number;
6
+ isRandom: boolean;
7
+ observedDistribution: number[];
8
+ }
9
+ /**
10
+ * Quadrat analysis lays a set of equal-size areas(quadrat) over the study area and counts
11
+ * the number of features in each quadrat and creates a frequency table.
12
+ * The table lists the number of quadrats containing no features,
13
+ * the number containing one feature, two features, and so on,
14
+ * all the way up to the quadrat containing the most features.
15
+ * The method then creates the frequency table for the random distribution, usually based on a Poisson distribution.
16
+ * The method uses the distribution to calculate the probability for 0 feature occuring,
17
+ * 1 feature occuring, 2 features, and so on,
18
+ * and lists these probabilities in the frequency table.
19
+ * By comparing the two frequency tables, you can see whether the features create a pattern.
20
+ * If the table for the observed distribution has more quadrats containing many features than the
21
+ * table for the random distribution dose, then the features create a clustered pattern.
22
+ *
23
+ * It is hard to judge the frequency tables are similar or different just by looking at them.
24
+ * So, we can use serval statistical tests to find out how much the frequency tables differ.
25
+ * We use Kolmogorov-Smirnov test.This method calculates cumulative probabilities for both distributions,
26
+ * and then compares the cumulative probabilities at each class level and selects the largest absolute difference D.
27
+ * Then, the test compares D to the critical value for a confidence level you specify.
28
+ * If D is greater than the critical value, the difference between the observed distribution and
29
+ * the random distribution is significant. The greater the value the bigger the difference.
30
+ *
31
+ * Traditionally, squares are used for the shape of the quadrats, in a regular grid(square-grid).
32
+ * Some researchers suggest that the quadrat size equal twice the size of mean area per feature,
33
+ * which is simply the area of the study area divided by the number of features.
34
+ *
35
+ *
36
+ * @name quadratAnalysis
37
+ * @param {FeatureCollection<Point>} pointFeatureSet point set to study
38
+ * @param {Object} [options={}] optional parameters
39
+ * @param {bbox} [options.studyBbox] bbox representing the study area
40
+ * @param {number} [options.confidenceLevel=20] a confidence level.
41
+ * The unit is percentage . 5 means 95%, value must be in {@link K_TABLE}
42
+ * @returns {Object} result {@link QuadratAnalysisResult}
43
+ * @example
44
+ *
45
+ * var bbox = [-65, 40, -63, 42];
46
+ * var dataset = turf.randomPoint(100, { bbox: bbox });
47
+ * var result = turf.quadratAnalysis(dataset);
48
+ *
49
+ */
50
+ declare function quadratAnalysis(pointFeatureSet: FeatureCollection<Point>, options: {
51
+ studyBbox?: [number, number, number, number];
52
+ confidenceLevel?: 20 | 15 | 10 | 5 | 2 | 1;
53
+ }): QuadratAnalysisResult;
54
+
55
+ export { type QuadratAnalysisResult, quadratAnalysis as default, quadratAnalysis };
@@ -1,5 +1,6 @@
1
- import { FeatureCollection, Point } from "geojson";
2
- export interface QuadratAnalysisResult {
1
+ import { FeatureCollection, Point } from 'geojson';
2
+
3
+ interface QuadratAnalysisResult {
3
4
  criticalValue: number;
4
5
  maxAbsoluteDifference: number;
5
6
  isRandom: boolean;
@@ -46,7 +47,9 @@ export interface QuadratAnalysisResult {
46
47
  * var result = turf.quadratAnalysis(dataset);
47
48
  *
48
49
  */
49
- export default function quadratAnalysis(pointFeatureSet: FeatureCollection<Point>, options: {
50
+ declare function quadratAnalysis(pointFeatureSet: FeatureCollection<Point>, options: {
50
51
  studyBbox?: [number, number, number, number];
51
52
  confidenceLevel?: 20 | 15 | 10 | 5 | 2 | 1;
52
53
  }): QuadratAnalysisResult;
54
+
55
+ export { type QuadratAnalysisResult, quadratAnalysis as default, quadratAnalysis };
@@ -0,0 +1,114 @@
1
+ // index.ts
2
+ import { area } from "@turf/area";
3
+ import { bbox as turfBBox } from "@turf/bbox";
4
+ import { bboxPolygon } from "@turf/bbox-polygon";
5
+ import { getCoord } from "@turf/invariant";
6
+ import { squareGrid } from "@turf/square-grid";
7
+ function quadratAnalysis(pointFeatureSet, options) {
8
+ options = options || {};
9
+ const studyBbox = options.studyBbox || turfBBox(pointFeatureSet);
10
+ const confidenceLevel = options.confidenceLevel || 20;
11
+ const points = pointFeatureSet.features;
12
+ const numOfPoints = points.length;
13
+ const sizeOfArea = area(bboxPolygon(studyBbox));
14
+ const lengthOfSide = Math.sqrt(sizeOfArea / numOfPoints * 2);
15
+ const grid = squareGrid(studyBbox, lengthOfSide, {
16
+ units: "meters"
17
+ });
18
+ const quadrats = grid.features;
19
+ const quadratIdDict = {};
20
+ for (let i = 0; i < quadrats.length; i++) {
21
+ quadratIdDict[i] = {
22
+ box: turfBBox(quadrats[i]),
23
+ cnt: 0
24
+ };
25
+ }
26
+ let sumOfPoint = 0;
27
+ for (const pt of points) {
28
+ for (const key of Object.keys(quadratIdDict)) {
29
+ const box = quadratIdDict[key].box;
30
+ if (inBBox(getCoord(pt), box)) {
31
+ quadratIdDict[key].cnt += 1;
32
+ sumOfPoint += 1;
33
+ break;
34
+ }
35
+ }
36
+ }
37
+ let maxCnt = 0;
38
+ for (const key of Object.keys(quadratIdDict)) {
39
+ const cnt = quadratIdDict[key].cnt;
40
+ if (cnt > maxCnt) {
41
+ maxCnt = cnt;
42
+ }
43
+ }
44
+ const expectedDistribution = [];
45
+ const numOfQuadrat = Object.keys(quadratIdDict).length;
46
+ const lambda = sumOfPoint / numOfQuadrat;
47
+ let cumulativeProbility = 0;
48
+ for (let x = 0; x < maxCnt + 1; x++) {
49
+ cumulativeProbility += Math.exp(-lambda) * Math.pow(lambda, x) / factorial(x);
50
+ expectedDistribution.push(cumulativeProbility);
51
+ }
52
+ const observedDistribution = [];
53
+ let cumulativeObservedQuads = 0;
54
+ for (let x = 0; x < maxCnt + 1; x++) {
55
+ for (const key of Object.keys(quadratIdDict)) {
56
+ if (quadratIdDict[key].cnt === x) {
57
+ cumulativeObservedQuads += 1;
58
+ }
59
+ }
60
+ const p = cumulativeObservedQuads / numOfQuadrat;
61
+ observedDistribution.push(p);
62
+ }
63
+ let maxDifference = 0;
64
+ for (let x = 0; x < maxCnt + 1; x++) {
65
+ const difference = Math.abs(
66
+ expectedDistribution[x] - observedDistribution[x]
67
+ );
68
+ if (difference > maxDifference) {
69
+ maxDifference = difference;
70
+ }
71
+ }
72
+ const k = K_TABLE[confidenceLevel];
73
+ const criticalValue = k / Math.sqrt(numOfQuadrat);
74
+ const result = {
75
+ criticalValue,
76
+ isRandom: true,
77
+ maxAbsoluteDifference: maxDifference,
78
+ observedDistribution
79
+ };
80
+ if (maxDifference > criticalValue) {
81
+ result.isRandom = false;
82
+ }
83
+ return result;
84
+ }
85
+ var K_TABLE = {
86
+ 20: 1.07275,
87
+ 15: 1.13795,
88
+ 10: 1.22385,
89
+ 5: 1.3581,
90
+ 2: 1.51743,
91
+ 1: 1.62762
92
+ };
93
+ function inBBox(pt, bbox) {
94
+ return bbox[0] <= pt[0] && bbox[1] <= pt[1] && bbox[2] >= pt[0] && bbox[3] >= pt[1];
95
+ }
96
+ function factorial(num) {
97
+ const f = [];
98
+ function inner(n) {
99
+ if (n === 0 || n === 1) {
100
+ return 1;
101
+ }
102
+ if (f[n] > 0) {
103
+ return f[n];
104
+ }
105
+ return f[n] = inner(n - 1) * n;
106
+ }
107
+ return inner(num);
108
+ }
109
+ var turf_quadrat_analysis_default = quadratAnalysis;
110
+ export {
111
+ turf_quadrat_analysis_default as default,
112
+ quadratAnalysis
113
+ };
114
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../index.ts"],"sourcesContent":["import { BBox, FeatureCollection, Point } from \"geojson\";\nimport { area } from \"@turf/area\";\nimport { bbox as turfBBox } from \"@turf/bbox\";\nimport { bboxPolygon } from \"@turf/bbox-polygon\";\nimport { getCoord } from \"@turf/invariant\";\nimport { squareGrid } from \"@turf/square-grid\";\n\ninterface QuadratAnalysisResult {\n criticalValue: number;\n maxAbsoluteDifference: number;\n isRandom: boolean;\n observedDistribution: number[];\n}\n\n/**\n * Quadrat analysis lays a set of equal-size areas(quadrat) over the study area and counts\n * the number of features in each quadrat and creates a frequency table.\n * The table lists the number of quadrats containing no features,\n * the number containing one feature, two features, and so on,\n * all the way up to the quadrat containing the most features.\n * The method then creates the frequency table for the random distribution, usually based on a Poisson distribution.\n * The method uses the distribution to calculate the probability for 0 feature occuring,\n * 1 feature occuring, 2 features, and so on,\n * and lists these probabilities in the frequency table.\n * By comparing the two frequency tables, you can see whether the features create a pattern.\n * If the table for the observed distribution has more quadrats containing many features than the\n * table for the random distribution dose, then the features create a clustered pattern.\n *\n * It is hard to judge the frequency tables are similar or different just by looking at them.\n * So, we can use serval statistical tests to find out how much the frequency tables differ.\n * We use Kolmogorov-Smirnov test.This method calculates cumulative probabilities for both distributions,\n * and then compares the cumulative probabilities at each class level and selects the largest absolute difference D.\n * Then, the test compares D to the critical value for a confidence level you specify.\n * If D is greater than the critical value, the difference between the observed distribution and\n * the random distribution is significant. The greater the value the bigger the difference.\n *\n * Traditionally, squares are used for the shape of the quadrats, in a regular grid(square-grid).\n * Some researchers suggest that the quadrat size equal twice the size of mean area per feature,\n * which is simply the area of the study area divided by the number of features.\n *\n *\n * @name quadratAnalysis\n * @param {FeatureCollection<Point>} pointFeatureSet point set to study\n * @param {Object} [options={}] optional parameters\n * @param {bbox} [options.studyBbox] bbox representing the study area\n * @param {number} [options.confidenceLevel=20] a confidence level.\n * The unit is percentage . 5 means 95%, value must be in {@link K_TABLE}\n * @returns {Object} result {@link QuadratAnalysisResult}\n * @example\n *\n * var bbox = [-65, 40, -63, 42];\n * var dataset = turf.randomPoint(100, { bbox: bbox });\n * var result = turf.quadratAnalysis(dataset);\n *\n */\nfunction quadratAnalysis(\n pointFeatureSet: FeatureCollection<Point>,\n options: {\n studyBbox?: [number, number, number, number];\n confidenceLevel?: 20 | 15 | 10 | 5 | 2 | 1;\n }\n): QuadratAnalysisResult {\n options = options || {};\n const studyBbox = options.studyBbox || turfBBox(pointFeatureSet);\n const confidenceLevel = options.confidenceLevel || 20;\n const points = pointFeatureSet.features;\n\n // create square-grid\n const numOfPoints = points.length;\n const sizeOfArea = area(bboxPolygon(studyBbox));\n const lengthOfSide = Math.sqrt((sizeOfArea / numOfPoints) * 2);\n const grid = squareGrid(studyBbox, lengthOfSide, {\n units: \"meters\",\n });\n const quadrats = grid.features;\n\n // count the number of features in each quadrat\n const quadratIdDict: { [key: string]: { box: BBox; cnt: number } } = {};\n for (let i = 0; i < quadrats.length; i++) {\n quadratIdDict[i] = {\n box: turfBBox(quadrats[i]),\n cnt: 0,\n };\n }\n\n let sumOfPoint = 0;\n for (const pt of points) {\n for (const key of Object.keys(quadratIdDict)) {\n const box = quadratIdDict[key].box;\n if (inBBox(getCoord(pt), box)) {\n quadratIdDict[key].cnt += 1;\n sumOfPoint += 1;\n break;\n }\n }\n }\n\n // the most amount of features in quadrat\n let maxCnt = 0;\n for (const key of Object.keys(quadratIdDict)) {\n const cnt = quadratIdDict[key].cnt;\n if (cnt > maxCnt) {\n maxCnt = cnt;\n }\n }\n\n const expectedDistribution = [];\n const numOfQuadrat = Object.keys(quadratIdDict).length;\n const lambda = sumOfPoint / numOfQuadrat;\n\n // get the cumulative probability of the random distribution\n let cumulativeProbility = 0.0;\n for (let x = 0; x < maxCnt + 1; x++) {\n cumulativeProbility +=\n (Math.exp(-lambda) * Math.pow(lambda, x)) / factorial(x);\n expectedDistribution.push(cumulativeProbility);\n }\n\n // get the cumulative probability of the observed distribution\n const observedDistribution = [];\n let cumulativeObservedQuads = 0;\n for (let x = 0; x < maxCnt + 1; x++) {\n for (const key of Object.keys(quadratIdDict)) {\n if (quadratIdDict[key].cnt === x) {\n cumulativeObservedQuads += 1;\n }\n }\n const p = cumulativeObservedQuads / numOfQuadrat;\n observedDistribution.push(p);\n }\n\n // get the largest absolute difference between two distributions\n let maxDifference = 0;\n for (let x = 0; x < maxCnt + 1; x++) {\n const difference = Math.abs(\n expectedDistribution[x] - observedDistribution[x]\n );\n if (difference > maxDifference) {\n maxDifference = difference;\n }\n }\n\n const k = K_TABLE[confidenceLevel];\n\n // statistical test\n const criticalValue = k / Math.sqrt(numOfQuadrat);\n const result: QuadratAnalysisResult = {\n criticalValue,\n isRandom: true,\n maxAbsoluteDifference: maxDifference,\n observedDistribution,\n };\n\n if (maxDifference > criticalValue) {\n result.isRandom = false;\n }\n\n return result;\n}\n\n/**\n * the confidence level\n * @type {Object} K_TABLE\n * @property {number} 20\n * @property {number} 15\n * @property {number} 10\n * @property {number} 5\n * @property {number} 2\n * @property {number} 1\n */\nconst K_TABLE = {\n 20: 1.07275,\n 15: 1.13795,\n 10: 1.22385,\n 5: 1.3581,\n 2: 1.51743,\n 1: 1.62762,\n};\n\n/**\n * the return type of the quadratAnalysis\n * @typedef {Object} QuadratAnalysisResult\n * @property {number} criticalValue\n * @property {number} maxAbsoluteDifference\n * @property {boolean} isRandom\n * @property {Array.<number>} observedDistribution the cumulative distribution of observed features,\n * the index represents the number of features in the quadrat.\n */\n\n/**\n * inBBox from @turf/boolean-point-in-polygon\n *\n * @private\n * @param {Array<number>} pt point [x,y]\n * @param {BBox} bbox BBox [west, south, east, north]\n * @returns {boolean} true/false if point is inside BBox\n */\nfunction inBBox(pt: number[], bbox: BBox) {\n return (\n bbox[0] <= pt[0] && bbox[1] <= pt[1] && bbox[2] >= pt[0] && bbox[3] >= pt[1]\n );\n}\n\n/**\n * https://stackoverflow.com/questions/3959211/fast-factorial-function-in-javascript\n * @private\n * @param {number} num Number\n * @returns {number} the factorial of num\n */\nfunction factorial(num: number) {\n const f: number[] = [];\n function inner(n: number): number {\n if (n === 0 || n === 1) {\n return 1;\n }\n if (f[n] > 0) {\n return f[n];\n }\n return (f[n] = inner(n - 1) * n);\n }\n return inner(num);\n}\n\nexport { QuadratAnalysisResult, quadratAnalysis };\nexport default quadratAnalysis;\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turf/quadrat-analysis",
3
- "version": "7.0.0-alpha.2",
3
+ "version": "7.1.0-alpha.7+0ce6ecca0",
4
4
  "description": "turf quadrat-analysis module",
5
5
  "author": "Turf Authors",
6
6
  "contributors": [
@@ -23,53 +23,58 @@
23
23
  "turf",
24
24
  "quadrat-analysis"
25
25
  ],
26
- "main": "dist/js/index.js",
27
- "module": "dist/es/index.js",
26
+ "type": "module",
27
+ "main": "dist/cjs/index.cjs",
28
+ "module": "dist/esm/index.js",
29
+ "types": "dist/esm/index.d.ts",
28
30
  "exports": {
29
31
  "./package.json": "./package.json",
30
32
  ".": {
31
- "types": "./dist/js/index.d.ts",
32
- "import": "./dist/es/index.js",
33
- "require": "./dist/js/index.js"
33
+ "import": {
34
+ "types": "./dist/esm/index.d.ts",
35
+ "default": "./dist/esm/index.js"
36
+ },
37
+ "require": {
38
+ "types": "./dist/cjs/index.d.cts",
39
+ "default": "./dist/cjs/index.cjs"
40
+ }
34
41
  }
35
42
  },
36
- "types": "dist/js/index.d.ts",
37
43
  "sideEffects": false,
38
44
  "files": [
39
45
  "dist"
40
46
  ],
41
47
  "scripts": {
42
- "bench": "tsx bench.js",
43
- "build": "npm-run-all build:*",
44
- "build:es": "tsc --outDir dist/es --module esnext --declaration false && echo '{\"type\":\"module\"}' > dist/es/package.json",
45
- "build:js": "tsc",
46
- "docs": "tsx ../../scripts/generate-readmes",
47
- "test": "npm-run-all test:*",
48
- "test:tape": "tsx test.js"
48
+ "bench": "tsx bench.ts",
49
+ "build": "tsup --config ../../tsup.config.ts",
50
+ "docs": "tsx ../../scripts/generate-readmes.ts",
51
+ "test": "npm-run-all --npm-path npm test:*",
52
+ "test:tape": "tsx test.ts"
49
53
  },
50
54
  "devDependencies": {
51
- "@turf/nearest-neighbor-analysis": "^7.0.0-alpha.2",
52
- "@types/tape": "*",
53
- "benchmark": "*",
54
- "load-json-file": "*",
55
- "npm-run-all": "*",
56
- "tape": "*",
57
- "tslint": "*",
58
- "tsx": "*",
59
- "typescript": "*",
60
- "write-json-file": "*"
55
+ "@turf/nearest-neighbor-analysis": "^7.1.0-alpha.7+0ce6ecca0",
56
+ "@types/benchmark": "^2.1.5",
57
+ "@types/tape": "^4.2.32",
58
+ "benchmark": "^2.1.4",
59
+ "load-json-file": "^7.0.1",
60
+ "npm-run-all": "^4.1.5",
61
+ "tape": "^5.7.2",
62
+ "tsup": "^8.0.1",
63
+ "tsx": "^4.6.2",
64
+ "typescript": "^5.2.2",
65
+ "write-json-file": "^5.0.0"
61
66
  },
62
67
  "dependencies": {
63
- "@turf/area": "^7.0.0-alpha.2",
64
- "@turf/bbox": "^7.0.0-alpha.2",
65
- "@turf/bbox-polygon": "^7.0.0-alpha.2",
66
- "@turf/centroid": "^7.0.0-alpha.2",
67
- "@turf/helpers": "^7.0.0-alpha.2",
68
- "@turf/invariant": "^7.0.0-alpha.2",
69
- "@turf/point-grid": "^7.0.0-alpha.2",
70
- "@turf/random": "^7.0.0-alpha.2",
71
- "@turf/square-grid": "^7.0.0-alpha.2",
72
- "tslib": "^2.3.0"
68
+ "@turf/area": "^7.1.0-alpha.7+0ce6ecca0",
69
+ "@turf/bbox": "^7.1.0-alpha.7+0ce6ecca0",
70
+ "@turf/bbox-polygon": "^7.1.0-alpha.7+0ce6ecca0",
71
+ "@turf/centroid": "^7.1.0-alpha.7+0ce6ecca0",
72
+ "@turf/helpers": "^7.1.0-alpha.7+0ce6ecca0",
73
+ "@turf/invariant": "^7.1.0-alpha.7+0ce6ecca0",
74
+ "@turf/point-grid": "^7.1.0-alpha.7+0ce6ecca0",
75
+ "@turf/random": "^7.1.0-alpha.7+0ce6ecca0",
76
+ "@turf/square-grid": "^7.1.0-alpha.7+0ce6ecca0",
77
+ "tslib": "^2.6.2"
73
78
  },
74
- "gitHead": "dd35b52725945b4fa29a98d9a550733e06cc222e"
79
+ "gitHead": "0ce6ecca05829690270fec6d6bed2003495fe0ea"
75
80
  }
package/dist/es/index.js DELETED
@@ -1,187 +0,0 @@
1
- import area from "@turf/area";
2
- import turfBBox from "@turf/bbox";
3
- import bboxPolygon from "@turf/bbox-polygon";
4
- import { getCoord } from "@turf/invariant";
5
- import squareGrid from "@turf/square-grid";
6
- /**
7
- * Quadrat analysis lays a set of equal-size areas(quadrat) over the study area and counts
8
- * the number of features in each quadrat and creates a frequency table.
9
- * The table lists the number of quadrats containing no features,
10
- * the number containing one feature, two features, and so on,
11
- * all the way up to the quadrat containing the most features.
12
- * The method then creates the frequency table for the random distribution, usually based on a Poisson distribution.
13
- * The method uses the distribution to calculate the probability for 0 feature occuring,
14
- * 1 feature occuring, 2 features, and so on,
15
- * and lists these probabilities in the frequency table.
16
- * By comparing the two frequency tables, you can see whether the features create a pattern.
17
- * If the table for the observed distribution has more quadrats containing many features than the
18
- * table for the random distribution dose, then the features create a clustered pattern.
19
- *
20
- * It is hard to judge the frequency tables are similar or different just by looking at them.
21
- * So, we can use serval statistical tests to find out how much the frequency tables differ.
22
- * We use Kolmogorov-Smirnov test.This method calculates cumulative probabilities for both distributions,
23
- * and then compares the cumulative probabilities at each class level and selects the largest absolute difference D.
24
- * Then, the test compares D to the critical value for a confidence level you specify.
25
- * If D is greater than the critical value, the difference between the observed distribution and
26
- * the random distribution is significant. The greater the value the bigger the difference.
27
- *
28
- * Traditionally, squares are used for the shape of the quadrats, in a regular grid(square-grid).
29
- * Some researchers suggest that the quadrat size equal twice the size of mean area per feature,
30
- * which is simply the area of the study area divided by the number of features.
31
- *
32
- *
33
- * @name quadratAnalysis
34
- * @param {FeatureCollection<Point>} pointFeatureSet point set to study
35
- * @param {Object} [options={}] optional parameters
36
- * @param {bbox} [options.studyBbox] bbox representing the study area
37
- * @param {number} [options.confidenceLevel=20] a confidence level.
38
- * The unit is percentage . 5 means 95%, value must be in {@link K_TABLE}
39
- * @returns {Object} result {@link QuadratAnalysisResult}
40
- * @example
41
- *
42
- * var bbox = [-65, 40, -63, 42];
43
- * var dataset = turf.randomPoint(100, { bbox: bbox });
44
- * var result = turf.quadratAnalysis(dataset);
45
- *
46
- */
47
- export default function quadratAnalysis(pointFeatureSet, options) {
48
- options = options || {};
49
- const studyBbox = options.studyBbox || turfBBox(pointFeatureSet);
50
- const confidenceLevel = options.confidenceLevel || 20;
51
- const points = pointFeatureSet.features;
52
- // create square-grid
53
- const numOfPoints = points.length;
54
- const sizeOfArea = area(bboxPolygon(studyBbox));
55
- const lengthOfSide = Math.sqrt((sizeOfArea / numOfPoints) * 2);
56
- const grid = squareGrid(studyBbox, lengthOfSide, {
57
- units: "meters",
58
- });
59
- const quadrats = grid.features;
60
- // count the number of features in each quadrat
61
- const quadratIdDict = {};
62
- for (let i = 0; i < quadrats.length; i++) {
63
- quadratIdDict[i] = {
64
- box: turfBBox(quadrats[i]),
65
- cnt: 0,
66
- };
67
- }
68
- let sumOfPoint = 0;
69
- for (const pt of points) {
70
- for (const key of Object.keys(quadratIdDict)) {
71
- const box = quadratIdDict[key].box;
72
- if (inBBox(getCoord(pt), box)) {
73
- quadratIdDict[key].cnt += 1;
74
- sumOfPoint += 1;
75
- break;
76
- }
77
- }
78
- }
79
- // the most amount of features in quadrat
80
- let maxCnt = 0;
81
- for (const key of Object.keys(quadratIdDict)) {
82
- const cnt = quadratIdDict[key].cnt;
83
- if (cnt > maxCnt) {
84
- maxCnt = cnt;
85
- }
86
- }
87
- const expectedDistribution = [];
88
- const numOfQuadrat = Object.keys(quadratIdDict).length;
89
- const lambda = sumOfPoint / numOfQuadrat;
90
- // get the cumulative probability of the random distribution
91
- let cumulativeProbility = 0.0;
92
- for (let x = 0; x < maxCnt + 1; x++) {
93
- cumulativeProbility +=
94
- (Math.exp(-lambda) * Math.pow(lambda, x)) / factorial(x);
95
- expectedDistribution.push(cumulativeProbility);
96
- }
97
- // get the cumulative probability of the observed distribution
98
- const observedDistribution = [];
99
- let cumulativeObservedQuads = 0;
100
- for (let x = 0; x < maxCnt + 1; x++) {
101
- for (const key of Object.keys(quadratIdDict)) {
102
- if (quadratIdDict[key].cnt === x) {
103
- cumulativeObservedQuads += 1;
104
- }
105
- }
106
- const p = cumulativeObservedQuads / numOfQuadrat;
107
- observedDistribution.push(p);
108
- }
109
- // get the largest absolute difference between two distributions
110
- let maxDifference = 0;
111
- for (let x = 0; x < maxCnt + 1; x++) {
112
- const difference = Math.abs(expectedDistribution[x] - observedDistribution[x]);
113
- if (difference > maxDifference) {
114
- maxDifference = difference;
115
- }
116
- }
117
- const k = K_TABLE[confidenceLevel];
118
- // statistical test
119
- const criticalValue = k / Math.sqrt(numOfQuadrat);
120
- const result = {
121
- criticalValue,
122
- isRandom: true,
123
- maxAbsoluteDifference: maxDifference,
124
- observedDistribution,
125
- };
126
- if (maxDifference > criticalValue) {
127
- result.isRandom = false;
128
- }
129
- return result;
130
- }
131
- /**
132
- * the confidence level
133
- * @type {Object} K_TABLE
134
- * @property {number} 20
135
- * @property {number} 15
136
- * @property {number} 10
137
- * @property {number} 5
138
- * @property {number} 2
139
- * @property {number} 1
140
- */
141
- const K_TABLE = {
142
- 20: 1.07275,
143
- 15: 1.13795,
144
- 10: 1.22385,
145
- 5: 1.3581,
146
- 2: 1.51743,
147
- 1: 1.62762,
148
- };
149
- /**
150
- * the return type of the quadratAnalysis
151
- * @typedef {Object} QuadratAnalysisResult
152
- * @property {number} criticalValue
153
- * @property {number} maxAbsoluteDifference
154
- * @property {boolean} isRandom
155
- * @property {Array.<number>} observedDistribution the cumulative distribution of observed features,
156
- * the index represents the number of features in the quadrat.
157
- */
158
- /**
159
- * inBBox from @turf/boolean-point-in-polygon
160
- *
161
- * @private
162
- * @param {Array<number>} pt point [x,y]
163
- * @param {BBox} bbox BBox [west, south, east, north]
164
- * @returns {boolean} true/false if point is inside BBox
165
- */
166
- function inBBox(pt, bbox) {
167
- return (bbox[0] <= pt[0] && bbox[1] <= pt[1] && bbox[2] >= pt[0] && bbox[3] >= pt[1]);
168
- }
169
- /**
170
- * https://stackoverflow.com/questions/3959211/fast-factorial-function-in-javascript
171
- * @private
172
- * @param {number} num Number
173
- * @returns {number} the factorial of num
174
- */
175
- function factorial(num) {
176
- const f = [];
177
- function inner(n) {
178
- if (n === 0 || n === 1) {
179
- return 1;
180
- }
181
- if (f[n] > 0) {
182
- return f[n];
183
- }
184
- return (f[n] = inner(n - 1) * n);
185
- }
186
- return inner(num);
187
- }
@@ -1 +0,0 @@
1
- {"type":"module"}
package/dist/js/index.js DELETED
@@ -1,191 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- const area_1 = tslib_1.__importDefault(require("@turf/area"));
5
- const bbox_1 = tslib_1.__importDefault(require("@turf/bbox"));
6
- const bbox_polygon_1 = tslib_1.__importDefault(require("@turf/bbox-polygon"));
7
- const invariant_1 = require("@turf/invariant");
8
- const square_grid_1 = tslib_1.__importDefault(require("@turf/square-grid"));
9
- /**
10
- * Quadrat analysis lays a set of equal-size areas(quadrat) over the study area and counts
11
- * the number of features in each quadrat and creates a frequency table.
12
- * The table lists the number of quadrats containing no features,
13
- * the number containing one feature, two features, and so on,
14
- * all the way up to the quadrat containing the most features.
15
- * The method then creates the frequency table for the random distribution, usually based on a Poisson distribution.
16
- * The method uses the distribution to calculate the probability for 0 feature occuring,
17
- * 1 feature occuring, 2 features, and so on,
18
- * and lists these probabilities in the frequency table.
19
- * By comparing the two frequency tables, you can see whether the features create a pattern.
20
- * If the table for the observed distribution has more quadrats containing many features than the
21
- * table for the random distribution dose, then the features create a clustered pattern.
22
- *
23
- * It is hard to judge the frequency tables are similar or different just by looking at them.
24
- * So, we can use serval statistical tests to find out how much the frequency tables differ.
25
- * We use Kolmogorov-Smirnov test.This method calculates cumulative probabilities for both distributions,
26
- * and then compares the cumulative probabilities at each class level and selects the largest absolute difference D.
27
- * Then, the test compares D to the critical value for a confidence level you specify.
28
- * If D is greater than the critical value, the difference between the observed distribution and
29
- * the random distribution is significant. The greater the value the bigger the difference.
30
- *
31
- * Traditionally, squares are used for the shape of the quadrats, in a regular grid(square-grid).
32
- * Some researchers suggest that the quadrat size equal twice the size of mean area per feature,
33
- * which is simply the area of the study area divided by the number of features.
34
- *
35
- *
36
- * @name quadratAnalysis
37
- * @param {FeatureCollection<Point>} pointFeatureSet point set to study
38
- * @param {Object} [options={}] optional parameters
39
- * @param {bbox} [options.studyBbox] bbox representing the study area
40
- * @param {number} [options.confidenceLevel=20] a confidence level.
41
- * The unit is percentage . 5 means 95%, value must be in {@link K_TABLE}
42
- * @returns {Object} result {@link QuadratAnalysisResult}
43
- * @example
44
- *
45
- * var bbox = [-65, 40, -63, 42];
46
- * var dataset = turf.randomPoint(100, { bbox: bbox });
47
- * var result = turf.quadratAnalysis(dataset);
48
- *
49
- */
50
- function quadratAnalysis(pointFeatureSet, options) {
51
- options = options || {};
52
- const studyBbox = options.studyBbox || bbox_1.default(pointFeatureSet);
53
- const confidenceLevel = options.confidenceLevel || 20;
54
- const points = pointFeatureSet.features;
55
- // create square-grid
56
- const numOfPoints = points.length;
57
- const sizeOfArea = area_1.default(bbox_polygon_1.default(studyBbox));
58
- const lengthOfSide = Math.sqrt((sizeOfArea / numOfPoints) * 2);
59
- const grid = square_grid_1.default(studyBbox, lengthOfSide, {
60
- units: "meters",
61
- });
62
- const quadrats = grid.features;
63
- // count the number of features in each quadrat
64
- const quadratIdDict = {};
65
- for (let i = 0; i < quadrats.length; i++) {
66
- quadratIdDict[i] = {
67
- box: bbox_1.default(quadrats[i]),
68
- cnt: 0,
69
- };
70
- }
71
- let sumOfPoint = 0;
72
- for (const pt of points) {
73
- for (const key of Object.keys(quadratIdDict)) {
74
- const box = quadratIdDict[key].box;
75
- if (inBBox(invariant_1.getCoord(pt), box)) {
76
- quadratIdDict[key].cnt += 1;
77
- sumOfPoint += 1;
78
- break;
79
- }
80
- }
81
- }
82
- // the most amount of features in quadrat
83
- let maxCnt = 0;
84
- for (const key of Object.keys(quadratIdDict)) {
85
- const cnt = quadratIdDict[key].cnt;
86
- if (cnt > maxCnt) {
87
- maxCnt = cnt;
88
- }
89
- }
90
- const expectedDistribution = [];
91
- const numOfQuadrat = Object.keys(quadratIdDict).length;
92
- const lambda = sumOfPoint / numOfQuadrat;
93
- // get the cumulative probability of the random distribution
94
- let cumulativeProbility = 0.0;
95
- for (let x = 0; x < maxCnt + 1; x++) {
96
- cumulativeProbility +=
97
- (Math.exp(-lambda) * Math.pow(lambda, x)) / factorial(x);
98
- expectedDistribution.push(cumulativeProbility);
99
- }
100
- // get the cumulative probability of the observed distribution
101
- const observedDistribution = [];
102
- let cumulativeObservedQuads = 0;
103
- for (let x = 0; x < maxCnt + 1; x++) {
104
- for (const key of Object.keys(quadratIdDict)) {
105
- if (quadratIdDict[key].cnt === x) {
106
- cumulativeObservedQuads += 1;
107
- }
108
- }
109
- const p = cumulativeObservedQuads / numOfQuadrat;
110
- observedDistribution.push(p);
111
- }
112
- // get the largest absolute difference between two distributions
113
- let maxDifference = 0;
114
- for (let x = 0; x < maxCnt + 1; x++) {
115
- const difference = Math.abs(expectedDistribution[x] - observedDistribution[x]);
116
- if (difference > maxDifference) {
117
- maxDifference = difference;
118
- }
119
- }
120
- const k = K_TABLE[confidenceLevel];
121
- // statistical test
122
- const criticalValue = k / Math.sqrt(numOfQuadrat);
123
- const result = {
124
- criticalValue,
125
- isRandom: true,
126
- maxAbsoluteDifference: maxDifference,
127
- observedDistribution,
128
- };
129
- if (maxDifference > criticalValue) {
130
- result.isRandom = false;
131
- }
132
- return result;
133
- }
134
- exports.default = quadratAnalysis;
135
- /**
136
- * the confidence level
137
- * @type {Object} K_TABLE
138
- * @property {number} 20
139
- * @property {number} 15
140
- * @property {number} 10
141
- * @property {number} 5
142
- * @property {number} 2
143
- * @property {number} 1
144
- */
145
- const K_TABLE = {
146
- 20: 1.07275,
147
- 15: 1.13795,
148
- 10: 1.22385,
149
- 5: 1.3581,
150
- 2: 1.51743,
151
- 1: 1.62762,
152
- };
153
- /**
154
- * the return type of the quadratAnalysis
155
- * @typedef {Object} QuadratAnalysisResult
156
- * @property {number} criticalValue
157
- * @property {number} maxAbsoluteDifference
158
- * @property {boolean} isRandom
159
- * @property {Array.<number>} observedDistribution the cumulative distribution of observed features,
160
- * the index represents the number of features in the quadrat.
161
- */
162
- /**
163
- * inBBox from @turf/boolean-point-in-polygon
164
- *
165
- * @private
166
- * @param {Array<number>} pt point [x,y]
167
- * @param {BBox} bbox BBox [west, south, east, north]
168
- * @returns {boolean} true/false if point is inside BBox
169
- */
170
- function inBBox(pt, bbox) {
171
- return (bbox[0] <= pt[0] && bbox[1] <= pt[1] && bbox[2] >= pt[0] && bbox[3] >= pt[1]);
172
- }
173
- /**
174
- * https://stackoverflow.com/questions/3959211/fast-factorial-function-in-javascript
175
- * @private
176
- * @param {number} num Number
177
- * @returns {number} the factorial of num
178
- */
179
- function factorial(num) {
180
- const f = [];
181
- function inner(n) {
182
- if (n === 0 || n === 1) {
183
- return 1;
184
- }
185
- if (f[n] > 0) {
186
- return f[n];
187
- }
188
- return (f[n] = inner(n - 1) * n);
189
- }
190
- return inner(num);
191
- }