celldetective 1.3.9.post4__py3-none-any.whl → 1.4.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.
- celldetective/__init__.py +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/extra_properties.py +320 -24
- celldetective/gui/InitWindow.py +33 -45
- celldetective/gui/__init__.py +1 -0
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/btrack_options.py +26 -34
- celldetective/gui/classifier_widget.py +71 -80
- celldetective/gui/configure_new_exp.py +113 -17
- celldetective/gui/control_panel.py +68 -141
- celldetective/gui/generic_signal_plot.py +9 -12
- celldetective/gui/gui_utils.py +49 -21
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +246 -22
- celldetective/gui/measurement_options.py +32 -17
- celldetective/gui/neighborhood_options.py +10 -13
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +131 -75
- celldetective/gui/process_block.py +180 -123
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/measure_cells.py +5 -0
- celldetective/gui/processes/segment_cells.py +27 -6
- celldetective/gui/processes/track_cells.py +6 -0
- celldetective/gui/retrain_segmentation_model_options.py +12 -20
- celldetective/gui/retrain_signal_model_options.py +57 -56
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/signal_annotator.py +139 -72
- celldetective/gui/signal_annotator2.py +431 -635
- celldetective/gui/signal_annotator_options.py +8 -11
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +28 -25
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +106 -39
- celldetective/gui/workers.py +9 -3
- celldetective/io.py +73 -27
- celldetective/measure.py +63 -27
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +25 -17
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_relative.py +4 -1
- celldetective/scripts/segment_cells.py +0 -6
- celldetective/scripts/track_cells.py +3 -1
- celldetective/scripts/train_segmentation_model.py +7 -4
- celldetective/signals.py +29 -14
- celldetective/tracking.py +7 -2
- celldetective/utils.py +36 -8
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/METADATA +24 -16
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/RECORD +57 -55
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/WHEEL +1 -1
- tests/test_qt.py +21 -21
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -47,11 +47,7 @@ class BaseSegmentProcess(Process):
|
|
|
47
47
|
def write_folders(self):
|
|
48
48
|
|
|
49
49
|
self.mode = self.mode.lower()
|
|
50
|
-
|
|
51
|
-
if self.mode=="target" or self.mode=="targets":
|
|
52
|
-
self.label_folder = "labels_targets"
|
|
53
|
-
elif self.mode=="effector" or self.mode=="effectors":
|
|
54
|
-
self.label_folder = "labels_effectors"
|
|
50
|
+
self.label_folder = f"labels_{self.mode}"
|
|
55
51
|
|
|
56
52
|
if os.path.exists(self.pos+self.label_folder):
|
|
57
53
|
print('Erasing the previous labels folder...')
|
|
@@ -123,6 +119,14 @@ class SegmentCellDLProcess(BaseSegmentProcess):
|
|
|
123
119
|
def extract_model_input_parameters(self):
|
|
124
120
|
|
|
125
121
|
self.required_channels = self.input_config["channels"]
|
|
122
|
+
if 'selected_channels' in self.input_config:
|
|
123
|
+
self.required_channels = self.input_config['selected_channels']
|
|
124
|
+
|
|
125
|
+
self.target_cell_size = None
|
|
126
|
+
if 'target_cell_size_um' in self.input_config and 'cell_size_um' in self.input_config:
|
|
127
|
+
self.target_cell_size = self.input_config['target_cell_size_um']
|
|
128
|
+
self.cell_size = self.input_config['cell_size_um']
|
|
129
|
+
|
|
126
130
|
self.normalize_kwargs = _get_normalize_kwargs_from_config(self.input_config)
|
|
127
131
|
|
|
128
132
|
self.model_type = self.input_config['model_type']
|
|
@@ -152,6 +156,14 @@ class SegmentCellDLProcess(BaseSegmentProcess):
|
|
|
152
156
|
self.scale = _estimate_scale_factor(self.spatial_calibration, self.required_spatial_calibration)
|
|
153
157
|
print(f"Scale: {self.scale}...")
|
|
154
158
|
|
|
159
|
+
if self.target_cell_size is not None and self.scale is not None:
|
|
160
|
+
self.scale *= self.cell_size / self.target_cell_size
|
|
161
|
+
elif self.target_cell_size is not None:
|
|
162
|
+
if self.target_cell_size != self.cell_size:
|
|
163
|
+
self.scale = self.cell_size / self.target_cell_size
|
|
164
|
+
|
|
165
|
+
print(f"Scale accounting for expected cell size: {self.scale}...")
|
|
166
|
+
|
|
155
167
|
def locate_model_path(self):
|
|
156
168
|
|
|
157
169
|
self.model_complete_path = locate_segmentation_model(self.model_name)
|
|
@@ -183,7 +195,11 @@ class SegmentCellDLProcess(BaseSegmentProcess):
|
|
|
183
195
|
elif self.model_type=='cellpose':
|
|
184
196
|
model, scale_model = _prep_cellpose_model(self.model_name, self.model_complete_path, use_gpu=self.use_gpu, n_channels=len(self.required_channels), scale=self.scale)
|
|
185
197
|
|
|
186
|
-
|
|
198
|
+
list_indices = range(self.len_movie)
|
|
199
|
+
if self.flip:
|
|
200
|
+
list_indices = reversed(list_indices)
|
|
201
|
+
|
|
202
|
+
for t in tqdm(list_indices,desc="frame"):
|
|
187
203
|
|
|
188
204
|
f = _load_frames_to_segment(self.file, self.img_num_channels[:,t], scale_model=scale_model, normalize_kwargs=self.normalize_kwargs)
|
|
189
205
|
|
|
@@ -219,6 +235,7 @@ class SegmentCellDLProcess(BaseSegmentProcess):
|
|
|
219
235
|
pass
|
|
220
236
|
|
|
221
237
|
gc.collect()
|
|
238
|
+
print("Done.")
|
|
222
239
|
|
|
223
240
|
# Send end signal
|
|
224
241
|
self.queue.put("finished")
|
|
@@ -339,6 +356,9 @@ class SegmentCellThresholdProcess(BaseSegmentProcess):
|
|
|
339
356
|
def run(self):
|
|
340
357
|
|
|
341
358
|
self.indices = list(range(self.img_num_channels.shape[1]))
|
|
359
|
+
if self.flip:
|
|
360
|
+
self.indices = reversed(self.indices)
|
|
361
|
+
|
|
342
362
|
chunks = np.array_split(self.indices, self.n_threads)
|
|
343
363
|
|
|
344
364
|
with concurrent.futures.ThreadPoolExecutor(max_workers=self.n_threads) as executor:
|
|
@@ -349,6 +369,7 @@ class SegmentCellThresholdProcess(BaseSegmentProcess):
|
|
|
349
369
|
except Exception as e:
|
|
350
370
|
print("Exception: ", e)
|
|
351
371
|
|
|
372
|
+
print('Done.')
|
|
352
373
|
# Send end signal
|
|
353
374
|
self.queue.put("finished")
|
|
354
375
|
self.queue.close()
|
|
@@ -147,6 +147,12 @@ class TrackingProcess(Process):
|
|
|
147
147
|
self.napari_name = "napari_effector_trajectories.npy"
|
|
148
148
|
self.table_name = "trajectories_effectors.csv"
|
|
149
149
|
|
|
150
|
+
else:
|
|
151
|
+
self.label_folder = f"labels_{self.mode}"
|
|
152
|
+
self.instruction_file = os.sep.join(["configs",f"tracking_instructions_{self.mode}.json"])
|
|
153
|
+
self.napari_name = f"napari_{self.mode}_trajectories.npy"
|
|
154
|
+
self.table_name = f"trajectories_{self.mode}.csv"
|
|
155
|
+
|
|
150
156
|
def extract_experiment_parameters(self):
|
|
151
157
|
|
|
152
158
|
self.movie_prefix = ConfigSectionMap(self.config,"MovieSettings")["movie_prefix"]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import
|
|
1
|
+
from PyQt5.QtWidgets import QApplication,QRadioButton, QScrollArea, QComboBox, QFrame, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
|
-
from PyQt5.QtGui import QDoubleValidator, QIntValidator
|
|
4
|
-
from celldetective.gui.gui_utils import center_window
|
|
3
|
+
from PyQt5.QtGui import QDoubleValidator, QIntValidator
|
|
4
|
+
from celldetective.gui.gui_utils import center_window, generic_message
|
|
5
5
|
from celldetective.gui.layouts import ChannelNormGenerator
|
|
6
6
|
|
|
7
7
|
from superqt import QLabeledDoubleSlider,QLabeledSlider
|
|
@@ -16,11 +16,10 @@ import json
|
|
|
16
16
|
import os
|
|
17
17
|
from glob import glob
|
|
18
18
|
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
|
|
19
|
+
from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
|
|
22
|
+
class ConfigSegmentationModelTraining(CelldetectiveMainWindow):
|
|
24
23
|
|
|
25
24
|
"""
|
|
26
25
|
UI to set segmentation model training instructions.
|
|
@@ -33,7 +32,6 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
33
32
|
self.parent_window = parent_window
|
|
34
33
|
self.use_gpu = self.parent_window.use_gpu
|
|
35
34
|
self.setWindowTitle("Train segmentation model")
|
|
36
|
-
self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','mexican-hat.png'])))
|
|
37
35
|
self.mode = self.parent_window.mode
|
|
38
36
|
self.exp_dir = self.parent_window.exp_dir
|
|
39
37
|
self.soft_path = get_software_location()
|
|
@@ -62,7 +60,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
62
60
|
|
|
63
61
|
# Create button widget and layout
|
|
64
62
|
self.scroll_area = QScrollArea(self)
|
|
65
|
-
self.button_widget =
|
|
63
|
+
self.button_widget = CelldetectiveWidget()
|
|
66
64
|
self.main_layout = QVBoxLayout()
|
|
67
65
|
self.button_widget.setLayout(self.main_layout)
|
|
68
66
|
self.main_layout.setContentsMargins(30,30,30,30)
|
|
@@ -154,7 +152,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
154
152
|
self.epochs_slider.setRange(1,300)
|
|
155
153
|
self.epochs_slider.setSingleStep(1)
|
|
156
154
|
self.epochs_slider.setTickInterval(1)
|
|
157
|
-
self.epochs_slider.setOrientation(
|
|
155
|
+
self.epochs_slider.setOrientation(Qt.Horizontal)
|
|
158
156
|
self.epochs_slider.setValue(100)
|
|
159
157
|
epochs_layout.addWidget(self.epochs_slider, 70)
|
|
160
158
|
layout.addLayout(epochs_layout)
|
|
@@ -241,7 +239,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
241
239
|
self.augmentation_slider = QLabeledDoubleSlider()
|
|
242
240
|
self.augmentation_slider.setSingleStep(0.01)
|
|
243
241
|
self.augmentation_slider.setTickInterval(0.01)
|
|
244
|
-
self.augmentation_slider.setOrientation(
|
|
242
|
+
self.augmentation_slider.setOrientation(Qt.Horizontal)
|
|
245
243
|
self.augmentation_slider.setRange(0.01, 3)
|
|
246
244
|
self.augmentation_slider.setValue(2.0)
|
|
247
245
|
|
|
@@ -253,7 +251,7 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
253
251
|
self.validation_slider = QLabeledDoubleSlider()
|
|
254
252
|
self.validation_slider.setSingleStep(0.01)
|
|
255
253
|
self.validation_slider.setTickInterval(0.01)
|
|
256
|
-
self.validation_slider.setOrientation(
|
|
254
|
+
self.validation_slider.setOrientation(Qt.Horizontal)
|
|
257
255
|
self.validation_slider.setRange(0,0.9)
|
|
258
256
|
self.validation_slider.setValue(0.2)
|
|
259
257
|
validation_split_layout.addWidget(self.validation_slider, 70)
|
|
@@ -587,14 +585,8 @@ class ConfigSegmentationModelTraining(QMainWindow, Styles):
|
|
|
587
585
|
try:
|
|
588
586
|
lr = float(self.lr_le.text().replace(',','.'))
|
|
589
587
|
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
|
|
588
|
+
generic_message('Invalid value encountered for the learning rate.')
|
|
589
|
+
return None
|
|
598
590
|
|
|
599
591
|
bs = int(self.bs_le.text())
|
|
600
592
|
epochs = self.epochs_slider.value()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import
|
|
1
|
+
from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
3
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QIcon
|
|
4
4
|
from celldetective.gui.gui_utils import center_window
|
|
@@ -14,12 +14,12 @@ import json
|
|
|
14
14
|
import os
|
|
15
15
|
from glob import glob
|
|
16
16
|
from datetime import datetime
|
|
17
|
-
from celldetective.gui import
|
|
17
|
+
from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
|
|
18
18
|
from pandas.api.types import is_numeric_dtype
|
|
19
19
|
from celldetective.gui.processes.train_signal_model import TrainSignalModelProcess
|
|
20
20
|
from celldetective.gui.workers import ProgressWindow
|
|
21
21
|
|
|
22
|
-
class ConfigSignalModelTraining(
|
|
22
|
+
class ConfigSignalModelTraining(CelldetectiveMainWindow):
|
|
23
23
|
|
|
24
24
|
"""
|
|
25
25
|
UI to set measurement instructions.
|
|
@@ -31,7 +31,6 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
31
31
|
super().__init__()
|
|
32
32
|
self.parent_window = parent_window
|
|
33
33
|
self.setWindowTitle("Train signal model")
|
|
34
|
-
self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','mexican-hat.png'])))
|
|
35
34
|
self.mode = self.parent_window.mode
|
|
36
35
|
self.exp_dir = self.parent_window.exp_dir
|
|
37
36
|
self.soft_path = get_software_location()
|
|
@@ -69,7 +68,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
69
68
|
|
|
70
69
|
# Create button widget and layout
|
|
71
70
|
self.scroll_area = QScrollArea(self)
|
|
72
|
-
self.button_widget =
|
|
71
|
+
self.button_widget = CelldetectiveWidget()
|
|
73
72
|
self.main_layout = QVBoxLayout()
|
|
74
73
|
self.button_widget.setLayout(self.main_layout)
|
|
75
74
|
self.main_layout.setContentsMargins(30,30,30,30)
|
|
@@ -156,7 +155,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
156
155
|
self.epochs_slider.setRange(1,3000)
|
|
157
156
|
self.epochs_slider.setSingleStep(1)
|
|
158
157
|
self.epochs_slider.setTickInterval(1)
|
|
159
|
-
self.epochs_slider.setOrientation(
|
|
158
|
+
self.epochs_slider.setOrientation(Qt.Horizontal)
|
|
160
159
|
self.epochs_slider.setValue(300)
|
|
161
160
|
epochs_layout.addWidget(self.epochs_slider, 70)
|
|
162
161
|
layout.addLayout(epochs_layout)
|
|
@@ -243,7 +242,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
243
242
|
self.augmentation_slider = QLabeledDoubleSlider()
|
|
244
243
|
self.augmentation_slider.setSingleStep(0.01)
|
|
245
244
|
self.augmentation_slider.setTickInterval(0.01)
|
|
246
|
-
self.augmentation_slider.setOrientation(
|
|
245
|
+
self.augmentation_slider.setOrientation(Qt.Horizontal)
|
|
247
246
|
self.augmentation_slider.setRange(1, 5)
|
|
248
247
|
self.augmentation_slider.setValue(2)
|
|
249
248
|
|
|
@@ -255,7 +254,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
255
254
|
self.validation_slider = QLabeledDoubleSlider()
|
|
256
255
|
self.validation_slider.setSingleStep(0.01)
|
|
257
256
|
self.validation_slider.setTickInterval(0.01)
|
|
258
|
-
self.validation_slider.setOrientation(
|
|
257
|
+
self.validation_slider.setOrientation(Qt.Horizontal)
|
|
259
258
|
self.validation_slider.setRange(0,0.9)
|
|
260
259
|
self.validation_slider.setValue(0.25)
|
|
261
260
|
validation_split_layout.addWidget(self.validation_slider, 70)
|
|
@@ -332,7 +331,7 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
332
331
|
self.model_length_slider.setSingleStep(1)
|
|
333
332
|
self.model_length_slider.setTickInterval(1)
|
|
334
333
|
self.model_length_slider.setSingleStep(1)
|
|
335
|
-
self.model_length_slider.setOrientation(
|
|
334
|
+
self.model_length_slider.setOrientation(Qt.Horizontal)
|
|
336
335
|
self.model_length_slider.setRange(0,1024)
|
|
337
336
|
self.model_length_slider.setValue(128)
|
|
338
337
|
model_length_layout.addWidget(self.model_length_slider, 70)
|
|
@@ -341,25 +340,22 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
341
340
|
def neighborhood_changed(self):
|
|
342
341
|
|
|
343
342
|
neigh = self.neighborhood_choice_cb.currentText()
|
|
344
|
-
self.current_neighborhood = neigh
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
343
|
+
self.current_neighborhood = neigh
|
|
344
|
+
for pop in self.dataframes.keys():
|
|
345
|
+
self.current_neighborhood = self.current_neighborhood.replace(f'{pop}_ref_', '')
|
|
346
|
+
|
|
347
|
+
self.reference_population = self.neighborhood_choice_cb.currentText().split('_')[0]
|
|
348
|
+
if '_(' in self.current_neighborhood and ')_' in self.current_neighborhood:
|
|
349
|
+
self.neighbor_population = self.current_neighborhood.split('_(')[-1].split(')_')[0].split('-')[-1]
|
|
350
|
+
self.reference_population = self.current_neighborhood.split('_(')[-1].split(')_')[0].split('-')[0]
|
|
351
351
|
else:
|
|
352
|
-
if 'self' in
|
|
353
|
-
self.neighbor_population =
|
|
354
|
-
|
|
355
|
-
self.neighbor_population = 'targets'
|
|
356
|
-
|
|
352
|
+
if 'self' in self.current_neighborhood:
|
|
353
|
+
self.neighbor_population = self.reference_population
|
|
354
|
+
|
|
357
355
|
print(f'Current neighborhood: {self.current_neighborhood}')
|
|
358
356
|
print(f'New reference population: {self.reference_population}')
|
|
359
357
|
print(f'New neighbor population: {self.neighbor_population}')
|
|
360
358
|
|
|
361
|
-
# reload reference signals / neighbor signals / pair signals
|
|
362
|
-
# fill the channel cbs
|
|
363
359
|
self.df_reference = self.dataframes[self.reference_population]
|
|
364
360
|
self.df_neighbor = self.dataframes[self.neighbor_population]
|
|
365
361
|
self.df_pairs = load_experiment_tables(self.parent_window.exp_dir, population='pairs', load_pickle=False)
|
|
@@ -374,45 +370,50 @@ class ConfigSignalModelTraining(QMainWindow, Styles):
|
|
|
374
370
|
self.signals = ['--'] + num_cols_pairs + num_cols_reference + num_cols_neighbor
|
|
375
371
|
|
|
376
372
|
for cb in self.ch_norm.channel_cbs:
|
|
377
|
-
# try:
|
|
378
|
-
# cb.disconnect()
|
|
379
|
-
# except:
|
|
380
|
-
# pass
|
|
381
373
|
cb.clear()
|
|
382
374
|
cb.addItems(self.signals)
|
|
383
375
|
|
|
384
376
|
def fill_available_neighborhoods(self):
|
|
385
|
-
|
|
386
|
-
df_targets = load_experiment_tables(self.parent_window.exp_dir, population='targets', load_pickle=True)
|
|
387
|
-
df_effectors = load_experiment_tables(self.parent_window.exp_dir, population='effectors', load_pickle=True)
|
|
388
|
-
|
|
389
|
-
self.dataframes = {
|
|
390
|
-
'targets': df_targets,
|
|
391
|
-
'effectors': df_effectors,
|
|
392
|
-
}
|
|
393
377
|
|
|
378
|
+
self.dataframes = {}
|
|
394
379
|
self.neighborhood_cols = []
|
|
395
|
-
self.
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
380
|
+
for population in self.parent_window.parent_window.populations:
|
|
381
|
+
df_pop = load_experiment_tables(self.parent_window.exp_dir, population=pop, load_pickle=True)
|
|
382
|
+
self.dataframes.update({pop: df_pop})
|
|
383
|
+
if df_pop is not None:
|
|
384
|
+
self.neighborhood_cols.extend(
|
|
385
|
+
[f'{pop}_ref_' + c for c in list(df_pop.columns) if c.startswith('neighborhood')])
|
|
386
|
+
|
|
387
|
+
# df_targets = load_experiment_tables(self.parent_window.exp_dir, population='targets', load_pickle=True)
|
|
388
|
+
# df_effectors = load_experiment_tables(self.parent_window.exp_dir, population='effectors', load_pickle=True)
|
|
389
|
+
#
|
|
390
|
+
# self.dataframes = {
|
|
391
|
+
# 'targets': df_targets,
|
|
392
|
+
# 'effectors': df_effectors,
|
|
393
|
+
# }
|
|
394
|
+
#
|
|
395
|
+
# self.neighborhood_cols = []
|
|
396
|
+
# self.reference_populations = []
|
|
397
|
+
# self.neighbor_populations = []
|
|
398
|
+
# if df_targets is not None:
|
|
399
|
+
# self.neighborhood_cols.extend(['target_ref_'+c for c in list(df_targets.columns) if c.startswith('neighborhood')])
|
|
400
|
+
# self.reference_populations.extend(['targets' for c in list(df_targets.columns) if c.startswith('neighborhood')])
|
|
401
|
+
# for c in list(df_targets.columns):
|
|
402
|
+
# if c.startswith('neighborhood') and '_2_' in c:
|
|
403
|
+
# self.neighbor_populations.append('effectors')
|
|
404
|
+
# elif c.startswith('neighborhood') and 'self' in c:
|
|
405
|
+
# self.neighbor_populations.append('targets')
|
|
406
|
+
#
|
|
407
|
+
# if df_effectors is not None:
|
|
408
|
+
# self.neighborhood_cols.extend(['effector_ref_'+c for c in list(df_effectors.columns) if c.startswith('neighborhood')])
|
|
409
|
+
# self.reference_populations.extend(['effectors' for c in list(df_effectors.columns) if c.startswith('neighborhood')])
|
|
410
|
+
# for c in list(df_effectors.columns):
|
|
411
|
+
# if c.startswith('neighborhood') and '_2_' in c:
|
|
412
|
+
# self.neighbor_populations.append('targets')
|
|
413
|
+
# elif c.startswith('neighborhood') and 'self' in c:
|
|
414
|
+
# self.neighbor_populations.append('effectors')
|
|
415
|
+
#
|
|
416
|
+
# print(f"The following neighborhoods were detected: {self.neighborhood_cols=} {self.reference_populations=} {self.neighbor_populations=}")
|
|
416
417
|
|
|
417
418
|
self.neighborhood_choice_cb.addItems(self.neighborhood_cols)
|
|
418
419
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import
|
|
1
|
+
from PyQt5.QtWidgets import QGridLayout, QComboBox, QVBoxLayout, QLabel, QLineEdit, QHBoxLayout, QRadioButton, QFileDialog, QPushButton, QMessageBox
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
|
-
from celldetective.gui.gui_utils import center_window
|
|
3
|
+
from celldetective.gui.gui_utils import center_window, generic_message
|
|
4
4
|
from celldetective.gui.layouts import ChannelNormGenerator
|
|
5
|
-
from celldetective.gui import ThresholdConfigWizard
|
|
5
|
+
from celldetective.gui import ThresholdConfigWizard, CelldetectiveWidget
|
|
6
6
|
from PyQt5.QtGui import QDoubleValidator
|
|
7
7
|
from superqt.fonticon import icon
|
|
8
8
|
from fonticon_mdi6 import MDI6
|
|
@@ -16,7 +16,7 @@ import gc
|
|
|
16
16
|
from cellpose.models import CellposeModel
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class SegmentationModelLoader(
|
|
19
|
+
class SegmentationModelLoader(CelldetectiveWidget):
|
|
20
20
|
|
|
21
21
|
"""
|
|
22
22
|
Upload a segmentation model or define a Threshold pipeline.
|
|
@@ -27,15 +27,10 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
27
27
|
super().__init__()
|
|
28
28
|
self.parent_window = parent_window
|
|
29
29
|
self.mode = self.parent_window.mode
|
|
30
|
-
|
|
31
|
-
self.target_folder = "segmentation_targets"
|
|
32
|
-
elif self.mode=="effectors":
|
|
33
|
-
self.target_folder = "segmentation_effectors"
|
|
30
|
+
self.target_folder = f"segmentation_{self.mode}"
|
|
34
31
|
self.setWindowTitle('Upload model')
|
|
35
32
|
self.generate_content()
|
|
36
|
-
self.setWindowIcon(self.celldetective_icon)
|
|
37
33
|
center_window(self)
|
|
38
|
-
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
39
34
|
|
|
40
35
|
def generate_content(self):
|
|
41
36
|
|
|
@@ -230,14 +225,9 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
230
225
|
self.destination = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]+f"/models/{self.target_folder}/"+self.modelname
|
|
231
226
|
self.folder_dest = self.destination
|
|
232
227
|
else:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
msgBox.setWindowTitle("Warning")
|
|
237
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
238
|
-
returnValue = msgBox.exec()
|
|
239
|
-
if returnValue == QMessageBox.Ok:
|
|
240
|
-
return None
|
|
228
|
+
generic_message(
|
|
229
|
+
"StarDist model not recognized... Please ensure that it contains a thresholds.json file or that it is a valid StarDist model...")
|
|
230
|
+
return None
|
|
241
231
|
|
|
242
232
|
if self.seg_mode=="cellpose":
|
|
243
233
|
self.file_label.setText(self.filename.split("/")[-1])
|
|
@@ -264,15 +254,8 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
264
254
|
self.merge_lbl.hide()
|
|
265
255
|
self.file_label.setText(self.filename[0].split("/")[-1])
|
|
266
256
|
else:
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
msgBox.setText("You selected more than one pipeline. Please set a merging procedure for the resulting masks...")
|
|
270
|
-
msgBox.setWindowTitle("Warning")
|
|
271
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
272
|
-
returnValue = msgBox.exec()
|
|
273
|
-
if returnValue == QMessageBox.Ok:
|
|
274
|
-
pass
|
|
275
|
-
|
|
257
|
+
generic_message(
|
|
258
|
+
"You selected more than one pipeline. Please set a merging procedure for the resulting masks...")
|
|
276
259
|
self.merge_cb.show()
|
|
277
260
|
self.merge_lbl.show()
|
|
278
261
|
self.file_label.setText(f"{n_files} configs loaded...")
|
|
@@ -327,14 +310,8 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
327
310
|
channels.append(self.channel_layout.channel_cbs[i].currentText())
|
|
328
311
|
|
|
329
312
|
if self.file_label.text()=='No file chosen':
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
msgBox.setText("Please select a model first.")
|
|
333
|
-
msgBox.setWindowTitle("Warning")
|
|
334
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
335
|
-
returnValue = msgBox.exec()
|
|
336
|
-
if returnValue == QMessageBox.Ok:
|
|
337
|
-
return None
|
|
313
|
+
generic_message('Please select a model first...')
|
|
314
|
+
return None
|
|
338
315
|
|
|
339
316
|
if not self.threshold_button.isChecked():
|
|
340
317
|
|
|
@@ -343,14 +320,8 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
343
320
|
try:
|
|
344
321
|
shutil.copytree(self.filename, self.destination)
|
|
345
322
|
except FileExistsError:
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
msgBox.setText("A model with the same name already exists in the models folder. Please rename it.")
|
|
349
|
-
msgBox.setWindowTitle("Warning")
|
|
350
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
351
|
-
returnValue = msgBox.exec()
|
|
352
|
-
if returnValue == QMessageBox.Ok:
|
|
353
|
-
return None
|
|
323
|
+
generic_message("A model with the same name already exists in the models folder. Please rename it.")
|
|
324
|
+
return None
|
|
354
325
|
|
|
355
326
|
elif self.cellpose_button.isChecked():
|
|
356
327
|
|
|
@@ -359,15 +330,8 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
359
330
|
os.mkdir(self.folder_dest)
|
|
360
331
|
shutil.copy(self.filename, self.destination)
|
|
361
332
|
except FileExistsError:
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
msgBox.setText("A model with the same name already exists in the models folder. Please rename it.")
|
|
365
|
-
msgBox.setWindowTitle("Warning")
|
|
366
|
-
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
367
|
-
returnValue = msgBox.exec()
|
|
368
|
-
if returnValue == QMessageBox.Ok:
|
|
369
|
-
return None
|
|
370
|
-
|
|
333
|
+
generic_message("A model with the same name already exists in the models folder. Please rename it.")
|
|
334
|
+
return None
|
|
371
335
|
try:
|
|
372
336
|
model = CellposeModel(pretrained_model=self.destination, model_type=None, nchan=len(channels))
|
|
373
337
|
self.scale_model = model.diam_mean
|
|
@@ -392,16 +356,11 @@ class SegmentationModelLoader(QWidget, Styles):
|
|
|
392
356
|
if not isinstance(self.filename, list):
|
|
393
357
|
if not self.filename is None:
|
|
394
358
|
self.filename = [self.filename]
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
elif self.mode=="effectors":
|
|
401
|
-
self.parent_window.threshold_config_effectors = self.filename
|
|
402
|
-
self.parent_window.seg_model_list.setCurrentText('Threshold')
|
|
403
|
-
print('Path to the traditional segmentation pipeline successfully set in celldetective...')
|
|
404
|
-
self.close()
|
|
359
|
+
|
|
360
|
+
idx = self.parent_window.parent_window.populations.index(self.mode)
|
|
361
|
+
self.parent_window.threshold_configs[idx] = self.filename
|
|
362
|
+
self.parent_window.seg_model_list.setCurrentText('Threshold')
|
|
363
|
+
self.close()
|
|
405
364
|
|
|
406
365
|
def generate_input_config(self):
|
|
407
366
|
|