Comparing version 1.1.5 to 2.0.0
{ | ||
"name": "ml-gsd", | ||
"version": "1.1.5", | ||
"version": "1.1.6", | ||
"description": "Global Spectra Deconvolution", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
{ | ||
"name": "ml-gsd", | ||
"version": "1.1.5", | ||
"version": "2.0.0", | ||
"description": "Global Spectra Deconvolution", | ||
@@ -11,2 +11,4 @@ "main": "src/index.js", | ||
"scripts": { | ||
"eslint": "eslint src test", | ||
"eslint-fix": "npm run eslint -- --fix", | ||
"test": "mocha --require should --reporter mocha-better-spec-reporter --recursive", | ||
@@ -27,2 +29,5 @@ "build": "cheminfo build --root GSD" | ||
"author": "Andres Castillo", | ||
"contributors": [ | ||
"Miguel Asencio <maasencioh@gmail.com> (https://github.com/maasencioh)" | ||
], | ||
"license": "MIT", | ||
@@ -34,6 +39,10 @@ "bugs": { | ||
"devDependencies": { | ||
"cheminfo-tools": "^1.0.2", | ||
"cheminfo-tools": "^1.3.1", | ||
"eslint": "^3.4.0", | ||
"eslint-config-cheminfo": "^1.1.2", | ||
"eslint-plugin-no-only-tests": "^1.1.0", | ||
"mocha": "^2.2.5", | ||
"mocha-better-spec-reporter": "^2.1.1", | ||
"should": "^7.0.2", | ||
"ml-stat": "^1.1.0", | ||
"chemcalc": "^3.0.6" | ||
@@ -43,3 +52,2 @@ }, | ||
"ml-optimize-lorentzian": "0.1.1", | ||
"ml-stat": "^1.1.0", | ||
"xy-parser": "^1.2.0", | ||
@@ -46,0 +54,0 @@ "ml-savitzky-golay-generalized": "1.1.0", |
# global-spectral-deconvolution | ||
[![NPM version][npm-image]][npm-url] | ||
[![build status][travis-image]][travis-url] | ||
[![David deps][david-image]][david-url] | ||
[![npm download][download-image]][download-url] | ||
Global Spectra Deconvolution + Peak optimizer | ||
@@ -8,6 +13,6 @@ | ||
#### minMaxRatio=0.00025 (0-1) | ||
Threshold to determine if a given peak should be considered as a noise, bases on its relative height compared to the higest peak. | ||
Threshold to determine if a given peak should be considered as a noise, bases on its relative height compared to the highest peak. | ||
#### broadRatio=0.00 (0-1) | ||
If broadRatio is higher than 0, then all the peaks which second derivative smaller than broadRatio*maxAbsSecondDerivative will be marked with the soft mask equal to true. | ||
If `broadRatio` is higher than 0, then all the peaks which second derivative smaller than `broadRatio * maxAbsSecondDerivative` will be marked with the soft mask equal to true. | ||
@@ -24,23 +29,52 @@ #### noiseLevel=0 (-inf, inf) | ||
#### realTopDetection=false [true||false] | ||
Use a cuadratic optmizations with the peak and its 3 closest neighbors to determine the true x,y values of the peak? | ||
Use a quadratic optimizations with the peak and its 3 closest neighbors to determine the true x,y values of the peak? | ||
#### sgOptions={windowSize: 5, polynomial: 3} | ||
Savitzky-Golay paramters. windowSize should be odd; polynomial is the degree of the polinomial to use in the approximations. > 2 | ||
Savitzky-Golay parameters. windowSize should be odd; polynomial is the degree of the polynomial to use in the approximations. It should be bigger than 2. | ||
#### heightFactor=0 | ||
Factor to multiply the calculated height (usually 2). | ||
#### boundaries=false | ||
Return also the inflection points of the peaks | ||
#### derivativeThreshold=0 | ||
Filters based on the amplitude of the first derivative | ||
## Example | ||
``` | ||
```js | ||
var CC = require('chemcalc'); | ||
var Stat = require('ml-stat'); | ||
var peakPicking = require("../src/index"); | ||
var peakPicking = require('ml-gsd'); | ||
var spectrum=CC.analyseMF("Cl2.Br2", {isotopomers:'arrayXXYY', fwhm:0.01, gaussianWidth: 11}); | ||
var xy=spectrum.arrayXXYY; | ||
var x=xy[0]; | ||
var y=xy[1]; | ||
var spectrum = CC.analyseMF("Cl2.Br2", {isotopomers:'arrayXXYY', fwhm:0.01, gaussianWidth: 11}); | ||
var xy = spectrum.arrayXXYY; | ||
var x = xy[0]; | ||
var y = xy[1]; | ||
//Just a fake noiseLevel | ||
var noiseLevel=Stat.array.median(y.filter(function(a) {return (a>0)}))*3; | ||
var noiseLevel = Stat.array.median(y.filter(function(a) {return (a > 0)})) * 3; | ||
var result=peakPicking.gsd(x, y, {noiseLevel: noiseLevel, minMaxRatio:0, broadRatio:0,smoothY:false,realTopDetection:true}); | ||
result = peakPicking.post.optimizePeaks(result,x,y,1,"gaussian"); | ||
var options = { | ||
noiseLevel: noiseLevel, | ||
minMaxRatio:0, | ||
broadRatio:0, | ||
smoothY:false, | ||
realTopDetection:true | ||
}; | ||
var result = peakPicking.gsd(x, y, options); | ||
result = peakPicking.post.optimizePeaks(result, x, y, 1, "gaussian"); | ||
``` | ||
## License | ||
[MIT](./LICENSE) | ||
[npm-image]: https://img.shields.io/npm/v/ml-gsd.svg?style=flat-square | ||
[npm-url]: https://npmjs.org/package/ml-gsd | ||
[travis-image]: https://img.shields.io/travis/mljs/global-spectral-deconvolution/master.svg?style=flat-square | ||
[travis-url]: https://travis-ci.org/mljs/global-spectral-deconvolution | ||
[david-image]: https://img.shields.io/david/mljs/global-spectral-deconvolution.svg?style=flat-square | ||
[david-url]: https://david-dm.org/mljs/global-spectral-deconvolution | ||
[download-image]: https://img.shields.io/npm/dm/ml-gsd.svg?style=flat-square | ||
[download-url]: https://npmjs.org/package/ml-gsd |
365
src/gsd.js
@@ -1,35 +0,58 @@ | ||
var Opt = require("ml-optimize-lorentzian"); | ||
var stats = require("ml-stat"); | ||
var extend = require('extend'); | ||
var SG = require('ml-savitzky-golay-generalized'); | ||
'use strict'; | ||
var sgDefOptions = { | ||
windowSize: 9, | ||
polynomial: 3 | ||
const extend = require('extend'); | ||
const SG = require('ml-savitzky-golay-generalized'); | ||
const defaultOptions = { | ||
sgOptions: { | ||
windowSize: 9, | ||
polynomial: 3 | ||
}, | ||
minMaxRatio: 0.00025, | ||
broadRatio: 0.00, | ||
maxCriteria: true, | ||
smoothY: true, | ||
realTopDetection: false, | ||
heightFactor: 0, | ||
boundaries: false, | ||
derivativeThreshold: -1 | ||
}; | ||
/** | ||
* Global spectra deconvolution | ||
* @param {Array<Number>} x - Independent variable | ||
* @param {Array<Number>} yIn - Dependent variable | ||
* @param {Object} [options] - Options object | ||
* @param {Object} [options.sgOptions] - Options object for Savitzky-Golay filter. See https://github.com/mljs/savitzky-golay-generalized#options | ||
* @param {Number} [options.sgOptions.windowSize = 9] - points to use in the approximations | ||
* @param {Number} [options.sgOptions.polynomial = 3] - degree of the polynomial to use in the approximations | ||
* @param {Number} [options.minMaxRatio = 0.00025] - Threshold to determine if a given peak should be considered as a noise | ||
* @param {Number} [options.broadRatio = 0.00] - If `broadRatio` is higher than 0, then all the peaks which second derivative | ||
* smaller than `broadRatio * maxAbsSecondDerivative` will be marked with the soft mask equal to true. | ||
* @param {Number} [options.noiseLevel = 0] - Noise threshold in spectrum units | ||
* @param {Boolean} [options.maxCriteria = true] - Peaks are local maximum(true) or minimum(false) | ||
* @param {Boolean} [options.smoothY = true] - Select the peak intensities from a smoothed version of the independent variables | ||
* @param {Boolean} [options.realTopDetection = false] - Use a quadratic optimizations with the peak and its 3 closest neighbors | ||
* to determine the true x,y values of the peak? | ||
* @param {Number} [options.heightFactor = 0] - Factor to multiply the calculated height (usually 2) | ||
* @param {Boolean} [options.boundaries = false] - Return also the inflection points of the peaks | ||
* @param {Number} [options.derivativeThreshold = -1] - Filters based on the amplitude of the first derivative | ||
* @return {Array<Object>} | ||
*/ | ||
function gsd(x, yIn, options) { | ||
options = extend({}, defaultOptions, options); | ||
let sgOptions = options.sgOptions; | ||
const y = [].concat(yIn); | ||
function gsd(x, y, options){ | ||
//options = extend({}, defaultOptions, options); | ||
var options=Object.create(options || {}); | ||
if (options.minMaxRatio===undefined) options.minMaxRatio=0.00025; | ||
if (options.broadRatio===undefined) options.broadRatio=0.00; | ||
if (options.noiseLevel===undefined) options.noiseLevel=undefined; | ||
if (options.noiseFactor===undefined) options.noiseFactor=3; | ||
if (options.maxCriteria===undefined) options.maxCriteria=true; | ||
if (options.smoothY===undefined) options.smoothY=true; | ||
if (options.realTopDetection===undefined) options.realTopDetection=false; | ||
var sgOptions = extend({}, sgDefOptions, options.sgOptions); | ||
//console.log(JSON.stringify(stats.array.minMax(y))); | ||
if(options.noiseLevel===undefined){ | ||
//We have to know if x is equally spaced | ||
var maxDx=0, minDx=Number.MAX_VALUE,tmp; | ||
for(var i=0;i< x.length-1;i++){ | ||
var tmp = Math.abs(x[i+1]-x[i]); | ||
if(tmp<minDx){ | ||
if (!('noiseLevel' in options)) { | ||
// We have to know if x is equally spaced | ||
var maxDx = 0, | ||
minDx = Number.MAX_VALUE, | ||
tmp; | ||
for (let i = 0; i < x.length - 1; ++i) { | ||
tmp = Math.abs(x[i + 1] - x[i]); | ||
if (tmp < minDx) { | ||
minDx = tmp; | ||
} | ||
if(tmp>maxDx){ | ||
if (tmp > maxDx) { | ||
maxDx = tmp; | ||
@@ -39,24 +62,19 @@ } | ||
if((maxDx-minDx)/maxDx<0.05){ | ||
if ((maxDx - minDx) / maxDx < 0.05) { | ||
options.noiseLevel = getNoiseLevel(y); | ||
//console.log(options.noiseLevel+" "+stats.array.median(y)); | ||
} | ||
else{ | ||
} else { | ||
options.noiseLevel = 0; | ||
} | ||
} | ||
//console.log("options.noiseLevel "+options.noiseLevel); | ||
y=[].concat(y); | ||
var yCorrection = {m:1, b:options.noiseLevel}; | ||
if(!options.maxCriteria){ | ||
yCorrection.m =-1; | ||
yCorrection.b*=-1; | ||
const yCorrection = {m: 1, b: options.noiseLevel}; | ||
if (!options.maxCriteria) { | ||
yCorrection.m = -1; | ||
yCorrection.b *= -1; | ||
} | ||
for (var i=0; i<y.length; i++){ | ||
y[i]=yCorrection.m*y[i]-yCorrection.b; | ||
for (let i = 0; i < y.length; i++) { | ||
y[i] = yCorrection.m * y[i] - yCorrection.b; | ||
} | ||
for (var i=0; i<y.length; i++) { | ||
for (let i = 0; i < y.length; i++) { | ||
if (y[i] < 0) { | ||
@@ -66,122 +84,141 @@ y[i] = 0; | ||
} | ||
//If the max difference between delta x is less than 5%, then, we can assume it to be equally spaced variable | ||
var Y = y; | ||
if((maxDx-minDx)/maxDx<0.05){ | ||
if(options.smoothY) | ||
Y = SG(y, x[1]-x[0], {windowSize:sgOptions.windowSize, polynomial:sgOptions.polynomial,derivative:0}); | ||
var dY = SG(y, x[1]-x[0], {windowSize:sgOptions.windowSize, polynomial:sgOptions.polynomial,derivative:1}); | ||
var ddY = SG(y, x[1]-x[0], {windowSize:sgOptions.windowSize, polynomial:sgOptions.polynomial,derivative:2}); | ||
// If the max difference between delta x is less than 5%, then, we can assume it to be equally spaced variable | ||
let Y = y; | ||
let dY, ddY; | ||
if ((maxDx - minDx) / maxDx < 0.05) { | ||
if (options.smoothY) | ||
Y = SG(y, x[1] - x[0], {windowSize: sgOptions.windowSize, polynomial: sgOptions.polynomial, derivative: 0}); | ||
dY = SG(y, x[1] - x[0], {windowSize: sgOptions.windowSize, polynomial: sgOptions.polynomial, derivative: 1}); | ||
ddY = SG(y, x[1] - x[0], {windowSize: sgOptions.windowSize, polynomial: sgOptions.polynomial, derivative: 2}); | ||
} else { | ||
if (options.smoothY) | ||
Y = SG(y, x, {windowSize: sgOptions.windowSize, polynomial: sgOptions.polynomial, derivative: 0}); | ||
dY = SG(y, x, {windowSize: sgOptions.windowSize, polynomial: sgOptions.polynomial, derivative: 1}); | ||
ddY = SG(y, x, {windowSize: sgOptions.windowSize, polynomial: sgOptions.polynomial, derivative: 2}); | ||
} | ||
else{ | ||
if(options.smoothY) | ||
Y = SG(y, x, {windowSize:sgOptions.windowSize, polynomial:sgOptions.polynomial,derivative:0}); | ||
var dY = SG(y, x, {windowSize:sgOptions.windowSize, polynomial:sgOptions.polynomial,derivative:1}); | ||
var ddY = SG(y, x, {windowSize:sgOptions.windowSize, polynomial:sgOptions.polynomial,derivative:2}); | ||
} | ||
var X = x; | ||
var dx = x[1]-x[0]; | ||
var maxDdy=0; | ||
const X = x; | ||
const dx = x[1] - x[0]; | ||
var maxDdy = 0; | ||
var maxY = 0; | ||
//console.log(Y.length); | ||
for (var i = 0; i < Y.length ; i++){ | ||
if(Math.abs(ddY[i])>maxDdy){ | ||
for (let i = 0; i < Y.length; i++) { | ||
if (Math.abs(ddY[i]) > maxDdy) { | ||
maxDdy = Math.abs(ddY[i]); | ||
} | ||
if(Math.abs(Y[i])>maxY){ | ||
if (Math.abs(Y[i]) > maxY) { | ||
maxY = Math.abs(Y[i]); | ||
} | ||
} | ||
//console.log(maxY+"x"+maxDy+"x"+maxDdy); | ||
var minddY = []; | ||
var intervalL = []; | ||
var intervalR = []; | ||
var lastMax = null; | ||
var lastMin = null; | ||
var broadMask = new Array(); | ||
//console.log(dx); | ||
//By the intermediate value theorem We cannot find 2 consecutive maxima or minima | ||
for (var i = 1; i < Y.length -1 ; i++){ | ||
//console.log(dY[i]); | ||
if ((dY[i] < dY[i-1]) && (dY[i] <= dY[i+1])|| | ||
(dY[i] <= dY[i-1]) && (dY[i] < dY[i+1])) { | ||
lastMin = X[i]; | ||
//console.log("min "+lastMin); | ||
if(dx>0&&lastMax!=null){ | ||
intervalL.push(lastMax); | ||
intervalR.push(lastMin); | ||
var minddY = new Array(Y.length - 2); | ||
var intervalL = new Array(Y.length); | ||
var intervalR = new Array(Y.length); | ||
var broadMask = new Array(Y.length - 2); | ||
var minddYLen = 0; | ||
var intervalLLen = 0; | ||
var intervalRLen = 0; | ||
var broadMaskLen = 0; | ||
// By the intermediate value theorem We cannot find 2 consecutive maximum or minimum | ||
for (let i = 1; i < Y.length - 1; ++i) { | ||
// filter based on derivativeThreshold | ||
if (Math.abs(dY[i]) > options.derivativeThreshold) { | ||
// Minimum in first derivative | ||
if ((dY[i] < dY[i - 1]) && (dY[i] <= dY[i + 1]) || | ||
(dY[i] <= dY[i - 1]) && (dY[i] < dY[i + 1])) { | ||
lastMin = { | ||
x: X[i], | ||
index: i | ||
}; | ||
if (dx > 0 && lastMax !== null) { | ||
intervalL[intervalLLen++] = lastMax; | ||
intervalR[intervalRLen++] = lastMin; | ||
} | ||
} | ||
} | ||
if ((dY[i] >= dY[i-1]) && (dY[i] > dY[i+1])|| | ||
(dY[i] > dY[i-1]) && (dY[i] >= dY[i+1])) { | ||
lastMax = X[i]; | ||
//console.log("max "+lastMax); | ||
if(dx<0&&lastMin!=null){ | ||
intervalL.push(lastMax); | ||
intervalR.push(lastMin); | ||
// Maximum in first derivative | ||
if ((dY[i] >= dY[i - 1]) && (dY[i] > dY[i + 1]) || | ||
(dY[i] > dY[i - 1]) && (dY[i] >= dY[i + 1])) { | ||
lastMax = { | ||
x: X[i], | ||
index: i | ||
}; | ||
if (dx < 0 && lastMin !== null) { | ||
intervalL[intervalLLen++] = lastMax; | ||
intervalR[intervalRLen++] = lastMin; | ||
} | ||
} | ||
} | ||
if ((ddY[i] < ddY[i-1]) && (ddY[i] < ddY[i+1])) { | ||
minddY.push(i);//( [X[i], Y[i], i] ); // TODO should we change this to have 3 arrays ? Huge overhead creating arrays | ||
if(Math.abs(ddY[i])>options.broadRatio*maxDdy){ // TODO should this be a parameter = | ||
broadMask.push(false); | ||
} | ||
else{ | ||
broadMask.push(true); | ||
} | ||
// Minimum in second derivative | ||
if ((ddY[i] < ddY[i - 1]) && (ddY[i] < ddY[i + 1])) { | ||
// TODO should we change this to have 3 arrays ? Huge overhead creating arrays | ||
minddY[minddYLen++] = i; //( [X[i], Y[i], i] ); | ||
broadMask[broadMaskLen++] = Math.abs(ddY[i]) <= options.broadRatio * maxDdy; | ||
} | ||
} | ||
// | ||
//console.log(intervalL.length+" "+minddY.length+" "+broadMask.length); | ||
var signals = []; | ||
var lastK = 0,possible, k, f,frequency, distanceJ, minDistance, gettingCloser; | ||
for (var j = 0; j < minddY.length; j++){ | ||
frequency = X[minddY[j]];//minddY[j][0]; | ||
minddY.length = minddYLen; | ||
intervalL.length = intervalLLen; | ||
intervalR.length = intervalRLen; | ||
broadMask.length = broadMaskLen; | ||
let signals = new Array(minddY.length); | ||
let signalsLen = 0; | ||
let lastK = 0; | ||
let possible, frequency, distanceJ, minDistance, gettingCloser; | ||
for (let j = 0; j < minddY.length; ++j) { | ||
frequency = X[minddY[j]]; | ||
possible = -1; | ||
k=lastK+1; | ||
let k = lastK + 1; | ||
minDistance = Number.MAX_VALUE; | ||
distanceJ = 0; | ||
gettingCloser=true; | ||
while(possible==-1&&k<intervalL.length&&gettingCloser){ | ||
distanceJ = Math.abs(frequency-(intervalL[k]+intervalR[k])/2); | ||
gettingCloser = true; | ||
while (possible === -1 && (k < intervalL.length) && gettingCloser) { | ||
distanceJ = Math.abs(frequency - (intervalL[k].x + intervalR[k].x) / 2); | ||
//Still getting closer? | ||
if(distanceJ<minDistance){ | ||
if (distanceJ < minDistance) { | ||
minDistance = distanceJ; | ||
} | ||
else{ | ||
} else { | ||
gettingCloser = false; | ||
} | ||
if( distanceJ <Math.abs(intervalL[k]-intervalR[k])/2){ | ||
possible=k; | ||
if (distanceJ < Math.abs(intervalL[k].x - intervalR[k].x) / 2) { | ||
possible = k; | ||
lastK = k; | ||
} | ||
k++; | ||
++k; | ||
} | ||
//console.log(lastK+" "+intervalL.length+" possible "+k); | ||
if (possible!=-1){ | ||
//console.log(height); | ||
if (Math.abs(Y[minddY[j]]) > options.minMaxRatio*maxY) { | ||
signals.push({ | ||
i:minddY[j], | ||
if (possible !== -1) { | ||
if (Math.abs(Y[minddY[j]]) > options.minMaxRatio * maxY) { | ||
signals[signalsLen++] = { | ||
index: minddY[j], | ||
x: frequency, | ||
y: (Y[minddY[j]]-yCorrection.b)/yCorrection.m, | ||
width:Math.abs(intervalR[possible] - intervalL[possible]),//widthCorrection | ||
soft:broadMask[j] | ||
}) | ||
y: (Y[minddY[j]] + yCorrection.b) / yCorrection.m, | ||
width: Math.abs(intervalR[possible].x - intervalL[possible].x), //widthCorrection | ||
soft: broadMask[j] | ||
}; | ||
if (options.boundaries) { | ||
signals[signalsLen - 1].left = intervalL[possible]; | ||
signals[signalsLen - 1].right = intervalR[possible]; | ||
} | ||
if (options.heightFactor) { | ||
let yLeft = Y[intervalL[possible].index]; | ||
let yRight = Y[intervalR[possible].index]; | ||
signals[signalsLen - 1].height = options.heightFactor * (signals[signalsLen - 1].y - ((yLeft + yRight) / 2)); | ||
} | ||
} | ||
} | ||
} | ||
signals.length = signalsLen; | ||
if (options.realTopDetection) | ||
realTopDetection(signals, X, Y); | ||
if(options.realTopDetection){ | ||
realTopDetection(signals,X,Y); | ||
} | ||
//Correct the values to fit the original spectra data | ||
for(var j=0;j<signals.length;j++){ | ||
signals[j].base=options.noiseLevel; | ||
for (let j = 0; j < signals.length; j++) { | ||
signals[j].base = options.noiseLevel; | ||
} | ||
@@ -197,17 +234,17 @@ | ||
function getNoiseLevel(y){ | ||
var mean = 0,stddev=0; | ||
var length = y.length,i=0; | ||
for(i = 0; i < length; i++){ | ||
mean+=y[i]; | ||
function getNoiseLevel(y) { | ||
var mean = 0, stddev = 0; | ||
var length = y.length; | ||
for (let i = 0; i < length; ++i) { | ||
mean += y[i]; | ||
} | ||
mean/=length; | ||
mean /= length; | ||
var averageDeviations = new Array(length); | ||
for (i = 0; i < length; i++) | ||
for (let i = 0; i < length; ++i) | ||
averageDeviations[i] = Math.abs(y[i] - mean); | ||
averageDeviations.sort(); | ||
if (length % 2 == 1) { | ||
stddev = averageDeviations[(length-1)/2] / 0.6745; | ||
if (length % 2 === 1) { | ||
stddev = averageDeviations[(length - 1) / 2] / 0.6745; | ||
} else { | ||
stddev = 0.5*(averageDeviations[length/2]+averageDeviations[length/2-1]) / 0.6745; | ||
stddev = 0.5 * (averageDeviations[length / 2] + averageDeviations[length / 2 - 1]) / 0.6745; | ||
} | ||
@@ -218,30 +255,22 @@ | ||
function realTopDetection(peakList, x, y){ | ||
//console.log(peakList); | ||
//console.log(x); | ||
//console.log(y); | ||
var listP = []; | ||
var alpha, beta, gamma, p,currentPoint; | ||
for(var j=0;j<peakList.length;j++){ | ||
function realTopDetection(peakList, x, y) { | ||
var alpha, beta, gamma, p, currentPoint; | ||
for (var j = 0; j < peakList.length; j++) { | ||
currentPoint = peakList[j].i;//peakList[j][2]; | ||
var tmp = currentPoint; | ||
//The detected peak could be moved 1 or 2 unit to left or right. | ||
if(y[currentPoint-1]>=y[currentPoint-2] | ||
&&y[currentPoint-1]>=y[currentPoint]) { | ||
if (y[currentPoint - 1] >= y[currentPoint - 2] | ||
&& y[currentPoint - 1] >= y[currentPoint]) { | ||
currentPoint--; | ||
} | ||
else{ | ||
if(y[currentPoint+1]>=y[currentPoint] | ||
&&y[currentPoint+1]>=y[currentPoint+2]) { | ||
} else { | ||
if (y[currentPoint + 1] >= y[currentPoint] | ||
&& y[currentPoint + 1] >= y[currentPoint + 2]) { | ||
currentPoint++; | ||
} | ||
else{ | ||
if(y[currentPoint-2]>=y[currentPoint-3] | ||
&&y[currentPoint-2]>=y[currentPoint-1]) { | ||
currentPoint-=2; | ||
} | ||
else{ | ||
if(y[currentPoint+2]>=y[currentPoint+1] | ||
&&y[currentPoint+2]>=y[currentPoint+3]) { | ||
currentPoint+=2; | ||
} else { | ||
if (y[currentPoint - 2] >= y[currentPoint - 3] | ||
&& y[currentPoint - 2] >= y[currentPoint - 1]) { | ||
currentPoint -= 2; | ||
} else { | ||
if (y[currentPoint + 2] >= y[currentPoint + 1] | ||
&& y[currentPoint + 2] >= y[currentPoint + 3]) { | ||
currentPoint += 2; | ||
} | ||
@@ -251,5 +280,5 @@ } | ||
} | ||
if(y[currentPoint-1]>0&&y[currentPoint+1]>0 | ||
&&y[currentPoint]>=y[currentPoint-1] | ||
&&y[currentPoint]>=y[currentPoint+1]) { | ||
if (y[currentPoint - 1] > 0 && y[currentPoint + 1] > 0 | ||
&& y[currentPoint] >= y[currentPoint - 1] | ||
&& y[currentPoint] >= y[currentPoint + 1]) { | ||
alpha = 20 * Math.log10(y[currentPoint - 1]); | ||
@@ -261,6 +290,4 @@ beta = 20 * Math.log10(y[currentPoint]); | ||
//console.log(x[currentPoint]+" "+tmp+" "+currentPoint); | ||
peakList[j].x = x[currentPoint] + (x[currentPoint]-x[currentPoint-1])*p; | ||
peakList[j].y = y[currentPoint] - 0.25 * (y[currentPoint - 1] | ||
- y[currentPoint + 1]) * p;//signal.peaks[j].intensity); | ||
//console.log(y[tmp]+" "+peakList[j].y); | ||
peakList[j].x = x[currentPoint] + (x[currentPoint] - x[currentPoint - 1]) * p; | ||
peakList[j].y = y[currentPoint] - 0.25 * (y[currentPoint - 1] - y[currentPoint + 1]) * p; | ||
} | ||
@@ -270,2 +297,2 @@ } | ||
module.exports=gsd; | ||
module.exports = gsd; |
@@ -0,3 +1,4 @@ | ||
'use strict'; | ||
module.exports.post = require("../src/optimize"); | ||
module.exports.gsd = require("../src/gsd"); | ||
module.exports.post = require('../src/optimize'); | ||
module.exports.gsd = require('../src/gsd'); |
/** | ||
* Created by acastillo on 9/6/15. | ||
*/ | ||
var Opt = require("ml-optimize-lorentzian"); | ||
'use strict'; | ||
function sampleFunction(from, to, x, y, lastIndex){ | ||
var Opt = require('ml-optimize-lorentzian'); | ||
function sampleFunction(from, to, x, y, lastIndex) { | ||
var nbPoints = x.length; | ||
var sampleX = []; | ||
var sampleY = []; | ||
var direction = Math.sign(x[1]-x[0]);//Direction of the derivative | ||
if(direction==-1){ | ||
lastIndex[0]= x.length-1; | ||
var direction = Math.sign(x[1] - x[0]);//Direction of the derivative | ||
if (direction === -1) { | ||
lastIndex[0] = x.length - 1; | ||
} | ||
var delta = Math.abs(to-from)/2; | ||
var mid = (from+to)/2; | ||
var delta = Math.abs(to - from) / 2; | ||
var mid = (from + to) / 2; | ||
var stop = false; | ||
var index = lastIndex[0]; | ||
while(!stop&&index<nbPoints&&index>=0){ | ||
if(Math.abs(x[index]-mid)<=delta){ | ||
while (!stop && index < nbPoints && index >= 0) { | ||
if (Math.abs(x[index] - mid) <= delta) { | ||
sampleX.push(x[index]); | ||
sampleY.push(y[index]); | ||
index+=direction; | ||
} | ||
//It is outside the range. | ||
else{ | ||
if(Math.sign(mid-x[index])==1){ | ||
index += direction; | ||
} else { | ||
//It is outside the range. | ||
if (Math.sign(mid - x[index]) === 1) { | ||
//We'll reach the mid going in the current direction | ||
index+=direction; | ||
} | ||
else{ | ||
index += direction; | ||
} else { | ||
//There is not more peaks in the current range | ||
stop=true; | ||
stop = true; | ||
} | ||
@@ -39,16 +38,17 @@ } | ||
} | ||
lastIndex[0]=index; | ||
lastIndex[0] = index; | ||
return [sampleX, sampleY]; | ||
} | ||
function optimizePeaks(peakList,x,y,n, fnType){ | ||
var i, j, lastIndex=[0]; | ||
var groups = groupPeaks(peakList,n); | ||
function optimizePeaks(peakList, x, y, n, fnType) { | ||
var i, j, lastIndex = [0]; | ||
var groups = groupPeaks(peakList, n); | ||
var result = []; | ||
var factor = 1; | ||
if(fnType=="gaussian") | ||
if (fnType === 'gaussian') | ||
factor = 1.17741;//From https://en.wikipedia.org/wiki/Gaussian_function#Properties | ||
for(i=0;i<groups.length;i++){ | ||
var sampling, error, opts; | ||
for (i = 0; i < groups.length; i++) { | ||
var peaks = groups[i].group; | ||
if(peaks.length>1){ | ||
if (peaks.length > 1) { | ||
//Multiple peaks | ||
@@ -58,13 +58,13 @@ //console.log("Pending group of overlaped peaks "+peaks.length); | ||
//console.log(groups[i].limits); | ||
var sampling = sampleFunction(groups[i].limits[0]-groups[i].limits[1],groups[i].limits[0]+groups[i].limits[1],x,y,lastIndex); | ||
sampling = sampleFunction(groups[i].limits[0] - groups[i].limits[1], groups[i].limits[0] + groups[i].limits[1], x, y, lastIndex); | ||
//console.log(sampling); | ||
if(sampling[0].length>5){ | ||
var error = peaks[0].width/1000; | ||
var opts = [ 3, 100, error, error, error, error*10, error*10, 11, 9, 1 ]; | ||
if (sampling[0].length > 5) { | ||
error = peaks[0].width / 1000; | ||
opts = [ 3, 100, error, error, error, error * 10, error * 10, 11, 9, 1 ]; | ||
//var gauss = Opt.optimizeSingleGaussian(sampling[0], sampling[1], opts, peaks); | ||
var optPeaks = []; | ||
if(fnType=="gaussian") | ||
if (fnType === 'gaussian') | ||
optPeaks = Opt.optimizeGaussianSum(sampling, peaks, opts); | ||
else{ | ||
if(fnType=="lorentzian"){ | ||
else { | ||
if (fnType === 'lorentzian') { | ||
optPeaks = Opt.optimizeLorentzianSum(sampling, peaks, opts); | ||
@@ -74,29 +74,28 @@ } | ||
//console.log(optPeak); | ||
for(j=0;j<optPeaks.length;j++){ | ||
result.push({x:optPeaks[j][0][0],y:optPeaks[j][1][0],width:optPeaks[j][2][0]*factor}); | ||
for (j = 0; j < optPeaks.length; j++) { | ||
result.push({x: optPeaks[j][0][0], y: optPeaks[j][1][0], width: optPeaks[j][2][0] * factor}); | ||
} | ||
} | ||
} | ||
else{ | ||
} else { | ||
//Single peak | ||
peaks = peaks[0]; | ||
var sampling = sampleFunction(peaks.x-n*peaks.width, | ||
peaks.x+n*peaks.width,x,y,lastIndex); | ||
sampling = sampleFunction(peaks.x - n * peaks.width, | ||
peaks.x + n * peaks.width, x, y, lastIndex); | ||
//console.log("here2"); | ||
//console.log(groups[i].limits); | ||
if(sampling[0].length>5){ | ||
var error = peaks.width/1000; | ||
var opts = [ 3, 100, error, error, error, error*10, error*10, 11, 9, 1 ]; | ||
if (sampling[0].length > 5) { | ||
error = peaks.width / 1000; | ||
opts = [3, 100, error, error, error, error * 10, error * 10, 11, 9, 1]; | ||
//var gauss = Opt.optimizeSingleGaussian(sampling[0], sampling[1], opts, peaks); | ||
//var gauss = Opt.optimizeSingleGaussian([sampling[0],sampling[1]], peaks, opts); | ||
var optPeak = []; | ||
if(fnType=="gaussian") | ||
var optPeak = Opt.optimizeSingleGaussian([sampling[0],sampling[1]], peaks, opts); | ||
else{ | ||
if(fnType=="lorentzian"){ | ||
var optPeak = Opt.optimizeSingleLorentzian([sampling[0],sampling[1]], peaks, opts); | ||
if (fnType === 'gaussian') | ||
optPeak = Opt.optimizeSingleGaussian([sampling[0], sampling[1]], peaks, opts); | ||
else { | ||
if (fnType === 'lorentzian') { | ||
optPeak = Opt.optimizeSingleLorentzian([sampling[0], sampling[1]], peaks, opts); | ||
} | ||
} | ||
//console.log(optPeak); | ||
result.push({x:optPeak[0][0],y:optPeak[1][0],width:optPeak[2][0]*factor}); // From https://en.wikipedia.org/wiki/Gaussian_function#Properties} | ||
result.push({x: optPeak[0][0], y: optPeak[1][0], width: optPeak[2][0] * factor}); // From https://en.wikipedia.org/wiki/Gaussian_function#Properties} | ||
} | ||
@@ -109,54 +108,53 @@ } | ||
function groupPeaks(peakList,nL){ | ||
function groupPeaks(peakList, nL) { | ||
var group = []; | ||
var groups = []; | ||
var i, j; | ||
var limits = [peakList[0].x,nL*peakList[0].width]; | ||
var limits = [peakList[0].x, nL * peakList[0].width]; | ||
var upperLimit, lowerLimit; | ||
//Merge forward | ||
for(i=0;i<peakList.length;i++){ | ||
for (i = 0; i < peakList.length; i++) { | ||
//If the 2 things overlaps | ||
if(Math.abs(peakList[i].x-limits[0])<(nL*peakList[i].width+limits[1])){ | ||
if (Math.abs(peakList[i].x - limits[0]) < (nL * peakList[i].width + limits[1])) { | ||
//Add the peak to the group | ||
group.push(peakList[i]); | ||
//Update the group limits | ||
upperLimit = limits[0]+limits[1]; | ||
if(peakList[i].x+nL*peakList[i].width>upperLimit){ | ||
upperLimit = peakList[i].x+nL*peakList[i].width; | ||
upperLimit = limits[0] + limits[1]; | ||
if (peakList[i].x + nL * peakList[i].width > upperLimit) { | ||
upperLimit = peakList[i].x + nL * peakList[i].width; | ||
} | ||
lowerLimit = limits[0]-limits[1]; | ||
if(peakList[i].x-nL*peakList[i].width<lowerLimit){ | ||
lowerLimit = peakList[i].x-nL*peakList[i].width; | ||
lowerLimit = limits[0] - limits[1]; | ||
if (peakList[i].x - nL * peakList[i].width < lowerLimit) { | ||
lowerLimit = peakList[i].x - nL * peakList[i].width; | ||
} | ||
limits = [(upperLimit+lowerLimit)/2,Math.abs(upperLimit-lowerLimit)/2]; | ||
limits = [(upperLimit + lowerLimit) / 2, Math.abs(upperLimit - lowerLimit) / 2]; | ||
} | ||
else{ | ||
groups.push({limits:limits,group:group}); | ||
} else { | ||
groups.push({limits: limits, group: group}); | ||
//var optmimalPeak = fitSpectrum(group,limits,spectrum); | ||
group=[peakList[i]]; | ||
limits = [peakList[i].x,nL*peakList[i].width]; | ||
group = [peakList[i]]; | ||
limits = [peakList[i].x, nL * peakList[i].width]; | ||
} | ||
} | ||
groups.push({limits:limits,group:group}); | ||
groups.push({limits: limits, group: group}); | ||
//Merge backward | ||
for(i =groups.length-2;i>=0;i--){ | ||
for (i = groups.length - 2; i >= 0; i--) { | ||
//The groups overlaps | ||
if(Math.abs(groups[i].limits[0]-groups[i+1].limits[0])< | ||
(groups[i].limits[1]+groups[i+1].limits[1])/2){ | ||
for(j=0;j<groups[i+1].group.length;j++){ | ||
groups[i].group.push(groups[i+1].group[j]); | ||
if (Math.abs(groups[i].limits[0] - groups[i + 1].limits[0]) < | ||
(groups[i].limits[1] + groups[i + 1].limits[1]) / 2) { | ||
for (j = 0; j < groups[i + 1].group.length; j++) { | ||
groups[i].group.push(groups[i + 1].group[j]); | ||
} | ||
upperLimit = groups[i].limits[0]+groups[i].limits[1]; | ||
if(groups[i+1].limits[0]+groups[i+1].limits[1]>upperLimit){ | ||
upperLimit = groups[i+1].limits[0]+groups[i+1].limits[1]; | ||
upperLimit = groups[i].limits[0] + groups[i].limits[1]; | ||
if (groups[i + 1].limits[0] + groups[i + 1].limits[1] > upperLimit) { | ||
upperLimit = groups[i + 1].limits[0] + groups[i + 1].limits[1]; | ||
} | ||
lowerLimit = groups[i].limits[0]-groups[i].limits[1]; | ||
if(groups[i+1].limits[0]-groups[i+1].limits[1]<lowerLimit){ | ||
lowerLimit = groups[i+1].limits[0]-groups[i+1].limits[1]; | ||
lowerLimit = groups[i].limits[0] - groups[i].limits[1]; | ||
if (groups[i + 1].limits[0] - groups[i + 1].limits[1] < lowerLimit) { | ||
lowerLimit = groups[i + 1].limits[0] - groups[i + 1].limits[1]; | ||
} | ||
//console.log(limits); | ||
groups[i].limits = [(upperLimit+lowerLimit)/2,Math.abs(upperLimit-lowerLimit)/2]; | ||
groups[i].limits = [(upperLimit + lowerLimit) / 2, Math.abs(upperLimit - lowerLimit) / 2]; | ||
groups.splice(i+1,1); | ||
groups.splice(i + 1, 1); | ||
} | ||
@@ -171,15 +169,14 @@ } | ||
*/ | ||
function joinBroadPeaks(peakList, options){ | ||
function joinBroadPeaks(peakList, options) { | ||
var width = options.width; | ||
var broadLines=[]; | ||
var broadLines = []; | ||
//Optimize the possible broad lines | ||
var max=0, maxI=0,count=1; | ||
var isPartOf = false; | ||
for(var i=peakList.length-1;i>=0;i--){ | ||
if(peakList[i].soft){ | ||
broadLines.push(peakList.splice(i,1)[0]); | ||
var max = 0, maxI = 0, count = 1; | ||
for (let i = peakList.length - 1; i >= 0; i--) { | ||
if (peakList[i].soft) { | ||
broadLines.push(peakList.splice(i, 1)[0]); | ||
} | ||
} | ||
//Push a feak peak | ||
broadLines.push({x:Number.MAX_VALUE}); | ||
broadLines.push({x: Number.MAX_VALUE}); | ||
@@ -190,7 +187,7 @@ var candidates = [[broadLines[0].x, | ||
for(var i=1;i<broadLines.length;i++){ | ||
for (let i = 1; i < broadLines.length; i++) { | ||
//console.log(broadLines[i-1].x+" "+broadLines[i].x); | ||
if(Math.abs(broadLines[i-1].x-broadLines[i].x)<width){ | ||
candidates.push([broadLines[i].x,broadLines[i].y]); | ||
if(broadLines[i].y>max){ | ||
if (Math.abs(broadLines[i - 1].x - broadLines[i].x) < width) { | ||
candidates.push([broadLines[i].x, broadLines[i].y]); | ||
if (broadLines[i].y > max) { | ||
max = broadLines[i].y; | ||
@@ -201,15 +198,15 @@ maxI = i; | ||
count++; | ||
} | ||
else{ | ||
if(count>2){ | ||
var fitted = Opt.optimizeSingleLorentzian(candidates, | ||
{x: broadLines[maxI].x, y:max, width: Math.abs(candidates[0][0]-candidates[candidates.length-1][0])}); | ||
peakList.push({x:fitted[0][0],y:fitted[1][0],width:fitted[2][0],soft:false}); | ||
} else { | ||
if (count > 2) { | ||
var fitted = Opt.optimizeSingleLorentzian(candidates, | ||
{x: broadLines[maxI].x, y: max, width: Math.abs(candidates[0][0] - candidates[candidates.length - 1][0])}); | ||
peakList.push({x: fitted[0][0], y: fitted[1][0], width: fitted[2][0], soft: false}); | ||
} | ||
else{ | ||
} else { | ||
//Put back the candidates to the signals list | ||
indexes.map(function(index){peakList.push(broadLines[index])}); | ||
indexes.map(function (index) { | ||
peakList.push(broadLines[index]); | ||
}); | ||
} | ||
candidates = [[broadLines[i].x,broadLines[i].y]]; | ||
candidates = [[broadLines[i].x, broadLines[i].y]]; | ||
indexes = [i]; | ||
@@ -230,3 +227,5 @@ max = broadLines[i].y; | ||
/*if(options.broadRatio>0){ | ||
/* | ||
var isPartOf = true | ||
if(options.broadRatio>0){ | ||
var broadLines=[[Number.MAX_VALUE,0,0]]; | ||
@@ -279,3 +278,3 @@ //Optimize the possible broad lines | ||
module.exports={optimizePeaks:optimizePeaks,joinBroadPeaks:joinBroadPeaks}; | ||
module.exports = {optimizePeaks: optimizePeaks, joinBroadPeaks: joinBroadPeaks}; | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
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
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 14 instances in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
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
2445023
4
38
8436
79
9
2
90
15
- Removedml-stat@^1.1.0
- Removedml-stat@1.3.3(transitive)