celldetective 1.3.9.post5__py3-none-any.whl → 1.4.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/__init__.py +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/exceptions.py +11 -0
- celldetective/extra_properties.py +132 -0
- celldetective/filters.py +7 -1
- celldetective/gui/InitWindow.py +37 -46
- celldetective/gui/__init__.py +3 -9
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_annotator.py +786 -0
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/classifier_widget.py +86 -94
- celldetective/gui/configure_new_exp.py +163 -46
- celldetective/gui/control_panel.py +76 -146
- celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
- celldetective/gui/generic_signal_plot.py +11 -13
- celldetective/gui/gui_utils.py +54 -23
- celldetective/gui/help/neighborhood.json +2 -2
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +265 -31
- celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +125 -72
- celldetective/gui/process_block.py +283 -188
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/downloader.py +37 -34
- celldetective/gui/processes/measure_cells.py +19 -8
- celldetective/gui/processes/segment_cells.py +47 -11
- celldetective/gui/processes/track_cells.py +18 -13
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/settings/__init__.py +7 -0
- celldetective/gui/settings/_settings_base.py +70 -0
- celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
- celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
- celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
- celldetective/gui/settings/_settings_segmentation.py +49 -0
- celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
- celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
- celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
- celldetective/gui/styles.py +2 -1
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +53 -25
- celldetective/gui/table_ops/__init__.py +0 -0
- celldetective/gui/table_ops/merge_groups.py +118 -0
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +107 -42
- celldetective/gui/workers.py +8 -4
- celldetective/io.py +137 -57
- celldetective/links/zenodo.json +145 -144
- celldetective/measure.py +94 -53
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +56 -35
- celldetective/regionprops/_regionprops.py +16 -5
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_cells.py +5 -5
- celldetective/scripts/measure_relative.py +20 -12
- celldetective/scripts/segment_cells.py +4 -10
- celldetective/scripts/segment_cells_thresholds.py +3 -3
- celldetective/scripts/track_cells.py +10 -8
- celldetective/scripts/train_segmentation_model.py +18 -6
- celldetective/signals.py +29 -14
- celldetective/tracking.py +14 -3
- celldetective/utils.py +91 -62
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
- celldetective-1.4.1.dist-info/RECORD +123 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
- tests/gui/__init__.py +0 -0
- tests/gui/test_new_project.py +228 -0
- tests/gui/test_project.py +99 -0
- tests/test_preprocessing.py +2 -2
- celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
- celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
- celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
- celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
- celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
- celldetective/models/signal_detection/NucCond/config_input.json +0 -1
- celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
- celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
- celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
- celldetective/models/signal_detection/NucCond/scores.npy +0 -0
- celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
- celldetective-1.3.9.post5.dist-info/RECORD +0 -129
- tests/test_qt.py +0 -103
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from PyQt5.QtWidgets import QCheckBox
|
|
2
|
+
from PyQt5.QtCore import QSize
|
|
3
|
+
from superqt.fonticon import icon
|
|
4
|
+
from fonticon_mdi6 import MDI6
|
|
5
|
+
from celldetective.gui.settings._settings_base import CelldetectiveSettingsPanel
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
class SettingsSegmentation(CelldetectiveSettingsPanel):
|
|
10
|
+
|
|
11
|
+
def __init__(self, parent_window=None):
|
|
12
|
+
|
|
13
|
+
super().__init__(title="Configure segmentation")
|
|
14
|
+
self.parent_window = parent_window
|
|
15
|
+
self.mode = self.parent_window.mode
|
|
16
|
+
self.exp_dir = self.parent_window.exp_dir
|
|
17
|
+
self._instructions_path = self.parent_window.exp_dir + f"configs/segmentation_instructions_{self.mode}.json"
|
|
18
|
+
self._add_to_layout()
|
|
19
|
+
self._load_previous_instructions()
|
|
20
|
+
|
|
21
|
+
def _create_widgets(self):
|
|
22
|
+
super()._create_widgets()
|
|
23
|
+
|
|
24
|
+
self.flip_segmentation_checkbox: QCheckBox = QCheckBox("Segment frames in reverse order")
|
|
25
|
+
self.flip_segmentation_checkbox.setIcon(icon(MDI6.camera_flip_outline,color="black"))
|
|
26
|
+
self.flip_segmentation_checkbox.setIconSize(QSize(20, 20))
|
|
27
|
+
self.flip_segmentation_checkbox.setStyleSheet(self.button_select_all)
|
|
28
|
+
self.flip_segmentation_checkbox.setToolTip("Flip the order of the frames for segmentation.")
|
|
29
|
+
|
|
30
|
+
def _add_to_layout(self):
|
|
31
|
+
self._layout.addWidget(self.flip_segmentation_checkbox)
|
|
32
|
+
self._layout.addWidget(self.submit_btn)
|
|
33
|
+
#self._widget.adjustSize()
|
|
34
|
+
|
|
35
|
+
def _load_previous_instructions(self):
|
|
36
|
+
if os.path.exists(self._instructions_path):
|
|
37
|
+
with open(self._instructions_path, "r") as f:
|
|
38
|
+
instructions = json.load(f)
|
|
39
|
+
if isinstance(instructions.get("flip"),bool):
|
|
40
|
+
self.flip_segmentation_checkbox.setChecked(instructions.get("flip"))
|
|
41
|
+
|
|
42
|
+
def _write_instructions(self):
|
|
43
|
+
instructions = {"flip": self.flip_segmentation_checkbox.isChecked()}
|
|
44
|
+
print('Segmentation instructions: ', instructions)
|
|
45
|
+
file_name = self._instructions_path
|
|
46
|
+
with open(file_name, 'w') as f:
|
|
47
|
+
json.dump(instructions, f, indent=4)
|
|
48
|
+
print('Done.')
|
|
49
|
+
self.close()
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import
|
|
1
|
+
from PyQt5.QtWidgets import QRadioButton, QComboBox, QFrame, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
|
-
from
|
|
4
|
-
from celldetective.gui.gui_utils import center_window
|
|
3
|
+
from celldetective.gui.gui_utils import generic_message
|
|
5
4
|
from celldetective.gui.layouts import ChannelNormGenerator
|
|
6
5
|
|
|
7
6
|
from superqt import QLabeledDoubleSlider,QLabeledSlider
|
|
8
7
|
from superqt.fonticon import icon
|
|
9
8
|
from fonticon_mdi6 import MDI6
|
|
10
|
-
from celldetective.utils import get_software_location
|
|
11
9
|
from celldetective.io import get_segmentation_datasets_list, locate_segmentation_dataset, get_segmentation_models_list
|
|
12
10
|
from celldetective.segmentation import train_segmentation_model
|
|
13
11
|
from celldetective.gui.layouts import CellposeParamsWidget
|
|
@@ -16,11 +14,9 @@ import json
|
|
|
16
14
|
import os
|
|
17
15
|
from glob import glob
|
|
18
16
|
from datetime import datetime
|
|
19
|
-
from celldetective.gui import
|
|
20
|
-
from celldetective.gui.processes.train_segmentation_model import TrainSegModelProcess
|
|
21
|
-
from celldetective.gui.workers import ProgressWindow
|
|
17
|
+
from celldetective.gui.settings._settings_base import CelldetectiveSettingsPanel
|
|
22
18
|
|
|
23
|
-
class
|
|
19
|
+
class SettingsSegmentationModelTraining(CelldetectiveSettingsPanel):
|
|
24
20
|
|
|
25
21
|
"""
|
|
26
22
|
UI to set segmentation model training instructions.
|
|
@@ -29,86 +25,56 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
29
25
|
|
|
30
26
|
def __init__(self, parent_window=None):
|
|
31
27
|
|
|
32
|
-
super().__init__()
|
|
33
28
|
self.parent_window = parent_window
|
|
34
29
|
self.use_gpu = self.parent_window.use_gpu
|
|
35
|
-
self.setWindowTitle("Train segmentation model")
|
|
36
|
-
self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','mexican-hat.png'])))
|
|
37
30
|
self.mode = self.parent_window.mode
|
|
38
31
|
self.exp_dir = self.parent_window.exp_dir
|
|
39
|
-
self.
|
|
40
|
-
self.pretrained_model = None
|
|
32
|
+
self.pretrained_model = None
|
|
41
33
|
self.dataset_folder = None
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
self.onlyFloat = QDoubleValidator()
|
|
45
|
-
self.onlyInt = QIntValidator()
|
|
46
|
-
|
|
47
|
-
self.screen_height = self.parent_window.parent_window.parent_window.screen_height
|
|
48
|
-
center_window(self)
|
|
34
|
+
super().__init__(title="Train segmentation model")
|
|
49
35
|
|
|
50
|
-
self.
|
|
51
|
-
self.
|
|
52
|
-
self.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
self.software_models_dir = os.sep.join([self._software_path, 'celldetective', 'models', f'segmentation_{self.mode}'])
|
|
37
|
+
self._add_to_layout()
|
|
38
|
+
self._load_previous_instructions()
|
|
39
|
+
|
|
40
|
+
self._adjustSize()
|
|
41
|
+
self.resize(int(self.width()), int(self._screen_height * 0.8))
|
|
42
|
+
|
|
43
|
+
def _add_to_layout(self):
|
|
44
|
+
|
|
45
|
+
self._layout.addWidget(self.model_frame)
|
|
46
|
+
self._layout.addWidget(self.data_frame)
|
|
47
|
+
self._layout.addWidget(self.hyper_frame)
|
|
48
|
+
self._layout.addWidget(self.submit_warning)
|
|
49
|
+
self._layout.addWidget(self.submit_btn)
|
|
50
|
+
|
|
51
|
+
def _create_widgets(self):
|
|
57
52
|
|
|
58
53
|
"""
|
|
59
54
|
Create the multibox design.
|
|
60
55
|
|
|
61
56
|
"""
|
|
62
57
|
|
|
63
|
-
|
|
64
|
-
self.scroll_area = QScrollArea(self)
|
|
65
|
-
self.button_widget = QWidget()
|
|
66
|
-
self.main_layout = QVBoxLayout()
|
|
67
|
-
self.button_widget.setLayout(self.main_layout)
|
|
68
|
-
self.main_layout.setContentsMargins(30,30,30,30)
|
|
69
|
-
|
|
70
|
-
# first frame for FEATURES
|
|
58
|
+
super()._create_widgets()
|
|
71
59
|
self.model_frame = QFrame()
|
|
72
60
|
self.model_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
73
61
|
self.populate_model_frame()
|
|
74
|
-
self.main_layout.addWidget(self.model_frame)
|
|
75
62
|
|
|
76
63
|
self.data_frame = QFrame()
|
|
77
64
|
self.data_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
78
65
|
self.populate_data_frame()
|
|
79
|
-
self.main_layout.addWidget(self.data_frame)
|
|
80
66
|
|
|
81
67
|
self.hyper_frame = QFrame()
|
|
82
68
|
self.hyper_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
83
69
|
self.populate_hyper_frame()
|
|
84
|
-
self.main_layout.addWidget(self.hyper_frame)
|
|
85
70
|
|
|
86
|
-
self.submit_btn = QPushButton('Train')
|
|
87
|
-
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
88
|
-
self.submit_btn.clicked.connect(self.prep_model)
|
|
89
|
-
self.main_layout.addWidget(self.submit_btn)
|
|
90
71
|
self.submit_btn.setEnabled(False)
|
|
91
72
|
self.submit_warning = QLabel('')
|
|
92
|
-
self.
|
|
73
|
+
self.submit_btn.setText("Train")
|
|
93
74
|
|
|
94
75
|
self.spatial_calib_le.textChanged.connect(self.activate_train_btn)
|
|
95
76
|
self.modelname_le.setText(f"Untitled_model_{datetime.today().strftime('%Y-%m-%d')}")
|
|
96
77
|
|
|
97
|
-
#self.populate_left_panel()
|
|
98
|
-
#grid.addLayout(self.left_side, 0, 0, 1, 1)
|
|
99
|
-
self.button_widget.adjustSize()
|
|
100
|
-
|
|
101
|
-
self.scroll_area.setAlignment(Qt.AlignCenter)
|
|
102
|
-
self.scroll_area.setWidget(self.button_widget)
|
|
103
|
-
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
104
|
-
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
105
|
-
self.scroll_area.setWidgetResizable(True)
|
|
106
|
-
self.setCentralWidget(self.scroll_area)
|
|
107
|
-
self.show()
|
|
108
|
-
|
|
109
|
-
QApplication.processEvents()
|
|
110
|
-
self.adjustScrollArea()
|
|
111
|
-
|
|
112
78
|
def populate_hyper_frame(self):
|
|
113
79
|
|
|
114
80
|
"""
|
|
@@ -137,14 +103,14 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
137
103
|
lr_layout = QHBoxLayout()
|
|
138
104
|
lr_layout.addWidget(QLabel('learning rate: '),30)
|
|
139
105
|
self.lr_le = QLineEdit('0,0003')
|
|
140
|
-
self.lr_le.setValidator(self.
|
|
106
|
+
self.lr_le.setValidator(self._floatValidator)
|
|
141
107
|
lr_layout.addWidget(self.lr_le, 70)
|
|
142
108
|
layout.addLayout(lr_layout)
|
|
143
109
|
|
|
144
110
|
bs_layout = QHBoxLayout()
|
|
145
111
|
bs_layout.addWidget(QLabel('batch size: '),30)
|
|
146
112
|
self.bs_le = QLineEdit('8')
|
|
147
|
-
self.bs_le.setValidator(self.
|
|
113
|
+
self.bs_le.setValidator(self._intValidator)
|
|
148
114
|
bs_layout.addWidget(self.bs_le, 70)
|
|
149
115
|
layout.addLayout(bs_layout)
|
|
150
116
|
|
|
@@ -154,7 +120,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
154
120
|
self.epochs_slider.setRange(1,300)
|
|
155
121
|
self.epochs_slider.setSingleStep(1)
|
|
156
122
|
self.epochs_slider.setTickInterval(1)
|
|
157
|
-
self.epochs_slider.setOrientation(
|
|
123
|
+
self.epochs_slider.setOrientation(Qt.Horizontal)
|
|
158
124
|
self.epochs_slider.setValue(100)
|
|
159
125
|
epochs_layout.addWidget(self.epochs_slider, 70)
|
|
160
126
|
layout.addLayout(epochs_layout)
|
|
@@ -241,7 +207,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
241
207
|
self.augmentation_slider = QLabeledDoubleSlider()
|
|
242
208
|
self.augmentation_slider.setSingleStep(0.01)
|
|
243
209
|
self.augmentation_slider.setTickInterval(0.01)
|
|
244
|
-
self.augmentation_slider.setOrientation(
|
|
210
|
+
self.augmentation_slider.setOrientation(Qt.Horizontal)
|
|
245
211
|
self.augmentation_slider.setRange(0.01, 3)
|
|
246
212
|
self.augmentation_slider.setValue(2.0)
|
|
247
213
|
|
|
@@ -253,7 +219,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
253
219
|
self.validation_slider = QLabeledDoubleSlider()
|
|
254
220
|
self.validation_slider.setSingleStep(0.01)
|
|
255
221
|
self.validation_slider.setTickInterval(0.01)
|
|
256
|
-
self.validation_slider.setOrientation(
|
|
222
|
+
self.validation_slider.setOrientation(Qt.Horizontal)
|
|
257
223
|
self.validation_slider.setRange(0,0.9)
|
|
258
224
|
self.validation_slider.setValue(0.2)
|
|
259
225
|
validation_split_layout.addWidget(self.validation_slider, 70)
|
|
@@ -320,7 +286,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
320
286
|
parent_pxtoum = f"{self.parent_window.parent_window.PxToUm}"
|
|
321
287
|
self.spatial_calib_le = QLineEdit(parent_pxtoum.replace('.',','))
|
|
322
288
|
self.spatial_calib_le.setPlaceholderText('e.g. 0.1 µm per pixel')
|
|
323
|
-
self.spatial_calib_le.setValidator(self.
|
|
289
|
+
self.spatial_calib_le.setValidator(self._floatValidator)
|
|
324
290
|
spatial_calib_layout.addWidget(self.spatial_calib_le, 70)
|
|
325
291
|
layout.addLayout(spatial_calib_layout)
|
|
326
292
|
|
|
@@ -351,17 +317,11 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
351
317
|
|
|
352
318
|
def showDialog_pretrained(self):
|
|
353
319
|
|
|
354
|
-
# try:
|
|
355
|
-
# self.cancel_pretrained.click()
|
|
356
|
-
# except Exception as e:
|
|
357
|
-
# print(e)
|
|
358
|
-
# pass
|
|
359
|
-
|
|
360
320
|
self.clear_pretrained()
|
|
361
321
|
self.pretrained_model = None
|
|
362
322
|
self.pretrained_model = QFileDialog.getExistingDirectory(
|
|
363
323
|
self, "Open Directory",
|
|
364
|
-
os.sep.join([self.
|
|
324
|
+
os.sep.join([self._software_path, 'celldetective', 'models', f'segmentation_generic','']),
|
|
365
325
|
QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks,
|
|
366
326
|
)
|
|
367
327
|
|
|
@@ -533,18 +493,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
533
493
|
|
|
534
494
|
self.spatial_calib_le.setText(str(spatial_calib).replace('.',','))
|
|
535
495
|
|
|
536
|
-
def
|
|
537
|
-
|
|
538
|
-
"""
|
|
539
|
-
Auto-adjust scroll area to fill space
|
|
540
|
-
(from https://stackoverflow.com/questions/66417576/make-qscrollarea-use-all-available-space-of-qmainwindow-height-axis)
|
|
541
|
-
"""
|
|
542
|
-
|
|
543
|
-
step = 5
|
|
544
|
-
while self.scroll_area.verticalScrollBar().isVisible() and self.height() < self.maximumHeight():
|
|
545
|
-
self.resize(self.width(), self.height() + step)
|
|
546
|
-
|
|
547
|
-
def prep_model(self):
|
|
496
|
+
def _write_instructions(self):
|
|
548
497
|
|
|
549
498
|
model_name = self.modelname_le.text()
|
|
550
499
|
pretrained_model = self.pretrained_model
|
|
@@ -587,14 +536,8 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
587
536
|
try:
|
|
588
537
|
lr = float(self.lr_le.text().replace(',','.'))
|
|
589
538
|
except:
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
msgBox.setText("Invalid value encountered for the learning rate.")
|
|
593
|
-
msgBox.setWindowTitle("Warning")
|
|
594
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
595
|
-
returnValue = msgBox.exec()
|
|
596
|
-
if returnValue == QMessageBox.Ok:
|
|
597
|
-
return None
|
|
539
|
+
generic_message('Invalid value encountered for the learning rate.')
|
|
540
|
+
return None
|
|
598
541
|
|
|
599
542
|
bs = int(self.bs_le.text())
|
|
600
543
|
epochs = self.epochs_slider.value()
|
|
@@ -631,4 +574,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
631
574
|
|
|
632
575
|
self.parent_window.init_seg_model_list()
|
|
633
576
|
idx = self.parent_window.seg_model_list.findText(model_name)
|
|
634
|
-
self.parent_window.seg_model_list.setCurrentIndex(idx)
|
|
577
|
+
self.parent_window.seg_model_list.setCurrentIndex(idx)
|
|
578
|
+
|
|
579
|
+
def _load_previous_instructions(self):
|
|
580
|
+
pass
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Copyright © 2023 Laboratoire Adhesion et Inflammation, Authored by Remy Torro.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from PyQt5.QtWidgets import
|
|
5
|
+
from PyQt5.QtWidgets import QComboBox, QLabel, QRadioButton, QLineEdit, QApplication, QPushButton, QScrollArea, QVBoxLayout, QHBoxLayout
|
|
6
6
|
from PyQt5.QtCore import Qt, QSize
|
|
7
7
|
from celldetective.gui.gui_utils import center_window, QHSeperationLine
|
|
8
8
|
from superqt import QLabeledDoubleSlider, QLabeledSlider
|
|
@@ -12,9 +12,9 @@ import numpy as np
|
|
|
12
12
|
from superqt.fonticon import icon
|
|
13
13
|
from fonticon_mdi6 import MDI6
|
|
14
14
|
import os
|
|
15
|
-
from celldetective.gui import
|
|
15
|
+
from celldetective.gui.settings._settings_base import CelldetectiveSettingsPanel
|
|
16
16
|
|
|
17
|
-
class
|
|
17
|
+
class SettingsSignalAnnotator(CelldetectiveSettingsPanel):
|
|
18
18
|
|
|
19
19
|
"""
|
|
20
20
|
UI to set normalization and animation parameters for the annotator tool.
|
|
@@ -23,68 +23,94 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
23
23
|
|
|
24
24
|
def __init__(self, parent_window=None):
|
|
25
25
|
|
|
26
|
-
super().__init__()
|
|
27
26
|
self.parent_window = parent_window
|
|
28
|
-
self.setWindowTitle("Configure signal annotator")
|
|
29
27
|
self.mode = self.parent_window.mode
|
|
30
28
|
self.exp_dir = self.parent_window.exp_dir
|
|
31
|
-
self.soft_path = get_software_location()
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
elif self.mode=="effectors":
|
|
36
|
-
self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_effectors.json"
|
|
37
|
-
elif self.mode == "pairs":
|
|
30
|
+
self.instructions_path = self.parent_window.exp_dir + f"configs/signal_annotator_config_{self.mode}.json"
|
|
31
|
+
if self.mode == "pairs":
|
|
38
32
|
self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_neighborhood.json"
|
|
39
33
|
|
|
40
|
-
exp_config = self.exp_dir +"config.ini"
|
|
41
|
-
#self.config_path = self.exp_dir + self.config_name
|
|
42
34
|
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
43
35
|
self.channel_names = np.array(self.channel_names)
|
|
44
36
|
self.channels = np.array(self.channels)
|
|
45
37
|
self.log_option = False
|
|
38
|
+
|
|
39
|
+
super().__init__(title="Configure signal annotator")
|
|
46
40
|
|
|
47
|
-
self.
|
|
48
|
-
|
|
41
|
+
self._add_to_layout()
|
|
42
|
+
self._load_previous_instructions()
|
|
43
|
+
|
|
44
|
+
self._adjustSize()
|
|
45
|
+
self.resize(int(self.width()), int(self._screen_height * 0.55))
|
|
46
|
+
|
|
47
|
+
def _add_to_layout(self):
|
|
48
|
+
|
|
49
|
+
sub_layout = QVBoxLayout()
|
|
50
|
+
sub_layout.setContentsMargins(10,10,10,20)
|
|
51
|
+
sub_layout.setContentsMargins(30,30,30,30)
|
|
52
|
+
sub_layout.addWidget(self._modality_lbl)
|
|
53
|
+
|
|
54
|
+
# Create radio buttons
|
|
55
|
+
option_layout = QHBoxLayout()
|
|
56
|
+
option_layout.addWidget(self.gs_btn, alignment=Qt.AlignCenter)
|
|
57
|
+
option_layout.addWidget(self.rgb_btn, alignment=Qt.AlignCenter)
|
|
58
|
+
sub_layout.addLayout(option_layout)
|
|
59
|
+
|
|
60
|
+
btn_hbox = QHBoxLayout()
|
|
61
|
+
btn_hbox.addWidget(QLabel(''), 90)
|
|
62
|
+
btn_hbox.addWidget(self.log_btn, 5,alignment=Qt.AlignRight)
|
|
63
|
+
btn_hbox.addWidget(self.percentile_btn, 5,alignment=Qt.AlignRight)
|
|
64
|
+
sub_layout.addLayout(btn_hbox)
|
|
49
65
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
for i in range(3):
|
|
67
|
+
hlayout = QHBoxLayout()
|
|
68
|
+
hlayout.addWidget(self.channel_cbs_lbls[i], 20)
|
|
69
|
+
hlayout.addWidget(self.channel_cbs[i], 80)
|
|
70
|
+
sub_layout.addLayout(hlayout)
|
|
54
71
|
|
|
72
|
+
hlayout2 = QHBoxLayout()
|
|
73
|
+
hlayout2.addWidget(self.min_val_lbls[i], 20)
|
|
74
|
+
hlayout2.addWidget(self.min_val_les[i], 80)
|
|
75
|
+
sub_layout.addLayout(hlayout2)
|
|
76
|
+
|
|
77
|
+
hlayout3 = QHBoxLayout()
|
|
78
|
+
hlayout3.addWidget(self.max_val_lbls[i], 20)
|
|
79
|
+
hlayout3.addWidget(self.max_val_les[i], 80)
|
|
80
|
+
sub_layout.addLayout(hlayout3)
|
|
55
81
|
|
|
56
|
-
|
|
82
|
+
sub_layout.addWidget(self.hsep)
|
|
83
|
+
hbox_frac = QHBoxLayout()
|
|
84
|
+
hbox_frac.addWidget(self._fraction_lbl, 20)
|
|
85
|
+
hbox_frac.addWidget(self.fraction_slider, 80)
|
|
86
|
+
sub_layout.addLayout(hbox_frac)
|
|
87
|
+
|
|
88
|
+
hbox_interval = QHBoxLayout()
|
|
89
|
+
hbox_interval.addWidget(self._interval_lbl, 20)
|
|
90
|
+
hbox_interval.addWidget(self.interval_slider, 80)
|
|
91
|
+
sub_layout.addLayout(hbox_interval)
|
|
92
|
+
|
|
93
|
+
self._layout.addLayout(sub_layout)
|
|
94
|
+
|
|
95
|
+
self._layout.addWidget(self.submit_btn)
|
|
96
|
+
|
|
97
|
+
def _create_widgets(self):
|
|
57
98
|
|
|
58
99
|
"""
|
|
59
100
|
Create the widgets.
|
|
60
101
|
|
|
61
102
|
"""
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
self.
|
|
65
|
-
|
|
66
|
-
self.
|
|
67
|
-
self.main_layout.setContentsMargins(30,30,30,30)
|
|
68
|
-
|
|
69
|
-
sub_layout = QVBoxLayout()
|
|
70
|
-
sub_layout.setContentsMargins(10,10,10,20)
|
|
71
|
-
|
|
72
|
-
self.button_widget.setLayout(self.main_layout)
|
|
73
|
-
sub_layout.setContentsMargins(30,30,30,30)
|
|
74
|
-
|
|
75
|
-
sub_layout.addWidget(QLabel('Modality: '))
|
|
103
|
+
super()._create_widgets()
|
|
104
|
+
|
|
105
|
+
self._modality_lbl = QLabel("Modality: ")
|
|
106
|
+
self._fraction_lbl = QLabel("fraction: ")
|
|
107
|
+
self._interval_lbl = QLabel('interval [ms]: ')
|
|
76
108
|
|
|
77
|
-
# Create radio buttons
|
|
78
|
-
option_layout = QHBoxLayout()
|
|
79
109
|
self.gs_btn = QRadioButton('grayscale')
|
|
80
110
|
self.gs_btn.setChecked(True)
|
|
81
|
-
|
|
82
|
-
|
|
111
|
+
|
|
83
112
|
self.rgb_btn = QRadioButton('RGB')
|
|
84
|
-
option_layout.addWidget(self.rgb_btn, alignment=Qt.AlignCenter)
|
|
85
|
-
sub_layout.addLayout(option_layout)
|
|
86
113
|
|
|
87
|
-
btn_hbox = QHBoxLayout()
|
|
88
114
|
|
|
89
115
|
self.percentile_btn = QPushButton()
|
|
90
116
|
self.percentile_btn.setIcon(icon(MDI6.percent_circle_outline,color="black"))
|
|
@@ -100,11 +126,6 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
100
126
|
self.log_btn.setToolTip("Log-transform the intensities.")
|
|
101
127
|
self.log_btn.setIconSize(QSize(20, 20))
|
|
102
128
|
|
|
103
|
-
btn_hbox.addWidget(QLabel(''), 90)
|
|
104
|
-
btn_hbox.addWidget(self.log_btn, 5,alignment=Qt.AlignRight)
|
|
105
|
-
btn_hbox.addWidget(self.percentile_btn, 5,alignment=Qt.AlignRight)
|
|
106
|
-
sub_layout.addLayout(btn_hbox)
|
|
107
|
-
|
|
108
129
|
self.channel_cbs = [QComboBox() for i in range(3)]
|
|
109
130
|
self.channel_cbs_lbls = [QLabel() for i in range(3)]
|
|
110
131
|
|
|
@@ -118,23 +139,13 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
118
139
|
|
|
119
140
|
for i in range(3):
|
|
120
141
|
|
|
121
|
-
hlayout = QHBoxLayout()
|
|
122
142
|
self.channel_cbs[i].addItems(self.channel_names)
|
|
123
143
|
self.channel_cbs[i].setCurrentIndex(i)
|
|
124
144
|
self.channel_cbs_lbls[i].setText(self.rgb_text[i])
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
145
|
+
|
|
146
|
+
self.min_val_les[i].setValidator(self._floatValidator)
|
|
147
|
+
self.max_val_les[i].setValidator(self._floatValidator)
|
|
128
148
|
|
|
129
|
-
hlayout2 = QHBoxLayout()
|
|
130
|
-
hlayout2.addWidget(self.min_val_lbls[i], 20)
|
|
131
|
-
hlayout2.addWidget(self.min_val_les[i], 80)
|
|
132
|
-
sub_layout.addLayout(hlayout2)
|
|
133
|
-
|
|
134
|
-
hlayout3 = QHBoxLayout()
|
|
135
|
-
hlayout3.addWidget(self.max_val_lbls[i], 20)
|
|
136
|
-
hlayout3.addWidget(self.max_val_les[i], 80)
|
|
137
|
-
sub_layout.addLayout(hlayout3)
|
|
138
149
|
|
|
139
150
|
self.enable_channels()
|
|
140
151
|
|
|
@@ -142,56 +153,22 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
142
153
|
self.rgb_btn.toggled.connect(self.enable_channels)
|
|
143
154
|
|
|
144
155
|
self.hsep = QHSeperationLine()
|
|
145
|
-
sub_layout.addWidget(self.hsep)
|
|
146
|
-
|
|
147
|
-
hbox_frac = QHBoxLayout()
|
|
148
|
-
hbox_frac.addWidget(QLabel('fraction: '), 20)
|
|
149
156
|
|
|
150
157
|
self.fraction_slider = QLabeledDoubleSlider()
|
|
151
158
|
self.fraction_slider.setSingleStep(0.05)
|
|
152
159
|
self.fraction_slider.setTickInterval(0.05)
|
|
153
160
|
self.fraction_slider.setSingleStep(1)
|
|
154
|
-
self.fraction_slider.setOrientation(
|
|
161
|
+
self.fraction_slider.setOrientation(Qt.Horizontal)
|
|
155
162
|
self.fraction_slider.setRange(0.1,1)
|
|
156
163
|
self.fraction_slider.setValue(0.25)
|
|
157
164
|
|
|
158
|
-
hbox_frac.addWidget(self.fraction_slider, 80)
|
|
159
|
-
sub_layout.addLayout(hbox_frac)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
hbox_interval = QHBoxLayout()
|
|
163
|
-
hbox_interval.addWidget(QLabel('interval [ms]: '), 20)
|
|
164
|
-
|
|
165
165
|
self.interval_slider = QLabeledSlider()
|
|
166
166
|
self.interval_slider.setSingleStep(1)
|
|
167
167
|
self.interval_slider.setTickInterval(1)
|
|
168
168
|
self.interval_slider.setSingleStep(1)
|
|
169
|
-
self.interval_slider.setOrientation(
|
|
169
|
+
self.interval_slider.setOrientation(Qt.Horizontal)
|
|
170
170
|
self.interval_slider.setRange(1,1000)
|
|
171
171
|
self.interval_slider.setValue(1)
|
|
172
|
-
hbox_interval.addWidget(self.interval_slider, 80)
|
|
173
|
-
sub_layout.addLayout(hbox_interval)
|
|
174
|
-
|
|
175
|
-
self.main_layout.addLayout(sub_layout)
|
|
176
|
-
|
|
177
|
-
self.submit_btn = QPushButton('Save')
|
|
178
|
-
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
179
|
-
self.submit_btn.clicked.connect(self.write_instructions)
|
|
180
|
-
self.main_layout.addWidget(self.submit_btn)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
self.button_widget.adjustSize()
|
|
184
|
-
self.scroll_area.setAlignment(Qt.AlignCenter)
|
|
185
|
-
self.scroll_area.setWidget(self.button_widget)
|
|
186
|
-
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
187
|
-
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
188
|
-
self.scroll_area.setWidgetResizable(True)
|
|
189
|
-
self.setCentralWidget(self.scroll_area)
|
|
190
|
-
self.show()
|
|
191
|
-
|
|
192
|
-
self.read_instructions()
|
|
193
|
-
|
|
194
|
-
QApplication.processEvents()
|
|
195
172
|
|
|
196
173
|
def enable_channels(self):
|
|
197
174
|
|
|
@@ -210,7 +187,6 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
210
187
|
self.channel_cbs_lbls[k].setEnabled(False)
|
|
211
188
|
|
|
212
189
|
for k in range(3):
|
|
213
|
-
|
|
214
190
|
self.min_val_les[k].setEnabled(False)
|
|
215
191
|
self.min_val_lbls[k].setEnabled(False)
|
|
216
192
|
self.max_val_les[k].setEnabled(False)
|
|
@@ -222,7 +198,6 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
222
198
|
self.percentile_btn.setEnabled(True)
|
|
223
199
|
|
|
224
200
|
for k in range(3):
|
|
225
|
-
|
|
226
201
|
self.channel_cbs[k].setEnabled(True)
|
|
227
202
|
self.channel_cbs_lbls[k].setEnabled(True)
|
|
228
203
|
|
|
@@ -259,7 +234,7 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
259
234
|
self.max_val_lbls[k].setText('Max percentile: ')
|
|
260
235
|
self.max_val_les[k].setText('99.99')
|
|
261
236
|
|
|
262
|
-
def
|
|
237
|
+
def _write_instructions(self):
|
|
263
238
|
|
|
264
239
|
"""
|
|
265
240
|
Save the current configuration.
|
|
@@ -270,7 +245,7 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
270
245
|
max_i = 3 if self.rgb_btn.isChecked() else 1
|
|
271
246
|
channels = []
|
|
272
247
|
for i in range(max_i):
|
|
273
|
-
channels.append([self.channel_cbs[i].currentText(), float(self.min_val_les[i].text()), float(self.max_val_les[i].text())])
|
|
248
|
+
channels.append([self.channel_cbs[i].currentText(), float(self.min_val_les[i].text().replace(',','.')), float(self.max_val_les[i].text().replace(',','.'))])
|
|
274
249
|
instructions.update({'channels': channels})
|
|
275
250
|
|
|
276
251
|
print('Instructions: ', instructions)
|
|
@@ -280,7 +255,7 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
280
255
|
print('Done.')
|
|
281
256
|
self.close()
|
|
282
257
|
|
|
283
|
-
def
|
|
258
|
+
def _load_previous_instructions(self):
|
|
284
259
|
|
|
285
260
|
"""
|
|
286
261
|
Read and set the widgets to the last configuration.
|
|
@@ -315,8 +290,8 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
315
290
|
for i in range(max_iter):
|
|
316
291
|
idx = self.channel_cbs[i].findText(channels[i][0])
|
|
317
292
|
self.channel_cbs[i].setCurrentIndex(idx)
|
|
318
|
-
self.min_val_les[i].setText(str(channels[i][1]))
|
|
319
|
-
self.max_val_les[i].setText(str(channels[i][2]))
|
|
293
|
+
self.min_val_les[i].setText(str(channels[i][1]).replace('.',','))
|
|
294
|
+
self.max_val_les[i].setText(str(channels[i][2]).replace('.',','))
|
|
320
295
|
|
|
321
296
|
if 'fraction' in instructions:
|
|
322
297
|
fraction = instructions['fraction']
|