Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ml-gsd

Package Overview
Dependencies
Maintainers
10
Versions
77
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ml-gsd - npm Package Compare versions

Comparing version 5.0.2 to 6.0.0

CHANGELOG.md

179

lib/index.js

@@ -6,3 +6,3 @@ 'use strict';

var SG = require('ml-savitzky-golay-generalized');
var mlOptimizeLorentzian = require('ml-optimize-lorentzian');
var mlSpectraFitting = require('ml-spectra-fitting');

@@ -15,5 +15,6 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

* Global spectra deconvolution
* @param {Array<number>} x - Independent variable
* @param {Array<number>} yIn - Dependent variable
* @param {object} [options] - Options object
* @param {object} data - Object data with x and y arrays
* @param {Array<number>} [data.x] - Independent variable
* @param {Array<number>} [data.y] - 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

@@ -34,3 +35,3 @@ * @param {number} [options.sgOptions.windowSize = 9] - points to use in the approximations

*/
function gsd(x, yIn, options = {}) {
function gsd(data, options = {}) {
let {

@@ -51,2 +52,4 @@ noiseLevel,

let { y: yIn, x } = data;
const y = yIn.slice();

@@ -355,6 +358,20 @@ let equalSpaced = isEqualSpaced(x);

function optimizePeaks(peakList, x, y, options = {}) {
/**
* Optimize the position (x), max intensity (y), full width at half maximum (width)
* and the ratio of gaussian contribution (mu) if it's required. It supports three kind of shapes: gaussian, lorentzian and pseudovoigt
* @param {object} data - An object containing the x and y data to be fitted.
* @param {Array} peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
* @param {object} [options = {}] -
* @param {string} [options.kind = 'gaussian'] - kind of shape used to fitting, lorentzian, gaussian and pseudovoigt are supported.
* @param {number} [options.factorWidth = 4] - times of width to group peaks.
* @param {object} [options.joinPeaks = true] - if true the peaks could be grouped if the separation between them are inside of a range of factorWidth * width
* @param {object} [options.optimizationOptions] - options of ml-levenberg-marquardt optimization package.
*/
const kindSupported = ['gaussian', 'lorentzian', 'pseudovoigt'];
function optimizePeaks(data, peakList, options = {}) {
const {
functionName = 'gaussian',
factorWidth = 4,
joinPeaks = true,
optimizationOptions = {

@@ -367,9 +384,10 @@ damping: 1.5,

let { x, y } = data;
checkFuncName(functionName, optimizationOptions);
let lastIndex = [0];
let groups = groupPeaks(peakList, factorWidth);
let groups = groupPeaks(peakList, factorWidth, joinPeaks);
let result = [];
let factor = 1;
if (functionName === 'gaussian') {
factor = 1.17741;
} // From https://en.wikipedia.org/wiki/Gaussian_function#Properties
let sampling;

@@ -387,24 +405,10 @@ for (let i = 0; i < groups.length; i++) {

);
if (sampling[0].length > 5) {
let optPeaks = [];
if (functionName === 'gaussian') {
optPeaks = mlOptimizeLorentzian.optimizeGaussianSum(sampling, peaks, optimizationOptions);
} else {
if (functionName === 'lorentzian') {
optPeaks = mlOptimizeLorentzian.optimizeLorentzianSum(
sampling,
peaks,
optimizationOptions,
);
}
}
if (sampling.x.length > 5) {
let { peaks: optPeaks } = mlSpectraFitting.optimize(sampling, peaks, {
kind: functionName,
lmOptions: optimizationOptions,
});
for (let j = 0; j < optPeaks.length; j++) {
let { parameters } = optPeaks[j];
result.push({
x: parameters[0],
y: parameters[1],
width: parameters[2] * factor,
index: peaks[j].index,
});
optPeaks[j].index = peaks.index;
result.push(optPeaks[j]);
}

@@ -423,27 +427,10 @@ }

if (sampling[0].length > 5) {
let fitResult = [];
if (functionName === 'gaussian') {
fitResult = mlOptimizeLorentzian.optimizeSingleGaussian(
[sampling[0], sampling[1]],
peaks,
optimizationOptions,
);
} else {
if (functionName === 'lorentzian') {
fitResult = mlOptimizeLorentzian.optimizeSingleLorentzian(
[sampling[0], sampling[1]],
peaks,
optimizationOptions,
);
}
}
let { parameters } = fitResult;
result.push({
x: parameters[0],
y: parameters[1],
width: parameters[2] * factor,
index: peaks.index,
}); // From https://en.wikipedia.org/wiki/Gaussian_function#Properties}
if (sampling.x.length > 5) {
let fitResult = mlSpectraFitting.optimize(sampling, [peaks], {
kind: functionName,
lmOptions: optimizationOptions,
});
let { peaks: optPeaks } = fitResult;
optPeaks[0].index = peaks.index;
result.push(optPeaks[0]);
}

@@ -485,6 +472,6 @@ }

lastIndex[0] = index;
return [sampleX, sampleY];
return { x: sampleX, y: sampleY };
}
function groupPeaks(peakList, nL) {
function groupPeaks(peakList, nL, joinPeaks) {
let group = [];

@@ -498,4 +485,4 @@ let groups = [];

if (
Math.abs(peakList[i].x - limits[0]) <
nL * peakList[i].width + limits[1]
joinPeaks &&
Math.abs(peakList[i].x - limits[0]) < nL * peakList[i].width + limits[1]
) {

@@ -519,3 +506,2 @@ // Add the peak to the group

groups.push({ limits: limits, group: group });
// var optmimalPeak = fitSpectrum(group,limits,spectrum);
group = [peakList[i]];

@@ -556,6 +542,21 @@ limits = [peakList[i].x, nL * peakList[i].width];

function checkFuncName(functionName, optimizationOptions) {
let kind = functionName.toLowerCase().replace(/[^a-z]/g, '');
let isSupported = kindSupported.some((ks) => ks === kind);
if (isSupported) {
optimizationOptions.kind = kind;
} else {
throw new Error(
`Kind of function unsupported. Just these kind are supported: ${kindSupported.join(
', ',
)}`,
);
}
}
/**
* This function try to join the peaks that seems to belong to a broad signal in a single broad peak.
* @param peakList
* @param options
* @param {Array} peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
* @param {object} [options = {}] -
* @param {number} options.width - width limit to join peaks.
*/

@@ -579,9 +580,8 @@ function joinBroadPeaks(peakList, options = {}) {

let candidates = [[broadLines[0].x, broadLines[0].y]];
let indexes = [broadLines[0].index];
let candidates = { x: [broadLines[0].x], y: [broadLines[0].y] };
let indexes = [0];
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]);
candidates.x.push(broadLines[i].x);
candidates.y.push(broadLines[i].y);
if (broadLines[i].y > max) {

@@ -591,23 +591,25 @@ max = broadLines[i].y;

}
indexes.push(broadLines[i].index);
indexes.push(i);
count++;
} else {
if (count > 2) {
let fitted = mlOptimizeLorentzian.optimizeSingleLorentzian(candidates, {
x: broadLines[maxI].x,
y: max,
width: Math.abs(
candidates[0][0] - candidates[candidates.length - 1][0],
),
});
let { parameters } = fitted;
peakList.push({
x: parameters[0],
y: parameters[1],
width: parameters[2],
index: Math.floor(
indexes.reduce((a, b) => a + b, 0) / indexes.length,
),
soft: false,
});
let fitted = mlSpectraFitting.optimize(
candidates,
[
{
x: broadLines[maxI].x,
y: max,
width: Math.abs(
candidates.x[0] - candidates.x[candidates.x.length - 1],
),
},
],
{ kind: 'lorentzian' },
);
let { peaks: peak } = fitted;
peak[0].index = Math.floor(
indexes.reduce((a, b) => a + b, 0) / indexes.length,
);
peak[0].soft = false;
peakList.push(peak[0]);
} else {

@@ -619,3 +621,3 @@ // Put back the candidates to the signals list

}
candidates = [[broadLines[i].x, broadLines[i].y]];
candidates = { x: [broadLines[i].x], y: [broadLines[i].y] };
indexes = [i];

@@ -627,3 +629,2 @@ max = broadLines[i].y;

}
peakList.sort(function (a, b) {

@@ -630,0 +631,0 @@ return a.x - b.x;

{
"name": "ml-gsd",
"version": "5.0.2",
"version": "6.0.0",
"description": "Global Spectra Deconvolution",

@@ -15,3 +15,3 @@ "main": "lib/index.js",

"scripts": {
"build": "cheminfo-build --entry src/index.js --root GSD",
"build": "rollup -c && cheminfo-build --entry src/index.js --root GSD",
"eslint": "eslint src --cache",

@@ -44,26 +44,34 @@ "eslint-fix": "npm run eslint -- --fix",

"homepage": "https://github.com/mljs/global-spectral-deconvolution",
"jest": {
"testEnvironment": "node"
},
"prettier": {
"arrowParens": "always",
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all"
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.10.4",
"@babel/plugin-transform-modules-commonjs": "^7.12.1",
"chemcalc": "^3.4.1",
"cheminfo-tools": "^1.23.3",
"eslint": "^7.9.0",
"eslint-config-cheminfo": "^3.0.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^23.20.0",
"cheminfo-build": "^1.1.8",
"eslint": "^7.12.1",
"eslint-config-cheminfo": "^5.2.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jest": "^24.1.0",
"eslint-plugin-prettier": "^3.1.4",
"jest": "^26.4.2",
"esm": "^3.2.25",
"jest": "^26.6.3",
"mf-global": "^1.3.0",
"ml-stat": "^1.3.3",
"prettier": "^2.1.2",
"rollup": "^2.28.2",
"spectrum-generator": "^4.0.2",
"rollup": "^2.33.1",
"spectrum-generator": "^4.4.0",
"xy-parser": "^3.0.0"
},
"dependencies": {
"ml-optimize-lorentzian": "^0.2.0",
"ml-savitzky-golay-generalized": "2.0.2"
},
"jest": {
"verbose": true,
"testURL": "http://localhost/"
"ml-savitzky-golay-generalized": "2.0.2",
"ml-spectra-fitting": "^0.5.0"
}
}
# global-spectral-deconvolution
[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[![David deps][david-image]][david-url]

@@ -10,2 +9,6 @@ [![npm download][download-image]][download-url]

`gsd`is using an algorithm that is searching for inflection points to determine the position of peaks and the width of the peaks are between the 2 inflection points. The result of GSD yield to an array of object containing {x, y and width}. However this width is based on the inflection point and may be different from the 'fwhm' (Full Width Half Maximum).
The second algorithm (`optimize`) will optimize the width as a FWHM to match the original peak. After optimization the width with therefore be always FWHM whichever is the function used.
## [API documentation](http://mljs.github.io/global-spectral-deconvolution/)

@@ -53,3 +56,3 @@

### GSD.post.broadenPeaks(peakList, {factor=2, overlap=false})
### GSD.broadenPeaks(peakList, {factor=2, overlap=false})

@@ -59,5 +62,5 @@ We enlarge the peaks and add the properties from and to.

### GSD.post.joinBroadPeaks
### GSD.joinBroadPeaks
### GSD.post.optimizePeaks
### GSD.optimizePeaks

@@ -67,31 +70,24 @@ ## Example

```js
var CC = require('chemcalc');
var Stat = require('ml-stat');
var peakPicking = require('ml-gsd');
import { IsotopicDistribution } from 'mf-global';
import { gsd, optimizePeaks } from '../src';
var spectrum = CC.analyseMF('Cl2.Br2', {
isotopomers: 'arrayXXYY',
fwhm: 0.01,
gaussianWidth: 11
// generate a sample spectrum of the form {x:[], y:[]}
const data = new IsotopicDistribution('C').getGaussian();
let peaks = gsd(data, {
noiseLevel: 0,
minMaxRatio: 0.00025, // Threshold to determine if a given peak should be considered as a noise
realTopDetection: true,
maxCriteria: true, // inverted:false
smoothY: false,
sgOptions: { windowSize: 7, polynomial: 3 },
});
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;
console.log(peaks); // array of peaks {x,y,width}, width = distance between inflection points
// GSD
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');
let optimized = optimizePeaks(data, peaks);
console.log(optimized); // array of peaks {x,y,width}, width = FWHM
```

@@ -105,4 +101,2 @@

[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

@@ -109,0 +103,0 @@ [david-url]: https://david-dm.org/mljs/global-spectral-deconvolution

@@ -16,8 +16,11 @@ /**

let pp = gsd(spectrum[0], spectrum[1], {
noiseLevel: 57000.21889405926, // 1049200.537996172/2,
minMaxRatio: 0.01,
broadRatio: 0.0025,
sgOptions: { windowSize: 13, polynomial: 3 },
});
let pp = gsd(
{ x: spectrum[0], y: spectrum[1] },
{
noiseLevel: 57000.21889405926, // 1049200.537996172/2,
minMaxRatio: 0.01,
broadRatio: 0.0025,
sgOptions: { windowSize: 13, polynomial: 3 },
},
);

@@ -24,0 +27,0 @@ joinBroadPeaks(pp, { width: 0.25 });

@@ -12,11 +12,14 @@ import { readFileSync } from 'fs';

);
let result = gsd(spectrum[0], spectrum[1], {
noiseLevel: 1049200.537996172 / 2,
minMaxRatio: 0.01,
broadRatio: 0.0025,
sgOptions: {
windowSize: 9,
polynomial: 3,
let result = gsd(
{ x: spectrum[0], y: spectrum[1] },
{
noiseLevel: 1049200.537996172 / 2,
minMaxRatio: 0.01,
broadRatio: 0.0025,
sgOptions: {
windowSize: 9,
polynomial: 3,
},
},
});
);
joinBroadPeaks(result, { width: 0.25 });

@@ -23,0 +26,0 @@ expect(result).toHaveLength(14);

@@ -11,13 +11,14 @@ import { readFileSync } from 'fs';

);
let result = gsd(spectrum[0], spectrum[1], {
// noiseLevel: 1049200.537996172,
minMaxRatio: 0.03,
smoothY: false,
realTopDetection: true,
sgOptions: { windowSize: 5, polynomial: 3 },
});
// console.log(spectrum[1][13223]);
// console.log(result);
let result = gsd(
{ x: spectrum[0], y: spectrum[1] },
{
// noiseLevel: 1049200.537996172,
minMaxRatio: 0.03,
smoothY: false,
realTopDetection: true,
sgOptions: { windowSize: 5, polynomial: 3 },
},
);
expect(result).toHaveLength(21);
});
});

@@ -11,3 +11,3 @@ import { readFileSync } from 'fs';

);
gsd(spectrum.x, spectrum.y, {
gsd(spectrum, {
noiseLevel: 32,

@@ -14,0 +14,0 @@ minMaxRatio: 0.03,

@@ -28,10 +28,13 @@ import { gsd, optimizePeaks } from '..';

it('Check result', () => {
let result = gsd(x, y, {
noiseLevel: noiseLevel,
minMaxRatio: 0,
broadRatio: 0,
smoothY: false,
realTopDetection: true,
});
result = optimizePeaks(result, x, y, {
let result = gsd(
{ x, y },
{
noiseLevel: noiseLevel,
minMaxRatio: 0,
broadRatio: 0,
smoothY: false,
realTopDetection: true,
},
);
result = optimizePeaks({ x, y }, result, {
factorWidth: 1,

@@ -38,0 +41,0 @@ functionName: 'gaussian',

import { gsd } from '..';
describe('Simple test cases', () => {
let X = [];
let Y = [];
let x = [];
let y = [];
for (let i = 0; i < 10; i++) {
X.push(X.length);
Y.push(0);
x.push(x.length);
y.push(0);
}
for (let i = 0; i <= 10; i++) {
X.push(X.length);
Y.push(i > 5 ? 10 - i : i);
x.push(x.length);
y.push(i > 5 ? 10 - i : i);
}
for (let i = 0; i < 10; i++) {
X.push(X.length);
Y.push(0);
x.push(x.length);
y.push(0);
}
it('gsd not realtop', () => {
let peaks = gsd(X, Y, {
realTopDetection: false,
smoothY: true,
sgOptions: {
windowSize: 5,
polynomial: 3,
let peaks = gsd(
{ x, y },
{
realTopDetection: false,
smoothY: true,
sgOptions: {
windowSize: 5,
polynomial: 3,
},
},
});
);

@@ -35,12 +38,15 @@ expect(peaks[0].y).toBeCloseTo(4.657, 3);

it('gsd not realtop asymetric', () => {
let Y2 = Y.slice(0);
let Y2 = y.slice(0);
Y2[14] = 5;
let peaks = gsd(X, Y2, {
realTopDetection: false,
smoothY: true,
sgOptions: {
windowSize: 5,
polynomial: 3,
let peaks = gsd(
{ x, y: Y2 },
{
realTopDetection: false,
smoothY: true,
sgOptions: {
windowSize: 5,
polynomial: 3,
},
},
});
);

@@ -68,12 +74,15 @@ expect(peaks).toStrictEqual([

it('gsd realtop', () => {
let Y2 = Y.slice();
let Y2 = y.slice();
Y2[14] = 5;
let peaks = gsd(X, Y2, {
realTopDetection: true,
smoothY: false,
sgOptions: {
windowSize: 5,
polynomial: 3,
let peaks = gsd(
{ x, y: Y2 },
{
realTopDetection: true,
smoothY: false,
sgOptions: {
windowSize: 5,
polynomial: 3,
},
},
});
);
expect(peaks).toStrictEqual([

@@ -80,0 +89,0 @@ {

@@ -1,4 +0,4 @@

import { gsd } from '..';
import { gsd, optimizePeaks } from '..';
const { SpectrumGenerator } = require('spectrum-generator');
const { generateSpectrum } = require('spectrum-generator');

@@ -8,11 +8,10 @@ describe('Global spectra deconvolution with simulated spectra', () => {

it('Should provide the right result ...', () => {
const sg = new SpectrumGenerator({ start: 0, end: 100, pointsPerUnit: 10 });
const peaks = [
{ x: 0.1, y: 0.2, width: 0.1 },
{ x: -0.1, y: 0.2, width: 0.3 },
];
sg.addPeak([20, 100], { width: 5 });
sg.addPeak([50, 50], { width: 5 });
sg.addPeak([70, 20], { width: 5 });
const data = generateSpectrum(peaks, { from: -1, to: 1, nbPoints: 101 });
let spectrum = sg.getSpectrum();
let result = gsd(spectrum.x, spectrum.y, {
let peakList = gsd(data, {
minMaxRatio: 0,

@@ -23,6 +22,11 @@ realTopDetection: false,

expect(result[0]).toMatchObject({ x: 20, y: 100 });
expect(result[1]).toMatchObject({ x: 50, y: 50 });
expect(result[2]).toMatchObject({ x: 70, y: 20 });
let optPeaks = optimizePeaks(data, peakList, {});
expect(optPeaks[0].x).toBeCloseTo(-0.1, 2);
expect(optPeaks[0].y).toBeCloseTo(0.2, 2);
expect(optPeaks[0].width).toBeCloseTo(0.3, 2);
expect(optPeaks[1].x).toBeCloseTo(0.1, 2);
expect(optPeaks[1].y).toBeCloseTo(0.2, 2);
expect(optPeaks[1].width).toBeCloseTo(0.1, 2);
});
});

@@ -18,8 +18,11 @@ import { readFileSync } from 'fs';

);
let result = gsd(spectrum[0], spectrum[1], {
// noiseLevel: 0.001,
minMaxRatio: 0,
realTopDetection: true,
smoothY: false,
});
let result = gsd(
{ x: spectrum[0], y: spectrum[1] },
{
// noiseLevel: 0.001,
minMaxRatio: 0,
realTopDetection: true,
smoothY: false,
},
);

@@ -53,8 +56,11 @@ expect(result[0].x).toBeCloseTo(24, 2);

}
let ans = gsd(times, tic, {
noiseLevel: 0,
realTopDetection: false,
smoothY: false,
sgOptions: { windowSize: 5, polynomial: 3 },
});
let ans = gsd(
{ x: times, y: tic },
{
noiseLevel: 0,
realTopDetection: false,
smoothY: false,
sgOptions: { windowSize: 5, polynomial: 3 },
},
);

@@ -61,0 +67,0 @@ expect(ans).toHaveLength(10);

@@ -21,3 +21,3 @@ import { readFileSync } from 'fs';

let result = gsd(spectrum.x, spectrum.y, {
let result = gsd(spectrum, {
noiseLevel: noiseLevel,

@@ -24,0 +24,0 @@ minMaxRatio: 0.0,

import { gsd } from '..';
test('Simple test cases', () => {
let X = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let Y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0];
let peaks = gsd(X, Y, {
noiseLevel: 0,
minMaxRatio: 0.00025, // Threshold to determine if a given peak should be considered as a noise
realTopDetection: true,
maxCriteria: true, // inverted:false
smoothY: false,
sgOptions: { windowSize: 7, polynomial: 3 },
});
let x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0];
let peaks = gsd(
{ x, y },
{
noiseLevel: 0,
minMaxRatio: 0.00025, // Threshold to determine if a given peak should be considered as a noise
realTopDetection: true,
maxCriteria: true, // inverted:false
smoothY: false,
sgOptions: { windowSize: 7, polynomial: 3 },
},
);
expect(peaks[0].x).toBe(8);
});

@@ -5,5 +5,6 @@ import SG from 'ml-savitzky-golay-generalized';

* Global spectra deconvolution
* @param {Array<number>} x - Independent variable
* @param {Array<number>} yIn - Dependent variable
* @param {object} [options] - Options object
* @param {object} data - Object data with x and y arrays
* @param {Array<number>} [data.x] - Independent variable
* @param {Array<number>} [data.y] - 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

@@ -24,3 +25,3 @@ * @param {number} [options.sgOptions.windowSize = 9] - points to use in the approximations

*/
export function gsd(x, yIn, options = {}) {
export function gsd(data, options = {}) {
let {

@@ -41,2 +42,4 @@ noiseLevel,

let { y: yIn, x } = data;
const y = yIn.slice();

@@ -43,0 +46,0 @@ let equalSpaced = isEqualSpaced(x);

@@ -1,7 +0,8 @@

import { optimizeSingleLorentzian } from 'ml-optimize-lorentzian';
import { optimize } from 'ml-spectra-fitting';
/**
* This function try to join the peaks that seems to belong to a broad signal in a single broad peak.
* @param peakList
* @param options
* @param {Array} peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
* @param {object} [options = {}] -
* @param {number} options.width - width limit to join peaks.
*/

@@ -25,9 +26,8 @@ export function joinBroadPeaks(peakList, options = {}) {

let candidates = [[broadLines[0].x, broadLines[0].y]];
let indexes = [broadLines[0].index];
let candidates = { x: [broadLines[0].x], y: [broadLines[0].y] };
let indexes = [0];
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]);
candidates.x.push(broadLines[i].x);
candidates.y.push(broadLines[i].y);
if (broadLines[i].y > max) {

@@ -37,23 +37,25 @@ max = broadLines[i].y;

}
indexes.push(broadLines[i].index);
indexes.push(i);
count++;
} else {
if (count > 2) {
let fitted = optimizeSingleLorentzian(candidates, {
x: broadLines[maxI].x,
y: max,
width: Math.abs(
candidates[0][0] - candidates[candidates.length - 1][0],
),
});
let { parameters } = fitted;
peakList.push({
x: parameters[0],
y: parameters[1],
width: parameters[2],
index: Math.floor(
indexes.reduce((a, b) => a + b, 0) / indexes.length,
),
soft: false,
});
let fitted = optimize(
candidates,
[
{
x: broadLines[maxI].x,
y: max,
width: Math.abs(
candidates.x[0] - candidates.x[candidates.x.length - 1],
),
},
],
{ kind: 'lorentzian' },
);
let { peaks: peak } = fitted;
peak[0].index = Math.floor(
indexes.reduce((a, b) => a + b, 0) / indexes.length,
);
peak[0].soft = false;
peakList.push(peak[0]);
} else {

@@ -65,3 +67,3 @@ // Put back the candidates to the signals list

}
candidates = [[broadLines[i].x, broadLines[i].y]];
candidates = { x: [broadLines[i].x], y: [broadLines[i].y] };
indexes = [i];

@@ -73,3 +75,2 @@ max = broadLines[i].y;

}
peakList.sort(function (a, b) {

@@ -76,0 +77,0 @@ return a.x - b.x;

@@ -1,12 +0,21 @@

import {
optimizeGaussianSum,
optimizeLorentzianSum,
optimizeSingleGaussian,
optimizeSingleLorentzian,
} from 'ml-optimize-lorentzian';
import { optimize } from 'ml-spectra-fitting';
export function optimizePeaks(peakList, x, y, options = {}) {
/**
* Optimize the position (x), max intensity (y), full width at half maximum (width)
* and the ratio of gaussian contribution (mu) if it's required. It supports three kind of shapes: gaussian, lorentzian and pseudovoigt
* @param {object} data - An object containing the x and y data to be fitted.
* @param {Array} peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
* @param {object} [options = {}] -
* @param {string} [options.kind = 'gaussian'] - kind of shape used to fitting, lorentzian, gaussian and pseudovoigt are supported.
* @param {number} [options.factorWidth = 4] - times of width to group peaks.
* @param {object} [options.joinPeaks = true] - if true the peaks could be grouped if the separation between them are inside of a range of factorWidth * width
* @param {object} [options.optimizationOptions] - options of ml-levenberg-marquardt optimization package.
*/
const kindSupported = ['gaussian', 'lorentzian', 'pseudovoigt'];
export function optimizePeaks(data, peakList, options = {}) {
const {
functionName = 'gaussian',
factorWidth = 4,
joinPeaks = true,
optimizationOptions = {

@@ -19,9 +28,10 @@ damping: 1.5,

let { x, y } = data;
checkFuncName(functionName, optimizationOptions);
let lastIndex = [0];
let groups = groupPeaks(peakList, factorWidth);
let groups = groupPeaks(peakList, factorWidth, joinPeaks);
let result = [];
let factor = 1;
if (functionName === 'gaussian') {
factor = 1.17741;
} // From https://en.wikipedia.org/wiki/Gaussian_function#Properties
let sampling;

@@ -39,24 +49,10 @@ for (let i = 0; i < groups.length; i++) {

);
if (sampling[0].length > 5) {
let optPeaks = [];
if (functionName === 'gaussian') {
optPeaks = optimizeGaussianSum(sampling, peaks, optimizationOptions);
} else {
if (functionName === 'lorentzian') {
optPeaks = optimizeLorentzianSum(
sampling,
peaks,
optimizationOptions,
);
}
}
if (sampling.x.length > 5) {
let { peaks: optPeaks } = optimize(sampling, peaks, {
kind: functionName,
lmOptions: optimizationOptions,
});
for (let j = 0; j < optPeaks.length; j++) {
let { parameters } = optPeaks[j];
result.push({
x: parameters[0],
y: parameters[1],
width: parameters[2] * factor,
index: peaks[j].index,
});
optPeaks[j].index = peaks.index;
result.push(optPeaks[j]);
}

@@ -75,27 +71,10 @@ }

if (sampling[0].length > 5) {
let fitResult = [];
if (functionName === 'gaussian') {
fitResult = optimizeSingleGaussian(
[sampling[0], sampling[1]],
peaks,
optimizationOptions,
);
} else {
if (functionName === 'lorentzian') {
fitResult = optimizeSingleLorentzian(
[sampling[0], sampling[1]],
peaks,
optimizationOptions,
);
}
}
let { parameters } = fitResult;
result.push({
x: parameters[0],
y: parameters[1],
width: parameters[2] * factor,
index: peaks.index,
}); // From https://en.wikipedia.org/wiki/Gaussian_function#Properties}
if (sampling.x.length > 5) {
let fitResult = optimize(sampling, [peaks], {
kind: functionName,
lmOptions: optimizationOptions,
});
let { peaks: optPeaks } = fitResult;
optPeaks[0].index = peaks.index;
result.push(optPeaks[0]);
}

@@ -137,6 +116,6 @@ }

lastIndex[0] = index;
return [sampleX, sampleY];
return { x: sampleX, y: sampleY };
}
function groupPeaks(peakList, nL) {
function groupPeaks(peakList, nL, joinPeaks) {
let group = [];

@@ -150,4 +129,4 @@ let groups = [];

if (
Math.abs(peakList[i].x - limits[0]) <
nL * peakList[i].width + limits[1]
joinPeaks &&
Math.abs(peakList[i].x - limits[0]) < nL * peakList[i].width + limits[1]
) {

@@ -171,3 +150,2 @@ // Add the peak to the group

groups.push({ limits: limits, group: group });
// var optmimalPeak = fitSpectrum(group,limits,spectrum);
group = [peakList[i]];

@@ -207,1 +185,15 @@ limits = [peakList[i].x, nL * peakList[i].width];

}
function checkFuncName(functionName, optimizationOptions) {
let kind = functionName.toLowerCase().replace(/[^a-z]/g, '');
let isSupported = kindSupported.some((ks) => ks === kind);
if (isSupported) {
optimizationOptions.kind = kind;
} else {
throw new Error(
`Kind of function unsupported. Just these kind are supported: ${kindSupported.join(
', ',
)}`,
);
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc