funcnodes-span 0.1.7__tar.gz → 0.1.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {funcnodes_span-0.1.7 → funcnodes_span-0.1.8}/PKG-INFO +1 -1
- {funcnodes_span-0.1.7 → funcnodes_span-0.1.8}/funcnodes_span/__init__.py +1 -1
- {funcnodes_span-0.1.7 → funcnodes_span-0.1.8}/funcnodes_span/peak_analysis.py +129 -3
- {funcnodes_span-0.1.7 → funcnodes_span-0.1.8}/pyproject.toml +1 -3
- {funcnodes_span-0.1.7 → funcnodes_span-0.1.8}/README.md +0 -0
- {funcnodes_span-0.1.7 → funcnodes_span-0.1.8}/funcnodes_span/normalization.py +0 -0
- {funcnodes_span-0.1.7 → funcnodes_span-0.1.8}/funcnodes_span/smoothing.py +0 -0
|
@@ -2,10 +2,11 @@ from funcnodes import NodeDecorator, Shelf
|
|
|
2
2
|
import numpy as np
|
|
3
3
|
from enum import Enum
|
|
4
4
|
from exposedfunctionality import controlled_wrapper
|
|
5
|
-
from typing import Optional, TypedDict, List
|
|
5
|
+
from typing import Optional, TypedDict, List, Tuple
|
|
6
6
|
from scipy.signal import find_peaks
|
|
7
7
|
from scipy.stats import norm
|
|
8
|
-
from scipy import interpolate
|
|
8
|
+
from scipy import signal, interpolate
|
|
9
|
+
from scipy.ndimage import gaussian_filter1d
|
|
9
10
|
import copy
|
|
10
11
|
import lmfit
|
|
11
12
|
import plotly.graph_objs as go
|
|
@@ -332,6 +333,25 @@ class FittingModel(Enum):
|
|
|
332
333
|
return cls.Gaussian.value
|
|
333
334
|
|
|
334
335
|
|
|
336
|
+
@NodeDecorator(
|
|
337
|
+
"span.basics.interpolation_1d",
|
|
338
|
+
name="Interpolation 1D",
|
|
339
|
+
outputs=[
|
|
340
|
+
{
|
|
341
|
+
"name": "x_interpolated",
|
|
342
|
+
},
|
|
343
|
+
{"name": "y_interpolated"},
|
|
344
|
+
],
|
|
345
|
+
)
|
|
346
|
+
def interpolation_1d(
|
|
347
|
+
x: np.array, y: np.array, multipled_by: int = 10
|
|
348
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
349
|
+
f_interpol = interpolate.interp1d(x, y)
|
|
350
|
+
x_interpolated = np.linspace(x[0], x[-1], num=len(x) * multipled_by, endpoint=True)
|
|
351
|
+
y_interpolated = f_interpol(x_interpolated)
|
|
352
|
+
return x_interpolated, y_interpolated
|
|
353
|
+
|
|
354
|
+
|
|
335
355
|
@NodeDecorator(id="span.basics.fit", name="Fit 1D")
|
|
336
356
|
def fit_1D(
|
|
337
357
|
x_array: np.ndarray,
|
|
@@ -469,6 +489,109 @@ def fit_1D(
|
|
|
469
489
|
return peak_properties_list
|
|
470
490
|
|
|
471
491
|
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
@NodeDecorator(
|
|
496
|
+
"span.basics.force_fit",
|
|
497
|
+
name="Advanced peak finder",
|
|
498
|
+
)
|
|
499
|
+
def force_peak_finder(
|
|
500
|
+
x: np.array,
|
|
501
|
+
y: np.array,
|
|
502
|
+
basic_peaks: PeakProperties,
|
|
503
|
+
) -> List[PeakProperties]:
|
|
504
|
+
# """
|
|
505
|
+
# Identify and return the two peaks around the main peak in the given peaks dictionary.
|
|
506
|
+
|
|
507
|
+
# Parameters:
|
|
508
|
+
# - peaks (dict): A dictionary containing peak information.
|
|
509
|
+
# It should have the keys 'peaks' and 'data'.
|
|
510
|
+
# 'peaks' should contain a list of dictionaries with keys 'Initial index', 'Index', and 'Ending index'.
|
|
511
|
+
# 'data' should contain arrays 'x' and 'y'.
|
|
512
|
+
|
|
513
|
+
# Returns:
|
|
514
|
+
# - dict: A dictionary containing information about the two identified peaks.
|
|
515
|
+
# """
|
|
516
|
+
peaks = copy.deepcopy(basic_peaks)
|
|
517
|
+
|
|
518
|
+
main_peak_i_index = peaks["i_index"]
|
|
519
|
+
main_peak_r_index = peaks["index"]
|
|
520
|
+
main_peak_f_index = peaks["f_index"]
|
|
521
|
+
y_array = y
|
|
522
|
+
x_array = x
|
|
523
|
+
# Calculate first and second derivatives
|
|
524
|
+
y_array_p = np.diff(y_array, 1, -1, y_array[0])
|
|
525
|
+
y_array_pp = np.diff(y_array, 2, -1, y_array[0:2])
|
|
526
|
+
# Smooth derivatives using Gaussian filter
|
|
527
|
+
y_array_p = gaussian_filter1d(y_array_p, 5)
|
|
528
|
+
y_array_pp = gaussian_filter1d(y_array_pp, 5)
|
|
529
|
+
|
|
530
|
+
maxx = [main_peak_r_index]
|
|
531
|
+
minn = [main_peak_i_index, main_peak_f_index]
|
|
532
|
+
# Find local maxima and minima of derivatives
|
|
533
|
+
max_p = signal.argrelmax(y_array_p)[0]
|
|
534
|
+
min_p = signal.argrelmin(y_array_p)[0]
|
|
535
|
+
max_pp = signal.argrelmax(y_array_pp)[0]
|
|
536
|
+
min_pp = signal.argrelmin(y_array_pp)[0]
|
|
537
|
+
|
|
538
|
+
# main_peak_i_index = peaks["i_index"]
|
|
539
|
+
# main_peak_r_index = peaks["index"]
|
|
540
|
+
# main_peak_f_index = peaks["f_index"]
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
# Determine which peak is on the left and right side of the main peak
|
|
544
|
+
if (
|
|
545
|
+
x_array[main_peak_r_index] - x_array[main_peak_i_index]
|
|
546
|
+
> x_array[main_peak_f_index] - x_array[main_peak_r_index]
|
|
547
|
+
): # seond peak is in the leftside of the max peak #TODO: fix this
|
|
548
|
+
common_point = max([num for num in max_pp if num < main_peak_r_index])
|
|
549
|
+
|
|
550
|
+
print("Left convoluted")
|
|
551
|
+
peak1 = {
|
|
552
|
+
"I.Index": main_peak_i_index,
|
|
553
|
+
"R.Index": max(
|
|
554
|
+
[num for num in min_p if num < main_peak_r_index]
|
|
555
|
+
), # TODO: fix this
|
|
556
|
+
"F.Index": common_point,
|
|
557
|
+
}
|
|
558
|
+
peak2 = {
|
|
559
|
+
"I.Index": common_point,
|
|
560
|
+
"R.Index": main_peak_r_index,
|
|
561
|
+
"F.Index": main_peak_f_index,
|
|
562
|
+
}
|
|
563
|
+
else:
|
|
564
|
+
common_point = next((x for x in max_pp if x > main_peak_r_index), None)
|
|
565
|
+
print("Right convoluted")
|
|
566
|
+
peak1 = {
|
|
567
|
+
"I.Index": main_peak_i_index,
|
|
568
|
+
"R.Index": main_peak_r_index,
|
|
569
|
+
"F.Index": common_point,
|
|
570
|
+
}
|
|
571
|
+
peak2 = {
|
|
572
|
+
"I.Index": common_point,
|
|
573
|
+
"R.Index": next((x for x in max_p if x > main_peak_r_index), None),
|
|
574
|
+
"F.Index": main_peak_f_index,
|
|
575
|
+
}
|
|
576
|
+
peak_lst = []
|
|
577
|
+
peak_lst.append([peak1["I.Index"], peak1["R.Index"], peak1["F.Index"]])
|
|
578
|
+
peak_lst.append([peak2["I.Index"], peak2["R.Index"], peak2["F.Index"]])
|
|
579
|
+
peak_properties_list = []
|
|
580
|
+
for peak_nr, peak in enumerate(peak_lst):
|
|
581
|
+
peak_properties = compute_peak_properties(
|
|
582
|
+
x_array=x_array,
|
|
583
|
+
y_array=y_array,
|
|
584
|
+
peak_indices=peak,
|
|
585
|
+
peak_nr=peak_nr,
|
|
586
|
+
is_force_fitted=True,
|
|
587
|
+
)
|
|
588
|
+
peak_properties_list.append(peak_properties)
|
|
589
|
+
|
|
590
|
+
return peak_properties_list
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
|
|
472
595
|
# Define a mapping from "C0", "C1", etc., to CSS color names
|
|
473
596
|
color_map = {
|
|
474
597
|
"C0": "blue",
|
|
@@ -487,6 +610,9 @@ color_map = {
|
|
|
487
610
|
@NodeDecorator(id="span.basics.fit.plot", name="Plot fit 1D")
|
|
488
611
|
def plot_fitted_peaks(peaks: List[PeakProperties]) -> go.Figure:
|
|
489
612
|
peak = peaks[0]
|
|
613
|
+
if not peak['_is_fitted']:
|
|
614
|
+
raise ValueError("No fitting information is available.")
|
|
615
|
+
|
|
490
616
|
x = peak["fitting_info"]["userkws"]["x"]
|
|
491
617
|
# Extract data from peaks
|
|
492
618
|
y = peak["fitting_info"]["data"]
|
|
@@ -549,7 +675,7 @@ def plot_fitted_peaks(peaks: List[PeakProperties]) -> go.Figure:
|
|
|
549
675
|
|
|
550
676
|
|
|
551
677
|
PEAKS_NODE_SHELF = Shelf(
|
|
552
|
-
nodes=[peak_finder, fit_1D, plot_fitted_peaks],
|
|
678
|
+
nodes=[peak_finder, interpolation_1d, force_peak_finder, fit_1D, plot_fitted_peaks],
|
|
553
679
|
subshelves=[],
|
|
554
680
|
name="Peak analysis",
|
|
555
681
|
description="Tools for the peak analysis of the spectra",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "funcnodes-span"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.8"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = ["Kourosh Rezaei <kouroshrezaei90@gmail.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -8,12 +8,10 @@ readme = "README.md"
|
|
|
8
8
|
[tool.poetry.dependencies]
|
|
9
9
|
python = "^3.11"
|
|
10
10
|
scipy = "^1.14.0"
|
|
11
|
-
|
|
12
11
|
lmfit = "^1.3.2"
|
|
13
12
|
funcnodes = "^0.2.21"
|
|
14
13
|
funcnodes_numpy = "^0.1.57"
|
|
15
14
|
funcnodes_pandas = "^0.1.9"
|
|
16
|
-
|
|
17
15
|
funcnodes_plotly = "^0.1.7"
|
|
18
16
|
|
|
19
17
|
pooch = "^1.8.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|