ml-spectra-processing
Advanced tools
Comparing version 0.4.0 to 0.5.0
200
lib/index.js
@@ -491,2 +491,124 @@ 'use strict'; | ||
/** | ||
* Finds all the max values | ||
* If the values are equal the middle | ||
* of the equal part will be the position of the signal! | ||
* | ||
* @param {object} [points={}] - Object of points contains property x (an ordered increasing array) and y (an array) | ||
* @return {Array} Array of points | ||
*/ | ||
function maximaY(points = {}) { | ||
check(points); | ||
const { x, y } = points; | ||
if (x.length < 3) return []; | ||
let maxima = []; | ||
let startEqualIndex = -1; | ||
for (let i = 1; i < x.length - 1; i++) { | ||
if (y[i - 1] < y[i] && y[i + 1] < y[i]) { | ||
maxima.push({ x: x[i], y: y[i], index: i }); | ||
} else if (y[i - 1] < y[i] && y[i + 1] === y[i]) { | ||
startEqualIndex = i; | ||
} else if (y[i - 1] === y[i] && y[i + 1] < y[i]) { | ||
let index = ((i + startEqualIndex) / 2) >> 0; | ||
maxima.push({ x: x[index], y: y[index], index }); | ||
} | ||
} | ||
return maxima; | ||
} | ||
/** | ||
* Finds all the min values | ||
* If the values are equal the middle | ||
* of the equal part will be the position of the signal! | ||
* | ||
* @param {object} [points={}] - Object of points contains property x (an ordered increasing array) and y (an array) | ||
* @return {Array} Array of points | ||
*/ | ||
function minimaY(points = {}) { | ||
check(points); | ||
const { x, y } = points; | ||
if (x.length < 3) return []; | ||
let maxima = []; | ||
let startEqualIndex = -1; | ||
for (let i = 1; i < x.length - 1; i++) { | ||
if (y[i - 1] > y[i] && y[i + 1] > y[i]) { | ||
maxima.push({ x: x[i], y: y[i], index: i }); | ||
} else if (y[i - 1] > y[i] && y[i + 1] === y[i]) { | ||
startEqualIndex = i; | ||
} else if (y[i - 1] === y[i] && y[i + 1] > y[i]) { | ||
let index = ((i + startEqualIndex) / 2) >> 0; | ||
maxima.push({ x: x[index], y: y[index], index }); | ||
} | ||
} | ||
return maxima; | ||
} | ||
/** | ||
* Returns an information about a signal | ||
* | ||
* We expect ordered data and equidistant X axis | ||
* You can use the method helper if required: | ||
* ML.ArrayXY.uniqueX | ||
* ML.ArrayXY.sortX | ||
* ML.ArrayXY.equallySpaced | ||
* | ||
* @param {object} [points={}] - Object of points contains property x (an ordered increasing array) and y (an array) | ||
* @param {object} [options={}] | ||
* @param {number} [options.target] | ||
* @param {number} [options.targetIndex] | ||
* @return {object} Information about signal | ||
*/ | ||
function peakInfo(points = {}, options = {}) { | ||
check(points); | ||
const { x, y } = points; | ||
if (x.length < 3) return undefined; | ||
let { targetIndex, target } = options; | ||
if (targetIndex === undefined) { | ||
if (target !== undefined) { | ||
targetIndex = findClosestIndex(x, target); | ||
} | ||
} | ||
if (targetIndex === undefined) { | ||
throw new Error('peakInfo: need to specify target or targetIndex'); | ||
} | ||
let i = targetIndex; | ||
let currentDiff = y[i] - y[i + 1]; | ||
let multiplier = currentDiff < 0 ? -1 : 1; | ||
currentDiff *= multiplier; | ||
while (i < x.length - 1) { | ||
i++; | ||
let newDiff = (y[i] - y[i + 1]) * multiplier; | ||
if (newDiff < currentDiff) break; | ||
currentDiff = newDiff; | ||
} | ||
let after = { x: x[i], y: y[i] }; | ||
i = targetIndex; | ||
currentDiff = (y[i] - y[i - 1]) * multiplier; | ||
while (i > 1) { | ||
i--; | ||
let newDiff = (y[i] - y[i - 1]) * multiplier; | ||
if (newDiff < currentDiff) break; | ||
currentDiff = newDiff; | ||
} | ||
let before = { x: x[i], y: y[i] }; | ||
return { | ||
inflectionBefore: before, | ||
inflectionAfter: after, | ||
extrema: { x: x[targetIndex], y: y[targetIndex] }, | ||
inflectionMiddle: { | ||
x: (before.x + after.x) / 2, | ||
y: (before.y + after.y) / 2, | ||
}, | ||
width: Math.abs(before.x - after.x), | ||
}; | ||
} | ||
const XY = { | ||
@@ -497,3 +619,5 @@ check, | ||
maxY, | ||
maximaY, | ||
maxYPoint, | ||
minimaY, | ||
minYPoint, | ||
@@ -506,2 +630,3 @@ reduce, | ||
realMinYPoint, | ||
peakInfo, | ||
}; | ||
@@ -523,3 +648,3 @@ | ||
re: data.re.slice(0, zeroFilling), | ||
im: data.im.slice(0, zeroFilling) | ||
im: data.im.slice(0, zeroFilling), | ||
}; | ||
@@ -549,3 +674,3 @@ } | ||
re: newRE, | ||
im: newIM | ||
im: newIM, | ||
}; | ||
@@ -649,3 +774,5 @@ } | ||
if (Array.isArray(array2)) { | ||
if (array1.length !== array2.length) throw new Error('sub: size of array1 and array2 must be identical'); | ||
if (array1.length !== array2.length) { | ||
throw new Error('sub: size of array1 and array2 must be identical'); | ||
} | ||
} else { | ||
@@ -678,7 +805,16 @@ isConstant = true; | ||
if (array.length < 5) { | ||
throw Error('boxPlot: can not calculate info if array contains less than 3 elements'); | ||
throw Error( | ||
'boxPlot: can not calculate info if array contains less than 3 elements', | ||
); | ||
} | ||
let info = { Q1: 0.0, Q2: 0.0, Q3: 0.0, min: array[0], max: array[array.length - 1] }; | ||
let info = { | ||
Q1: 0.0, | ||
Q2: 0.0, | ||
Q3: 0.0, | ||
min: array[0], | ||
max: array[array.length - 1], | ||
}; | ||
let q1max, q3min; | ||
if (array.length % 2 === 1) { // odd | ||
if (array.length % 2 === 1) { | ||
// odd | ||
let middle = (array.length - 1) / 2; | ||
@@ -688,3 +824,4 @@ info.Q2 = array[middle]; | ||
q3min = middle + 1; | ||
} else { // even | ||
} else { | ||
// even | ||
q3min = array.length / 2; | ||
@@ -717,3 +854,5 @@ q1max = q3min - 1; | ||
if (Array.isArray(array2)) { | ||
if (array1.length !== array2.length) throw new Error('sub: size of array1 and array2 must be identical'); | ||
if (array1.length !== array2.length) { | ||
throw new Error('sub: size of array1 and array2 must be identical'); | ||
} | ||
} else { | ||
@@ -750,3 +889,5 @@ isConstant = true; | ||
if (Array.isArray(array2)) { | ||
if (array1.length !== array2.length) throw new Error('sub: size of array1 and array2 must be identical'); | ||
if (array1.length !== array2.length) { | ||
throw new Error('sub: size of array1 and array2 must be identical'); | ||
} | ||
} else { | ||
@@ -783,3 +924,5 @@ isConstant = true; | ||
if (shift < 0) shift += array.length; | ||
return array.slice(array.length - shift).concat(array.slice(0, array.length - shift)); | ||
return array | ||
.slice(array.length - shift) | ||
.concat(array.slice(0, array.length - shift)); | ||
} | ||
@@ -797,3 +940,5 @@ | ||
if (Array.isArray(array2)) { | ||
if (array1.length !== array2.length) throw new Error('sub: size of array1 and array2 must be identical'); | ||
if (array1.length !== array2.length) { | ||
throw new Error('sub: size of array1 and array2 must be identical'); | ||
} | ||
} else { | ||
@@ -818,2 +963,34 @@ isConstant = true; | ||
/** | ||
/** | ||
* Calculates the correlation between 2 vectors | ||
* https://en.wikipedia.org/wiki/Correlation_and_dependence | ||
* | ||
* @param {Array} [A] - the array that will be rotated | ||
* @param {Array} [B] | ||
* @return {Array} | ||
*/ | ||
function correlation(A, B) { | ||
let n = A.length; | ||
let sumA = 0; | ||
let sumA2 = 0; | ||
let sumB = 0; | ||
let sumB2 = 0; | ||
let sumAB = 0; | ||
for (let i = 0; i < n; i++) { | ||
let a = A[i]; | ||
let b = B[i]; | ||
sumA += a; | ||
sumA2 += a ** 2; | ||
sumB += b; | ||
sumB2 += b ** 2; | ||
sumAB += a * b; | ||
} | ||
return ( | ||
(n * sumAB - sumA * sumB) / | ||
(Math.sqrt(n * sumA2 - sumA ** 2) * Math.sqrt(n * sumB2 - sumB ** 2)) | ||
); | ||
} | ||
const X = { | ||
@@ -828,2 +1005,3 @@ add, | ||
subtract, | ||
correlation, | ||
}; | ||
@@ -830,0 +1008,0 @@ |
{ | ||
"name": "ml-spectra-processing", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Various method to process spectra", | ||
@@ -12,2 +12,3 @@ "main": "lib/index.js", | ||
"scripts": { | ||
"build": "rollup -c && cheminfo-build --root SpectraProcessing", | ||
"eslint": "eslint src", | ||
@@ -43,10 +44,13 @@ "eslint-fix": "npm run eslint -- --fix", | ||
"devDependencies": { | ||
"@babel/plugin-transform-modules-commonjs": "^7.5.0", | ||
"eslint": "^6.0.1", | ||
"eslint-config-cheminfo": "^1.20.1", | ||
"eslint-plugin-import": "^2.18.0", | ||
"eslint-plugin-jest": "^22.7.1", | ||
"@babel/plugin-transform-modules-commonjs": "^7.6.0", | ||
"cheminfo-build": "^1.0.3", | ||
"eslint": "^6.5.1", | ||
"eslint-config-cheminfo": "^2.0.3", | ||
"eslint-plugin-import": "^2.18.2", | ||
"eslint-plugin-jest": "^22.17.0", | ||
"eslint-plugin-prettier": "^3.1.1", | ||
"esm": "^3.2.25", | ||
"jest": "^24.8.0", | ||
"rollup": "^1.16.7" | ||
"jest": "^24.9.0", | ||
"prettier": "^1.18.2", | ||
"rollup": "^1.23.1" | ||
}, | ||
@@ -53,0 +57,0 @@ "dependencies": { |
@@ -13,3 +13,5 @@ /** | ||
if (Array.isArray(array2)) { | ||
if (array1.length !== array2.length) throw new Error('sub: size of array1 and array2 must be identical'); | ||
if (array1.length !== array2.length) { | ||
throw new Error('sub: size of array1 and array2 must be identical'); | ||
} | ||
} else { | ||
@@ -33,2 +35,1 @@ isConstant = true; | ||
} | ||
@@ -9,7 +9,16 @@ /** | ||
if (array.length < 5) { | ||
throw Error('boxPlot: can not calculate info if array contains less than 3 elements'); | ||
throw Error( | ||
'boxPlot: can not calculate info if array contains less than 3 elements', | ||
); | ||
} | ||
let info = { Q1: 0.0, Q2: 0.0, Q3: 0.0, min: array[0], max: array[array.length - 1] }; | ||
let info = { | ||
Q1: 0.0, | ||
Q2: 0.0, | ||
Q3: 0.0, | ||
min: array[0], | ||
max: array[array.length - 1], | ||
}; | ||
let q1max, q3min; | ||
if (array.length % 2 === 1) { // odd | ||
if (array.length % 2 === 1) { | ||
// odd | ||
let middle = (array.length - 1) / 2; | ||
@@ -19,3 +28,4 @@ info.Q2 = array[middle]; | ||
q3min = middle + 1; | ||
} else { // even | ||
} else { | ||
// even | ||
q3min = array.length / 2; | ||
@@ -35,2 +45,1 @@ q1max = q3min - 1; | ||
} | ||
@@ -13,3 +13,5 @@ /** | ||
if (Array.isArray(array2)) { | ||
if (array1.length !== array2.length) throw new Error('sub: size of array1 and array2 must be identical'); | ||
if (array1.length !== array2.length) { | ||
throw new Error('sub: size of array1 and array2 must be identical'); | ||
} | ||
} else { | ||
@@ -33,2 +35,1 @@ isConstant = true; | ||
} | ||
@@ -9,2 +9,3 @@ import { add } from './add'; | ||
import { subtract } from './subtract'; | ||
import { correlation } from './correlation'; | ||
@@ -20,2 +21,3 @@ export const X = { | ||
subtract, | ||
correlation, | ||
}; |
@@ -13,3 +13,5 @@ /** | ||
if (Array.isArray(array2)) { | ||
if (array1.length !== array2.length) throw new Error('sub: size of array1 and array2 must be identical'); | ||
if (array1.length !== array2.length) { | ||
throw new Error('sub: size of array1 and array2 must be identical'); | ||
} | ||
} else { | ||
@@ -33,2 +35,1 @@ isConstant = true; | ||
} | ||
@@ -13,4 +13,5 @@ /** | ||
if (shift < 0) shift += array.length; | ||
return array.slice(array.length - shift).concat(array.slice(0, array.length - shift)); | ||
return array | ||
.slice(array.length - shift) | ||
.concat(array.slice(0, array.length - shift)); | ||
} | ||
@@ -11,3 +11,5 @@ /** | ||
if (Array.isArray(array2)) { | ||
if (array1.length !== array2.length) throw new Error('sub: size of array1 and array2 must be identical'); | ||
if (array1.length !== array2.length) { | ||
throw new Error('sub: size of array1 and array2 must be identical'); | ||
} | ||
} else { | ||
@@ -31,2 +33,1 @@ isConstant = true; | ||
} | ||
@@ -15,3 +15,3 @@ /** | ||
re: data.re.slice(0, zeroFilling), | ||
im: data.im.slice(0, zeroFilling) | ||
im: data.im.slice(0, zeroFilling), | ||
}; | ||
@@ -41,5 +41,4 @@ } | ||
re: newRE, | ||
im: newIM | ||
im: newIM, | ||
}; | ||
} | ||
@@ -13,2 +13,5 @@ import { check } from './check'; | ||
import { realMaxYPoint } from './realMaxYPoint'; | ||
import { maximaY } from './maximaY'; | ||
import { minimaY } from './minimaY'; | ||
import { peakInfo } from './peakInfo'; | ||
@@ -20,3 +23,5 @@ export const XY = { | ||
maxY, | ||
maximaY, | ||
maxYPoint, | ||
minimaY, | ||
minYPoint, | ||
@@ -29,2 +34,3 @@ reduce, | ||
realMinYPoint, | ||
peakInfo, | ||
}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
61886
39
1807
11