celldetective 1.4.0__py3-none-any.whl → 1.4.1.post1__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 (78) hide show
  1. celldetective/_version.py +1 -1
  2. celldetective/exceptions.py +11 -0
  3. celldetective/filters.py +7 -1
  4. celldetective/gui/InitWindow.py +4 -1
  5. celldetective/gui/__init__.py +2 -9
  6. celldetective/gui/about.py +2 -2
  7. celldetective/gui/base_annotator.py +786 -0
  8. celldetective/gui/classifier_widget.py +18 -13
  9. celldetective/gui/configure_new_exp.py +51 -30
  10. celldetective/gui/control_panel.py +10 -7
  11. celldetective/gui/{signal_annotator.py → event_annotator.py} +473 -1437
  12. celldetective/gui/generic_signal_plot.py +2 -1
  13. celldetective/gui/gui_utils.py +5 -2
  14. celldetective/gui/help/neighborhood.json +2 -2
  15. celldetective/gui/layouts.py +21 -11
  16. celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +3 -1
  17. celldetective/gui/process_block.py +129 -91
  18. celldetective/gui/processes/downloader.py +37 -34
  19. celldetective/gui/processes/measure_cells.py +14 -8
  20. celldetective/gui/processes/segment_cells.py +438 -314
  21. celldetective/gui/processes/track_cells.py +12 -13
  22. celldetective/gui/settings/__init__.py +7 -0
  23. celldetective/gui/settings/_settings_base.py +70 -0
  24. celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +35 -91
  25. celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +28 -81
  26. celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +1 -1
  27. celldetective/gui/settings/_settings_segmentation.py +49 -0
  28. celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +33 -79
  29. celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +73 -95
  30. celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +64 -87
  31. celldetective/gui/styles.py +2 -1
  32. celldetective/gui/survival_ui.py +1 -1
  33. celldetective/gui/tableUI.py +25 -0
  34. celldetective/gui/table_ops/__init__.py +0 -0
  35. celldetective/gui/table_ops/merge_groups.py +118 -0
  36. celldetective/gui/viewers.py +3 -5
  37. celldetective/gui/workers.py +0 -2
  38. celldetective/io.py +98 -55
  39. celldetective/links/zenodo.json +145 -144
  40. celldetective/measure.py +31 -26
  41. celldetective/preprocessing.py +34 -21
  42. celldetective/regionprops/_regionprops.py +16 -5
  43. celldetective/scripts/measure_cells.py +5 -5
  44. celldetective/scripts/measure_relative.py +16 -11
  45. celldetective/scripts/segment_cells.py +4 -4
  46. celldetective/scripts/segment_cells_thresholds.py +3 -3
  47. celldetective/scripts/track_cells.py +7 -7
  48. celldetective/scripts/train_segmentation_model.py +10 -1
  49. celldetective/tracking.py +10 -4
  50. celldetective/utils.py +59 -58
  51. {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/METADATA +1 -1
  52. celldetective-1.4.1.post1.dist-info/RECORD +123 -0
  53. tests/gui/__init__.py +0 -0
  54. tests/gui/test_new_project.py +228 -0
  55. tests/{test_qt.py → gui/test_project.py} +22 -26
  56. tests/test_preprocessing.py +2 -2
  57. celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
  58. celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  59. celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
  60. celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
  61. celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  62. celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
  63. celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
  64. celldetective/models/signal_detection/NucCond/config_input.json +0 -1
  65. celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
  66. celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
  67. celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
  68. celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
  69. celldetective/models/signal_detection/NucCond/scores.npy +0 -0
  70. celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
  71. celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
  72. celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
  73. celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
  74. celldetective-1.4.0.dist-info/RECORD +0 -131
  75. {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/WHEEL +0 -0
  76. {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/entry_points.txt +0 -0
  77. {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/licenses/LICENSE +0 -0
  78. {celldetective-1.4.0.dist-info → celldetective-1.4.1.post1.dist-info}/top_level.txt +0 -0
@@ -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
@@ -155,12 +153,12 @@ class TrackingProcess(Process):
155
153
 
156
154
  def extract_experiment_parameters(self):
157
155
 
158
- self.movie_prefix = ConfigSectionMap(self.config,"MovieSettings")["movie_prefix"]
159
- self.spatial_calibration = float(ConfigSectionMap(self.config,"MovieSettings")["pxtoum"])
160
- self.time_calibration = float(ConfigSectionMap(self.config,"MovieSettings")["frametomin"])
161
- self.len_movie = float(ConfigSectionMap(self.config,"MovieSettings")["len_movie"])
162
- self.shape_x = int(ConfigSectionMap(self.config,"MovieSettings")["shape_x"])
163
- 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"])
164
162
 
165
163
  self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
166
164
  self.nbr_channels = len(self.channel_names)
@@ -246,7 +244,9 @@ class TrackingProcess(Process):
246
244
 
247
245
  print('Features successfully measured...')
248
246
 
249
- df = pd.concat(self.timestep_dataframes)
247
+ df = pd.concat(self.timestep_dataframes)
248
+ df = df.replace([np.inf, -np.inf], np.nan)
249
+
250
250
  df.reset_index(inplace=True, drop=True)
251
251
  df = _mask_intensity_measurements(df, self.mask_channels)
252
252
 
@@ -280,8 +280,7 @@ class TrackingProcess(Process):
280
280
  trajectories.to_csv(self.pos+os.sep.join(['output', 'tables', self.table_name]), index=False)
281
281
  print(f"Trajectory table successfully exported in {os.sep.join(['output', 'tables'])}...")
282
282
 
283
- if os.path.exists(self.pos+os.sep.join(['output', 'tables', self.table_name.replace('.csv','.pkl')])):
284
- 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')]))
285
284
 
286
285
  del trajectories; del napari_data;
287
286
  gc.collect()
@@ -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
@@ -1,12 +1,9 @@
1
- from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
1
+ from PyQt5.QtWidgets import QMessageBox, QComboBox, QFrame, QCheckBox, 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
5
3
  from celldetective.gui.layouts import ChannelNormGenerator
6
4
  from superqt import QLabeledDoubleSlider, QLabeledSlider, QSearchableComboBox
7
5
  from superqt.fonticon import icon
8
6
  from fonticon_mdi6 import MDI6
9
- from celldetective.utils import get_software_location
10
7
  from celldetective.io import locate_signal_dataset, get_signal_datasets_list, load_experiment_tables
11
8
  from celldetective.signals import train_signal_model
12
9
  import numpy as np
@@ -14,12 +11,12 @@ import json
14
11
  import os
15
12
  from glob import glob
16
13
  from datetime import datetime
17
- from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
18
14
  from pandas.api.types import is_numeric_dtype
19
15
  from celldetective.gui.processes.train_signal_model import TrainSignalModelProcess
20
16
  from celldetective.gui.workers import ProgressWindow
17
+ from celldetective.gui.settings._settings_base import CelldetectiveSettingsPanel
21
18
 
22
- class ConfigSignalModelTraining(CelldetectiveMainWindow):
19
+ class SettingsEventDetectionModelTraining(CelldetectiveSettingsPanel):
23
20
 
24
21
  """
25
22
  UI to set measurement instructions.
@@ -28,87 +25,62 @@ class ConfigSignalModelTraining(CelldetectiveMainWindow):
28
25
 
29
26
  def __init__(self, parent_window=None, signal_mode='single-cells'):
30
27
 
31
- super().__init__()
32
28
  self.parent_window = parent_window
33
- self.setWindowTitle("Train signal model")
34
29
  self.mode = self.parent_window.mode
35
30
  self.exp_dir = self.parent_window.exp_dir
36
- self.soft_path = get_software_location()
37
- self.pretrained_model = None
31
+ self.pretrained_model = None
38
32
  self.dataset_folder = None
39
33
  self.current_neighborhood = None
40
34
  self.reference_population = None
41
35
  self.neighbor_population = None
42
36
  self.signal_mode = signal_mode
37
+
38
+ super().__init__(title="Train event detection model")
43
39
 
44
40
  if self.signal_mode=='single-cells':
45
- self.signal_models_dir = self.soft_path+os.sep+os.sep.join(['celldetective','models','signal_detection'])
41
+ self.signal_models_dir = self._software_path+os.sep+os.sep.join(['celldetective','models','signal_detection'])
46
42
  elif self.signal_mode=='pairs':
47
- self.signal_models_dir = self.soft_path+os.sep+os.sep.join(['celldetective','models','pair_signal_detection'])
43
+ self.signal_models_dir = self._software_path+os.sep+os.sep.join(['celldetective','models','pair_signal_detection'])
48
44
  self.mode = 'pairs'
45
+
46
+ self._add_to_layout()
47
+ self._load_previous_instructions()
48
+
49
+ self._adjustSize()
50
+ new_width = int(self.width()*1.2)
51
+ self.resize(new_width, int(self._screen_height * 0.8))
52
+ self.setMinimumWidth(new_width)
53
+
54
+ def _add_to_layout(self):
55
+ self._layout.addWidget(self.model_frame)
56
+ self._layout.addWidget(self.data_frame)
57
+ self._layout.addWidget(self.hyper_frame)
58
+ self._layout.addWidget(self.submit_btn)
49
59
 
50
- self.onlyFloat = QDoubleValidator()
51
- self.onlyInt = QIntValidator()
52
-
53
- self.screen_height = self.parent_window.parent_window.parent_window.screen_height
54
- center_window(self)
55
-
56
- self.setMinimumWidth(500)
57
- self.setMinimumHeight(int(0.3*self.screen_height))
58
- self.setMaximumHeight(int(0.8*self.screen_height))
59
- self.populate_widget()
60
- #self.load_previous_measurement_instructions()
61
-
62
- def populate_widget(self):
60
+ def _create_widgets(self):
63
61
 
64
62
  """
65
63
  Create the multibox design.
66
64
 
67
65
  """
66
+ super()._create_widgets()
68
67
 
69
- # Create button widget and layout
70
- self.scroll_area = QScrollArea(self)
71
- self.button_widget = CelldetectiveWidget()
72
- self.main_layout = QVBoxLayout()
73
- self.button_widget.setLayout(self.main_layout)
74
- self.main_layout.setContentsMargins(30,30,30,30)
75
-
76
68
  # first frame for FEATURES
77
69
  self.model_frame = QFrame()
78
70
  self.model_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
79
71
  self.populate_model_frame()
80
- self.main_layout.addWidget(self.model_frame)
81
72
 
82
73
  self.data_frame = QFrame()
83
74
  self.data_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
84
75
  self.populate_data_frame()
85
- self.main_layout.addWidget(self.data_frame)
86
76
 
87
77
  self.hyper_frame = QFrame()
88
78
  self.hyper_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
89
79
  self.populate_hyper_frame()
90
- self.main_layout.addWidget(self.hyper_frame)
91
80
 
92
- self.submit_btn = QPushButton('Train')
93
- self.submit_btn.setStyleSheet(self.button_style_sheet)
94
- self.submit_btn.clicked.connect(self.prep_model)
95
- self.main_layout.addWidget(self.submit_btn)
96
81
  self.submit_btn.setEnabled(False)
82
+ self.submit_btn.setText("Train")
97
83
 
98
- #self.populate_left_panel()
99
- #grid.addLayout(self.left_side, 0, 0, 1, 1)
100
- self.button_widget.adjustSize()
101
-
102
- self.scroll_area.setAlignment(Qt.AlignCenter)
103
- self.scroll_area.setWidget(self.button_widget)
104
- self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
105
- self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
106
- self.scroll_area.setWidgetResizable(True)
107
- self.setCentralWidget(self.scroll_area)
108
- self.show()
109
-
110
- QApplication.processEvents()
111
- self.adjustScrollArea()
112
84
 
113
85
  def populate_hyper_frame(self):
114
86
 
@@ -138,14 +110,14 @@ class ConfigSignalModelTraining(CelldetectiveMainWindow):
138
110
  lr_layout = QHBoxLayout()
139
111
  lr_layout.addWidget(QLabel('learning rate: '),30)
140
112
  self.lr_le = QLineEdit('0,01')
141
- self.lr_le.setValidator(self.onlyFloat)
113
+ self.lr_le.setValidator(self._floatValidator)
142
114
  lr_layout.addWidget(self.lr_le, 70)
143
115
  layout.addLayout(lr_layout)
144
116
 
145
117
  bs_layout = QHBoxLayout()
146
118
  bs_layout.addWidget(QLabel('batch size: '),30)
147
119
  self.bs_le = QLineEdit('64')
148
- self.bs_le.setValidator(self.onlyInt)
120
+ self.bs_le.setValidator(self._intValidator)
149
121
  bs_layout.addWidget(self.bs_le, 70)
150
122
  layout.addLayout(bs_layout)
151
123
 
@@ -378,42 +350,11 @@ class ConfigSignalModelTraining(CelldetectiveMainWindow):
378
350
  self.dataframes = {}
379
351
  self.neighborhood_cols = []
380
352
  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})
353
+ df_pop = load_experiment_tables(self.parent_window.exp_dir, population=population, load_pickle=True)
354
+ self.dataframes.update({population: df_pop})
383
355
  if df_pop is not None:
384
356
  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=}")
357
+ [f'{population}_ref_' + c for c in list(df_pop.columns) if c.startswith('neighborhood')])
417
358
 
418
359
  self.neighborhood_choice_cb.addItems(self.neighborhood_cols)
419
360
 
@@ -519,7 +460,7 @@ class ConfigSignalModelTraining(CelldetectiveMainWindow):
519
460
  while self.scroll_area.verticalScrollBar().isVisible() and self.height() < self.maximumHeight():
520
461
  self.resize(self.width(), self.height() + step)
521
462
 
522
- def prep_model(self):
463
+ def _write_instructions(self):
523
464
 
524
465
  model_name = self.modelname_le.text()
525
466
  pretrained_model = self.pretrained_model
@@ -597,4 +538,7 @@ class ConfigSignalModelTraining(CelldetectiveMainWindow):
597
538
  # return None
598
539
 
599
540
  train_signal_model(model_folder+"training_instructions.json")
600
- self.parent_window.refresh_signal_models()
541
+ self.parent_window.refresh_signal_models()
542
+
543
+ def _load_previous_instructions(self):
544
+ pass
@@ -1,11 +1,10 @@
1
1
  from subprocess import Popen
2
2
 
3
- from PyQt5.QtWidgets import QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, \
3
+ from PyQt5.QtWidgets import QMessageBox, QComboBox, QFrame, QCheckBox, \
4
4
  QGridLayout, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
5
5
  from PyQt5.QtCore import Qt, QSize
6
- from PyQt5.QtGui import QDoubleValidator, QIntValidator
7
6
 
8
- from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, \
7
+ from celldetective.gui.gui_utils import FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, \
9
8
  GeometryChoice, OperationChoice
10
9
  from superqt import QLabeledDoubleSlider
11
10
  from superqt.fonticon import icon
@@ -27,10 +26,10 @@ from pathlib import Path
27
26
  from celldetective.gui.viewers import CellEdgeVisualizer, SpotDetectionVisualizer
28
27
  from celldetective.gui.layouts import ProtocolDesignerLayout, BackgroundFitCorrectionLayout, LocalCorrectionLayout
29
28
  from celldetective.gui.gui_utils import PreprocessingLayout2
30
- from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
29
+ from celldetective.gui.settings._settings_base import CelldetectiveSettingsPanel
31
30
 
32
31
 
33
- class ConfigMeasurements(CelldetectiveMainWindow):
32
+ class SettingsMeasurements(CelldetectiveSettingsPanel):
34
33
  """
35
34
  UI to set measurement instructions.
36
35
 
@@ -38,49 +37,33 @@ class ConfigMeasurements(CelldetectiveMainWindow):
38
37
 
39
38
  def __init__(self, parent_window=None):
40
39
 
41
- super().__init__()
42
-
43
40
  self.parent_window = parent_window
44
- self.setWindowTitle("Configure measurements")
45
41
  self.mode = self.parent_window.mode
46
42
  self.exp_dir = self.parent_window.exp_dir
47
43
  self.background_correction = []
48
44
  self.config_name = f"btrack_config_{self.mode}.json"
49
45
  self.measure_instructions_path = self.parent_window.exp_dir + f"configs/measurement_instructions_{self.mode}.json"
50
- self.soft_path = get_software_location()
51
46
  self.clear_previous = False
52
-
53
- exp_config = self.exp_dir + "config.ini"
54
47
  self.config_path = self.exp_dir + self.config_name
55
48
  self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
56
49
  self.channel_names = np.array(self.channel_names)
57
50
  self.channels = np.array(self.channels)
51
+
52
+ super().__init__("Configure measurements")
58
53
 
59
- self.screen_height = self.parent_window.parent_window.parent_window.screen_height
60
- center_window(self)
61
-
62
- self.onlyFloat = QDoubleValidator()
63
- self.onlyInt = QIntValidator()
64
-
65
- self.setMinimumWidth(500)
66
- self.setMinimumHeight(int(0.3 * self.screen_height))
67
- self.setMaximumHeight(int(0.8 * self.screen_height))
68
- self.populate_widget()
69
- self.load_previous_measurement_instructions()
70
-
71
- def populate_widget(self):
54
+ self._add_to_layout()
55
+ self._load_previous_instructions()
56
+
57
+ self._adjustSize()
58
+ self.resize(int(self.width()), int(self._screen_height * 0.8))
59
+
60
+ def _create_widgets(self):
72
61
 
73
62
  """
74
63
  Create the multibox design.
75
64
 
76
65
  """
77
-
78
- # Create button widget and layout
79
- self.scroll_area = QScrollArea(self)
80
- self.button_widget = CelldetectiveWidget()
81
- main_layout = QVBoxLayout()
82
- self.button_widget.setLayout(main_layout)
83
- main_layout.setContentsMargins(30, 30, 30, 30)
66
+ super()._create_widgets()
84
67
 
85
68
  self.normalisation_frame = QFrame()
86
69
  self.normalisation_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
@@ -98,48 +81,31 @@ class ConfigMeasurements(CelldetectiveMainWindow):
98
81
  self.normalisation_frame.setLayout(self.protocol_layout)
99
82
 
100
83
  #self.populate_normalisation_tabs()
101
- main_layout.addWidget(self.normalisation_frame)
102
84
 
103
85
  # first frame for FEATURES
104
86
  self.features_frame = QFrame()
105
87
  self.features_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
106
88
  self.populate_features_frame()
107
- main_layout.addWidget(self.features_frame)
108
89
 
109
90
  # second frame for ISOTROPIC MEASUREMENTS
110
91
  self.iso_frame = QFrame()
111
92
  self.iso_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
112
93
  self.populate_iso_frame()
113
- main_layout.addWidget(self.iso_frame)
114
94
 
115
95
  self.spot_detection_frame = QFrame()
116
96
  self.spot_detection_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
117
97
  self.populate_spot_detection()
118
- main_layout.addWidget(self.spot_detection_frame)
119
98
 
120
99
  self.clear_previous_btn = QCheckBox('clear previous measurements')
121
- main_layout.addWidget(self.clear_previous_btn)
122
-
123
- self.submit_btn = QPushButton('Save')
124
- self.submit_btn.setStyleSheet(self.button_style_sheet)
125
- self.submit_btn.clicked.connect(self.write_instructions)
126
- main_layout.addWidget(self.submit_btn)
127
-
128
- # self.populate_left_panel()
129
- # grid.addLayout(self.left_side, 0, 0, 1, 1)
130
- self.button_widget.adjustSize()
131
-
132
- self.scroll_area.setAlignment(Qt.AlignCenter)
133
- self.scroll_area.setWidget(self.button_widget)
134
- self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
135
- self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
136
- self.scroll_area.setWidgetResizable(True)
137
- self.setCentralWidget(self.scroll_area)
138
- self.show()
139
-
140
- QApplication.processEvents()
141
- self.adjustScrollArea()
142
100
 
101
+ def _add_to_layout(self):
102
+ self._layout.addWidget(self.normalisation_frame)
103
+ self._layout.addWidget(self.features_frame)
104
+ self._layout.addWidget(self.iso_frame)
105
+ self._layout.addWidget(self.spot_detection_frame)
106
+ self._layout.addWidget(self.clear_previous_btn)
107
+ self._layout.addWidget(self.submit_btn)
108
+
143
109
  def populate_iso_frame(self):
144
110
 
145
111
  """
@@ -431,7 +397,7 @@ class ConfigMeasurements(CelldetectiveMainWindow):
431
397
 
432
398
  def go_to_extraprops(self):
433
399
 
434
- path = os.sep.join([self.soft_path,'celldetective',os.sep,'extra_properties.py'])
400
+ path = os.sep.join([self._software_path,'celldetective',os.sep,'extra_properties.py'])
435
401
  try:
436
402
  Popen(f'explorer {os.path.realpath(path)}')
437
403
  except:
@@ -487,7 +453,7 @@ class ConfigMeasurements(CelldetectiveMainWindow):
487
453
  while self.scroll_area.verticalScrollBar().isVisible() and self.height() < self.maximumHeight():
488
454
  self.resize(self.width(), self.height() + step)
489
455
 
490
- def write_instructions(self):
456
+ def _write_instructions(self):
491
457
 
492
458
  """
493
459
  Write the selected options in a json file for later reading by the software.
@@ -566,7 +532,7 @@ class ConfigMeasurements(CelldetectiveMainWindow):
566
532
  else:
567
533
  self.haralick_options = None
568
534
 
569
- def load_previous_measurement_instructions(self):
535
+ def _load_previous_instructions(self):
570
536
 
571
537
  """
572
538
  Read the measurmeent options from a previously written json file and format properly for the UI.
@@ -685,18 +651,6 @@ class ConfigMeasurements(CelldetectiveMainWindow):
685
651
  else:
686
652
  self.operations_list.list_widget.clear()
687
653
 
688
- # if 'radial_intensity' in measurement_instructions:
689
- # radial_intensity = measurement_instructions['radial_intensity']
690
- # if radial_intensity is not None:
691
- # self.radial_intensity_btn.setChecked(True)
692
- # self.step_size.setText(str(radial_intensity['radial_step']))
693
- # self.step_size.setEnabled(True)
694
- # self.step_lbl.setEnabled(True)
695
- # for checkbox in self.channel_chechkboxes:
696
- # checkbox.setEnabled(True)
697
- # if checkbox.text() in radial_intensity['radial_channels']:
698
- # checkbox.setChecked(True)
699
-
700
654
  if 'clear_previous' in measurement_instructions:
701
655
  self.clear_previous = measurement_instructions['clear_previous']
702
656
  self.clear_previous_btn.setChecked(self.clear_previous)
@@ -718,6 +672,7 @@ class ConfigMeasurements(CelldetectiveMainWindow):
718
672
  returnValue = msgBox.exec()
719
673
  if returnValue == QMessageBox.Ok:
720
674
  self.current_stack = None
675
+ self.test_frame = None
721
676
  return None
722
677
  else:
723
678
  self.current_stack = movies[0]
@@ -946,7 +901,7 @@ class ConfigMeasurements(CelldetectiveMainWindow):
946
901
  diam_hbox = QHBoxLayout()
947
902
  self.diameter_lbl = QLabel('Spot diameter: ')
948
903
  self.diameter_value = QLineEdit()
949
- self.diameter_value.setValidator(self.onlyFloat)
904
+ self.diameter_value.setValidator(self._floatValidator)
950
905
  self.diameter_value.setText('7')
951
906
  self.diameter_value.textChanged.connect(self.enable_spot_preview)
952
907
 
@@ -957,7 +912,7 @@ class ConfigMeasurements(CelldetectiveMainWindow):
957
912
  thresh_hbox = QHBoxLayout()
958
913
  self.threshold_lbl = QLabel('Spot threshold: ')
959
914
  self.threshold_value = QLineEdit()
960
- self.threshold_value.setValidator(self.onlyFloat)
915
+ self.threshold_value.setValidator(self._floatValidator)
961
916
  self.threshold_value.setText('0')
962
917
  self.threshold_value.textChanged.connect(self.enable_spot_preview)
963
918
 
@@ -965,14 +920,6 @@ class ConfigMeasurements(CelldetectiveMainWindow):
965
920
  thresh_hbox.addWidget(self.threshold_value, 70)
966
921
  layout.addLayout(thresh_hbox)
967
922
 
968
- # #invert_layout = QHBoxLayout()
969
- # self.invert_check = QCheckBox('invert')
970
- # self.invert_value_le = QLineEdit('65535')
971
- # self.invert_value_le.setValidator(self.onlyFloat)
972
- # layout.addWidget(self.invert_check, 6, 0)
973
- # layout.addWidget(self.invert_value_le, 6, 1)
974
- # #layout.addLayout(invert_layout, 5, 1, 1, 1)
975
-
976
923
  self.spot_detection_widgets = [self.spot_channel,
977
924
  self.spot_channel_lbl,
978
925
  self.diameter_value,
@@ -12,7 +12,7 @@ from celldetective.gui.viewers import CellSizeViewer, CellEdgeVisualizer
12
12
  from celldetective.gui import CelldetectiveWidget
13
13
 
14
14
 
15
- class ConfigNeighborhoods(CelldetectiveWidget):
15
+ class SettingsNeighborhood(CelldetectiveWidget):
16
16
 
17
17
  """
18
18
  Widget to configure neighborhood measurements.
@@ -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()