From bac3756ae924138a3002ea2ae2c0827db40ff4f6 Mon Sep 17 00:00:00 2001 From: patquem Date: Mon, 5 Aug 2024 11:01:15 +0200 Subject: [PATCH 01/10] add rosettasciio in dependencies --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index d4e1643..6d08297 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ dependencies = [ "lmfit", "parse", "dill", + "rosettasciio", "pywin32; platform_system == 'Windows'", ] From 95e2f77dd9f239983800945378641d596605f649 Mon Sep 17 00:00:00 2001 From: patquem Date: Mon, 5 Aug 2024 11:06:47 +0200 Subject: [PATCH 02/10] include preprocess() in multiprocessing --- fitspy/spectra.py | 6 +++--- fitspy/spectrum.py | 8 ++------ fitspy/utils_mp.py | 29 ++++++++++++++++++++++------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/fitspy/spectra.py b/fitspy/spectra.py index 05b083e..4bf2a4f 100644 --- a/fitspy/spectra.py +++ b/fitspy/spectra.py @@ -211,8 +211,6 @@ def apply_model(self, model_dict, fnames=None, ncpus=1, fit_only=False, spectrum, _ = self.get_objects(fname) spectrum.set_attributes(model_dict) spectrum.fname = fname # reassign the correct fname - if not fit_only: - spectrum.preprocess() spectra.append(spectrum) queue_incr = Queue() @@ -222,10 +220,12 @@ def apply_model(self, model_dict, fnames=None, ncpus=1, fit_only=False, if ncpus == 1: for spectrum in spectra: + if not fit_only: + spectrum.preprocess() spectrum.fit() queue_incr.put(1) else: - fit_mp(spectra, ncpus, queue_incr) + fit_mp(spectra, ncpus, queue_incr, fit_only) self.pbar_index = 0 # reinitialize pbar_index after the calculation thread.join() diff --git a/fitspy/spectrum.py b/fitspy/spectrum.py index 32009b1..f7efc39 100644 --- a/fitspy/spectrum.py +++ b/fitspy/spectrum.py @@ -230,9 +230,8 @@ def preprocess(self): subtract_baseline() and normalize() """ self.load_profile(self.fname) - if self.baseline.is_subtracted: - self.baseline.is_subtracted = False - self.subtract_baseline() + self.baseline.is_subtracted = False + self.subtract_baseline() self.normalize() def load_profile(self, fname, xmin=None, xmax=None): @@ -620,9 +619,6 @@ def fit(self, fit_method=None, fit_negative=None, fit_outliers=None, def auto_baseline(self): """ set baseline.mode to 'Semi-Auto """ - msg = "Method auto_baseline() will be deprecated.\n" - msg += "Set spectrum.baseline.mode attribute to 'Semi-Auto' instead." - warnings.warn(msg, DeprecationWarning, stacklevel=2) self.baseline.mode = 'Semi-Auto' def subtract_baseline(self): diff --git a/fitspy/utils_mp.py b/fitspy/utils_mp.py index a7807cc..ccc7176 100644 --- a/fitspy/utils_mp.py +++ b/fitspy/utils_mp.py @@ -14,7 +14,10 @@ def fit(params): """ Fitting function used in multiprocessing """ - x0, y0, x, y, peak_models_, bkg_models_, fit_params, outliers_limit = params + (x0, y0, x, y, peak_models_, bkg_models_, + fit_params, outliers_limit, fit_only) = params + + res = () spectrum = Spectrum() spectrum.x0 = x0 @@ -25,10 +28,17 @@ def fit(params): spectrum.bkg_model = dill.loads(bkg_models_) spectrum.fit_params = fit_params spectrum.outliers_limit = outliers_limit + + if not fit_only: + spectrum.preprocess() + res += (spectrum.x, spectrum.y, spectrum.baseline.y_eval) + spectrum.fit() + res += (dill.dumps(spectrum.result_fit),) + shared_queue.put(1) - return dill.dumps(spectrum.result_fit) + return res def initializer(queue_incr): @@ -37,10 +47,10 @@ def initializer(queue_incr): shared_queue = queue_incr -def fit_mp(spectra, ncpus, queue_incr): +def fit_mp(spectra, ncpus, queue_incr, fit_only): """ Multiprocessing fit function applied to spectra """ - # models and fit_params are assumed to be consistent across all spectra , + # models and fit_params are assumed to be consistent across all spectra, # the 2 dill.dumps are performed once to limit the CPU cost peak_models_ = dill.dumps(spectra[0].peak_models) bkg_models_ = dill.dumps(spectra[0].bkg_model) @@ -50,15 +60,20 @@ def fit_mp(spectra, ncpus, queue_incr): args = [] for spectrum in spectra: args.append((spectrum.x0, spectrum.y0, spectrum.x, spectrum.y, - peak_models_, bkg_models_, fit_params, outliers_limit)) + peak_models_, bkg_models_, fit_params, outliers_limit, + fit_only)) with ProcessPoolExecutor(initializer=initializer, initargs=(queue_incr,), max_workers=ncpus) as executor: results = tuple(executor.map(fit, args)) - for result_fit_, spectrum in zip(results, spectra): - spectrum.result_fit = dill.loads(result_fit_) + for res, spectrum in zip(results, spectra): + if not fit_only: + spectrum.x = res[0] + spectrum.y = res[1] + spectrum.baseline.y_eval = res[2] + spectrum.result_fit = dill.loads(res[-1]) spectrum.reassign_params() # import os From c0ed2857d64c306c4b399e9d2592ae052ce89c70 Mon Sep 17 00:00:00 2001 From: patquem Date: Mon, 5 Aug 2024 11:11:22 +0200 Subject: [PATCH 03/10] bugfix: manage xmin/range_min and xmax/range_max separately --- fitspy/spectrum.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/fitspy/spectrum.py b/fitspy/spectrum.py index f7efc39..9bd78ec 100644 --- a/fitspy/spectrum.py +++ b/fitspy/spectrum.py @@ -237,11 +237,6 @@ def preprocess(self): def load_profile(self, fname, xmin=None, xmax=None): """ Load profile from 'fname' with 1 header line and 2 (x,y) columns""" - if xmin is not None: - self.range_min = xmin - if xmax is not None: - self.range_max = xmax - # raw profile loading if self.x0 is None: x0, y0 = get_1d_profile(fname) @@ -253,17 +248,20 @@ def load_profile(self, fname, xmin=None, xmax=None): self.fname = fname - # (re)initialization or cropping + if xmin is not None: + self.range_min = xmin + if xmax is not None: + self.range_max = xmax + if self.range_min is None: self.range_min = self.x0.min() + if self.range_max is None: self.range_max = self.x0.max() - self.x = self.x0.copy() - self.y = self.y0.copy() - else: - ind_min = closest_index(self.x0, self.range_min) - ind_max = closest_index(self.x0, self.range_max) - self.x = self.x0[ind_min:ind_max + 1].copy() - self.y = self.y0[ind_min:ind_max + 1].copy() + + ind_min = closest_index(self.x0, self.range_min) + ind_max = closest_index(self.x0, self.range_max) + self.x = self.x0[ind_min:ind_max + 1].copy() + self.y = self.y0[ind_min:ind_max + 1].copy() def calculate_outliers(self): """ Return outliers points (x,y) coordinates """ From 9b30dceb490e0d488c80976145e7cb961d4a67f0 Mon Sep 17 00:00:00 2001 From: patquem Date: Mon, 5 Aug 2024 11:12:58 +0200 Subject: [PATCH 04/10] make test_gui_auto_decomposition and test_nogui_auto_decomposition similar --- examples/ex_nogui_auto_decomposition.py | 4 ++-- tests/test_gui_auto_decomposition.py | 11 ++++++----- tests/test_nogui_auto_decomposition.py | 25 +++++++++++-------------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/examples/ex_nogui_auto_decomposition.py b/examples/ex_nogui_auto_decomposition.py index a425415..6db0b90 100644 --- a/examples/ex_nogui_auto_decomposition.py +++ b/examples/ex_nogui_auto_decomposition.py @@ -23,10 +23,10 @@ def auto_decomposition(verbosity=True, show_plots=False): spectra_list = [] for fname in fnames: spectrum = Spectrum() - spectrum.load_profile(fname) + spectrum.load_profile(fname, xmin=55) spectrum.auto_baseline() spectrum.subtract_baseline() - spectrum.auto_peaks(model_name="LorentzianAsym") + spectrum.auto_peaks(model_name="Lorentzian") # spectrum.fit() # fit is already performed during auto_peaks processing spectra_list.append(spectrum) diff --git a/tests/test_gui_auto_decomposition.py b/tests/test_gui_auto_decomposition.py index 9d72f7f..7b0307f 100644 --- a/tests/test_gui_auto_decomposition.py +++ b/tests/test_gui_auto_decomposition.py @@ -4,6 +4,11 @@ from examples.ex_gui_auto_decomposition import gui_auto_decomposition from utils import extract_results, display_is_ok +# REFS shared with test_nogui_auto_decomposition +REFS = [[142.2017338937751, 28029.56087034003, 8.277805414840545], + [137.67515324567708, 18759.15930233963, 14.979941168937462], + [366.6105573370797, 8114.486816783022, 43.73282414562729]] + @pytest.mark.skipif(not display_is_ok(), reason="DISPLAY problem") def test_gui_auto_decomposition(tmp_path): @@ -12,9 +17,5 @@ def test_gui_auto_decomposition(tmp_path): results = extract_results(dirname_res=tmp_path) # print(results) - refs = [[142.2017338937751, 28029.56087034003, 8.277805414840545], - [137.67515324567708, 18759.15930233963, 14.979941168937462], - [366.6105573370797, 8114.486816783022, 43.73282414562729]] - - for result, reference in zip(results, refs): + for result, reference in zip(results, REFS): assert result == approx(reference, rel=2e-2) diff --git a/tests/test_nogui_auto_decomposition.py b/tests/test_nogui_auto_decomposition.py index 3989ef8..7dc126f 100644 --- a/tests/test_nogui_auto_decomposition.py +++ b/tests/test_nogui_auto_decomposition.py @@ -2,24 +2,21 @@ import pytest from pytest import approx +from tests.test_gui_auto_decomposition import REFS + from examples.ex_nogui_auto_decomposition import auto_decomposition def test_auto_decomposition(): spectra = auto_decomposition(verbosity=False) - # refs = [] - # for i in range(3): - # ampli = spectra[i].peak_models[0].param_hints['ampli']['value'] - # refs.append([np.sum(spectra[i].y), ampli]) - # print(refs) - - refs = [[695742.9828417138, 28035.104052186613], - [645910.1509814768, 18783.270429923425], - [588544.9856527029, 8125.02943468474]] + results = [] + for i in range(3): + x0 = spectra[i].peak_models[0].param_hints['x0']['value'] + ampli = spectra[i].peak_models[0].param_hints['ampli']['value'] + fwhm = spectra[i].peak_models[0].param_hints['fwhm']['value'] + results.append([x0, ampli, fwhm]) + # print(results) - assert len(spectra) > 0 - for spectrum, ref in zip(spectra, refs): - ampli = spectrum.peak_models[0].param_hints['ampli']['value'] - assert np.sum(spectrum.y) == approx(ref[0], rel=1e-2) - assert ampli == approx(ref[1], rel=1e-2) + for result, reference in zip(results, REFS): + assert result == approx(reference, rel=2e-2) From 4e0bebfea1c23dc115d41abc6f4dc73a2c7c1702 Mon Sep 17 00:00:00 2001 From: patquem Date: Mon, 5 Aug 2024 12:18:00 +0200 Subject: [PATCH 05/10] bugfix: manage no points in baseline.eval() --- fitspy/baseline.py | 5 ++++- fitspy/spectrum.py | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/fitspy/baseline.py b/fitspy/baseline.py index cc71363..56a138d 100644 --- a/fitspy/baseline.py +++ b/fitspy/baseline.py @@ -107,7 +107,10 @@ def eval(self, x, y=None): # use the original points or the attached points to an y-profile points = self.points if y is None else self.attach_points(x, y) - if len(points[1]) == 1: + if len(points[1]) == 0: + self.y_eval = None + + elif len(points[1]) == 1: self.y_eval = points[1] * np.ones_like(x) elif self.mode == 'Linear': diff --git a/fitspy/spectrum.py b/fitspy/spectrum.py index 9bd78ec..054f6a8 100644 --- a/fitspy/spectrum.py +++ b/fitspy/spectrum.py @@ -626,8 +626,10 @@ def subtract_baseline(self): x, y = self.x, None if self.baseline.attached or self.baseline.mode == 'Semi-Auto': y = self.y_no_outliers - self.y -= self.baseline.eval(x=x, y=y) - self.baseline.is_subtracted = True + self.baseline.eval(x=x, y=y) + if self.baseline.y_eval is not None: + self.y -= self.baseline.y_eval + self.baseline.is_subtracted = True def auto_peaks(self, model_name): """ Create automatically 'model_name' peak-models in the limit of From 3b85858075abf15369c6c5019fa733625155403a Mon Sep 17 00:00:00 2001 From: patquem Date: Mon, 5 Aug 2024 14:11:11 +0200 Subject: [PATCH 06/10] bugfix: manage case where baseline.y_eval is None --- fitspy/spectrum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fitspy/spectrum.py b/fitspy/spectrum.py index 054f6a8..f2291e8 100644 --- a/fitspy/spectrum.py +++ b/fitspy/spectrum.py @@ -693,7 +693,7 @@ def plot(self, ax, ax.hlines(y=y_noise_level, xmin=x[0], xmax=x[-1], colors='r', linestyles='dashed', lw=0.5, label="Noise level") - if show_baseline and self.baseline.is_subtracted: + if show_baseline and self.baseline.y_eval is not None: ax.plot(x, self.baseline.y_eval, 'g', label="Baseline") y_bkg = np.zeros_like(x) From 22376d6ca01a6ee4f2337ff8390b3a1915b7cf42 Mon Sep 17 00:00:00 2001 From: patquem Date: Mon, 5 Aug 2024 14:11:48 +0200 Subject: [PATCH 07/10] bugfix: pass baseline_params to the workers --- fitspy/utils_mp.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/fitspy/utils_mp.py b/fitspy/utils_mp.py index ccc7176..8ab1edd 100644 --- a/fitspy/utils_mp.py +++ b/fitspy/utils_mp.py @@ -15,9 +15,7 @@ def fit(params): """ Fitting function used in multiprocessing """ (x0, y0, x, y, peak_models_, bkg_models_, - fit_params, outliers_limit, fit_only) = params - - res = () + fit_params, baseline_params, outliers_limit, fit_only) = params spectrum = Spectrum() spectrum.x0 = x0 @@ -30,11 +28,14 @@ def fit(params): spectrum.outliers_limit = outliers_limit if not fit_only: + for attr, value in baseline_params.items(): + setattr(spectrum.baseline, attr, value) spectrum.preprocess() - res += (spectrum.x, spectrum.y, spectrum.baseline.y_eval) - spectrum.fit() - res += (dill.dumps(spectrum.result_fit),) + + res = (dill.dumps(spectrum.result_fit),) + if not fit_only: + res += (spectrum.x, spectrum.y, spectrum.baseline.y_eval) shared_queue.put(1) @@ -55,25 +56,26 @@ def fit_mp(spectra, ncpus, queue_incr, fit_only): peak_models_ = dill.dumps(spectra[0].peak_models) bkg_models_ = dill.dumps(spectra[0].bkg_model) fit_params = spectra[0].fit_params + baseline_params = vars(spectra[0].baseline) outliers_limit = spectra[0].outliers_limit args = [] for spectrum in spectra: args.append((spectrum.x0, spectrum.y0, spectrum.x, spectrum.y, - peak_models_, bkg_models_, fit_params, outliers_limit, - fit_only)) + peak_models_, bkg_models_, fit_params, + baseline_params, outliers_limit, fit_only)) with ProcessPoolExecutor(initializer=initializer, initargs=(queue_incr,), max_workers=ncpus) as executor: - results = tuple(executor.map(fit, args)) + results = executor.map(fit, args) for res, spectrum in zip(results, spectra): + spectrum.result_fit = dill.loads(res[0]) if not fit_only: - spectrum.x = res[0] - spectrum.y = res[1] - spectrum.baseline.y_eval = res[2] - spectrum.result_fit = dill.loads(res[-1]) + spectrum.x = res[1] + spectrum.y = res[2] + spectrum.baseline.y_eval = res[3] spectrum.reassign_params() # import os From 47dcbe6c25cf33b2e291e51c8f97365909292f54 Mon Sep 17 00:00:00 2001 From: patquem Date: Tue, 6 Aug 2024 17:41:49 +0200 Subject: [PATCH 08/10] revisit range_min/range_max application --- fitspy/app/callbacks.py | 48 +++++++++++++++++++++++++---------------- fitspy/app/gui.py | 4 ++-- fitspy/app/utils.py | 9 ++++++++ fitspy/spectrum.py | 21 +++++++++--------- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/fitspy/app/callbacks.py b/fitspy/app/callbacks.py index 392221d..f293653 100644 --- a/fitspy/app/callbacks.py +++ b/fitspy/app/callbacks.py @@ -20,6 +20,7 @@ from fitspy import CMAP from fitspy.app.utils import convert_dict_from_tk_variables +from fitspy.app.utils import is_convertible_to_float class Callbacks: @@ -737,34 +738,41 @@ def fit_all(self): def set_spectrum_range(self, delete_tabview=True): """ Set range to the current spectrum """ - self.current_spectrum.range_min = float(self.range_min.get()) - self.current_spectrum.range_max = float(self.range_max.get()) - self.current_spectrum.load_profile(self.current_spectrum.fname) - self.set_range() + if is_convertible_to_float(self.range_min.get()): + self.current_spectrum.range_min = float(self.range_min.get()) + + if is_convertible_to_float(self.range_max.get()): + self.current_spectrum.range_max = float(self.range_max.get()) + self.remove(delete_tabview=delete_tabview) + self.current_spectrum.load_profile(self.current_spectrum.fname) + self.update_attractors() def set_range(self): """ Set range from the spectrum to the appli """ - self.range_min.set(self.current_spectrum.x[0]) - self.range_max.set(self.current_spectrum.x[-1]) - self.current_spectrum.attractors_calculation() + self.range_min.set(self.current_spectrum.range_min) + self.range_max.set(self.current_spectrum.range_max) def apply_range_to_all(self): """ Apply the appli range to all the spectra """ - range_min = float(self.range_min.get()) - range_max = float(self.range_max.get()) - self.range_min.set(range_min) - self.range_max.set(range_max) - self.show_plot = False - current_fname = self.current_spectrum.fname - for spectrum in self.spectra.all: - self.current_spectrum = spectrum - self.set_spectrum_range(delete_tabview=False) - self.show_plot = True - self.reassign_current_spectrum(current_fname) + if is_convertible_to_float(self.range_min.get()): + range_min = float(self.range_min.get()) + for spectrum in self.spectra.all: + spectrum.range_min = range_min + + if is_convertible_to_float(self.range_max.get()): + range_max = float(self.range_max.get()) + for spectrum in self.spectra.all: + spectrum.range_max = range_max + + self.current_spectrum.load_profile(self.current_spectrum.fname) + self.update_attractors() + self.paramsview.delete() self.statsview.delete() + self.ax.clear() + self.plot() def normalize(self): """ Normalize all spectra from maximum or attractor position """ @@ -829,7 +837,8 @@ def remove(self, delete_tabview=True): """ Remove all the features (spectrum attributes, baseline, tabview) """ if self.current_spectrum is not None: self.current_spectrum.remove_models() - self.delete_baseline() + self.current_spectrum.baseline.points = [[], []] + self.current_spectrum.attractors = [] if delete_tabview: # expensive operation when doing a lot of times self.paramsview.delete() self.statsview.delete() @@ -979,6 +988,7 @@ def update(self, fname=None): self.update_markers(fname) self.current_spectrum, _ = self.spectra.get_objects(fname) + self.current_spectrum.load_profile(fname) self.show_plot = False self.set_range() diff --git a/fitspy/app/gui.py b/fitspy/app/gui.py index bdac24c..a21674e 100644 --- a/fitspy/app/gui.py +++ b/fitspy/app/gui.py @@ -113,8 +113,8 @@ def __init__(self): self.progressbar = ProgressBar(self.root) # Spectrum parameters - self.range_min = DoubleVar(value=-1) - self.range_max = DoubleVar(value=99999) + self.range_min = StringVar(value="None") + self.range_max = StringVar(value="None") self.attractors = BooleanVar(value=True) self.outliers_coef = DoubleVar(value=1.5) diff --git a/fitspy/app/utils.py b/fitspy/app/utils.py index 91124bb..80d0ece 100644 --- a/fitspy/app/utils.py +++ b/fitspy/app/utils.py @@ -68,6 +68,15 @@ def convert_dict_from_tk_variables(parent_dict, excluded_keys=None): return new_dict +def is_convertible_to_float(s): + """ Check a string can be convert to float """ + try: + float(s) + return True + except ValueError: + return False + + class ToggleFrame(LabelFrame): """ Class dedicated to Enable/Disable LabelFrame and its related children""" diff --git a/fitspy/spectrum.py b/fitspy/spectrum.py index f2291e8..f8493ac 100644 --- a/fitspy/spectrum.py +++ b/fitspy/spectrum.py @@ -6,7 +6,6 @@ import csv import itertools from copy import deepcopy -import warnings import numpy as np from scipy.signal import find_peaks from scipy.interpolate import interp1d @@ -253,15 +252,17 @@ def load_profile(self, fname, xmin=None, xmax=None): if xmax is not None: self.range_max = xmax - if self.range_min is None: - self.range_min = self.x0.min() - if self.range_max is None: - self.range_max = self.x0.max() - - ind_min = closest_index(self.x0, self.range_min) - ind_max = closest_index(self.x0, self.range_max) - self.x = self.x0[ind_min:ind_max + 1].copy() - self.y = self.y0[ind_min:ind_max + 1].copy() + if self.range_min is None and self.range_max is None: + self.x = self.x0.copy() + self.y = self.y0.copy() + else: + ind_min, ind_max = 0, len(self.x0) + if self.range_min is not None: + ind_min = closest_index(self.x0, self.range_min) + if self.range_max is not None: + ind_max = closest_index(self.x0, self.range_max) + self.x = self.x0[ind_min:ind_max + 1].copy() + self.y = self.y0[ind_min:ind_max + 1].copy() def calculate_outliers(self): """ Return outliers points (x,y) coordinates """ From bc62557a305b23253ca1e077f2889bb90cd38044 Mon Sep 17 00:00:00 2001 From: patquem Date: Wed, 7 Aug 2024 09:38:16 +0200 Subject: [PATCH 09/10] (re)introduce conditions for plotting baseline --- fitspy/spectrum.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fitspy/spectrum.py b/fitspy/spectrum.py index f8493ac..9a78d1d 100644 --- a/fitspy/spectrum.py +++ b/fitspy/spectrum.py @@ -694,7 +694,9 @@ def plot(self, ax, ax.hlines(y=y_noise_level, xmin=x[0], xmax=x[-1], colors='r', linestyles='dashed', lw=0.5, label="Noise level") - if show_baseline and self.baseline.y_eval is not None: + if show_baseline and self.baseline.is_subtracted: + if self.baseline.y_eval is None: + self.baseline.eval(x, self.y_no_outliers) ax.plot(x, self.baseline.y_eval, 'g', label="Baseline") y_bkg = np.zeros_like(x) From 64005aa00175e234418c511a0f14e6152d0dbec0 Mon Sep 17 00:00:00 2001 From: patquem Date: Wed, 7 Aug 2024 11:18:36 +0200 Subject: [PATCH 10/10] add apply_range() and replace load_profile() by preprocess() --- examples/ex_nogui_auto_decomposition.py | 4 ++- fitspy/app/callbacks.py | 13 ++++---- fitspy/spectrum.py | 41 +++++++++++++------------ 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/examples/ex_nogui_auto_decomposition.py b/examples/ex_nogui_auto_decomposition.py index 6db0b90..bb96b10 100644 --- a/examples/ex_nogui_auto_decomposition.py +++ b/examples/ex_nogui_auto_decomposition.py @@ -23,7 +23,8 @@ def auto_decomposition(verbosity=True, show_plots=False): spectra_list = [] for fname in fnames: spectrum = Spectrum() - spectrum.load_profile(fname, xmin=55) + spectrum.load_profile(fname) + spectrum.apply_range(range_min=55) spectrum.auto_baseline() spectrum.subtract_baseline() spectrum.auto_peaks(model_name="Lorentzian") @@ -54,6 +55,7 @@ def auto_decomposition(verbosity=True, show_plots=False): # Fitted spectra ax1.set_title('Flattened + Attractors + Fitted') + spectrum.preprocess() spectrum.plot(ax=ax1) ax1.legend() diff --git a/fitspy/app/callbacks.py b/fitspy/app/callbacks.py index f293653..5f56036 100644 --- a/fitspy/app/callbacks.py +++ b/fitspy/app/callbacks.py @@ -745,8 +745,8 @@ def set_spectrum_range(self, delete_tabview=True): self.current_spectrum.range_max = float(self.range_max.get()) self.remove(delete_tabview=delete_tabview) - self.current_spectrum.load_profile(self.current_spectrum.fname) - self.update_attractors() + self.current_spectrum.preprocess() + self.plot() def set_range(self): """ Set range from the spectrum to the appli """ @@ -766,9 +766,7 @@ def apply_range_to_all(self): for spectrum in self.spectra.all: spectrum.range_max = range_max - self.current_spectrum.load_profile(self.current_spectrum.fname) - self.update_attractors() - + self.current_spectrum.preprocess() self.paramsview.delete() self.statsview.delete() self.ax.clear() @@ -942,8 +940,9 @@ def add_items(self, fnames=None): fname_first_item = fname spectrum = Spectrum() - spectrum.load_profile(fname) + spectrum.fname = fname spectrum.attractors_params = attractors_params + spectrum.preprocess() self.spectra.append(spectrum) self.update(fname=fname_first_item or self.fileselector.filenames[0]) @@ -988,7 +987,7 @@ def update(self, fname=None): self.update_markers(fname) self.current_spectrum, _ = self.spectra.get_objects(fname) - self.current_spectrum.load_profile(fname) + self.current_spectrum.preprocess() self.show_plot = False self.set_range() diff --git a/fitspy/spectrum.py b/fitspy/spectrum.py index 9a78d1d..8cbbfa4 100644 --- a/fitspy/spectrum.py +++ b/fitspy/spectrum.py @@ -226,17 +226,18 @@ def set_attributes(self, model_dict): def preprocess(self): """ Preprocess the spectrum: call successively load_profile(), - subtract_baseline() and normalize() """ - + apply_range(), attractors_calculation(), subtract_baseline() and + normalize() """ self.load_profile(self.fname) + self.apply_range() + self.attractors_calculation() self.baseline.is_subtracted = False self.subtract_baseline() self.normalize() - def load_profile(self, fname, xmin=None, xmax=None): + def load_profile(self, fname): """ Load profile from 'fname' with 1 header line and 2 (x,y) columns""" - # raw profile loading if self.x0 is None: x0, y0 = get_1d_profile(fname) @@ -247,22 +248,26 @@ def load_profile(self, fname, xmin=None, xmax=None): self.fname = fname - if xmin is not None: - self.range_min = xmin - if xmax is not None: - self.range_max = xmax + self.x = self.x0.copy() + self.y = self.y0.copy() - if self.range_min is None and self.range_max is None: - self.x = self.x0.copy() - self.y = self.y0.copy() - else: - ind_min, ind_max = 0, len(self.x0) + def apply_range(self, range_min=None, range_max=None): + """ Apply range to the raw spectrum (and the baseline.y_eval) """ + + self.range_min = range_min or self.range_min + self.range_max = range_max or self.range_max + + if self.range_min is not None or self.range_max is not None: + ind_min, ind_max = 0, len(self.x) if self.range_min is not None: - ind_min = closest_index(self.x0, self.range_min) + ind_min = closest_index(self.x, self.range_min) if self.range_max is not None: - ind_max = closest_index(self.x0, self.range_max) - self.x = self.x0[ind_min:ind_max + 1].copy() - self.y = self.y0[ind_min:ind_max + 1].copy() + ind_max = closest_index(self.x, self.range_max) + + self.x = self.x[ind_min:ind_max + 1] + self.y = self.y[ind_min:ind_max + 1] + if self.baseline.y_eval is not None: + self.baseline.y_eval = self.baseline.y_eval[ind_min:ind_max + 1] def calculate_outliers(self): """ Return outliers points (x,y) coordinates """ @@ -695,8 +700,6 @@ def plot(self, ax, linestyles='dashed', lw=0.5, label="Noise level") if show_baseline and self.baseline.is_subtracted: - if self.baseline.y_eval is None: - self.baseline.eval(x, self.y_no_outliers) ax.plot(x, self.baseline.y_eval, 'g', label="Baseline") y_bkg = np.zeros_like(x)