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.
Files changed (57) hide show
  1. celldetective/__init__.py +0 -3
  2. celldetective/_version.py +1 -1
  3. celldetective/events.py +2 -4
  4. celldetective/extra_properties.py +320 -24
  5. celldetective/gui/InitWindow.py +33 -45
  6. celldetective/gui/__init__.py +1 -0
  7. celldetective/gui/about.py +19 -15
  8. celldetective/gui/analyze_block.py +34 -19
  9. celldetective/gui/base_components.py +23 -0
  10. celldetective/gui/btrack_options.py +26 -34
  11. celldetective/gui/classifier_widget.py +71 -80
  12. celldetective/gui/configure_new_exp.py +113 -17
  13. celldetective/gui/control_panel.py +68 -141
  14. celldetective/gui/generic_signal_plot.py +9 -12
  15. celldetective/gui/gui_utils.py +49 -21
  16. celldetective/gui/json_readers.py +5 -4
  17. celldetective/gui/layouts.py +246 -22
  18. celldetective/gui/measurement_options.py +32 -17
  19. celldetective/gui/neighborhood_options.py +10 -13
  20. celldetective/gui/plot_measurements.py +21 -17
  21. celldetective/gui/plot_signals_ui.py +131 -75
  22. celldetective/gui/process_block.py +180 -123
  23. celldetective/gui/processes/compute_neighborhood.py +594 -0
  24. celldetective/gui/processes/measure_cells.py +5 -0
  25. celldetective/gui/processes/segment_cells.py +27 -6
  26. celldetective/gui/processes/track_cells.py +6 -0
  27. celldetective/gui/retrain_segmentation_model_options.py +12 -20
  28. celldetective/gui/retrain_signal_model_options.py +57 -56
  29. celldetective/gui/seg_model_loader.py +21 -62
  30. celldetective/gui/signal_annotator.py +139 -72
  31. celldetective/gui/signal_annotator2.py +431 -635
  32. celldetective/gui/signal_annotator_options.py +8 -11
  33. celldetective/gui/survival_ui.py +49 -95
  34. celldetective/gui/tableUI.py +28 -25
  35. celldetective/gui/thresholds_gui.py +617 -1221
  36. celldetective/gui/viewers.py +106 -39
  37. celldetective/gui/workers.py +9 -3
  38. celldetective/io.py +73 -27
  39. celldetective/measure.py +63 -27
  40. celldetective/neighborhood.py +342 -268
  41. celldetective/preprocessing.py +25 -17
  42. celldetective/relative_measurements.py +50 -29
  43. celldetective/scripts/analyze_signals.py +4 -1
  44. celldetective/scripts/measure_relative.py +4 -1
  45. celldetective/scripts/segment_cells.py +0 -6
  46. celldetective/scripts/track_cells.py +3 -1
  47. celldetective/scripts/train_segmentation_model.py +7 -4
  48. celldetective/signals.py +29 -14
  49. celldetective/tracking.py +7 -2
  50. celldetective/utils.py +36 -8
  51. {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/METADATA +24 -16
  52. {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/RECORD +57 -55
  53. {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/WHEEL +1 -1
  54. tests/test_qt.py +21 -21
  55. {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info}/entry_points.txt +0 -0
  56. {celldetective-1.3.9.post4.dist-info → celldetective-1.4.0.dist-info/licenses}/LICENSE +0 -0
  57. {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
- for t in tqdm(range(self.len_movie),desc="frame"):
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 QDialog, QMainWindow, QApplication,QRadioButton, QMessageBox, QScrollArea, QComboBox, QFrame, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
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, QIcon
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 Styles
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
- class ConfigSegmentationModelTraining(QMainWindow, Styles):
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 = QWidget()
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(1)
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(1)
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(1)
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
- msgBox = QMessageBox()
591
- msgBox.setIcon(QMessageBox.Warning)
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 QMainWindow, QApplication, QDialog, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
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 Styles
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(QMainWindow, Styles):
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 = QWidget()
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(1)
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(1)
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(1)
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(1)
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.replace('target_ref_','').replace('effector_ref_','')
345
- self.reference_population = ['targets' if 'target' in neigh else 'effectors'][0]
346
- if 'target' in neigh:
347
- if 'self' in neigh:
348
- self.neighbor_population = 'targets'
349
- else:
350
- self.neighbor_population = 'effectors'
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 neigh:
353
- self.neighbor_population = 'effectors'
354
- else:
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.reference_populations = []
396
- self.neighbor_populations = []
397
- if df_targets is not None:
398
- self.neighborhood_cols.extend(['target_ref_'+c for c in list(df_targets.columns) if c.startswith('neighborhood')])
399
- self.reference_populations.extend(['targets' for c in list(df_targets.columns) if c.startswith('neighborhood')])
400
- for c in list(df_targets.columns):
401
- if c.startswith('neighborhood') and '_2_' in c:
402
- self.neighbor_populations.append('effectors')
403
- elif c.startswith('neighborhood') and 'self' in c:
404
- self.neighbor_populations.append('targets')
405
-
406
- if df_effectors is not None:
407
- self.neighborhood_cols.extend(['effector_ref_'+c for c in list(df_effectors.columns) if c.startswith('neighborhood')])
408
- self.reference_populations.extend(['effectors' for c in list(df_effectors.columns) if c.startswith('neighborhood')])
409
- for c in list(df_effectors.columns):
410
- if c.startswith('neighborhood') and '_2_' in c:
411
- self.neighbor_populations.append('targets')
412
- elif c.startswith('neighborhood') and 'self' in c:
413
- self.neighbor_populations.append('effectors')
414
-
415
- print(f"The following neighborhoods were detected: {self.neighborhood_cols=} {self.reference_populations=} {self.neighbor_populations=}")
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 QWidget, QGridLayout, QComboBox, QVBoxLayout, QLabel, QLineEdit, QHBoxLayout, QRadioButton, QFileDialog, QPushButton, QMessageBox
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(QWidget, Styles):
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
- if self.mode=="targets":
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
- msgBox = QMessageBox()
234
- msgBox.setIcon(QMessageBox.Warning)
235
- msgBox.setText("StarDist model not recognized... Please ensure that it contains a thresholds.json file or that it is a valid StarDist model...")
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
- msgBox = QMessageBox()
268
- msgBox.setIcon(QMessageBox.Warning)
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
- msgBox = QMessageBox()
331
- msgBox.setIcon(QMessageBox.Warning)
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
- msgBox = QMessageBox()
347
- msgBox.setIcon(QMessageBox.Warning)
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
- msgBox = QMessageBox()
363
- msgBox.setIcon(QMessageBox.Warning)
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
- if self.mode=="targets":
396
- self.parent_window.threshold_config_targets = self.filename
397
- self.parent_window.seg_model_list.setCurrentText('Threshold')
398
- print('Path to the traditional segmentation pipeline successfully set in celldetective...')
399
- self.close()
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