celldetective 1.0.2.post1__py3-none-any.whl → 1.1.1__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.
- celldetective/__main__.py +7 -21
- celldetective/events.py +2 -44
- celldetective/extra_properties.py +62 -52
- celldetective/filters.py +4 -5
- celldetective/gui/__init__.py +1 -1
- celldetective/gui/analyze_block.py +37 -10
- celldetective/gui/btrack_options.py +24 -23
- celldetective/gui/classifier_widget.py +62 -19
- celldetective/gui/configure_new_exp.py +32 -35
- celldetective/gui/control_panel.py +120 -81
- celldetective/gui/gui_utils.py +674 -396
- celldetective/gui/json_readers.py +7 -6
- celldetective/gui/layouts.py +756 -0
- celldetective/gui/measurement_options.py +98 -513
- celldetective/gui/neighborhood_options.py +322 -270
- celldetective/gui/plot_measurements.py +1114 -0
- celldetective/gui/plot_signals_ui.py +21 -20
- celldetective/gui/process_block.py +449 -169
- celldetective/gui/retrain_segmentation_model_options.py +27 -26
- celldetective/gui/retrain_signal_model_options.py +25 -24
- celldetective/gui/seg_model_loader.py +31 -27
- celldetective/gui/signal_annotator.py +2326 -2295
- celldetective/gui/signal_annotator_options.py +18 -16
- celldetective/gui/styles.py +16 -1
- celldetective/gui/survival_ui.py +67 -39
- celldetective/gui/tableUI.py +337 -48
- celldetective/gui/thresholds_gui.py +75 -71
- celldetective/gui/viewers.py +743 -0
- celldetective/io.py +247 -27
- celldetective/measure.py +43 -263
- celldetective/models/segmentation_effectors/primNK_cfse/config_input.json +29 -0
- celldetective/models/segmentation_effectors/primNK_cfse/cp-cfse-transfer +0 -0
- celldetective/models/segmentation_effectors/primNK_cfse/training_instructions.json +37 -0
- celldetective/neighborhood.py +498 -27
- celldetective/preprocessing.py +1023 -0
- celldetective/scripts/analyze_signals.py +7 -0
- celldetective/scripts/measure_cells.py +12 -0
- celldetective/scripts/segment_cells.py +20 -4
- celldetective/scripts/track_cells.py +11 -0
- celldetective/scripts/train_segmentation_model.py +35 -34
- celldetective/segmentation.py +14 -9
- celldetective/signals.py +234 -329
- celldetective/tracking.py +2 -2
- celldetective/utils.py +602 -49
- celldetective-1.1.1.dist-info/METADATA +305 -0
- celldetective-1.1.1.dist-info/RECORD +84 -0
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/top_level.txt +1 -0
- tests/__init__.py +0 -0
- tests/test_events.py +28 -0
- tests/test_filters.py +24 -0
- tests/test_io.py +70 -0
- tests/test_measure.py +141 -0
- tests/test_neighborhood.py +70 -0
- tests/test_preprocessing.py +37 -0
- tests/test_segmentation.py +93 -0
- tests/test_signals.py +135 -0
- tests/test_tracking.py +164 -0
- tests/test_utils.py +118 -0
- celldetective-1.0.2.post1.dist-info/METADATA +0 -221
- celldetective-1.0.2.post1.dist-info/RECORD +0 -66
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/LICENSE +0 -0
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/WHEEL +0 -0
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/entry_points.txt +0 -0
celldetective/gui/gui_utils.py
CHANGED
|
@@ -1,495 +1,773 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
-
from PyQt5.QtWidgets import QApplication, QFrame, QSizePolicy, QWidget, QLineEdit, QListWidget, QVBoxLayout, QComboBox, \
|
|
3
|
-
|
|
4
|
-
from PyQt5.QtCore import QEvent
|
|
2
|
+
from PyQt5.QtWidgets import QApplication, QMessageBox, QFrame, QSizePolicy, QWidget, QLineEdit, QListWidget, QVBoxLayout, QComboBox, \
|
|
3
|
+
QPushButton, QLabel, QHBoxLayout, QCheckBox, QButtonGroup, QRadioButton, QGridLayout, QSpacerItem
|
|
4
|
+
from PyQt5.QtCore import QEvent, Qt, QSize
|
|
5
|
+
from PyQt5.QtGui import QDoubleValidator, QIntValidator
|
|
6
|
+
|
|
5
7
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
|
6
8
|
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT
|
|
7
9
|
import matplotlib.pyplot as plt
|
|
8
10
|
import celldetective.extra_properties as extra_properties
|
|
9
11
|
from inspect import getmembers, isfunction
|
|
12
|
+
from superqt import QLabeledDoubleRangeSlider, QLabeledSlider, QLabeledDoubleSlider
|
|
13
|
+
from superqt.fonticon import icon
|
|
14
|
+
from fonticon_mdi6 import MDI6
|
|
10
15
|
|
|
16
|
+
from celldetective.io import auto_load_number_of_frames, load_frames
|
|
17
|
+
from celldetective.utils import _extract_channel_indices_from_config
|
|
18
|
+
from celldetective.filters import *
|
|
19
|
+
from celldetective.segmentation import filter_image
|
|
20
|
+
from stardist import fill_label_holes
|
|
11
21
|
|
|
12
22
|
def center_window(window):
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
"""
|
|
24
|
+
Center window in the middle of the screen.
|
|
25
|
+
"""
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
frameGm = window.frameGeometry()
|
|
28
|
+
screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos())
|
|
29
|
+
centerPoint = QApplication.desktop().screenGeometry(screen).center()
|
|
30
|
+
frameGm.moveCenter(centerPoint)
|
|
31
|
+
window.move(frameGm.topLeft())
|
|
22
32
|
|
|
23
33
|
|
|
24
34
|
class QHSeperationLine(QFrame):
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
'''
|
|
36
|
+
a horizontal seperation line\n
|
|
37
|
+
'''
|
|
28
38
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
def __init__(self):
|
|
40
|
+
super().__init__()
|
|
41
|
+
self.setMinimumWidth(1)
|
|
42
|
+
self.setFixedHeight(20)
|
|
43
|
+
self.setFrameShape(QFrame.HLine)
|
|
44
|
+
self.setFrameShadow(QFrame.Sunken)
|
|
45
|
+
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
|
|
36
46
|
|
|
37
47
|
|
|
38
48
|
class FeatureChoice(QWidget):
|
|
39
49
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
50
|
+
def __init__(self, parent_window):
|
|
51
|
+
super().__init__()
|
|
52
|
+
self.parent_window = parent_window
|
|
53
|
+
self.setWindowTitle("Add feature")
|
|
54
|
+
# Create the QComboBox and add some items
|
|
55
|
+
self.combo_box = QComboBox(self)
|
|
56
|
+
center_window(self)
|
|
57
|
+
|
|
58
|
+
standard_measurements = ["area",
|
|
59
|
+
"area_bbox",
|
|
60
|
+
"area_convex",
|
|
61
|
+
"area_filled",
|
|
62
|
+
"major_axis_length",
|
|
63
|
+
"minor_axis_length",
|
|
64
|
+
"eccentricity",
|
|
65
|
+
"equivalent_diameter_area",
|
|
66
|
+
"euler_number",
|
|
67
|
+
"extent",
|
|
68
|
+
"feret_diameter_max",
|
|
69
|
+
"orientation",
|
|
70
|
+
"perimeter",
|
|
71
|
+
"perimeter_crofton",
|
|
72
|
+
"solidity",
|
|
73
|
+
"intensity_mean",
|
|
74
|
+
"intensity_max",
|
|
75
|
+
"intensity_min",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
extra_props = getmembers(extra_properties, isfunction)
|
|
79
|
+
extra_props = [extra_props[i][0] for i in range(len(extra_props))]
|
|
80
|
+
if len(extra_props) > 0:
|
|
81
|
+
standard_measurements.extend(extra_props)
|
|
82
|
+
|
|
83
|
+
self.combo_box.addItems(standard_measurements)
|
|
84
|
+
|
|
85
|
+
self.add_btn = QPushButton("Add")
|
|
86
|
+
self.add_btn.clicked.connect(self.add_current_feature)
|
|
87
|
+
|
|
88
|
+
# Create the layout
|
|
89
|
+
layout = QVBoxLayout(self)
|
|
90
|
+
layout.addWidget(self.combo_box)
|
|
91
|
+
layout.addWidget(self.add_btn)
|
|
92
|
+
|
|
93
|
+
def add_current_feature(self):
|
|
94
|
+
filtername = self.combo_box.currentText()
|
|
95
|
+
self.parent_window.list_widget.addItems([filtername])
|
|
96
|
+
self.close()
|
|
87
97
|
|
|
88
98
|
|
|
89
99
|
class FilterChoice(QWidget):
|
|
90
100
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
101
|
+
def __init__(self, parent_window):
|
|
102
|
+
|
|
103
|
+
super().__init__()
|
|
104
|
+
self.parent_window = parent_window
|
|
105
|
+
self.setWindowTitle("Add filter")
|
|
106
|
+
# Create the QComboBox and add some items
|
|
107
|
+
center_window(self)
|
|
108
|
+
|
|
109
|
+
self.default_params = {
|
|
110
|
+
'gauss_filter': {'sigma': 2},
|
|
111
|
+
'median_filter': {'size': 4},
|
|
112
|
+
'maximum_filter': {'size': 4},
|
|
113
|
+
'minimum_filter': {'size': 4},
|
|
114
|
+
'percentile_filter': {'percentile': 99, 'size': 4},
|
|
115
|
+
'variance_filter': {'size': 4},
|
|
116
|
+
'std_filter': {'size': 4},
|
|
117
|
+
'laplace_filter': None,
|
|
118
|
+
'abs_filter': None,
|
|
119
|
+
'ln_filter': None,
|
|
120
|
+
'subtract_filter': {'value': 1},
|
|
121
|
+
'dog_filter': {'sigma_low': 0.8, 'sigma_high': 1.6},
|
|
122
|
+
'log_filter': {'sigma': 2},
|
|
123
|
+
'tophat_filter': {'size': 4, 'connectivity': 4},
|
|
124
|
+
'otsu_filter': None,
|
|
125
|
+
'local_filter': {'block_size': 73, 'method': 'mean', 'offset': 0},
|
|
126
|
+
'niblack_filter': {'window_size': 15, 'k': 0.2},
|
|
127
|
+
# 'sauvola_filter': {'window_size': 15, 'k': 0.2}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
layout = QVBoxLayout(self)
|
|
131
|
+
self.combo_box = QComboBox(self)
|
|
132
|
+
self.combo_box.addItems(list(self.default_params.keys()))
|
|
133
|
+
self.combo_box.currentTextChanged.connect(self.update_arguments)
|
|
134
|
+
layout.addWidget(self.combo_box)
|
|
135
|
+
|
|
136
|
+
self.arguments_le = [QLineEdit() for i in range(3)]
|
|
137
|
+
self.arguments_labels = [QLabel('') for i in range(3)]
|
|
138
|
+
for i in range(2):
|
|
139
|
+
hbox = QHBoxLayout()
|
|
140
|
+
hbox.addWidget(self.arguments_labels[i], 20)
|
|
141
|
+
hbox.addWidget(self.arguments_le[i], 80)
|
|
142
|
+
layout.addLayout(hbox)
|
|
143
|
+
|
|
144
|
+
self.add_btn = QPushButton("Add")
|
|
145
|
+
self.add_btn.clicked.connect(self.add_current_feature)
|
|
146
|
+
layout.addWidget(self.add_btn)
|
|
147
|
+
|
|
148
|
+
self.combo_box.setCurrentIndex(0)
|
|
149
|
+
self.update_arguments()
|
|
150
|
+
|
|
151
|
+
def add_current_feature(self):
|
|
152
|
+
|
|
153
|
+
filtername = self.combo_box.currentText()
|
|
154
|
+
self.parent_window.list_widget.addItems([filtername])
|
|
155
|
+
|
|
156
|
+
filter_instructions = [filtername.split('_')[0]]
|
|
157
|
+
for a in self.arguments_le:
|
|
158
|
+
arg = a.text()
|
|
159
|
+
arg_num = arg
|
|
160
|
+
if (arg != '') and arg_num.replace('.', '').replace(',', '').isnumeric():
|
|
161
|
+
num = float(arg)
|
|
162
|
+
if num.is_integer():
|
|
163
|
+
num = int(num)
|
|
164
|
+
filter_instructions.append(num)
|
|
165
|
+
elif arg != '':
|
|
166
|
+
filter_instructions.append(arg)
|
|
167
|
+
|
|
168
|
+
print(f'You added filter {filter_instructions}.')
|
|
169
|
+
|
|
170
|
+
self.parent_window.items.append(filter_instructions)
|
|
171
|
+
self.close()
|
|
172
|
+
|
|
173
|
+
def update_arguments(self):
|
|
174
|
+
|
|
175
|
+
selected_filter = self.combo_box.currentText()
|
|
176
|
+
arguments = self.default_params[selected_filter]
|
|
177
|
+
if arguments is not None:
|
|
178
|
+
args = list(arguments.keys())
|
|
179
|
+
for i in range(len(args)):
|
|
180
|
+
self.arguments_labels[i].setEnabled(True)
|
|
181
|
+
self.arguments_le[i].setEnabled(True)
|
|
182
|
+
|
|
183
|
+
self.arguments_labels[i].setText(args[i])
|
|
184
|
+
self.arguments_le[i].setText(str(arguments[args[i]]))
|
|
185
|
+
|
|
186
|
+
if len(args) < 2:
|
|
187
|
+
for i in range(len(args), 2):
|
|
188
|
+
self.arguments_labels[i].setEnabled(False)
|
|
189
|
+
self.arguments_labels[i].setText('')
|
|
190
|
+
self.arguments_le[i].setEnabled(False)
|
|
191
|
+
else:
|
|
192
|
+
for i in range(2):
|
|
193
|
+
self.arguments_labels[i].setEnabled(False)
|
|
194
|
+
self.arguments_le[i].setEnabled(False)
|
|
195
|
+
self.arguments_labels[i].setText('')
|
|
186
196
|
|
|
187
197
|
|
|
188
198
|
class OperationChoice(QWidget):
|
|
189
|
-
|
|
190
|
-
|
|
199
|
+
"""
|
|
200
|
+
Mini window to select an operation from numpy to apply on the ROI.
|
|
191
201
|
|
|
192
|
-
|
|
202
|
+
"""
|
|
193
203
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
204
|
+
def __init__(self, parent_window):
|
|
205
|
+
super().__init__()
|
|
206
|
+
self.parent_window = parent_window
|
|
207
|
+
self.setWindowTitle("Add feature")
|
|
208
|
+
# Create the QComboBox and add some items
|
|
209
|
+
self.combo_box = QComboBox(self)
|
|
210
|
+
center_window(self)
|
|
201
211
|
|
|
202
|
-
|
|
203
|
-
|
|
212
|
+
self.combo_box.addItems(["mean", "median", "average", "std", "var",
|
|
213
|
+
"nanmedian", "nanmean", "nanstd", "nanvar"])
|
|
204
214
|
|
|
205
|
-
|
|
206
|
-
|
|
215
|
+
self.add_btn = QPushButton("Add")
|
|
216
|
+
self.add_btn.clicked.connect(self.add_current_feature)
|
|
207
217
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
218
|
+
# Create the layout
|
|
219
|
+
layout = QVBoxLayout(self)
|
|
220
|
+
layout.addWidget(self.combo_box)
|
|
221
|
+
layout.addWidget(self.add_btn)
|
|
212
222
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
223
|
+
def add_current_feature(self):
|
|
224
|
+
filtername = self.combo_box.currentText()
|
|
225
|
+
self.parent_window.list_widget.addItems([filtername])
|
|
226
|
+
self.close()
|
|
217
227
|
|
|
218
228
|
|
|
219
229
|
class GeometryChoice(QWidget):
|
|
220
230
|
|
|
221
|
-
|
|
231
|
+
def __init__(self, parent_window):
|
|
222
232
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
233
|
+
super().__init__()
|
|
234
|
+
self.parent_window = parent_window
|
|
235
|
+
self.setWindowTitle("Set distances")
|
|
236
|
+
center_window(self)
|
|
227
237
|
|
|
228
|
-
|
|
238
|
+
# Create the QComboBox and add some items
|
|
229
239
|
|
|
230
|
-
|
|
231
|
-
|
|
240
|
+
self.dist_label = QLabel('Distance [px]: ')
|
|
241
|
+
self.dist_le = QLineEdit('10')
|
|
232
242
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
243
|
+
self.dist_outer_label = QLabel('Max distance [px]')
|
|
244
|
+
self.dist_outer_le = QLineEdit('100')
|
|
245
|
+
self.outer_to_hide = [self.dist_outer_le, self.dist_outer_label]
|
|
236
246
|
|
|
237
|
-
|
|
238
|
-
|
|
247
|
+
self.outer_btn = QCheckBox('outer distance')
|
|
248
|
+
self.outer_btn.clicked.connect(self.activate_outer_value)
|
|
239
249
|
|
|
240
|
-
|
|
241
|
-
|
|
250
|
+
self.add_btn = QPushButton("Add")
|
|
251
|
+
self.add_btn.clicked.connect(self.add_current_feature)
|
|
242
252
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
253
|
+
# Create the layout
|
|
254
|
+
layout = QVBoxLayout(self)
|
|
255
|
+
dist_layout = QHBoxLayout()
|
|
256
|
+
dist_layout.addWidget(self.dist_label, 30)
|
|
257
|
+
dist_layout.addWidget(self.dist_le, 70)
|
|
248
258
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
259
|
+
self.dist_outer_layout = QHBoxLayout()
|
|
260
|
+
self.dist_outer_layout.addWidget(self.dist_outer_label, 30)
|
|
261
|
+
self.dist_outer_layout.addWidget(self.dist_outer_le, 70)
|
|
252
262
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
263
|
+
layout.addLayout(dist_layout)
|
|
264
|
+
layout.addLayout(self.dist_outer_layout)
|
|
265
|
+
layout.addWidget(self.outer_btn)
|
|
266
|
+
layout.addWidget(self.add_btn)
|
|
257
267
|
|
|
258
|
-
|
|
259
|
-
|
|
268
|
+
for el in self.outer_to_hide:
|
|
269
|
+
el.hide()
|
|
260
270
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
271
|
+
def activate_outer_value(self):
|
|
272
|
+
if self.outer_btn.isChecked():
|
|
273
|
+
self.dist_label.setText('Min distance [px]: ')
|
|
274
|
+
for el in self.outer_to_hide:
|
|
275
|
+
el.show()
|
|
276
|
+
else:
|
|
277
|
+
self.dist_label.setText('Distance [px]: ')
|
|
278
|
+
for el in self.outer_to_hide:
|
|
279
|
+
el.hide()
|
|
270
280
|
|
|
271
|
-
|
|
281
|
+
def add_current_feature(self):
|
|
272
282
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
283
|
+
value = self.dist_le.text()
|
|
284
|
+
if self.outer_btn.isChecked():
|
|
285
|
+
value2 = self.dist_outer_le.text()
|
|
286
|
+
values = [value + '-' + value2]
|
|
287
|
+
else:
|
|
288
|
+
values = [value]
|
|
289
|
+
self.parent_window.list_widget.addItems(values)
|
|
290
|
+
self.close()
|
|
281
291
|
|
|
282
292
|
|
|
283
293
|
class DistanceChoice(QWidget):
|
|
284
294
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
295
|
+
def __init__(self, parent_window):
|
|
296
|
+
super().__init__()
|
|
297
|
+
self.parent_window = parent_window
|
|
298
|
+
self.setWindowTitle("Set distances")
|
|
299
|
+
center_window(self)
|
|
290
300
|
|
|
291
|
-
|
|
301
|
+
# Create the QComboBox and add some items
|
|
292
302
|
|
|
293
|
-
|
|
294
|
-
|
|
303
|
+
self.dist_label = QLabel('Distance [px]: ')
|
|
304
|
+
self.dist_le = QLineEdit('10')
|
|
295
305
|
|
|
296
|
-
|
|
297
|
-
|
|
306
|
+
self.add_btn = QPushButton("Add")
|
|
307
|
+
self.add_btn.clicked.connect(self.add_current_feature)
|
|
298
308
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
309
|
+
# Create the layout
|
|
310
|
+
layout = QVBoxLayout(self)
|
|
311
|
+
dist_layout = QHBoxLayout()
|
|
312
|
+
dist_layout.addWidget(self.dist_label, 30)
|
|
313
|
+
dist_layout.addWidget(self.dist_le, 70)
|
|
304
314
|
|
|
305
|
-
|
|
306
|
-
|
|
315
|
+
layout.addLayout(dist_layout)
|
|
316
|
+
layout.addWidget(self.add_btn)
|
|
307
317
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
318
|
+
def add_current_feature(self):
|
|
319
|
+
value = self.dist_le.text()
|
|
320
|
+
values = [value]
|
|
321
|
+
self.parent_window.list_widget.addItems(values)
|
|
322
|
+
self.close()
|
|
313
323
|
|
|
314
324
|
|
|
315
325
|
class ListWidget(QWidget):
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
326
|
+
"""
|
|
327
|
+
Generic list widget.
|
|
328
|
+
"""
|
|
319
329
|
|
|
320
|
-
|
|
330
|
+
def __init__(self, parent_window, choiceWidget, initial_features, dtype=str, channel_names=None):
|
|
321
331
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
332
|
+
super().__init__()
|
|
333
|
+
self.parent_window = parent_window
|
|
334
|
+
self.initial_features = initial_features
|
|
335
|
+
self.choiceWidget = choiceWidget
|
|
336
|
+
self.dtype = dtype
|
|
337
|
+
self.items = []
|
|
338
|
+
self.channel_names=channel_names
|
|
329
339
|
|
|
330
|
-
|
|
340
|
+
self.setFixedHeight(80)
|
|
331
341
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
342
|
+
# Initialize list widget
|
|
343
|
+
self.list_widget = QListWidget()
|
|
344
|
+
self.list_widget.addItems(initial_features)
|
|
335
345
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
346
|
+
# Set up layout
|
|
347
|
+
main_layout = QVBoxLayout()
|
|
348
|
+
main_layout.addWidget(self.list_widget)
|
|
349
|
+
self.setLayout(main_layout)
|
|
340
350
|
|
|
341
|
-
|
|
351
|
+
def addItem(self):
|
|
342
352
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
353
|
+
"""
|
|
354
|
+
Add a new item.
|
|
355
|
+
"""
|
|
346
356
|
|
|
347
|
-
|
|
348
|
-
|
|
357
|
+
self.addItemWindow = self.choiceWidget(self)
|
|
358
|
+
self.addItemWindow.show()
|
|
349
359
|
|
|
350
|
-
|
|
360
|
+
def getItems(self):
|
|
351
361
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
362
|
+
"""
|
|
363
|
+
Get all the items as a list.
|
|
364
|
+
"""
|
|
355
365
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
366
|
+
items = []
|
|
367
|
+
for x in range(self.list_widget.count()):
|
|
368
|
+
if len(self.list_widget.item(x).text().split('-')) == 2:
|
|
369
|
+
if self.list_widget.item(x).text()[0] == '-':
|
|
370
|
+
items.append(self.dtype(self.list_widget.item(x).text()))
|
|
371
|
+
else:
|
|
372
|
+
minn, maxx = self.list_widget.item(x).text().split('-')
|
|
373
|
+
to_add = [self.dtype(minn), self.dtype(maxx)]
|
|
374
|
+
items.append(to_add)
|
|
375
|
+
else:
|
|
376
|
+
items.append(self.dtype(self.list_widget.item(x).text()))
|
|
377
|
+
return items
|
|
368
378
|
|
|
369
379
|
|
|
370
380
|
|
|
371
|
-
|
|
381
|
+
def removeSel(self):
|
|
372
382
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
383
|
+
"""
|
|
384
|
+
Remove selected items.
|
|
385
|
+
"""
|
|
376
386
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
387
|
+
listItems = self.list_widget.selectedItems()
|
|
388
|
+
if not listItems: return
|
|
389
|
+
for item in listItems:
|
|
390
|
+
idx = self.list_widget.row(item)
|
|
391
|
+
self.list_widget.takeItem(idx)
|
|
392
|
+
if self.items:
|
|
393
|
+
del self.items[idx]
|
|
384
394
|
|
|
385
395
|
|
|
386
396
|
class FigureCanvas(QWidget):
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
397
|
+
"""
|
|
398
|
+
Generic figure canvas.
|
|
399
|
+
"""
|
|
400
|
+
|
|
401
|
+
def __init__(self, fig, title="", interactive=True):
|
|
402
|
+
super().__init__()
|
|
403
|
+
self.fig = fig
|
|
404
|
+
self.setWindowTitle(title)
|
|
405
|
+
self.canvas = FigureCanvasQTAgg(self.fig)
|
|
406
|
+
self.canvas.setStyleSheet("background-color: transparent;")
|
|
407
|
+
if interactive:
|
|
408
|
+
self.toolbar = NavigationToolbar2QT(self.canvas)
|
|
409
|
+
self.layout = QVBoxLayout(self)
|
|
410
|
+
self.layout.addWidget(self.canvas)
|
|
411
|
+
if interactive:
|
|
412
|
+
self.layout.addWidget(self.toolbar)
|
|
413
|
+
|
|
414
|
+
center_window(self)
|
|
415
|
+
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
416
|
+
|
|
417
|
+
def draw(self):
|
|
418
|
+
self.canvas.draw()
|
|
419
|
+
|
|
420
|
+
def closeEvent(self, event):
|
|
421
|
+
""" Delete figure on closing window. """
|
|
422
|
+
# self.canvas.ax.cla() # ****
|
|
423
|
+
self.fig.clf() # ****
|
|
424
|
+
plt.close(self.fig)
|
|
425
|
+
super(FigureCanvas, self).closeEvent(event)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
class QuickSliderLayout(QHBoxLayout):
|
|
429
|
+
|
|
430
|
+
"""docstring for ClassName"""
|
|
431
|
+
|
|
432
|
+
def __init__(self, label=None, slider=None, layout_ratio=(0.25,0.75), slider_initial_value=1, slider_range=(0,1), slider_tooltip=None, decimal_option=True, precision=1.0E-03, *args):
|
|
433
|
+
super().__init__(*args)
|
|
434
|
+
|
|
435
|
+
if label is not None and isinstance(label,str):
|
|
436
|
+
self.qlabel = QLabel(label)
|
|
437
|
+
self.addWidget(self.qlabel, int(100*layout_ratio[0]))
|
|
438
|
+
|
|
439
|
+
self.slider = slider
|
|
440
|
+
self.slider.setOrientation(1)
|
|
441
|
+
if decimal_option:
|
|
442
|
+
self.slider.setSingleStep(precision)
|
|
443
|
+
self.slider.setTickInterval(precision)
|
|
444
|
+
else:
|
|
445
|
+
self.slider.setSingleStep(1)
|
|
446
|
+
self.slider.setTickInterval(1)
|
|
447
|
+
|
|
448
|
+
self.slider.setRange(*slider_range)
|
|
449
|
+
self.slider.setValue(slider_initial_value)
|
|
450
|
+
if isinstance(slider_tooltip,str):
|
|
451
|
+
self.slider.setToolTip(slider_tooltip)
|
|
452
|
+
|
|
453
|
+
self.addWidget(self.slider, int(100*layout_ratio[1]))
|
|
454
|
+
|
|
455
|
+
class ThresholdLineEdit(QLineEdit):
|
|
456
|
+
|
|
457
|
+
"""docstring for ClassName"""
|
|
458
|
+
|
|
459
|
+
def __init__(self, init_value=2.0, connected_buttons=None, placeholder='px > thresh are masked',value_type='float',*args):
|
|
460
|
+
super().__init__(*args)
|
|
461
|
+
|
|
462
|
+
self.init_value = init_value
|
|
463
|
+
self.value_type = value_type
|
|
464
|
+
self.connected_buttons = connected_buttons
|
|
465
|
+
self.setPlaceholderText(placeholder)
|
|
466
|
+
|
|
467
|
+
if self.value_type=="float":
|
|
468
|
+
self.setValidator(QDoubleValidator())
|
|
469
|
+
else:
|
|
470
|
+
self.init_value = int(self.init_value)
|
|
471
|
+
self.setValidator(QIntValidator())
|
|
472
|
+
|
|
473
|
+
if self.connected_buttons is not None:
|
|
474
|
+
self.textChanged.connect(self.enable_btn)
|
|
475
|
+
print("init value of ",self.init_value," for threshold LE")
|
|
476
|
+
self.set_threshold(self.init_value)
|
|
477
|
+
|
|
478
|
+
def enable_btn(self):
|
|
479
|
+
|
|
480
|
+
thresh = self.get_threshold(show_warning=False)
|
|
481
|
+
if isinstance(self.connected_buttons, QPushButton):
|
|
482
|
+
cbs = [self.connected_buttons]
|
|
483
|
+
else:
|
|
484
|
+
cbs = self.connected_buttons
|
|
485
|
+
|
|
486
|
+
if thresh is None:
|
|
487
|
+
for c in cbs:
|
|
488
|
+
c.setEnabled(False)
|
|
489
|
+
else:
|
|
490
|
+
for c in cbs:
|
|
491
|
+
c.setEnabled(True)
|
|
492
|
+
|
|
493
|
+
def set_threshold(self, value):
|
|
494
|
+
|
|
495
|
+
try:
|
|
496
|
+
self.setText(str(value).replace('.',','))
|
|
497
|
+
except:
|
|
498
|
+
print('Please provide a valid threshold value...')
|
|
499
|
+
|
|
500
|
+
def get_threshold(self, show_warning=True):
|
|
501
|
+
|
|
502
|
+
try:
|
|
503
|
+
if self.value_type=='float':
|
|
504
|
+
thresh = float(self.text().replace(',','.'))
|
|
505
|
+
else:
|
|
506
|
+
thresh = int(self.text().replace(',','.'))
|
|
507
|
+
except ValueError:
|
|
508
|
+
if show_warning:
|
|
509
|
+
msgBox = QMessageBox()
|
|
510
|
+
msgBox.setWindowTitle('warning')
|
|
511
|
+
msgBox.setIcon(QMessageBox.Critical)
|
|
512
|
+
msgBox.setText("Please set a valid threshold value.")
|
|
513
|
+
msgBox.setWindowTitle("")
|
|
514
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
515
|
+
returnValue = msgBox.exec()
|
|
516
|
+
thresh = None
|
|
517
|
+
|
|
518
|
+
return thresh
|
|
519
|
+
|
|
520
|
+
# class BackgroundFitCorrectionLayout(QGridLayout):
|
|
521
|
+
|
|
522
|
+
# """docstring for ClassName"""
|
|
523
|
+
|
|
524
|
+
# def __init__(self, parent=None, *args):
|
|
525
|
+
# super().__init__(*args)
|
|
526
|
+
|
|
527
|
+
# self.parent = parent
|
|
528
|
+
# self.channel_names = self.parent.channel_names # check this
|
|
529
|
+
|
|
530
|
+
# self.setContentsMargins(15,15,15,15)
|
|
531
|
+
# self.generate_widgets()
|
|
532
|
+
# self.add_to_layout()
|
|
533
|
+
|
|
534
|
+
# def generate_widgets(self):
|
|
535
|
+
|
|
536
|
+
# self.channel_lbl = QLabel('Channel: ')
|
|
537
|
+
# self.channels_cb = QComboBox()
|
|
538
|
+
# self.channels_cb.addItems(self.channel_names)
|
|
539
|
+
|
|
540
|
+
# self.thresh_lbl = QLabel('Threshold: ')
|
|
541
|
+
# self.thresh_lbl.setToolTip('Threshold on the STD-filtered image.\nPixel values above the threshold are\nconsidered as non-background and are\nmasked prior to background estimation.')
|
|
542
|
+
# self.threshold_viewer_btn = QPushButton()
|
|
543
|
+
# self.threshold_viewer_btn.setIcon(icon(MDI6.image_check, color="k"))
|
|
544
|
+
# self.threshold_viewer_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
|
|
545
|
+
# self.threshold_viewer_btn.clicked.connect(self.set_threshold_graphically)
|
|
546
|
+
|
|
547
|
+
# self.model_lbl = QLabel('Model: ')
|
|
548
|
+
# self.models_cb = QComboBox()
|
|
549
|
+
# self.models_cb.addItems(['Paraboloid', 'Place'])
|
|
550
|
+
|
|
551
|
+
# self.operation_lbl = QLabel('Operation: ')
|
|
552
|
+
# self.operation_group = QButtonGroup()
|
|
553
|
+
# self.subtract_btn = QRadioButton('Subtract')
|
|
554
|
+
# self.divide_btn = QRadioButton('Divide')
|
|
555
|
+
# self.subtract_btn.toggled.connect(self.activate_clipping_options)
|
|
556
|
+
# self.divide_btn.toggled.connect(self.activate_clipping_options)
|
|
557
|
+
|
|
558
|
+
# self.operation_group.addButton(self.subtract_btn)
|
|
559
|
+
# self.operation_group.addButton(self.divide_btn)
|
|
560
|
+
|
|
561
|
+
# self.clip_group = QButtonGroup()
|
|
562
|
+
# self.clip_btn = QRadioButton('Clip')
|
|
563
|
+
# self.clip_not_btn = QRadioButton('Do not clip')
|
|
564
|
+
|
|
565
|
+
# self.clip_group.addButton(self.clip_btn)
|
|
566
|
+
# self.clip_group.addButton(self.clip_not_btn)
|
|
567
|
+
|
|
568
|
+
# self.corrected_stack_viewer = QPushButton("")
|
|
569
|
+
# self.corrected_stack_viewer.setStyleSheet(self.parent.parent.parent.button_select_all)
|
|
570
|
+
# self.corrected_stack_viewer.setIcon(icon(MDI6.eye_outline, color="black"))
|
|
571
|
+
# self.corrected_stack_viewer.setToolTip("View corrected image")
|
|
572
|
+
# self.corrected_stack_viewer.setIconSize(QSize(20, 20))
|
|
573
|
+
|
|
574
|
+
# self.add_correction_btn = QPushButton('Add correction')
|
|
575
|
+
# self.add_correction_btn.setStyleSheet(self.parent.parent.parent.button_style_sheet_2)
|
|
576
|
+
# self.add_correction_btn.setIcon(icon(MDI6.plus, color="#1565c0"))
|
|
577
|
+
# self.add_correction_btn.setToolTip('Add correction.')
|
|
578
|
+
# self.add_correction_btn.setIconSize(QSize(25, 25))
|
|
579
|
+
# self.add_correction_btn.clicked.connect(self.add_instructions_to_parent_list)
|
|
580
|
+
|
|
581
|
+
# self.threshold_le = ThresholdLineEdit(init_value=2, connected_buttons=[self.threshold_viewer_btn,
|
|
582
|
+
# self.corrected_stack_viewer,
|
|
583
|
+
# self.add_correction_btn
|
|
584
|
+
# ])
|
|
585
|
+
|
|
586
|
+
# def add_to_layout(self):
|
|
587
|
+
|
|
588
|
+
# channel_layout = QHBoxLayout()
|
|
589
|
+
# channel_layout.addWidget(self.channel_lbl, 25)
|
|
590
|
+
# channel_layout.addWidget(self.channels_cb, 75)
|
|
591
|
+
# self.addLayout(channel_layout, 0, 0, 1, 3)
|
|
592
|
+
|
|
593
|
+
# threshold_layout = QHBoxLayout()
|
|
594
|
+
# threshold_layout.addWidget(self.thresh_lbl, 25)
|
|
595
|
+
# threshold_layout.addWidget(self.threshold_le, 70)
|
|
596
|
+
# threshold_layout.addWidget(self.threshold_viewer_btn, 5)
|
|
597
|
+
# self.addLayout(threshold_layout, 1, 0, 1, 3)
|
|
598
|
+
|
|
599
|
+
# model_layout = QHBoxLayout()
|
|
600
|
+
# model_layout.addWidget(self.model_lbl, 25)
|
|
601
|
+
# model_layout.addWidget(self.models_cb, 75)
|
|
602
|
+
# self.addLayout(model_layout, 2, 0, 1, 3)
|
|
603
|
+
|
|
604
|
+
# operation_layout = QHBoxLayout()
|
|
605
|
+
# operation_layout.addWidget(self.operation_lbl, 25)
|
|
606
|
+
# operation_layout.addWidget(self.subtract_btn, 75//2, alignment=Qt.AlignCenter)
|
|
607
|
+
# operation_layout.addWidget(self.divide_btn, 75//2, alignment=Qt.AlignCenter)
|
|
608
|
+
# self.addLayout(operation_layout, 3, 0, 1, 3)
|
|
609
|
+
|
|
610
|
+
# clip_layout = QHBoxLayout()
|
|
611
|
+
# clip_layout.addWidget(QLabel(''), 25)
|
|
612
|
+
# clip_layout.addWidget(self.clip_btn, 75//4, alignment=Qt.AlignCenter)
|
|
613
|
+
# clip_layout.addWidget(self.clip_not_btn, 75//4, alignment=Qt.AlignCenter)
|
|
614
|
+
# clip_layout.addWidget(QLabel(''), 75//2)
|
|
615
|
+
# self.addLayout(clip_layout, 4, 0, 1, 3)
|
|
616
|
+
|
|
617
|
+
# self.addWidget(self.corrected_stack_viewer, 4, 2, 1, 1)
|
|
618
|
+
# self.addWidget(self.add_correction_btn, 5, 0, 1, 3)
|
|
619
|
+
|
|
620
|
+
# self.subtract_btn.click()
|
|
621
|
+
# self.clip_not_btn.click()
|
|
622
|
+
|
|
623
|
+
# verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
|
624
|
+
# self.addItem(verticalSpacer, 5, 0, 1, 3)
|
|
625
|
+
|
|
626
|
+
# def add_instructions_to_parent_list(self):
|
|
627
|
+
|
|
628
|
+
# self.generate_instructions()
|
|
629
|
+
# self.parent.background_correction.append(self.instructions)
|
|
630
|
+
# correction_description = ""
|
|
631
|
+
# for index, (key, value) in enumerate(self.instructions.items()):
|
|
632
|
+
# if index > 0:
|
|
633
|
+
# correction_description += ", "
|
|
634
|
+
# correction_description += str(key) + " : " + str(value)
|
|
635
|
+
# self.parent.normalisation_list.addItem(correction_description)
|
|
636
|
+
|
|
637
|
+
# def generate_instructions(self):
|
|
638
|
+
|
|
639
|
+
# if self.subtract_btn.isChecked():
|
|
640
|
+
# operation = "subtract"
|
|
641
|
+
# else:
|
|
642
|
+
# operation = "divide"
|
|
643
|
+
# clip = None
|
|
644
|
+
|
|
645
|
+
# if self.clip_btn.isChecked() and self.subtract_btn.isChecked():
|
|
646
|
+
# clip = True
|
|
647
|
+
# else:
|
|
648
|
+
# clip = False
|
|
649
|
+
|
|
650
|
+
# self.instructions = {
|
|
651
|
+
# "target_channel": self.channels_cb.currentText(),
|
|
652
|
+
# "correction_type": "fit",
|
|
653
|
+
# "threshold_on_std": self.threshold_le.get_threshold(),
|
|
654
|
+
# "operation": operation,
|
|
655
|
+
# "clip": clip
|
|
656
|
+
# }
|
|
657
|
+
|
|
658
|
+
# def activate_clipping_options(self):
|
|
659
|
+
|
|
660
|
+
# if self.subtract_btn.isChecked():
|
|
661
|
+
# self.clip_btn.setEnabled(True)
|
|
662
|
+
# self.clip_not_btn.setEnabled(True)
|
|
663
|
+
|
|
664
|
+
# else:
|
|
665
|
+
# self.clip_btn.setEnabled(False)
|
|
666
|
+
# self.clip_not_btn.setEnabled(False)
|
|
667
|
+
|
|
668
|
+
# def set_target_channel(self):
|
|
669
|
+
|
|
670
|
+
# channel_indices = _extract_channel_indices_from_config(self.parent.parent.exp_config, [self.channels_cb.currentText()])
|
|
671
|
+
# self.target_channel = channel_indices[0]
|
|
672
|
+
|
|
673
|
+
# def set_threshold_graphically(self):
|
|
674
|
+
|
|
675
|
+
# self.parent.locate_image()
|
|
676
|
+
# self.set_target_channel()
|
|
677
|
+
# thresh = self.threshold_le.get_threshold()
|
|
678
|
+
|
|
679
|
+
# if self.parent.current_stack is not None and thresh is not None:
|
|
680
|
+
# self.viewer = ThresholdedStackVisualizer(initial_threshold=thresh,
|
|
681
|
+
# parent_le = self.threshold_le,
|
|
682
|
+
# preprocessing=[['gauss',2],["std",4]],
|
|
683
|
+
# stack_path=self.parent.current_stack,
|
|
684
|
+
# n_channels=len(self.channel_names),
|
|
685
|
+
# target_channel=self.target_channel,
|
|
686
|
+
# window_title='Set the exclusion threshold',
|
|
687
|
+
# )
|
|
688
|
+
# self.viewer.show()
|
|
411
689
|
|
|
412
690
|
|
|
413
691
|
def color_from_status(status, recently_modified=False):
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
692
|
+
if not recently_modified:
|
|
693
|
+
if status == 0:
|
|
694
|
+
return 'tab:blue'
|
|
695
|
+
elif status == 1:
|
|
696
|
+
return 'tab:red'
|
|
697
|
+
elif status == 2:
|
|
698
|
+
return 'yellow'
|
|
699
|
+
else:
|
|
700
|
+
return 'k'
|
|
701
|
+
else:
|
|
702
|
+
if status == 0:
|
|
703
|
+
return 'tab:cyan'
|
|
704
|
+
elif status == 1:
|
|
705
|
+
return 'tab:orange'
|
|
706
|
+
elif status == 2:
|
|
707
|
+
return 'tab:olive'
|
|
708
|
+
else:
|
|
709
|
+
return 'k'
|
|
432
710
|
|
|
433
711
|
def color_from_state(state, recently_modified=False):
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
712
|
+
unique_values = np.unique(state)
|
|
713
|
+
color_map={}
|
|
714
|
+
for value in unique_values:
|
|
715
|
+
color_map[value] = plt.cm.tab10(value)
|
|
716
|
+
if value == 99:
|
|
717
|
+
color_map[value] = 'k'
|
|
718
|
+
# colors = plt.cm.tab10(len(unique_values))
|
|
719
|
+
# color_map = dict(zip(unique_values, colors))
|
|
720
|
+
# print(color_map)
|
|
721
|
+
return color_map
|
|
444
722
|
|
|
445
723
|
|
|
446
724
|
|
|
447
725
|
|
|
448
726
|
def color_from_class(cclass, recently_modified=False):
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
727
|
+
if not recently_modified:
|
|
728
|
+
if cclass == 0:
|
|
729
|
+
return 'tab:red'
|
|
730
|
+
elif cclass == 1:
|
|
731
|
+
return 'tab:blue'
|
|
732
|
+
elif cclass == 2:
|
|
733
|
+
return 'yellow'
|
|
734
|
+
else:
|
|
735
|
+
return 'k'
|
|
736
|
+
else:
|
|
737
|
+
if cclass == 0:
|
|
738
|
+
return 'tab:orange'
|
|
739
|
+
elif cclass == 1:
|
|
740
|
+
return 'tab:cyan'
|
|
741
|
+
elif cclass == 2:
|
|
742
|
+
return 'tab:olive'
|
|
743
|
+
else:
|
|
744
|
+
return 'k'
|
|
467
745
|
|
|
468
746
|
|
|
469
747
|
class ChannelChoice(QWidget):
|
|
470
748
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
749
|
+
def __init__(self, parent_window):
|
|
750
|
+
super().__init__()
|
|
751
|
+
self.parent_window = parent_window
|
|
752
|
+
#self.channel_names = channel_names
|
|
753
|
+
self.setWindowTitle("Choose target channel")
|
|
754
|
+
# Create the QComboBox and add some items
|
|
755
|
+
self.combo_box = QComboBox(self)
|
|
756
|
+
center_window(self)
|
|
479
757
|
|
|
480
|
-
|
|
758
|
+
channels = parent_window.channel_names
|
|
481
759
|
|
|
482
|
-
|
|
760
|
+
self.combo_box.addItems(channels)
|
|
483
761
|
|
|
484
|
-
|
|
485
|
-
|
|
762
|
+
self.add_btn = QPushButton("Add")
|
|
763
|
+
self.add_btn.clicked.connect(self.add_current_channel)
|
|
486
764
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
765
|
+
# Create the layout
|
|
766
|
+
layout = QVBoxLayout(self)
|
|
767
|
+
layout.addWidget(self.combo_box)
|
|
768
|
+
layout.addWidget(self.add_btn)
|
|
491
769
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
770
|
+
def add_current_channel(self):
|
|
771
|
+
filtername = self.combo_box.currentText()
|
|
772
|
+
self.parent_window.list_widget.addItems([filtername])
|
|
773
|
+
self.close()
|