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.
Files changed (94) hide show
  1. celldetective/__init__.py +0 -3
  2. celldetective/_version.py +1 -1
  3. celldetective/events.py +2 -4
  4. celldetective/exceptions.py +11 -0
  5. celldetective/extra_properties.py +132 -0
  6. celldetective/filters.py +7 -1
  7. celldetective/gui/InitWindow.py +37 -46
  8. celldetective/gui/__init__.py +3 -9
  9. celldetective/gui/about.py +19 -15
  10. celldetective/gui/analyze_block.py +34 -19
  11. celldetective/gui/base_annotator.py +786 -0
  12. celldetective/gui/base_components.py +23 -0
  13. celldetective/gui/classifier_widget.py +86 -94
  14. celldetective/gui/configure_new_exp.py +163 -46
  15. celldetective/gui/control_panel.py +76 -146
  16. celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
  17. celldetective/gui/generic_signal_plot.py +11 -13
  18. celldetective/gui/gui_utils.py +54 -23
  19. celldetective/gui/help/neighborhood.json +2 -2
  20. celldetective/gui/json_readers.py +5 -4
  21. celldetective/gui/layouts.py +265 -31
  22. celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
  23. celldetective/gui/plot_measurements.py +21 -17
  24. celldetective/gui/plot_signals_ui.py +125 -72
  25. celldetective/gui/process_block.py +283 -188
  26. celldetective/gui/processes/compute_neighborhood.py +594 -0
  27. celldetective/gui/processes/downloader.py +37 -34
  28. celldetective/gui/processes/measure_cells.py +19 -8
  29. celldetective/gui/processes/segment_cells.py +47 -11
  30. celldetective/gui/processes/track_cells.py +18 -13
  31. celldetective/gui/seg_model_loader.py +21 -62
  32. celldetective/gui/settings/__init__.py +7 -0
  33. celldetective/gui/settings/_settings_base.py +70 -0
  34. celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
  35. celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
  36. celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
  37. celldetective/gui/settings/_settings_segmentation.py +49 -0
  38. celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
  39. celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
  40. celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
  41. celldetective/gui/styles.py +2 -1
  42. celldetective/gui/survival_ui.py +49 -95
  43. celldetective/gui/tableUI.py +53 -25
  44. celldetective/gui/table_ops/__init__.py +0 -0
  45. celldetective/gui/table_ops/merge_groups.py +118 -0
  46. celldetective/gui/thresholds_gui.py +617 -1221
  47. celldetective/gui/viewers.py +107 -42
  48. celldetective/gui/workers.py +8 -4
  49. celldetective/io.py +137 -57
  50. celldetective/links/zenodo.json +145 -144
  51. celldetective/measure.py +94 -53
  52. celldetective/neighborhood.py +342 -268
  53. celldetective/preprocessing.py +56 -35
  54. celldetective/regionprops/_regionprops.py +16 -5
  55. celldetective/relative_measurements.py +50 -29
  56. celldetective/scripts/analyze_signals.py +4 -1
  57. celldetective/scripts/measure_cells.py +5 -5
  58. celldetective/scripts/measure_relative.py +20 -12
  59. celldetective/scripts/segment_cells.py +4 -10
  60. celldetective/scripts/segment_cells_thresholds.py +3 -3
  61. celldetective/scripts/track_cells.py +10 -8
  62. celldetective/scripts/train_segmentation_model.py +18 -6
  63. celldetective/signals.py +29 -14
  64. celldetective/tracking.py +14 -3
  65. celldetective/utils.py +91 -62
  66. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
  67. celldetective-1.4.1.dist-info/RECORD +123 -0
  68. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
  69. tests/gui/__init__.py +0 -0
  70. tests/gui/test_new_project.py +228 -0
  71. tests/gui/test_project.py +99 -0
  72. tests/test_preprocessing.py +2 -2
  73. celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
  74. celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  75. celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
  76. celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
  77. celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  78. celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
  79. celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
  80. celldetective/models/signal_detection/NucCond/config_input.json +0 -1
  81. celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
  82. celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
  83. celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
  84. celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
  85. celldetective/models/signal_detection/NucCond/scores.npy +0 -0
  86. celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
  87. celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
  88. celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
  89. celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
  90. celldetective-1.3.9.post5.dist-info/RECORD +0 -129
  91. tests/test_qt.py +0 -103
  92. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
  93. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
  94. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/top_level.txt +0 -0
@@ -6,7 +6,7 @@ import json
6
6
  from pathlib import Path, PurePath
7
7
 
8
8
  from celldetective.io import auto_load_number_of_frames, load_frames, locate_labels
9
- from celldetective.utils import extract_experiment_channels, ConfigSectionMap, _get_img_num_per_channel
9
+ from celldetective.utils import extract_experiment_channels, config_section_to_dict, _get_img_num_per_channel
10
10
  from celldetective.utils import remove_trajectory_measurements, _extract_coordinates_from_features, _remove_invalid_cols
11
11
  from celldetective.measure import drop_tonal_features, measure_features, measure_isotropic_intensity, measure_radial_distance_to_center, center_of_mass_to_abs_coordinates
12
12
 
@@ -17,9 +17,14 @@ import concurrent.futures
17
17
  import pandas as pd
18
18
  from natsort import natsorted
19
19
  from art import tprint
20
+ from typing import Optional, Union
20
21
 
21
22
 
22
23
  class MeasurementProcess(Process):
24
+
25
+ pos: Optional[Union[str,Path]] = None
26
+ mode: Optional[str] = None
27
+ n_threads: int = 1
23
28
 
24
29
  def __init__(self, queue=None, process_args=None):
25
30
 
@@ -166,14 +171,19 @@ class MeasurementProcess(Process):
166
171
  self.table_name = "trajectories_effectors.csv"
167
172
  self.instruction_file = os.sep.join(["configs","measurement_instructions_effectors.json"])
168
173
 
174
+ else:
175
+ self.label_folder = f"labels_{self.mode}"
176
+ self.table_name = f"trajectories_{self.mode}.csv"
177
+ self.instruction_file = os.sep.join(["configs",f"measurement_instructions_{self.mode}.json"])
178
+
169
179
  def extract_experiment_parameters(self):
170
180
 
171
- self.movie_prefix = ConfigSectionMap(self.config,"MovieSettings")["movie_prefix"]
172
- self.spatial_calibration = float(ConfigSectionMap(self.config,"MovieSettings")["pxtoum"])
173
- self.time_calibration = float(ConfigSectionMap(self.config,"MovieSettings")["frametomin"])
174
- self.len_movie = float(ConfigSectionMap(self.config,"MovieSettings")["len_movie"])
175
- self.shape_x = int(ConfigSectionMap(self.config,"MovieSettings")["shape_x"])
176
- self.shape_y = int(ConfigSectionMap(self.config,"MovieSettings")["shape_y"])
181
+ self.movie_prefix = config_section_to_dict(self.config, "MovieSettings")["movie_prefix"]
182
+ self.spatial_calibration = float(config_section_to_dict(self.config, "MovieSettings")["pxtoum"])
183
+ self.time_calibration = float(config_section_to_dict(self.config, "MovieSettings")["frametomin"])
184
+ self.len_movie = float(config_section_to_dict(self.config, "MovieSettings")["len_movie"])
185
+ self.shape_x = int(config_section_to_dict(self.config, "MovieSettings")["shape_x"])
186
+ self.shape_y = int(config_section_to_dict(self.config, "MovieSettings")["shape_y"])
177
187
 
178
188
  self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
179
189
  self.nbr_channels = len(self.channel_names)
@@ -326,7 +336,8 @@ class MeasurementProcess(Process):
326
336
 
327
337
  df = df.reset_index(drop=True)
328
338
  df = _remove_invalid_cols(df)
329
-
339
+ df = df.replace([np.inf, -np.inf], np.nan)
340
+
330
341
  df.to_csv(self.pos+os.sep.join(["output", "tables", self.table_name]), index=False)
331
342
  print(f'Measurement table successfully exported in {os.sep.join(["output", "tables"])}...')
332
343
  print('Done.')
@@ -5,7 +5,7 @@ import os
5
5
  import json
6
6
  import numpy as np
7
7
  from celldetective.io import extract_position_name, locate_segmentation_model, auto_load_number_of_frames, load_frames, _check_label_dims, _load_frames_to_segment
8
- from celldetective.utils import _rescale_labels, _segment_image_with_stardist_model, _segment_image_with_cellpose_model, _prep_stardist_model, _prep_cellpose_model, _get_normalize_kwargs_from_config, extract_experiment_channels, _estimate_scale_factor, _extract_channel_indices_from_config, ConfigSectionMap, _extract_nbr_channels_from_config, _get_img_num_per_channel
8
+ from celldetective.utils import _rescale_labels, _segment_image_with_stardist_model, _segment_image_with_cellpose_model, _prep_stardist_model, _prep_cellpose_model, _get_normalize_kwargs_from_config, extract_experiment_channels, _estimate_scale_factor, _extract_channel_indices_from_config, config_section_to_dict, _extract_nbr_channels_from_config, _get_img_num_per_channel
9
9
 
10
10
  from pathlib import Path, PurePath
11
11
  from glob import glob
@@ -39,19 +39,30 @@ class BaseSegmentProcess(Process):
39
39
  print(f"Position: {extract_position_name(self.pos)}...")
40
40
  print("Configuration file: ",self.config)
41
41
  print(f"Population: {self.mode}...")
42
-
42
+ self.instruction_file = os.sep.join(["configs", f"segmentation_instructions_{self.mode}.json"])
43
+
44
+ self.read_instructions()
43
45
  self.extract_experiment_parameters()
44
46
  self.detect_movie_length()
45
47
  self.write_folders()
48
+
49
+ def read_instructions(self):
50
+ print('Looking for instruction file...')
51
+ instr_path = PurePath(self.exp_dir,Path(f"{self.instruction_file}"))
52
+ if os.path.exists(instr_path):
53
+ with open(instr_path, 'r') as f:
54
+ _instructions = json.load(f)
55
+ print(f"Measurement instruction file successfully loaded...")
56
+ print(f"Instructions: {_instructions}...")
57
+ self.flip = _instructions.get("flip", False)
58
+ else:
59
+ self.flip = False
60
+
46
61
 
47
62
  def write_folders(self):
48
63
 
49
64
  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"
65
+ self.label_folder = f"labels_{self.mode}"
55
66
 
56
67
  if os.path.exists(self.pos+self.label_folder):
57
68
  print('Erasing the previous labels folder...')
@@ -62,9 +73,9 @@ class BaseSegmentProcess(Process):
62
73
 
63
74
  def extract_experiment_parameters(self):
64
75
 
65
- self.spatial_calibration = float(ConfigSectionMap(self.config,"MovieSettings")["pxtoum"])
66
- self.len_movie = float(ConfigSectionMap(self.config,"MovieSettings")["len_movie"])
67
- self.movie_prefix = ConfigSectionMap(self.config,"MovieSettings")["movie_prefix"]
76
+ self.spatial_calibration = float(config_section_to_dict(self.config, "MovieSettings")["pxtoum"])
77
+ self.len_movie = float(config_section_to_dict(self.config, "MovieSettings")["len_movie"])
78
+ self.movie_prefix = config_section_to_dict(self.config, "MovieSettings")["movie_prefix"]
68
79
  self.nbr_channels = _extract_nbr_channels_from_config(self.config)
69
80
  self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
70
81
 
@@ -123,6 +134,14 @@ class SegmentCellDLProcess(BaseSegmentProcess):
123
134
  def extract_model_input_parameters(self):
124
135
 
125
136
  self.required_channels = self.input_config["channels"]
137
+ if 'selected_channels' in self.input_config:
138
+ self.required_channels = self.input_config['selected_channels']
139
+
140
+ self.target_cell_size = None
141
+ if 'target_cell_size_um' in self.input_config and 'cell_size_um' in self.input_config:
142
+ self.target_cell_size = self.input_config['target_cell_size_um']
143
+ self.cell_size = self.input_config['cell_size_um']
144
+
126
145
  self.normalize_kwargs = _get_normalize_kwargs_from_config(self.input_config)
127
146
 
128
147
  self.model_type = self.input_config['model_type']
@@ -152,6 +171,14 @@ class SegmentCellDLProcess(BaseSegmentProcess):
152
171
  self.scale = _estimate_scale_factor(self.spatial_calibration, self.required_spatial_calibration)
153
172
  print(f"Scale: {self.scale}...")
154
173
 
174
+ if self.target_cell_size is not None and self.scale is not None:
175
+ self.scale *= self.cell_size / self.target_cell_size
176
+ elif self.target_cell_size is not None:
177
+ if self.target_cell_size != self.cell_size:
178
+ self.scale = self.cell_size / self.target_cell_size
179
+
180
+ print(f"Scale accounting for expected cell size: {self.scale}...")
181
+
155
182
  def locate_model_path(self):
156
183
 
157
184
  self.model_complete_path = locate_segmentation_model(self.model_name)
@@ -183,7 +210,11 @@ class SegmentCellDLProcess(BaseSegmentProcess):
183
210
  elif self.model_type=='cellpose':
184
211
  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
212
 
186
- for t in tqdm(range(self.len_movie),desc="frame"):
213
+ list_indices = range(self.len_movie)
214
+ if self.flip:
215
+ list_indices = reversed(list_indices)
216
+
217
+ for t in tqdm(list_indices,desc="frame"):
187
218
 
188
219
  f = _load_frames_to_segment(self.file, self.img_num_channels[:,t], scale_model=scale_model, normalize_kwargs=self.normalize_kwargs)
189
220
 
@@ -219,6 +250,7 @@ class SegmentCellDLProcess(BaseSegmentProcess):
219
250
  pass
220
251
 
221
252
  gc.collect()
253
+ print("Done.")
222
254
 
223
255
  # Send end signal
224
256
  self.queue.put("finished")
@@ -339,6 +371,9 @@ class SegmentCellThresholdProcess(BaseSegmentProcess):
339
371
  def run(self):
340
372
 
341
373
  self.indices = list(range(self.img_num_channels.shape[1]))
374
+ if self.flip:
375
+ self.indices = np.array(list(reversed(self.indices)))
376
+
342
377
  chunks = np.array_split(self.indices, self.n_threads)
343
378
 
344
379
  with concurrent.futures.ThreadPoolExecutor(max_workers=self.n_threads) as executor:
@@ -349,6 +384,7 @@ class SegmentCellThresholdProcess(BaseSegmentProcess):
349
384
  except Exception as e:
350
385
  print("Exception: ", e)
351
386
 
387
+ print('Done.')
352
388
  # Send end signal
353
389
  self.queue.put("finished")
354
390
  self.queue.close()
@@ -1,10 +1,8 @@
1
1
  from multiprocessing import Process
2
2
  import time
3
- import datetime
4
- import os
5
- import json
6
3
  from celldetective.io import auto_load_number_of_frames, _load_frames_to_measure, locate_labels
7
- from celldetective.utils import extract_experiment_channels, ConfigSectionMap, _get_img_num_per_channel, _mask_intensity_measurements
4
+ from celldetective.utils import config_section_to_dict, _get_img_num_per_channel, \
5
+ _mask_intensity_measurements, remove_file_if_exists
8
6
  from pathlib import Path, PurePath
9
7
  from glob import glob
10
8
  from tqdm import tqdm
@@ -147,14 +145,20 @@ class TrackingProcess(Process):
147
145
  self.napari_name = "napari_effector_trajectories.npy"
148
146
  self.table_name = "trajectories_effectors.csv"
149
147
 
148
+ else:
149
+ self.label_folder = f"labels_{self.mode}"
150
+ self.instruction_file = os.sep.join(["configs",f"tracking_instructions_{self.mode}.json"])
151
+ self.napari_name = f"napari_{self.mode}_trajectories.npy"
152
+ self.table_name = f"trajectories_{self.mode}.csv"
153
+
150
154
  def extract_experiment_parameters(self):
151
155
 
152
- self.movie_prefix = ConfigSectionMap(self.config,"MovieSettings")["movie_prefix"]
153
- self.spatial_calibration = float(ConfigSectionMap(self.config,"MovieSettings")["pxtoum"])
154
- self.time_calibration = float(ConfigSectionMap(self.config,"MovieSettings")["frametomin"])
155
- self.len_movie = float(ConfigSectionMap(self.config,"MovieSettings")["len_movie"])
156
- self.shape_x = int(ConfigSectionMap(self.config,"MovieSettings")["shape_x"])
157
- self.shape_y = int(ConfigSectionMap(self.config,"MovieSettings")["shape_y"])
156
+ self.movie_prefix = config_section_to_dict(self.config, "MovieSettings")["movie_prefix"]
157
+ self.spatial_calibration = float(config_section_to_dict(self.config, "MovieSettings")["pxtoum"])
158
+ self.time_calibration = float(config_section_to_dict(self.config, "MovieSettings")["frametomin"])
159
+ self.len_movie = float(config_section_to_dict(self.config, "MovieSettings")["len_movie"])
160
+ self.shape_x = int(config_section_to_dict(self.config, "MovieSettings")["shape_x"])
161
+ self.shape_y = int(config_section_to_dict(self.config, "MovieSettings")["shape_y"])
158
162
 
159
163
  self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
160
164
  self.nbr_channels = len(self.channel_names)
@@ -240,7 +244,9 @@ class TrackingProcess(Process):
240
244
 
241
245
  print('Features successfully measured...')
242
246
 
243
- df = pd.concat(self.timestep_dataframes)
247
+ df = pd.concat(self.timestep_dataframes)
248
+ df = df.replace([np.inf, -np.inf], np.nan)
249
+
244
250
  df.reset_index(inplace=True, drop=True)
245
251
  df = _mask_intensity_measurements(df, self.mask_channels)
246
252
 
@@ -274,8 +280,7 @@ class TrackingProcess(Process):
274
280
  trajectories.to_csv(self.pos+os.sep.join(['output', 'tables', self.table_name]), index=False)
275
281
  print(f"Trajectory table successfully exported in {os.sep.join(['output', 'tables'])}...")
276
282
 
277
- if os.path.exists(self.pos+os.sep.join(['output', 'tables', self.table_name.replace('.csv','.pkl')])):
278
- os.remove(self.pos+os.sep.join(['output', 'tables', self.table_name.replace('.csv','.pkl')]))
283
+ remove_file_if_exists(self.pos+os.sep.join(['output', 'tables', self.table_name.replace('.csv','.pkl')]))
279
284
 
280
285
  del trajectories; del napari_data;
281
286
  gc.collect()
@@ -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
 
@@ -0,0 +1,7 @@
1
+ from ._settings_measurements import SettingsMeasurements
2
+ from ._settings_segmentation import SettingsSegmentation
3
+ from ._settings_tracking import SettingsTracking
4
+ from ._settings_segmentation_model_training import SettingsSegmentationModelTraining
5
+ from ._settings_event_model_training import SettingsEventDetectionModelTraining
6
+ from ._settings_signal_annotator import SettingsSignalAnnotator
7
+ from ._settings_neighborhood import SettingsNeighborhood
@@ -0,0 +1,70 @@
1
+ from abc import abstractmethod
2
+ from PyQt5.QtWidgets import QApplication, QScrollArea, QSizePolicy, QVBoxLayout, QPushButton
3
+ from PyQt5.QtCore import Qt
4
+ from celldetective.utils import get_software_location
5
+ from celldetective.gui.gui_utils import center_window
6
+ from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
7
+ from PyQt5.QtGui import QDoubleValidator, QIntValidator
8
+
9
+ class CelldetectiveSettingsPanel(CelldetectiveMainWindow):
10
+
11
+ def __init__(self, title=""):
12
+
13
+ super().__init__()
14
+ self.setWindowTitle(title)
15
+
16
+ self._get_screen_height()
17
+ #self.setMinimumWidth(500)
18
+ self.setMaximumHeight(int(0.8 * self._screen_height))
19
+ self._scroll_area = QScrollArea(self)
20
+ self._floatValidator = QDoubleValidator()
21
+ self._intValidator = QIntValidator()
22
+ self._software_path = get_software_location()
23
+
24
+ self._create_widgets()
25
+ self._build_layouts()
26
+ self.center_window()
27
+
28
+ def _create_widgets(self):
29
+ self.submit_btn: QPushButton = QPushButton("Save")
30
+ self.submit_btn.setStyleSheet(self.button_style_sheet)
31
+ self.submit_btn.clicked.connect(self._write_instructions)
32
+
33
+ def center_window(self):
34
+ return center_window(self)
35
+
36
+ def _get_screen_height(self):
37
+ app = QApplication.instance()
38
+ screen = app.primaryScreen()
39
+ geometry = screen.availableGeometry()
40
+ self._screen_width, self._screen_height = geometry.getRect()[-2:]
41
+
42
+ def _adjustSize(self):
43
+ self._widget.adjustSize()
44
+ self._scroll_area.adjustSize()
45
+ self.adjustSize()
46
+
47
+ def _build_layouts(self):
48
+
49
+ self._layout: QVBoxLayout = QVBoxLayout()
50
+ self._widget: CelldetectiveWidget = CelldetectiveWidget()
51
+ self._widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
52
+
53
+ # Create button widget and layout
54
+ self._widget.setLayout(self._layout)
55
+ self._layout.setContentsMargins(30, 30, 30, 30)
56
+
57
+ self._scroll_area.setAlignment(Qt.AlignCenter)
58
+ self._scroll_area.setWidget(self._widget)
59
+ self._scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
60
+ self._scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
61
+ self._scroll_area.setWidgetResizable(True)
62
+ self.setCentralWidget(self._scroll_area)
63
+
64
+ QApplication.processEvents()
65
+
66
+ @abstractmethod
67
+ def _load_previous_instructions(self): pass
68
+
69
+ @abstractmethod
70
+ def _write_instructions(self): pass