Skip to content

Commit e62e27b

Browse files
authored
feat: update spectra-fitting package (#33)
* feat: update spectra-fitting package BREAKING CHANGES: kind is moved to shape:{kind} the options for the optimization package change to optimization object where you can select the kind of method to optimize * feat: improve coverage
1 parent 24f17ff commit e62e27b

File tree

6 files changed

+49
-18
lines changed

6 files changed

+49
-18
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
},
7373
"dependencies": {
7474
"ml-savitzky-golay-generalized": "2.0.2",
75-
"ml-spectra-fitting": "^0.6.0",
76-
"ml-peak-shape-generator": "^0.9.0"
75+
"ml-spectra-fitting": "^0.7.0",
76+
"ml-peak-shape-generator": "^0.10.0"
7777
}
7878
}

src/__tests__/massPeakPicking.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe('Check the peak picking of a simulated mass spectrum', () => {
3636
},
3737
);
3838
result = optimizePeaks({ x, y }, result, {
39-
factorWidth: 1,
39+
factorWidth: 4,
4040
functionName: 'gaussian',
4141
});
4242
expect(result[0].x).toBeCloseTo(69.938, 1);

src/__tests__/simulated.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ describe('Global spectra deconvolution with simulated spectra', () => {
1111
];
1212

1313
const data = generateSpectrum(peaks, { from: -1, to: 1, nbPoints: 101 });
14-
14+
data.y.reverse();
15+
data.x.reverse();
1516
let peakList = gsd(data, {
1617
minMaxRatio: 0,
1718
realTopDetection: false,
1819
smoothY: false,
20+
heightFactor: 1,
1921
});
2022

21-
let optPeaks = optimizePeaks(data, peakList, {});
23+
let optPeaks = optimizePeaks(data, peakList);
2224

2325
expect(optPeaks[0].x).toBeCloseTo(-0.1, 2);
2426
expect(optPeaks[0].y).toBeCloseTo(0.2, 2);
@@ -27,4 +29,22 @@ describe('Global spectra deconvolution with simulated spectra', () => {
2729
expect(optPeaks[1].y).toBeCloseTo(0.2, 2);
2830
expect(optPeaks[1].width).toBeCloseTo(0.1, 2);
2931
});
32+
it('Overlaped peaks', () => {
33+
const peaks = [
34+
{ x: 0.1, y: 0.4, width: 0.0 },
35+
{ x: 0.101, y: 0.5, width: 0.01 },
36+
{ x: 0.15, y: 0.4, width: 0.01 },
37+
{ x: 0.151, y: 0.3, width: 0.03 },
38+
];
39+
40+
const data = generateSpectrum(peaks, { from: 0, to: 1, nbPoints: 101 });
41+
42+
let optPeaks = optimizePeaks(data, peaks, {
43+
factorWidth: 1,
44+
optimization: { kind: 'lm', options: { maxIterations: 300 } },
45+
});
46+
expect(optPeaks[0].x).toBeCloseTo(0.15, 2);
47+
expect(optPeaks[0].y).toBeCloseTo(0.4, 2);
48+
expect(optPeaks[0].width).toBeCloseTo(0.01, 2);
49+
});
3050
});

src/gsd.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import SG from 'ml-savitzky-golay-generalized';
77
* @param {Array<number>} [data.x] - Independent variable
88
* @param {Array<number>} [data.y] - Dependent variable
99
* @param {object} [options={}] - Options object
10+
* @param {object} [options.shape={}] - Object that specified the kind of shape to calculate the FWHM instead of width between inflection points. see https://mljs.github.io/peak-shape-generator/#inflectionpointswidthtofwhm
1011
* @param {object} [options.sgOptions] - Options object for Savitzky-Golay filter. See https://github.com/mljs/savitzky-golay-generalized#options
1112
* @param {number} [options.sgOptions.windowSize = 9] - points to use in the approximations
1213
* @param {number} [options.sgOptions.polynomial = 3] - degree of the polynomial to use in the approximations

src/post/joinBroadPeaks.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,20 @@ import { optimize } from 'ml-spectra-fitting';
33
/**
44
* This function try to join the peaks that seems to belong to a broad signal in a single broad peak.
55
* @param {Array} peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
6-
* @param {object} [options = {}] -
7-
* @param {number} options.width - width limit to join peaks.
6+
* @param {object} [options = {}] - options
7+
* @param {number} [options.width=0.25] - width limit to join peaks.
8+
* @param {object} [options.shape={}] - it's specify the kind of shape used to fitting.
9+
* @param {string} [options.shape.kind = 'gaussian'] - kind of shape; lorentzian, gaussian and pseudovoigt are supported.
10+
* @param {object} [options.optimization = {}] - it's specify the kind and options of the algorithm use to optimize parameters.
11+
* @param {string} [options.optimization.kind = 'lm'] - kind of algorithm. By default it's levenberg-marquardt.
12+
* @param {object} [options.optimization.options = {}] - options for the specific kind of algorithm.
813
*/
914
export function joinBroadPeaks(peakList, options = {}) {
10-
let { shape = { kind: 'gaussian' }, width, lmOptions = {} } = options;
15+
let {
16+
width = 0.25,
17+
shape = { kind: 'gaussian' },
18+
optimization = { kind: 'lm' },
19+
} = options;
1120
let broadLines = [];
1221
// Optimize the possible broad lines
1322
let max = 0;
@@ -48,7 +57,7 @@ export function joinBroadPeaks(peakList, options = {}) {
4857
),
4958
},
5059
],
51-
{ shape, lmOptions },
60+
{ shape, optimization },
5261
);
5362
let { peaks: peak } = fitted;
5463
peak[0].index = Math.floor(

src/post/optimizePeaks.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import { optimize } from 'ml-spectra-fitting';
66
* @param {object} data - An object containing the x and y data to be fitted.
77
* @param {Array} peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
88
* @param {object} [options = {}] -
9-
* @param {string} [options.kind = 'gaussian'] - kind of shape used to fitting, lorentzian, gaussian and pseudovoigt are supported.
10-
* @param {number} [options.factorWidth = 4] - times of width to group peaks.
9+
* @param {number} [options.factorWidth = 1] - times of width to group peaks.
1110
* @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
12-
* @param {object} [options.optimizationOptions] - options of ml-levenberg-marquardt optimization package.
11+
* @param {object} [options.shape={}] - it's specify the kind of shape used to fitting.
12+
* @param {string} [options.shape.kind = 'gaussian'] - kind of shape; lorentzian, gaussian and pseudovoigt are supported.
13+
* @param {object} [options.optimization = {}] - it's specify the kind and options of the algorithm use to optimize parameters.
14+
* @param {object} [options.optimization.kind = 'lm'] - kind of algorithm. By default it's levenberg-marquardt.
15+
* @param {object} [options.optimization.options = {}] - options for the specific kind of algorithm.
1316
*/
1417

1518
export function optimizePeaks(data, peakList, options = {}) {
@@ -19,10 +22,8 @@ export function optimizePeaks(data, peakList, options = {}) {
1922
shape = {
2023
kind: 'gaussian',
2124
},
22-
optimizationOptions = {
23-
damping: 1.5,
24-
maxIterations: 100,
25-
errorTolerance: 10e-5,
25+
optimization = {
26+
kind: 'lm',
2627
},
2728
} = options;
2829

@@ -47,7 +48,7 @@ export function optimizePeaks(data, peakList, options = {}) {
4748
if (sampling.x.length > 5) {
4849
let { peaks: optPeaks } = optimize(sampling, peaks, {
4950
shape,
50-
lmOptions: optimizationOptions,
51+
optimization,
5152
});
5253
for (let j = 0; j < optPeaks.length; j++) {
5354
optPeaks[j].index = peaks.index;
@@ -68,7 +69,7 @@ export function optimizePeaks(data, peakList, options = {}) {
6869
if (sampling.x.length > 5) {
6970
let fitResult = optimize(sampling, [peaks], {
7071
shape,
71-
lmOptions: optimizationOptions,
72+
optimization,
7273
});
7374
let { peaks: optPeaks } = fitResult;
7475
optPeaks[0].index = peaks.index;

0 commit comments

Comments
 (0)