napari-musa 1.0.0__py3-none-any.whl
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.
- napari_musa/Widget_DataManager.py +864 -0
- napari_musa/Widgets_DataVisualization.py +257 -0
- napari_musa/Widgets_EndmembersExtraction.py +382 -0
- napari_musa/Widgets_Fusion.py +458 -0
- napari_musa/Widgets_NMF.py +265 -0
- napari_musa/Widgets_PCA.py +212 -0
- napari_musa/Widgets_UMAP.py +463 -0
- napari_musa/_version.py +34 -0
- napari_musa/main.py +150 -0
- napari_musa/modules/D_illuminants.mat +0 -0
- napari_musa/modules/data.py +48 -0
- napari_musa/modules/functions.py +1331 -0
- napari_musa/modules/plot.py +581 -0
- napari_musa/napari.yaml +15 -0
- napari_musa-1.0.0.dist-info/METADATA +156 -0
- napari_musa-1.0.0.dist-info/RECORD +20 -0
- napari_musa-1.0.0.dist-info/WHEEL +5 -0
- napari_musa-1.0.0.dist-info/entry_points.txt +2 -0
- napari_musa-1.0.0.dist-info/licenses/LICENSE +28 -0
- napari_musa-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"""Widget to visualize the data"""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from os.path import dirname
|
|
5
|
+
|
|
6
|
+
sys.path.append(dirname(dirname(__file__)))
|
|
7
|
+
|
|
8
|
+
import napari
|
|
9
|
+
from magicgui.widgets import (
|
|
10
|
+
CheckBox,
|
|
11
|
+
Container,
|
|
12
|
+
Label,
|
|
13
|
+
PushButton,
|
|
14
|
+
SpinBox,
|
|
15
|
+
)
|
|
16
|
+
from matplotlib.backends.backend_qt5agg import (
|
|
17
|
+
FigureCanvasQTAgg as FigureCanvas,
|
|
18
|
+
)
|
|
19
|
+
from matplotlib.backends.backend_qt5agg import (
|
|
20
|
+
NavigationToolbar2QT as NavigationToolbar,
|
|
21
|
+
)
|
|
22
|
+
from matplotlib.figure import Figure
|
|
23
|
+
from qtpy.QtWidgets import (
|
|
24
|
+
QGroupBox,
|
|
25
|
+
QHBoxLayout,
|
|
26
|
+
QScrollArea,
|
|
27
|
+
QVBoxLayout,
|
|
28
|
+
QWidget,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
from napari_musa.modules.functions import (
|
|
32
|
+
HSI2RGB,
|
|
33
|
+
falseRGB,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class DataVisualization(QWidget): # From QWidget
|
|
38
|
+
""" """
|
|
39
|
+
|
|
40
|
+
def __init__(self, viewer: napari.Viewer, data, plot, datamanager):
|
|
41
|
+
""" """
|
|
42
|
+
super().__init__() # Initialize the QWidget
|
|
43
|
+
self.viewer = viewer
|
|
44
|
+
self.data = data
|
|
45
|
+
self.plot = plot
|
|
46
|
+
self.datamanager = datamanager
|
|
47
|
+
# Configure the scroll area
|
|
48
|
+
scroll = QScrollArea()
|
|
49
|
+
scroll.setWidgetResizable(True)
|
|
50
|
+
content_widget = QWidget() # Container widget
|
|
51
|
+
content_layout = QVBoxLayout(
|
|
52
|
+
content_widget
|
|
53
|
+
) # Vertical layout: organize widgets from top to bottom
|
|
54
|
+
# Configure UI
|
|
55
|
+
self.createUI(
|
|
56
|
+
content_layout
|
|
57
|
+
) # The function to create the UI that fills the content_layout
|
|
58
|
+
# Configure principal layout
|
|
59
|
+
scroll.setWidget(
|
|
60
|
+
content_widget
|
|
61
|
+
) # content_widget is a content of scroll area
|
|
62
|
+
main_layout = QVBoxLayout(self)
|
|
63
|
+
main_layout.addWidget(scroll)
|
|
64
|
+
self.setLayout(main_layout)
|
|
65
|
+
|
|
66
|
+
def createUI(self, layout):
|
|
67
|
+
"""Create the components for the UI"""
|
|
68
|
+
layout.addWidget(self.create_rgb_box())
|
|
69
|
+
layout.addWidget(self.plot_box())
|
|
70
|
+
|
|
71
|
+
# %% Creation of UI boxes
|
|
72
|
+
# RGB BOX
|
|
73
|
+
def create_rgb_box(self):
|
|
74
|
+
"""Create box and elements for file opening"""
|
|
75
|
+
rgb_box = QGroupBox("Create RGB")
|
|
76
|
+
# rgb_box.setFixedHeight(200)
|
|
77
|
+
true_rgb_layout = QVBoxLayout()
|
|
78
|
+
true_rgb_layout.addSpacing(10)
|
|
79
|
+
# Elements
|
|
80
|
+
true_rgb_btn = PushButton(text="Create True RGB")
|
|
81
|
+
true_rgb_btn.clicked.connect(self.true_rgb_btn_f)
|
|
82
|
+
|
|
83
|
+
# Add widgets to the layout
|
|
84
|
+
true_rgb_layout.addWidget(
|
|
85
|
+
Container(widgets=[true_rgb_btn], layout="horizontal").native
|
|
86
|
+
)
|
|
87
|
+
true_rgb_layout.addSpacing(30)
|
|
88
|
+
#
|
|
89
|
+
# FALSE RGB
|
|
90
|
+
false_rgb_layout = QVBoxLayout()
|
|
91
|
+
false_rgb_layout.addSpacing(5)
|
|
92
|
+
R_layout, self.R_min_spinbox, self.R_max_spinbox = (
|
|
93
|
+
self.create_channel_falsergb_section([650, 700], "R")
|
|
94
|
+
)
|
|
95
|
+
false_rgb_layout.addLayout(R_layout)
|
|
96
|
+
false_rgb_layout.addSpacing(5)
|
|
97
|
+
#
|
|
98
|
+
G_layout, self.G_min_spinbox, self.G_max_spinbox = (
|
|
99
|
+
self.create_channel_falsergb_section([550, 600], "G")
|
|
100
|
+
)
|
|
101
|
+
false_rgb_layout.addLayout(G_layout)
|
|
102
|
+
false_rgb_layout.addSpacing(5)
|
|
103
|
+
#
|
|
104
|
+
B_layout, self.B_min_spinbox, self.B_max_spinbox = (
|
|
105
|
+
self.create_channel_falsergb_section([450, 500], "B")
|
|
106
|
+
)
|
|
107
|
+
false_rgb_layout.addLayout(B_layout)
|
|
108
|
+
false_rgb_layout.addSpacing(5)
|
|
109
|
+
# False RGB button
|
|
110
|
+
false_rgb_btn_layout = QHBoxLayout()
|
|
111
|
+
false_rgb_btn = PushButton(text="Create False RGB")
|
|
112
|
+
false_rgb_btn.clicked.connect(self.false_rgb_btn_f)
|
|
113
|
+
false_rgb_btn_layout.addWidget(
|
|
114
|
+
Container(widgets=[false_rgb_btn]).native
|
|
115
|
+
)
|
|
116
|
+
#
|
|
117
|
+
false_rgb_layout.addLayout(false_rgb_btn_layout)
|
|
118
|
+
true_rgb_layout.addLayout(false_rgb_layout)
|
|
119
|
+
rgb_box.setLayout(true_rgb_layout)
|
|
120
|
+
return rgb_box
|
|
121
|
+
|
|
122
|
+
def create_channel_falsergb_section(self, value, label_name):
|
|
123
|
+
""" """
|
|
124
|
+
channel_layout = QHBoxLayout()
|
|
125
|
+
label = Label(value=label_name)
|
|
126
|
+
# label.native.setFixedWidth(20)
|
|
127
|
+
# channel_layout.addSpacing(50)
|
|
128
|
+
channel_layout.addWidget(label.native)
|
|
129
|
+
min_spinbox = SpinBox(
|
|
130
|
+
min=0, max=2500, step=1, value=value[0], label=label_name
|
|
131
|
+
)
|
|
132
|
+
max_spinbox = SpinBox(min=0, max=2500, step=1, value=value[1])
|
|
133
|
+
channel_layout.addSpacing(50)
|
|
134
|
+
channel_layout.addWidget(min_spinbox.native)
|
|
135
|
+
channel_layout.addSpacing(50)
|
|
136
|
+
channel_layout.addWidget(max_spinbox.native)
|
|
137
|
+
|
|
138
|
+
return channel_layout, min_spinbox, max_spinbox
|
|
139
|
+
|
|
140
|
+
def plot_box(self):
|
|
141
|
+
"""Plot of the mean spectrum"""
|
|
142
|
+
plot_box = QGroupBox("Plot of mean spectrum")
|
|
143
|
+
plot_layout = QVBoxLayout()
|
|
144
|
+
plot_layout.addSpacing(10)
|
|
145
|
+
# Plot
|
|
146
|
+
plot_layout_graph = self.create_plot_graph_section()
|
|
147
|
+
plot_layout.addLayout(plot_layout_graph)
|
|
148
|
+
# Export
|
|
149
|
+
plot_layout_export_txt = self.create_plot_export_section()
|
|
150
|
+
plot_layout.addLayout(plot_layout_export_txt)
|
|
151
|
+
plot_box.setLayout(plot_layout)
|
|
152
|
+
return plot_box
|
|
153
|
+
|
|
154
|
+
def create_plot_graph_section(self):
|
|
155
|
+
"""Mean spectrum"""
|
|
156
|
+
plot_layout = QVBoxLayout()
|
|
157
|
+
|
|
158
|
+
self.meanspec_plot = FigureCanvas(Figure(figsize=(5, 3)))
|
|
159
|
+
self.meanspec_plot.setMinimumSize(300, 450)
|
|
160
|
+
self.meanspec_plot_toolbar = NavigationToolbar(
|
|
161
|
+
self.meanspec_plot, self
|
|
162
|
+
)
|
|
163
|
+
self.plot.customize_toolbar(self.meanspec_plot_toolbar)
|
|
164
|
+
self.plot.setup_plot(self.meanspec_plot)
|
|
165
|
+
#
|
|
166
|
+
# Buttons and checkboxes
|
|
167
|
+
controls_layout = QVBoxLayout()
|
|
168
|
+
self.std_plot_checkbox = CheckBox(text="Plot standard deviation")
|
|
169
|
+
self.norm_plot_checkbox = CheckBox(text="Normalize plot")
|
|
170
|
+
self.derivative_checkbox = CheckBox(text="Plot with derivative")
|
|
171
|
+
self.dimred_checkbox = CheckBox(text="Reduced dataset")
|
|
172
|
+
for c in [
|
|
173
|
+
self.std_plot_checkbox,
|
|
174
|
+
self.norm_plot_checkbox,
|
|
175
|
+
self.derivative_checkbox,
|
|
176
|
+
self.dimred_checkbox,
|
|
177
|
+
]:
|
|
178
|
+
controls_layout.addWidget(c.native)
|
|
179
|
+
#
|
|
180
|
+
plot_btn = PushButton(text="Mean spectrum")
|
|
181
|
+
plot_btn.clicked.connect(
|
|
182
|
+
lambda: self.plot.show_plot(
|
|
183
|
+
self.meanspec_plot,
|
|
184
|
+
mode=self.datamanager.modes_combobox.value,
|
|
185
|
+
std_flag=self.std_plot_checkbox.value,
|
|
186
|
+
norm_flag=self.norm_plot_checkbox.value,
|
|
187
|
+
reduced_dataset_flag=self.dimred_checkbox.value,
|
|
188
|
+
derivative_flag=self.derivative_checkbox.value,
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
controls_layout.addWidget(plot_btn.native)
|
|
192
|
+
plot_layout.addLayout(controls_layout)
|
|
193
|
+
plot_layout.addWidget(self.meanspec_plot)
|
|
194
|
+
plot_layout.addWidget(self.meanspec_plot_toolbar)
|
|
195
|
+
|
|
196
|
+
return plot_layout
|
|
197
|
+
|
|
198
|
+
def create_plot_export_section(self):
|
|
199
|
+
"""Export mean spectrum"""
|
|
200
|
+
export_txt_layout = QVBoxLayout()
|
|
201
|
+
|
|
202
|
+
export_txt_btn = PushButton(text="Export spectra")
|
|
203
|
+
export_txt_btn.clicked.connect(
|
|
204
|
+
lambda: self.plot.show_plot(
|
|
205
|
+
self.meanspec_plot,
|
|
206
|
+
mode=self.datamanager.modes_combobox.value,
|
|
207
|
+
std_flag=self.std_plot_checkbox.value,
|
|
208
|
+
norm_flag=self.norm_plot_checkbox.value,
|
|
209
|
+
reduced_dataset_flag=self.dimred_checkbox.value,
|
|
210
|
+
export_txt_flag=True,
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
export_txt_layout.addWidget(Container(widgets=[export_txt_btn]).native)
|
|
215
|
+
return export_txt_layout
|
|
216
|
+
|
|
217
|
+
# %% Buttons functions
|
|
218
|
+
def true_rgb_btn_f(self):
|
|
219
|
+
""" """
|
|
220
|
+
data_mode = self.datamanager.modes_combobox.value
|
|
221
|
+
self.data.rgb[data_mode] = HSI2RGB(
|
|
222
|
+
self.data.wls[data_mode],
|
|
223
|
+
self.data.hypercubes[data_mode],
|
|
224
|
+
self.data.hypercubes[data_mode].shape[0],
|
|
225
|
+
self.data.hypercubes[data_mode].shape[1],
|
|
226
|
+
65,
|
|
227
|
+
False,
|
|
228
|
+
)
|
|
229
|
+
self.viewer.add_image(
|
|
230
|
+
self.data.rgb[data_mode],
|
|
231
|
+
name=str(data_mode) + " RGB",
|
|
232
|
+
rgb=True,
|
|
233
|
+
metadata={"type": "rgb"},
|
|
234
|
+
)
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
def false_rgb_btn_f(self):
|
|
238
|
+
""" """
|
|
239
|
+
data_mode = self.datamanager.modes_combobox.value
|
|
240
|
+
R_values = [self.R_min_spinbox.value, self.R_max_spinbox.value]
|
|
241
|
+
G_values = [self.G_min_spinbox.value, self.G_max_spinbox.value]
|
|
242
|
+
B_values = [self.B_min_spinbox.value, self.B_max_spinbox.value]
|
|
243
|
+
falseRGB_image = falseRGB(
|
|
244
|
+
self.data.hypercubes[data_mode],
|
|
245
|
+
self.data.wls[data_mode],
|
|
246
|
+
R_values,
|
|
247
|
+
G_values,
|
|
248
|
+
B_values,
|
|
249
|
+
)
|
|
250
|
+
self.viewer.add_image(
|
|
251
|
+
falseRGB_image,
|
|
252
|
+
name=str(data_mode) + " - FALSE RGB",
|
|
253
|
+
rgb=True,
|
|
254
|
+
metadata={"type": "false_rgb"},
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# %% Other functions
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
""" """
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from os.path import dirname
|
|
5
|
+
|
|
6
|
+
sys.path.append(dirname(dirname(__file__)))
|
|
7
|
+
import napari
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pandas as pd
|
|
10
|
+
from magicgui.widgets import (
|
|
11
|
+
CheckBox,
|
|
12
|
+
ComboBox,
|
|
13
|
+
Container,
|
|
14
|
+
FloatSpinBox,
|
|
15
|
+
PushButton,
|
|
16
|
+
Select,
|
|
17
|
+
SpinBox,
|
|
18
|
+
)
|
|
19
|
+
from matplotlib.backends.backend_qt5agg import (
|
|
20
|
+
FigureCanvasQTAgg as FigureCanvas,
|
|
21
|
+
)
|
|
22
|
+
from matplotlib.backends.backend_qt5agg import (
|
|
23
|
+
NavigationToolbar2QT as NavigationToolbar,
|
|
24
|
+
)
|
|
25
|
+
from matplotlib.figure import Figure
|
|
26
|
+
from napari.utils.notifications import show_info
|
|
27
|
+
from qtpy.QtCore import QTimer
|
|
28
|
+
from qtpy.QtWidgets import (
|
|
29
|
+
QFileDialog,
|
|
30
|
+
QGroupBox,
|
|
31
|
+
QHBoxLayout,
|
|
32
|
+
QScrollArea,
|
|
33
|
+
QVBoxLayout,
|
|
34
|
+
QWidget,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
from napari_musa.modules.functions import (
|
|
38
|
+
NFINDR,
|
|
39
|
+
PPI,
|
|
40
|
+
SiVM,
|
|
41
|
+
inverse_metrics,
|
|
42
|
+
nnls_analysis,
|
|
43
|
+
sam_analysis,
|
|
44
|
+
vca,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class EndmembersExtraction(QWidget):
|
|
49
|
+
""" """
|
|
50
|
+
|
|
51
|
+
def __init__(self, viewer: napari.Viewer, data, plot):
|
|
52
|
+
""" """
|
|
53
|
+
super().__init__()
|
|
54
|
+
self.viewer = viewer
|
|
55
|
+
self.data = data
|
|
56
|
+
self.plot = plot
|
|
57
|
+
self.init_ui()
|
|
58
|
+
|
|
59
|
+
def init_ui(self):
|
|
60
|
+
""" """
|
|
61
|
+
scroll = QScrollArea()
|
|
62
|
+
scroll.setWidgetResizable(True)
|
|
63
|
+
content_widget = QWidget()
|
|
64
|
+
content_layout = QVBoxLayout(content_widget)
|
|
65
|
+
|
|
66
|
+
self.build_sivm_group(content_layout)
|
|
67
|
+
content_layout.addStretch()
|
|
68
|
+
|
|
69
|
+
scroll.setWidget(content_widget)
|
|
70
|
+
main_layout = QVBoxLayout(self)
|
|
71
|
+
main_layout.addWidget(scroll)
|
|
72
|
+
self.setLayout(main_layout)
|
|
73
|
+
|
|
74
|
+
def build_sivm_group(self, layout):
|
|
75
|
+
""" """
|
|
76
|
+
layout.addWidget(self.create_endmextr_controls())
|
|
77
|
+
layout.addWidget(self.create_upload_endmembers())
|
|
78
|
+
layout.addWidget(self.create_nnls())
|
|
79
|
+
layout.addWidget(self.create_sam())
|
|
80
|
+
layout.addStretch()
|
|
81
|
+
|
|
82
|
+
def create_endmextr_controls(self):
|
|
83
|
+
""" """
|
|
84
|
+
endm_box = QGroupBox("Endmembers")
|
|
85
|
+
endm_layout = QVBoxLayout()
|
|
86
|
+
endm_layout.addSpacing(10)
|
|
87
|
+
row1 = QHBoxLayout()
|
|
88
|
+
self.masked_dataset = CheckBox(text="Apply to masked dataset")
|
|
89
|
+
self.modes_combobox = ComboBox(
|
|
90
|
+
choices=self.data.modes, label="Select the imaging mode"
|
|
91
|
+
)
|
|
92
|
+
row1.addWidget(self.masked_dataset.native)
|
|
93
|
+
row1.addWidget(self.modes_combobox.native)
|
|
94
|
+
endm_layout.addLayout(row1)
|
|
95
|
+
|
|
96
|
+
# row2 = QHBoxLayout()
|
|
97
|
+
# row2.addWidget(self.masked_dataset.native)
|
|
98
|
+
# layout.addLayout(row2)
|
|
99
|
+
|
|
100
|
+
self.n_endmembers_spinbox = SpinBox(
|
|
101
|
+
min=1, max=500, value=10, step=1, name="Endmembers"
|
|
102
|
+
)
|
|
103
|
+
endm_layout.addWidget(
|
|
104
|
+
Container(widgets=[self.n_endmembers_spinbox]).native
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
row2 = QHBoxLayout()
|
|
108
|
+
self.modes_vertex_analysis = ComboBox(
|
|
109
|
+
choices=["SiVM", "VCA", "N-FINDR", "PPI"],
|
|
110
|
+
label="Select the endmembers extraction mode",
|
|
111
|
+
)
|
|
112
|
+
run_btn = PushButton(text="Run endmember analysis")
|
|
113
|
+
run_btn.clicked.connect(self.run_btn_f)
|
|
114
|
+
row2.addWidget(
|
|
115
|
+
Container(widgets=[self.modes_vertex_analysis, run_btn]).native
|
|
116
|
+
)
|
|
117
|
+
endm_layout.addLayout(row2)
|
|
118
|
+
|
|
119
|
+
row3 = QHBoxLayout()
|
|
120
|
+
self.sivm_basis_multiselecton = Select(
|
|
121
|
+
label="Select Bases", choices=[]
|
|
122
|
+
)
|
|
123
|
+
self.sivm_basis_multiselecton.changed.connect(
|
|
124
|
+
self.on_basis_selection_changed
|
|
125
|
+
)
|
|
126
|
+
row3.addWidget(self.sivm_basis_multiselecton.native)
|
|
127
|
+
endm_layout.addLayout(row3)
|
|
128
|
+
|
|
129
|
+
row4 = QVBoxLayout()
|
|
130
|
+
self.mean_plot = FigureCanvas(Figure(figsize=(5, 3)))
|
|
131
|
+
self.mean_plot.setMinimumSize(300, 450)
|
|
132
|
+
self.mean_plot_toolbar = NavigationToolbar(self.mean_plot, self)
|
|
133
|
+
self.plot.customize_toolbar(self.mean_plot_toolbar)
|
|
134
|
+
self.plot.setup_plot(self.mean_plot)
|
|
135
|
+
row4.addWidget(self.mean_plot)
|
|
136
|
+
row4.addWidget(self.mean_plot_toolbar)
|
|
137
|
+
# Export button
|
|
138
|
+
export_btn = PushButton(text="Export selected spectra")
|
|
139
|
+
export_btn.clicked.connect(self.export_spectrum)
|
|
140
|
+
row4.addWidget(Container(widgets=[export_btn]).native)
|
|
141
|
+
endm_layout.addLayout(row4)
|
|
142
|
+
|
|
143
|
+
endm_box.setLayout(endm_layout)
|
|
144
|
+
return endm_box
|
|
145
|
+
|
|
146
|
+
def create_upload_endmembers(self):
|
|
147
|
+
""" """
|
|
148
|
+
upload_endm_box = QGroupBox("Upload Endmembers")
|
|
149
|
+
upload_endm_layout = QVBoxLayout()
|
|
150
|
+
upload_endm_layout.addSpacing(10)
|
|
151
|
+
row1 = QHBoxLayout()
|
|
152
|
+
self.upload_endmembers_checkbox = CheckBox(
|
|
153
|
+
text="Use endmembers from file"
|
|
154
|
+
)
|
|
155
|
+
upload_endmember_btn = PushButton(text="Upload Endmembers")
|
|
156
|
+
upload_endmember_btn.clicked.connect(self.upload_endmembers_btn_f)
|
|
157
|
+
row1.addWidget(self.upload_endmembers_checkbox.native)
|
|
158
|
+
row1.addWidget(upload_endmember_btn.native)
|
|
159
|
+
upload_endm_layout.addLayout(row1)
|
|
160
|
+
upload_endm_box.setLayout(upload_endm_layout)
|
|
161
|
+
return upload_endm_box
|
|
162
|
+
|
|
163
|
+
def create_nnls(self):
|
|
164
|
+
""" """
|
|
165
|
+
nnls_box = QGroupBox("NNLS Analysis")
|
|
166
|
+
nnls_layout = QVBoxLayout()
|
|
167
|
+
|
|
168
|
+
run_btn = PushButton(text="Run NNLS")
|
|
169
|
+
run_btn.clicked.connect(self.run_nnls)
|
|
170
|
+
nnls_layout.addSpacing(10)
|
|
171
|
+
nnls_layout.addWidget(run_btn.native)
|
|
172
|
+
nnls_box.setLayout(nnls_layout)
|
|
173
|
+
return nnls_box
|
|
174
|
+
|
|
175
|
+
def create_sam(self):
|
|
176
|
+
sam_box = QGroupBox("SAM Analysis")
|
|
177
|
+
sam_layout = QVBoxLayout()
|
|
178
|
+
self.angle_spinbox = FloatSpinBox(
|
|
179
|
+
min=0.0, max=1.0, value=0.1, step=0.1, label="Cosine value"
|
|
180
|
+
)
|
|
181
|
+
run_sam_btn = PushButton(text="Run SAM")
|
|
182
|
+
run_sam_btn.clicked.connect(self.run_sam)
|
|
183
|
+
sam_layout.addSpacing(10)
|
|
184
|
+
sam_layout.addWidget(Container(widgets=[self.angle_spinbox]).native)
|
|
185
|
+
sam_layout.addWidget(run_sam_btn.native)
|
|
186
|
+
sam_box.setLayout(sam_layout)
|
|
187
|
+
return sam_box
|
|
188
|
+
|
|
189
|
+
def run_btn_f(self):
|
|
190
|
+
"""Perform SiVM"""
|
|
191
|
+
self.sivm_basis_multiselecton.value = []
|
|
192
|
+
mode = self.modes_combobox.value
|
|
193
|
+
analysis_mode = self.modes_vertex_analysis.value
|
|
194
|
+
n_basis = self.n_endmembers_spinbox.value
|
|
195
|
+
options = [f"Basis {i}" for i in range(n_basis)]
|
|
196
|
+
|
|
197
|
+
if self.masked_dataset.value:
|
|
198
|
+
dataset = self.data.hypercubes_masked[mode]
|
|
199
|
+
data_reshaped = dataset.reshape(
|
|
200
|
+
dataset.shape[0] * dataset.shape[1], -1
|
|
201
|
+
)
|
|
202
|
+
dataset = np.nan_to_num(dataset, nan=0)
|
|
203
|
+
|
|
204
|
+
self.points = np.array(
|
|
205
|
+
np.where(~np.isnan(np.mean(data_reshaped, axis=1)))
|
|
206
|
+
).flatten()
|
|
207
|
+
|
|
208
|
+
else:
|
|
209
|
+
dataset = self.data.hypercubes[mode]
|
|
210
|
+
self.points = []
|
|
211
|
+
|
|
212
|
+
if analysis_mode == "SiVM":
|
|
213
|
+
self.data.vertex_basis[mode] = SiVM(
|
|
214
|
+
dataset, n_bases=n_basis, points=self.points
|
|
215
|
+
)
|
|
216
|
+
elif analysis_mode == "VCA":
|
|
217
|
+
dataset_reshaped = dataset.reshape(
|
|
218
|
+
dataset.shape[0] * dataset.shape[1], -1
|
|
219
|
+
)
|
|
220
|
+
if len(self.points) > 0:
|
|
221
|
+
dataset_reshaped = dataset_reshaped[self.points, :]
|
|
222
|
+
self.data.vertex_basis[mode] = vca(
|
|
223
|
+
dataset_reshaped.transpose(), R=n_basis
|
|
224
|
+
)[0]
|
|
225
|
+
# CONTROLLARE SE VANNO E AGGIUNGERE I POINTS
|
|
226
|
+
elif analysis_mode == "N-FINDR":
|
|
227
|
+
self.data.vertex_basis[mode] = NFINDR(dataset, n_bases=n_basis)
|
|
228
|
+
print(self.vertex_basis[mode].shape)
|
|
229
|
+
|
|
230
|
+
elif analysis_mode == "PPI":
|
|
231
|
+
self.data.vertex_basis[mode] = PPI(dataset, n_bases=n_basis)
|
|
232
|
+
print(self.vertex_basis[mode].shape)
|
|
233
|
+
|
|
234
|
+
self.sivm_basis_multiselecton.choices = options
|
|
235
|
+
QTimer.singleShot(
|
|
236
|
+
0, lambda: show_info("Endmember analysis completed!")
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
def on_basis_selection_changed(self, value):
|
|
240
|
+
mode = self.modes_combobox.value
|
|
241
|
+
|
|
242
|
+
print("Selected bases:", value)
|
|
243
|
+
print("Shape of the array:", self.data.vertex_basis[mode].shape)
|
|
244
|
+
|
|
245
|
+
self.basis_numbers = sorted([int(s.split()[1]) for s in value])
|
|
246
|
+
self.selected_basis = self.data.vertex_basis[mode][
|
|
247
|
+
:, self.basis_numbers
|
|
248
|
+
]
|
|
249
|
+
print(self.selected_basis.shape)
|
|
250
|
+
self.selected_basis_to_show = self.selected_basis
|
|
251
|
+
|
|
252
|
+
if mode == "Fused":
|
|
253
|
+
fusion_point = self.data.wls[self.data.fusion_modes[0]].shape[0]
|
|
254
|
+
print(self.data.fusion_norm)
|
|
255
|
+
# xxx aggiustare corrections
|
|
256
|
+
print(self.data.fusion_params[0])
|
|
257
|
+
self.selected_basis_to_show[:fusion_point, :] = inverse_metrics(
|
|
258
|
+
self.selected_basis_to_show[:fusion_point, :],
|
|
259
|
+
self.data.fusion_norm,
|
|
260
|
+
self.data.fusion_params[0],
|
|
261
|
+
)
|
|
262
|
+
self.selected_basis_to_show[fusion_point:, :] = inverse_metrics(
|
|
263
|
+
self.selected_basis_to_show[fusion_point:, :],
|
|
264
|
+
self.data.fusion_norm,
|
|
265
|
+
self.data.fusion_params[1],
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
self.plot.show_spectra(
|
|
269
|
+
self.mean_plot,
|
|
270
|
+
self.selected_basis_to_show,
|
|
271
|
+
mode,
|
|
272
|
+
basis_numbers=self.basis_numbers,
|
|
273
|
+
export_txt_flag=False,
|
|
274
|
+
)
|
|
275
|
+
self.viewer.status = f"Selected basis: {self.basis_numbers}"
|
|
276
|
+
# QTimer.singleShot(0, lambda: show_info(f"Selected basis: {self.basis_numbers}"))
|
|
277
|
+
print("Selected basis: ", self.basis_numbers)
|
|
278
|
+
|
|
279
|
+
def export_spectrum(self):
|
|
280
|
+
"""Export the mean spectrum"""
|
|
281
|
+
mode = self.modes_combobox.value
|
|
282
|
+
|
|
283
|
+
self.plot.show_spectra(
|
|
284
|
+
self.mean_plot,
|
|
285
|
+
self.selected_basis_to_show,
|
|
286
|
+
mode,
|
|
287
|
+
basis_numbers=self.basis_numbers,
|
|
288
|
+
export_txt_flag=True,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
def upload_endmembers_btn_f(self):
|
|
292
|
+
"""Upload endmembers from file"""
|
|
293
|
+
|
|
294
|
+
filepath, _ = QFileDialog.getOpenFileName()
|
|
295
|
+
print(f"The file with path {filepath} will now be opened")
|
|
296
|
+
df_file = pd.read_csv(filepath, sep="\t")
|
|
297
|
+
|
|
298
|
+
# wl = df_file[[col for col in df_file.columns if "Wavelength" in col]]
|
|
299
|
+
spectra = df_file[
|
|
300
|
+
[col for col in df_file.columns if "Spectrum" in col]
|
|
301
|
+
]
|
|
302
|
+
# std = df_file[[col for col in df_file.columns if "Std" in col]]
|
|
303
|
+
|
|
304
|
+
self.uploaded_endmembers = spectra.to_numpy()
|
|
305
|
+
|
|
306
|
+
def run_nnls(self):
|
|
307
|
+
"""Perform NNLS"""
|
|
308
|
+
mode = self.modes_combobox.value
|
|
309
|
+
|
|
310
|
+
if self.masked_dataset.value:
|
|
311
|
+
dataset = self.data.hypercubes_masked[mode]
|
|
312
|
+
data_reshaped = dataset.reshape(
|
|
313
|
+
dataset.shape[0] * dataset.shape[1], -1
|
|
314
|
+
)
|
|
315
|
+
self.points = np.array(
|
|
316
|
+
np.where(~np.isnan(np.mean(data_reshaped, axis=1)))
|
|
317
|
+
).flatten()
|
|
318
|
+
|
|
319
|
+
dataset = np.nan_to_num(dataset, nan=0)
|
|
320
|
+
else:
|
|
321
|
+
dataset = self.data.hypercubes[mode]
|
|
322
|
+
self.points = []
|
|
323
|
+
|
|
324
|
+
if self.upload_endmembers_checkbox.value:
|
|
325
|
+
self.selected_basis = self.uploaded_endmembers
|
|
326
|
+
|
|
327
|
+
print(self.selected_basis.shape)
|
|
328
|
+
|
|
329
|
+
self.data.nnls_maps[mode] = nnls_analysis(
|
|
330
|
+
dataset, W=self.selected_basis
|
|
331
|
+
)
|
|
332
|
+
self.viewer.add_image(
|
|
333
|
+
self.data.nnls_maps[mode].transpose(2, 0, 1),
|
|
334
|
+
name=str(mode) + " - NNLS",
|
|
335
|
+
# ={"type": "hyperspectral_cube"},
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
def run_sam(self):
|
|
339
|
+
"""Perform SAM"""
|
|
340
|
+
mode = self.modes_combobox.value
|
|
341
|
+
|
|
342
|
+
if self.masked_dataset.value:
|
|
343
|
+
dataset = self.data.hypercubes_masked[mode]
|
|
344
|
+
data_reshaped = dataset.reshape(
|
|
345
|
+
dataset.shape[0] * dataset.shape[1], -1
|
|
346
|
+
)
|
|
347
|
+
self.points = np.array(
|
|
348
|
+
np.where(~np.isnan(np.mean(data_reshaped, axis=1)))
|
|
349
|
+
).flatten()
|
|
350
|
+
|
|
351
|
+
dataset = np.nan_to_num(dataset, nan=0)
|
|
352
|
+
else:
|
|
353
|
+
dataset = self.data.hypercubes[mode]
|
|
354
|
+
self.points = []
|
|
355
|
+
|
|
356
|
+
if self.upload_endmembers_checkbox.value:
|
|
357
|
+
self.selected_basis = self.uploaded_endmembers
|
|
358
|
+
|
|
359
|
+
self.data.sam_maps[mode] = sam_analysis(
|
|
360
|
+
dataset,
|
|
361
|
+
W=self.selected_basis,
|
|
362
|
+
angle=self.angle_spinbox.value,
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
self.viewer.add_image(
|
|
366
|
+
self.data.sam_maps[mode].transpose(2, 0, 1),
|
|
367
|
+
name=str(mode)
|
|
368
|
+
+ " - SAM with angle "
|
|
369
|
+
+ str(self.angle_spinbox.value),
|
|
370
|
+
colormap="gray_r",
|
|
371
|
+
# ={"type": "hyperspectral_cube"},
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
# %%
|
|
375
|
+
def update_number_H(self):
|
|
376
|
+
""" """
|
|
377
|
+
basis_index = self.viewer.dims.current_step[0]
|
|
378
|
+
basis_index = min(basis_index, len(self.basis_numbers) - 1)
|
|
379
|
+
print(f"basis_index={basis_index}, basis_numbers={self.basis_numbers}")
|
|
380
|
+
self.viewer.text_overlay.text = (
|
|
381
|
+
f"Basis number: {self.basis_numbers[basis_index]}"
|
|
382
|
+
)
|