{"version":3,"sources":["../../index.ts"],"sourcesContent":["import { FeatureCollection } from \"geojson\";\nimport { distanceWeight as spatialWeight } from \"@turf/distance-weight\";\nimport { featureEach } from \"@turf/meta\";\n\n/**\n * @typedef {object} MoranIndex\n * @property {number} moranIndex the moran's Index of the observed feature set\n * @property {number} expectedMoranIndex the moran's Index of the random distribution\n * @property {number} stdNorm the standard devitaion of the random distribution\n * @property {number} zNorm the z-score of the observe samples with regard to the random distribution\n */\ntype MoranIndex = {\n moranIndex: number;\n expectedMoranIndex: number;\n stdNorm: number;\n zNorm: number;\n};\n\n/**\n * Moran's I measures patterns of attribute values associated with features.\n * The method reveal whether similar values tend to occur near each other,\n * or whether high or low values are interspersed.\n *\n * Moran's I > 0 means a clusterd pattern.\n * Moran's I < 0 means a dispersed pattern.\n * Moran's I = 0 means a random pattern.\n *\n * In order to test the significance of the result. The z score is calculated.\n * A positive enough z-score (ex. >1.96) indicates clustering,\n * while a negative enough z-score (ex. <-1.96) indicates a dispersed pattern.\n *\n * the z-score can be calculated based on a normal or random assumption.\n *\n * **Bibliography***\n *\n * 1. [Moran's I](https://en.wikipedia.org/wiki/Moran%27s_I)\n *\n * 2. [pysal](http://pysal.readthedocs.io/en/latest/index.html)\n *\n * 3. Andy Mitchell, The ESRI Guide to GIS Analysis Volume 2: Spatial Measurements & Statistics.\n *\n * @function\n * @param {FeatureCollection} fc\n * @param {Object} options\n * @param {string} options.inputField the property name, must contain numeric values\n * @param {number} [options.threshold=100000] the distance threshold\n * @param {number} [options.p=2] the Minkowski p-norm distance parameter\n * @param {boolean} [options.binary=false] whether transfrom the distance to binary\n * @param {number} [options.alpha=-1] the distance decay parameter\n * @param {boolean} [options.standardization=true] wheter row standardization the distance\n * @returns {MoranIndex}\n * @example\n *\n * const bbox = [-65, 40, -63, 42];\n * const dataset = turf.randomPoint(100, { bbox: bbox });\n *\n * const result = turf.moranIndex(dataset, {\n * inputField: 'CRIME',\n * });\n */\n\nfunction moranIndex(\n fc: FeatureCollection,\n options: {\n inputField: string;\n threshold?: number;\n p?: number;\n binary?: boolean;\n alpha?: number;\n standardization?: boolean;\n }\n): MoranIndex {\n const inputField = options.inputField;\n const threshold = options.threshold || 100000;\n const p = options.p || 2;\n const binary = options.binary ?? false;\n const alpha = options.alpha || -1;\n const standardization = options.standardization ?? true;\n\n const weight = spatialWeight(fc, {\n alpha,\n binary,\n p,\n standardization,\n threshold,\n });\n\n const y: number[] = [];\n featureEach(fc, (feature) => {\n const feaProperties = feature.properties || {};\n // validate inputField exists\n y.push(feaProperties[inputField]);\n });\n\n const yMean = mean(y);\n const yVar = variance(y);\n let weightSum = 0;\n let s0 = 0;\n let s1 = 0;\n let s2 = 0;\n const n = weight.length;\n // validate y.length is the same as weight.length\n for (let i = 0; i < n; i++) {\n let subS2 = 0;\n for (let j = 0; j < n; j++) {\n weightSum += weight[i][j] * (y[i] - yMean) * (y[j] - yMean);\n s0 += weight[i][j];\n s1 += Math.pow(weight[i][j] + weight[j][i], 2);\n subS2 += weight[i][j] + weight[j][i];\n }\n s2 += Math.pow(subS2, 2);\n }\n s1 = 0.5 * s1;\n\n const moranIndex = weightSum / s0 / yVar;\n const expectedMoranIndex = -1 / (n - 1);\n const vNum = n * n * s1 - n * s2 + 3 * (s0 * s0);\n const vDen = (n - 1) * (n + 1) * (s0 * s0);\n const vNorm = vNum / vDen - expectedMoranIndex * expectedMoranIndex;\n const stdNorm = Math.sqrt(vNorm);\n const zNorm = (moranIndex - expectedMoranIndex) / stdNorm;\n\n return {\n expectedMoranIndex,\n moranIndex,\n stdNorm,\n zNorm,\n };\n}\n\n/**\n * get mean of a list\n *\n * @private\n * @param {number[]} y\n * @returns {number}\n *\n */\nfunction mean(y: number[]): number {\n let sum = 0;\n for (const item of y) {\n sum += item;\n }\n return sum / y.length;\n}\n/**\n * get variance of a list\n *\n * @private\n * @param {number[]} y\n * @returns {number}\n *\n */\nfunction variance(y: number[]): number {\n const yMean = mean(y);\n let sum = 0;\n for (const item of y) {\n sum += Math.pow(item - yMean, 2);\n }\n return sum / y.length;\n}\n\nexport { moranIndex, MoranIndex };\nexport default moranIndex;\n"],"mappings":";AACA,SAAS,kBAAkB,qBAAqB;AAChD,SAAS,mBAAmB;AA2D5B,SAAS,WACP,IACA,SAQY;AAvEd;AAwEE,QAAM,aAAa,QAAQ;AAC3B,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,IAAI,QAAQ,KAAK;AACvB,QAAM,UAAS,aAAQ,WAAR,YAAkB;AACjC,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,mBAAkB,aAAQ,oBAAR,YAA2B;AAEnD,QAAM,SAAS,cAAc,IAAI;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,IAAc,CAAC;AACrB,cAAY,IAAI,CAAC,YAAY;AAC3B,UAAM,gBAAgB,QAAQ,cAAc,CAAC;AAE7C,MAAE,KAAK,cAAc,UAAU,CAAC;AAAA,EAClC,CAAC;AAED,QAAM,QAAQ,KAAK,CAAC;AACpB,QAAM,OAAO,SAAS,CAAC;AACvB,MAAI,YAAY;AAChB,MAAI,KAAK;AACT,MAAI,KAAK;AACT,MAAI,KAAK;AACT,QAAM,IAAI,OAAO;AAEjB,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,QAAQ;AACZ,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,mBAAa,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC,IAAI;AACrD,YAAM,OAAO,CAAC,EAAE,CAAC;AACjB,YAAM,KAAK,IAAI,OAAO,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC;AAC7C,eAAS,OAAO,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,EAAE,CAAC;AAAA,IACrC;AACA,UAAM,KAAK,IAAI,OAAO,CAAC;AAAA,EACzB;AACA,OAAK,MAAM;AAEX,QAAMA,cAAa,YAAY,KAAK;AACpC,QAAM,qBAAqB,MAAM,IAAI;AACrC,QAAM,OAAO,IAAI,IAAI,KAAK,IAAI,KAAK,KAAK,KAAK;AAC7C,QAAM,QAAQ,IAAI,MAAM,IAAI,MAAM,KAAK;AACvC,QAAM,QAAQ,OAAO,OAAO,qBAAqB;AACjD,QAAM,UAAU,KAAK,KAAK,KAAK;AAC/B,QAAM,SAASA,cAAa,sBAAsB;AAElD,SAAO;AAAA,IACL;AAAA,IACA,YAAAA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAUA,SAAS,KAAK,GAAqB;AACjC,MAAI,MAAM;AACV,aAAW,QAAQ,GAAG;AACpB,WAAO;AAAA,EACT;AACA,SAAO,MAAM,EAAE;AACjB;AASA,SAAS,SAAS,GAAqB;AACrC,QAAM,QAAQ,KAAK,CAAC;AACpB,MAAI,MAAM;AACV,aAAW,QAAQ,GAAG;AACpB,WAAO,KAAK,IAAI,OAAO,OAAO,CAAC;AAAA,EACjC;AACA,SAAO,MAAM,EAAE;AACjB;AAGA,IAAO,2BAAQ;","names":["moranIndex"]}