From 5debaef3c63677eda3a4fdb6bc70a02929a2aeec Mon Sep 17 00:00:00 2001 From: jobo322 Date: Tue, 30 Jun 2026 10:05:15 -0500 Subject: [PATCH 1/6] feat: remove peak limit for optimization and adjust autoPeakPicking parameters --- src/component/panels/PeaksPanel/PeaksPanel.tsx | 8 +------- src/data/data1d/Spectrum1D/peaks/autoPeakPicking.ts | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/component/panels/PeaksPanel/PeaksPanel.tsx b/src/component/panels/PeaksPanel/PeaksPanel.tsx index 995fd25d4..794e189d7 100644 --- a/src/component/panels/PeaksPanel/PeaksPanel.tsx +++ b/src/component/panels/PeaksPanel/PeaksPanel.tsx @@ -111,14 +111,8 @@ function PeaksPanelInner(props: PeaksPanelInnerProps) { const filterPeaks = peaks.values.filter((peak) => isInRange(peak.x, { from, to }), ); - if (filterPeaks.length <= 15) { dispatch({ type: 'OPTIMIZE_PEAKS', payload: { peaks: filterPeaks } }); - } else { - toaster.show({ - message: 'optimization can be done on no more than 15 peaks', - intent: 'danger', - }); - } + }; function toggleViewProperty(key: keyof FilterType) { diff --git a/src/data/data1d/Spectrum1D/peaks/autoPeakPicking.ts b/src/data/data1d/Spectrum1D/peaks/autoPeakPicking.ts index 63cef1c70..da756b3e6 100644 --- a/src/data/data1d/Spectrum1D/peaks/autoPeakPicking.ts +++ b/src/data/data1d/Spectrum1D/peaks/autoPeakPicking.ts @@ -47,6 +47,7 @@ export function autoPeakPicking( direction, sensitivity: 100, shape: defaultPeakShape, + broadRatio: 0.0025, noiseLevel: noise * noiseFactor, minMaxRatio, // Threshold to determine if a given peak should be considered as a noise realTopDetection: true, From bab6c9768a4b41b575257bca097229ce0381c393 Mon Sep 17 00:00:00 2001 From: jobo322 Date: Wed, 1 Jul 2026 10:54:43 -0500 Subject: [PATCH 2/6] feat: optimize peak processing by removing peak limit and enhancing parameters --- .../data1d/Spectrum1D/peaks/optimizePeaks.ts | 199 +++++++++--------- 1 file changed, 102 insertions(+), 97 deletions(-) diff --git a/src/data/data1d/Spectrum1D/peaks/optimizePeaks.ts b/src/data/data1d/Spectrum1D/peaks/optimizePeaks.ts index 057b512c1..75da92d9e 100644 --- a/src/data/data1d/Spectrum1D/peaks/optimizePeaks.ts +++ b/src/data/data1d/Spectrum1D/peaks/optimizePeaks.ts @@ -36,109 +36,114 @@ export function optimizePeaks( groupingFactor: 10, stages: [ { - optimization: { - kind: 'lm', - options: { maxIterations: 20, errorTolerance: 1e-3 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) / 2, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, - }, - mu: { optimize: false }, - x: { optimize: false }, - y: { - optimize: true, - init: (peak: any) => peak.y * 0.8, - }, - }, + // Stage 1: local stabilization + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 20, errorTolerance: 1e-3 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, }, - { - optimization: { - kind: 'lm', - options: { maxIterations: 20, errorTolerance: 5e-4 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) / 2, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, - }, - mu: { optimize: false }, - x: { optimize: false }, - y: { - optimize: true, - }, - }, + mu: { optimize: false }, + x: { optimize: false }, + y: { + optimize: true, + init: (peak: any) => peak.y }, - { - optimization: { - kind: 'lm', - options: { maxIterations: 20, errorTolerance: 1e-5 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) / 2, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, - }, - mu: { optimize: true }, - x: { optimize: false }, - y: { - optimize: true, - }, - }, + }, + }, + { + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 20, errorTolerance: 1e-3 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, }, - { - optimization: { - kind: 'lm', - options: { maxIterations: 20, errorTolerance: 5e-4 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) / 3, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 3, - }, - mu: { optimize: true }, - x: { optimize: true }, - y: { optimize: true }, - }, + mu: { optimize: false }, + x: { optimize: false }, + y: { + optimize: true, + init: (peak: any) => peak.y }, - { - optimization: { - kind: 'lm', - options: { maxIterations: 20, errorTolerance: 1e-4 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) / 2, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, - }, - mu: { optimize: false }, - x: { optimize: true }, - y: { optimize: true }, - }, + }, + }, + { + // Stage 2: regroup into the real overlapping cluster + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 25, errorTolerance: 1e-4 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, }, - { - optimization: { - kind: 'lm', - options: { maxIterations: 20, errorTolerance: 1e-8 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) / 2, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, - }, - mu: { optimize: true }, - x: { optimize: true }, - y: { optimize: true }, - }, + mu: { optimize: true }, + x: { optimize: false }, + y: { optimize: true }, + }, + }, + { + // Stage 3: final polish + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 30, errorTolerance: 1e-5 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + }, + mu: { optimize: true }, + x: { + optimize: true, + min: (peak: any) => peak.x - (peak.shape?.fwhm ?? 0) / 4, + max: (peak: any) => peak.x + (peak.shape?.fwhm ?? 0) / 4, + }, + y: { optimize: true }, + }, + }, + { + // Stage 3: final polish + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 30, errorTolerance: 1e-5 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + }, + mu: { optimize: true }, + x: { + optimize: true, + min: (peak: any) => peak.x - (peak.shape?.fwhm ?? 0) / 4, + max: (peak: any) => peak.x + (peak.shape?.fwhm ?? 0) / 4, }, - ], + y: { optimize: true }, + }, + }, +], }); return mapPeaks(spectrum.peaks.values.concat(newPeaks), spectrum, { From a5609bd4303d04994b2c3552cf5345c4afdad223 Mon Sep 17 00:00:00 2001 From: jobo322 Date: Wed, 1 Jul 2026 10:56:36 -0500 Subject: [PATCH 3/6] chore: update ml-gsd --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4f25b97c1..b5b73ddff 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "ml-array-mean": "^2.0.0", "ml-array-median": "^2.0.0", "ml-conrec": "^6.0.0", - "ml-gsd": "^14.2.0", + "ml-gsd": "^14.2.1", "ml-signal-processing": "^2.2.2", "ml-spectra-processing": "^14.29.1", "ml-tree-similarity": "^2.2.0", From c2094102b93819d94c508a93fb8a88954d865575 Mon Sep 17 00:00:00 2001 From: jobo322 Date: Thu, 2 Jul 2026 08:27:52 -0500 Subject: [PATCH 4/6] chore: update package-lock.json --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0649e74e9..18773f771 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,7 +38,7 @@ "ml-array-mean": "^2.0.0", "ml-array-median": "^2.0.0", "ml-conrec": "^6.0.0", - "ml-gsd": "^14.2.0", + "ml-gsd": "^14.2.1", "ml-signal-processing": "^2.2.2", "ml-spectra-processing": "^14.29.1", "ml-tree-similarity": "^2.2.0", @@ -9401,9 +9401,9 @@ } }, "node_modules/ml-gsd": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/ml-gsd/-/ml-gsd-14.2.0.tgz", - "integrity": "sha512-dX/VA9yj8GnenbE7prMPuki9/8cV43VcTqaxeZ4stMuUuO98QhFKkkQ/rBgJ9/t0g/sXWtToihHGrIUbP8+AEA==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/ml-gsd/-/ml-gsd-14.2.1.tgz", + "integrity": "sha512-5RwHGZL61Pf7LBVaWkQ4Qsnr1CHFg+pZ4sAxpufEMM4pignoS6NqVkwAk0aCRb97gZsLIL3srDcRRExNcqGGpw==", "license": "MIT", "dependencies": { "cheminfo-types": "^1.15.0", From 77518d7880603e6316ee81ec43c5b4d0f9baea88 Mon Sep 17 00:00:00 2001 From: jobo322 Date: Thu, 2 Jul 2026 08:41:38 -0500 Subject: [PATCH 5/6] fix: uses the same minMaxRatio for maxAbsoluteRatio option --- .../panels/PeaksPanel/PeaksPanel.tsx | 3 +- .../Spectrum1D/peaks/autoPeakPicking.ts | 2 +- .../data1d/Spectrum1D/peaks/optimizePeaks.ts | 204 +++++++++--------- .../detectSignalsByMultipletAnalysis.ts | 1 + 4 files changed, 105 insertions(+), 105 deletions(-) diff --git a/src/component/panels/PeaksPanel/PeaksPanel.tsx b/src/component/panels/PeaksPanel/PeaksPanel.tsx index 794e189d7..680dc3706 100644 --- a/src/component/panels/PeaksPanel/PeaksPanel.tsx +++ b/src/component/panels/PeaksPanel/PeaksPanel.tsx @@ -111,8 +111,7 @@ function PeaksPanelInner(props: PeaksPanelInnerProps) { const filterPeaks = peaks.values.filter((peak) => isInRange(peak.x, { from, to }), ); - dispatch({ type: 'OPTIMIZE_PEAKS', payload: { peaks: filterPeaks } }); - + dispatch({ type: 'OPTIMIZE_PEAKS', payload: { peaks: filterPeaks } }); }; function toggleViewProperty(key: keyof FilterType) { diff --git a/src/data/data1d/Spectrum1D/peaks/autoPeakPicking.ts b/src/data/data1d/Spectrum1D/peaks/autoPeakPicking.ts index da756b3e6..05bc64342 100644 --- a/src/data/data1d/Spectrum1D/peaks/autoPeakPicking.ts +++ b/src/data/data1d/Spectrum1D/peaks/autoPeakPicking.ts @@ -47,8 +47,8 @@ export function autoPeakPicking( direction, sensitivity: 100, shape: defaultPeakShape, - broadRatio: 0.0025, noiseLevel: noise * noiseFactor, + maxAbsoluteRatio: minMaxRatio, // Threshold to determine if a given peak should be considered as a noise minMaxRatio, // Threshold to determine if a given peak should be considered as a noise realTopDetection: true, smoothY: false, diff --git a/src/data/data1d/Spectrum1D/peaks/optimizePeaks.ts b/src/data/data1d/Spectrum1D/peaks/optimizePeaks.ts index 75da92d9e..ae6401cbc 100644 --- a/src/data/data1d/Spectrum1D/peaks/optimizePeaks.ts +++ b/src/data/data1d/Spectrum1D/peaks/optimizePeaks.ts @@ -37,113 +37,113 @@ export function optimizePeaks( stages: [ { // Stage 1: local stabilization - factorLimits: 2, - maxNumberOfPeaks: 40, - optimization: { - kind: 'lm', - options: { maxIterations: 20, errorTolerance: 1e-3 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 20, errorTolerance: 1e-3 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + }, + mu: { optimize: false }, + x: { optimize: false }, + y: { + optimize: true, + init: (peak: any) => peak.y, + }, + }, }, - mu: { optimize: false }, - x: { optimize: false }, - y: { - optimize: true, - init: (peak: any) => peak.y - }, - }, - }, - { - factorLimits: 2, - maxNumberOfPeaks: 40, - optimization: { - kind: 'lm', - options: { maxIterations: 20, errorTolerance: 1e-3 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, - }, - mu: { optimize: false }, - x: { optimize: false }, - y: { - optimize: true, - init: (peak: any) => peak.y - }, - }, - }, - { - // Stage 2: regroup into the real overlapping cluster - factorLimits: 2, - maxNumberOfPeaks: 40, - optimization: { - kind: 'lm', - options: { maxIterations: 25, errorTolerance: 1e-4 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, - }, - mu: { optimize: true }, - x: { optimize: false }, - y: { optimize: true }, - }, - }, - { - // Stage 3: final polish - factorLimits: 2, - maxNumberOfPeaks: 40, - optimization: { - kind: 'lm', - options: { maxIterations: 30, errorTolerance: 1e-5 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + { + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 20, errorTolerance: 1e-3 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + }, + mu: { optimize: false }, + x: { optimize: false }, + y: { + optimize: true, + init: (peak: any) => peak.y, + }, + }, }, - mu: { optimize: true }, - x: { - optimize: true, - min: (peak: any) => peak.x - (peak.shape?.fwhm ?? 0) / 4, - max: (peak: any) => peak.x + (peak.shape?.fwhm ?? 0) / 4, + { + // Stage 2: regroup into the real overlapping cluster + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 25, errorTolerance: 1e-4 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + }, + mu: { optimize: true }, + x: { optimize: false }, + y: { optimize: true }, + }, }, - y: { optimize: true }, - }, - }, - { - // Stage 3: final polish - factorLimits: 2, - maxNumberOfPeaks: 40, - optimization: { - kind: 'lm', - options: { maxIterations: 30, errorTolerance: 1e-5 }, - }, - parameters: { - fwhm: { - optimize: true, - min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, - max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + { + // Stage 3: final polish + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 30, errorTolerance: 1e-5 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + }, + mu: { optimize: true }, + x: { + optimize: true, + min: (peak: any) => peak.x - (peak.shape?.fwhm ?? 0) / 4, + max: (peak: any) => peak.x + (peak.shape?.fwhm ?? 0) / 4, + }, + y: { optimize: true }, + }, }, - mu: { optimize: true }, - x: { - optimize: true, - min: (peak: any) => peak.x - (peak.shape?.fwhm ?? 0) / 4, - max: (peak: any) => peak.x + (peak.shape?.fwhm ?? 0) / 4, + { + // Stage 3: final polish + factorLimits: 2, + maxNumberOfPeaks: 40, + optimization: { + kind: 'lm', + options: { maxIterations: 30, errorTolerance: 1e-5 }, + }, + parameters: { + fwhm: { + optimize: true, + min: (peak: any) => (peak.shape?.fwhm ?? 0) * 0.5, + max: (peak: any) => (peak.shape?.fwhm ?? 0) * 2, + }, + mu: { optimize: true }, + x: { + optimize: true, + min: (peak: any) => peak.x - (peak.shape?.fwhm ?? 0) / 4, + max: (peak: any) => peak.x + (peak.shape?.fwhm ?? 0) / 4, + }, + y: { optimize: true }, + }, }, - y: { optimize: true }, - }, - }, -], + ], }); return mapPeaks(spectrum.peaks.values.concat(newPeaks), spectrum, { diff --git a/src/data/data1d/Spectrum1D/ranges/detectSignalsByMultipletAnalysis.ts b/src/data/data1d/Spectrum1D/ranges/detectSignalsByMultipletAnalysis.ts index 494402256..64c8e9f2b 100644 --- a/src/data/data1d/Spectrum1D/ranges/detectSignalsByMultipletAnalysis.ts +++ b/src/data/data1d/Spectrum1D/ranges/detectSignalsByMultipletAnalysis.ts @@ -35,6 +35,7 @@ export function detectSignalsByMultipletAnalysis( to, frequency, minMaxRatio: 0.1, + maxAbsoluteRatio: 0.1, broadWidth: 0.25, broadRatio: 0.0025, optimize: true, From 39b4dbe751692b6e8d8812f4364557b8b3424151 Mon Sep 17 00:00:00 2001 From: jobo322 Date: Thu, 2 Jul 2026 10:28:30 -0500 Subject: [PATCH 6/6] fix: uses the same value of minMaxRatio for maxAbsoluteRatio in ranges picking --- src/component/reducer/actions/RangesActions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/component/reducer/actions/RangesActions.ts b/src/component/reducer/actions/RangesActions.ts index c067b6996..80a79a577 100644 --- a/src/component/reducer/actions/RangesActions.ts +++ b/src/component/reducer/actions/RangesActions.ts @@ -234,6 +234,7 @@ function handleAutoRangesDetection( broadWidth: 0.05, thresholdFactor: 8, minMaxRatio, + maxAbsoluteRatio: minMaxRatio, direction: lookNegative ? 'both' : 'positive', }, };