celldetective 1.3.9.post5__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 +132 -0
  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 +68 -81
  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 +125 -72
  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 +129 -70
  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 +57 -20
  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.post5.dist-info → celldetective-1.4.0.dist-info}/METADATA +24 -16
  52. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/RECORD +57 -55
  53. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/WHEEL +1 -1
  54. tests/test_qt.py +21 -21
  55. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/entry_points.txt +0 -0
  56. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info/licenses}/LICENSE +0 -0
  57. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,9 @@
1
- from PyQt5.QtWidgets import QRadioButton, QButtonGroup, QMainWindow, QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QTextEdit, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
1
+ from PyQt5.QtWidgets import QRadioButton, QButtonGroup, QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QTextEdit, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
2
2
  from PyQt5.QtCore import Qt, QSize
3
3
  from PyQt5.QtGui import QDoubleValidator
4
4
 
5
5
  from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, help_generic
6
- from superqt import QLabeledDoubleSlider,QLabeledSlider
6
+ from superqt import QLabeledDoubleSlider, QLabeledSlider
7
7
  from superqt.fonticon import icon
8
8
  from fonticon_mdi6 import MDI6
9
9
  from celldetective.utils import extract_experiment_channels, get_software_location
@@ -16,9 +16,10 @@ import os
16
16
  import matplotlib.pyplot as plt
17
17
  from mpl_toolkits.axes_grid1 import make_axes_locatable
18
18
  from glob import glob
19
- from celldetective.gui import Styles
19
+ from celldetective.gui import CelldetectiveWidget, CelldetectiveMainWindow
20
20
 
21
- class ConfigTracking(QMainWindow, Styles):
21
+
22
+ class ConfigTracking(CelldetectiveMainWindow):
22
23
 
23
24
  """
24
25
  UI to set tracking parameters for bTrack.
@@ -34,15 +35,10 @@ class ConfigTracking(QMainWindow, Styles):
34
35
  self.exp_dir = self.parent_window.exp_dir
35
36
  self.floatValidator = QDoubleValidator()
36
37
 
37
- if self.mode=="targets":
38
- self.config_name = os.sep.join(["configs", "btrack_config_targets.json"])
39
- self.track_instructions_write_path = self.parent_window.exp_dir + os.sep.join(["configs","tracking_instructions_targets.json"])
40
- elif self.mode=="effectors":
41
- self.config_name = os.sep.join(["configs","btrack_config_effectors.json"])
42
- self.track_instructions_write_path = self.parent_window.exp_dir + os.sep.join(["configs", "tracking_instructions_effectors.json"])
38
+ self.config_name = os.sep.join(["configs", f"btrack_config_{self.mode}.json"])
39
+ self.track_instructions_write_path = self.parent_window.exp_dir + os.sep.join(["configs", f"tracking_instructions_{self.mode}.json"])
43
40
  self.soft_path = get_software_location()
44
41
 
45
- exp_config = self.exp_dir +"config.ini"
46
42
  self.config_path = self.exp_dir + self.config_name
47
43
  self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
48
44
  self.channel_names = np.array(self.channel_names)
@@ -66,10 +62,10 @@ class ConfigTracking(QMainWindow, Styles):
66
62
 
67
63
  # Create button widget and layout
68
64
  self.scroll_area = QScrollArea(self)
69
- self.button_widget = QWidget()
65
+ self.button_widget = CelldetectiveWidget()
70
66
  main_layout = QVBoxLayout()
71
67
  self.button_widget.setLayout(main_layout)
72
- main_layout.setContentsMargins(30,30,30,30)
68
+ main_layout.setContentsMargins(30, 30, 30, 30)
73
69
 
74
70
  # First collapsable Frame CONFIG
75
71
 
@@ -86,7 +82,7 @@ class ConfigTracking(QMainWindow, Styles):
86
82
  self.populate_config_frame()
87
83
 
88
84
  tracker_hbox = QHBoxLayout()
89
- tracker_hbox.setContentsMargins(15,15,15,15)
85
+ tracker_hbox.setContentsMargins(15, 15, 15, 15)
90
86
  tracker_hbox.addWidget(self.btrack_option, 50, alignment=Qt.AlignCenter)
91
87
  tracker_hbox.addWidget(self.trackpy_option, 50, alignment=Qt.AlignCenter)
92
88
  main_layout.addLayout(tracker_hbox)
@@ -149,7 +145,6 @@ class ConfigTracking(QMainWindow, Styles):
149
145
  #self.scroll_area.setMinimumHeight(self.minimum_height)
150
146
  #self.adjustSize()
151
147
 
152
-
153
148
  def populate_post_proc_frame(self):
154
149
 
155
150
  """
@@ -172,13 +167,13 @@ class ConfigTracking(QMainWindow, Styles):
172
167
  title_hbox = QHBoxLayout()
173
168
 
174
169
  self.collapse_post_proc_btn = QPushButton()
175
- self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down,color="black"))
170
+ self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down, color="black"))
176
171
  self.collapse_post_proc_btn.setIconSize(QSize(20, 20))
177
172
  self.collapse_post_proc_btn.setStyleSheet(self.button_select_all)
178
173
  #grid.addWidget(self.collapse_post_proc_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
179
174
 
180
175
  self.help_post_btn = QPushButton()
181
- self.help_post_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
176
+ self.help_post_btn.setIcon(icon(MDI6.help_circle, color=self.help_color))
182
177
  self.help_post_btn.setIconSize(QSize(20, 20))
183
178
  self.help_post_btn.clicked.connect(self.help_post)
184
179
  self.help_post_btn.setStyleSheet(self.button_select_all)
@@ -188,7 +183,7 @@ class ConfigTracking(QMainWindow, Styles):
188
183
  title_hbox.addWidget(QLabel(), 85, alignment=Qt.AlignCenter)
189
184
  title_hbox.addWidget(self.help_post_btn, 5)
190
185
  title_hbox.addWidget(self.collapse_post_proc_btn, 5)
191
- grid.addLayout(title_hbox, 0,0,1,4)
186
+ grid.addLayout(title_hbox, 0, 0, 1, 4)
192
187
 
193
188
  self.generate_post_proc_panel_contents()
194
189
  grid.addWidget(self.ContentsPostProc, 1, 0, 1, 4, alignment=Qt.AlignTop)
@@ -205,13 +200,13 @@ class ConfigTracking(QMainWindow, Styles):
205
200
  is_open = np.array([features_open, config_open, post_open])
206
201
 
207
202
  if self.ContentsPostProc.isHidden():
208
- self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down,color="black"))
203
+ self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_down, color="black"))
209
204
  self.collapse_post_proc_btn.setIconSize(QSize(20, 20))
210
205
  if len(is_open[is_open])==0:
211
206
  self.scroll_area.setMinimumHeight(int(self.minimum_height))
212
207
  self.adjustSize()
213
208
  else:
214
- self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_up,color="black"))
209
+ self.collapse_post_proc_btn.setIcon(icon(MDI6.chevron_up, color="black"))
215
210
  self.collapse_post_proc_btn.setIconSize(QSize(20, 20))
216
211
  self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
217
212
 
@@ -222,7 +217,7 @@ class ConfigTracking(QMainWindow, Styles):
222
217
  Helper for track post-processing strategy.
223
218
  """
224
219
 
225
- dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','track-postprocessing.json'])
220
+ dict_path = os.sep.join([get_software_location(), 'celldetective', 'gui', 'help', 'track-postprocessing.json'])
226
221
 
227
222
  with open(dict_path) as f:
228
223
  d = json.load(f)
@@ -246,7 +241,7 @@ class ConfigTracking(QMainWindow, Styles):
246
241
  Helper for track post-processing strategy.
247
242
  """
248
243
 
249
- dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','feature-btrack.json'])
244
+ dict_path = os.sep.join([get_software_location(), 'celldetective', 'gui', 'help', 'feature-btrack.json'])
250
245
 
251
246
  with open(dict_path) as f:
252
247
  d = json.load(f)
@@ -300,7 +295,7 @@ class ConfigTracking(QMainWindow, Styles):
300
295
  title_hbox.addWidget(QLabel(), 85, alignment=Qt.AlignCenter)
301
296
  title_hbox.addWidget(self.help_feature_btn, 5)
302
297
  title_hbox.addWidget(self.collapse_features_btn, 5)
303
- grid.addLayout(title_hbox, 0,0,1,4)
298
+ grid.addLayout(title_hbox, 0, 0, 1, 4)
304
299
 
305
300
  self.generate_feature_panel_contents()
306
301
  grid.addWidget(self.ContentsFeatures, 1, 0, 1, 4, alignment=Qt.AlignTop)
@@ -321,13 +316,13 @@ class ConfigTracking(QMainWindow, Styles):
321
316
  is_open = np.array([features_open, config_open, post_open])
322
317
 
323
318
  if self.ContentsFeatures.isHidden():
324
- self.collapse_features_btn.setIcon(icon(MDI6.chevron_down,color="black"))
319
+ self.collapse_features_btn.setIcon(icon(MDI6.chevron_down, color="black"))
325
320
  self.collapse_features_btn.setIconSize(QSize(20, 20))
326
321
  if len(is_open[is_open])==0:
327
322
  self.scroll_area.setMinimumHeight(int(self.minimum_height))
328
323
  self.adjustSize()
329
324
  else:
330
- self.collapse_features_btn.setIcon(icon(MDI6.chevron_up,color="black"))
325
+ self.collapse_features_btn.setIcon(icon(MDI6.chevron_up, color="black"))
331
326
  self.collapse_features_btn.setIconSize(QSize(20, 20))
332
327
  self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
333
328
 
@@ -351,7 +346,7 @@ class ConfigTracking(QMainWindow, Styles):
351
346
  self.min_tracklength_slider.setSingleStep(1)
352
347
  self.min_tracklength_slider.setTickInterval(1)
353
348
  self.min_tracklength_slider.setSingleStep(1)
354
- self.min_tracklength_slider.setOrientation(1)
349
+ self.min_tracklength_slider.setOrientation(Qt.Horizontal)
355
350
  self.min_tracklength_slider.setRange(0,self.parent_window.parent_window.len_movie)
356
351
  self.min_tracklength_slider.setValue(0)
357
352
  tracklength_layout.addWidget(QLabel('Min. tracklength: '),40)
@@ -391,7 +386,6 @@ class ConfigTracking(QMainWindow, Styles):
391
386
 
392
387
  layout.addLayout(clean_traj_sublayout)
393
388
 
394
-
395
389
  def generate_feature_panel_contents(self):
396
390
 
397
391
  self.ContentsFeatures = QFrame()
@@ -456,10 +450,9 @@ class ConfigTracking(QMainWindow, Styles):
456
450
 
457
451
  # Slider to set vmin & vmax
458
452
  self.haralick_scale_slider = QLabeledDoubleSlider()
459
- self.haralick_scale_slider.setSingleStep(0.05)
460
453
  self.haralick_scale_slider.setTickInterval(0.05)
461
454
  self.haralick_scale_slider.setSingleStep(1)
462
- self.haralick_scale_slider.setOrientation(1)
455
+ self.haralick_scale_slider.setOrientation(Qt.Horizontal)
463
456
  self.haralick_scale_slider.setRange(0,1)
464
457
  self.haralick_scale_slider.setValue(0.5)
465
458
  self.haralick_scale_lbl = QLabel('Scale: ')
@@ -671,7 +664,7 @@ class ConfigTracking(QMainWindow, Styles):
671
664
  self.memory_slider.setSingleStep(1)
672
665
  self.memory_slider.setTickInterval(1)
673
666
  self.memory_slider.setSingleStep(1)
674
- self.memory_slider.setOrientation(1)
667
+ self.memory_slider.setOrientation(Qt.Horizontal)
675
668
  self.memory_slider.setRange(0,self.parent_window.parent_window.len_movie)
676
669
  self.memory_slider.setValue(0)
677
670
  memory_layout.addWidget(self.memory_lbl, 30)
@@ -745,7 +738,7 @@ class ConfigTracking(QMainWindow, Styles):
745
738
  copyfile(self.filename, self.config_path)
746
739
  self.load_cell_config()
747
740
  except Exception as e:
748
- print(e, modelpath)
741
+ print(e)
749
742
  return None
750
743
 
751
744
  def reset_btrack_config(self):
@@ -994,7 +987,7 @@ class ConfigTracking(QMainWindow, Styles):
994
987
  if 'search_range' in tracking_instructions:
995
988
  search_range = tracking_instructions['search_range']
996
989
  if search_range is not None:
997
- self.search_range_le.setText(str(search_range).replace('.',','))
990
+ self.search_range_le.setText(str(search_range).replace('.', ','))
998
991
  if 'memory' in tracking_instructions:
999
992
  memory = tracking_instructions['memory']
1000
993
  if memory is not None:
@@ -1072,7 +1065,7 @@ class ConfigTracking(QMainWindow, Styles):
1072
1065
  Load the first frame of the first movie found in the experiment folder as a sample.
1073
1066
  """
1074
1067
 
1075
- movies = glob(self.parent_window.parent_window.exp_dir + os.sep.join(["*","*","movie",self.parent_window.parent_window.movie_prefix+"*.tif"]))
1068
+ movies = glob(self.parent_window.parent_window.exp_dir + os.sep.join(["*", "*", "movie", self.parent_window.parent_window.movie_prefix+"*.tif"]))
1076
1069
  if len(movies)==0:
1077
1070
  msgBox = QMessageBox()
1078
1071
  msgBox.setIcon(QMessageBox.Warning)
@@ -1088,7 +1081,6 @@ class ConfigTracking(QMainWindow, Styles):
1088
1081
  n_channels = len(self.channels)
1089
1082
  self.test_frame = load_frames(np.arange(n_channels), stack0, scale=None, normalize_input=False)
1090
1083
 
1091
-
1092
1084
  def control_haralick_digitalization(self):
1093
1085
 
1094
1086
  """
@@ -1,7 +1,7 @@
1
- from PyQt5.QtWidgets import QWidget, QLineEdit, QMessageBox, QHBoxLayout, QVBoxLayout, QPushButton, QLabel, \
1
+ from PyQt5.QtWidgets import QLineEdit, QMessageBox, QHBoxLayout, QVBoxLayout, QPushButton, QLabel, \
2
2
  QCheckBox, QRadioButton, QButtonGroup, QComboBox
3
3
  from PyQt5.QtCore import Qt, QSize
4
- from superqt import QLabeledSlider,QLabeledDoubleSlider, QSearchableComboBox
4
+ from superqt import QLabeledSlider, QLabeledDoubleSlider, QSearchableComboBox
5
5
  from superqt.fonticon import icon
6
6
  from fonticon_mdi6 import MDI6
7
7
 
@@ -11,11 +11,11 @@ import matplotlib.pyplot as plt
11
11
  import json
12
12
 
13
13
  from celldetective.gui.gui_utils import FigureCanvas, center_window, color_from_status, help_generic
14
- from celldetective.gui import Styles
14
+ from celldetective.gui.base_components import CelldetectiveWidget
15
15
  from celldetective.utils import get_software_location
16
16
  from celldetective.measure import classify_cells_from_query, interpret_track_classification
17
17
 
18
- class ClassifierWidget(QWidget, Styles):
18
+ class ClassifierWidget(CelldetectiveWidget):
19
19
 
20
20
  def __init__(self, parent_window):
21
21
 
@@ -33,7 +33,7 @@ class ClassifierWidget(QWidget, Styles):
33
33
 
34
34
  is_number = np.vectorize(lambda x: np.issubdtype(x, np.number))
35
35
  is_number_test = is_number(self.df.dtypes)
36
- self.cols = [col for t,col in zip(is_number_test,self.df.columns) if t]
36
+ self.cols = [col for t, col in zip(is_number_test, self.df.columns) if t]
37
37
 
38
38
  self.class_name = 'custom'
39
39
  self.name_le = QLineEdit(self.class_name)
@@ -44,7 +44,7 @@ class ClassifierWidget(QWidget, Styles):
44
44
 
45
45
 
46
46
  layout = QVBoxLayout(self)
47
- layout.setContentsMargins(30,30,30,30)
47
+ layout.setContentsMargins(30, 30, 30, 30)
48
48
 
49
49
  name_layout = QHBoxLayout()
50
50
  name_layout.addWidget(QLabel('class name: '), 33)
@@ -55,7 +55,7 @@ class ClassifierWidget(QWidget, Styles):
55
55
  fig_btn_hbox.addWidget(QLabel(''), 95)
56
56
  self.project_times_btn = QPushButton('')
57
57
  self.project_times_btn.setStyleSheet(self.parent_window.parent_window.parent_window.button_select_all)
58
- self.project_times_btn.setIcon(icon(MDI6.math_integral,color="black"))
58
+ self.project_times_btn.setIcon(icon(MDI6.math_integral, color="black"))
59
59
  self.project_times_btn.setToolTip("Project measurements at all times.")
60
60
  self.project_times_btn.setIconSize(QSize(20, 20))
61
61
  self.project_times = False
@@ -70,8 +70,8 @@ class ClassifierWidget(QWidget, Styles):
70
70
  # slider
71
71
  self.frame_slider = QLabeledSlider()
72
72
  self.frame_slider.setSingleStep(1)
73
- self.frame_slider.setOrientation(1)
74
- self.frame_slider.setRange(0,int(self.df.FRAME.max()) - 1)
73
+ self.frame_slider.setOrientation(Qt.Horizontal)
74
+ self.frame_slider.setRange(0, int(self.df.FRAME.max()) - 1)
75
75
  self.frame_slider.setValue(0)
76
76
  self.currentFrame = 0
77
77
 
@@ -84,8 +84,8 @@ class ClassifierWidget(QWidget, Styles):
84
84
  # transparency slider
85
85
  self.alpha_slider = QLabeledDoubleSlider()
86
86
  self.alpha_slider.setSingleStep(0.001)
87
- self.alpha_slider.setOrientation(1)
88
- self.alpha_slider.setRange(0,1)
87
+ self.alpha_slider.setOrientation(Qt.Horizontal)
88
+ self.alpha_slider.setRange(0, 1)
89
89
  self.alpha_slider.setValue(1.0)
90
90
  self.alpha_slider.setDecimals(3)
91
91
 
@@ -95,8 +95,8 @@ class ClassifierWidget(QWidget, Styles):
95
95
  layout.addLayout(slider_alpha_hbox)
96
96
 
97
97
 
98
- self.features_cb = [QSearchableComboBox() for i in range(2)]
99
- self.log_btns = [QPushButton() for i in range(2)]
98
+ self.features_cb = [QSearchableComboBox() for _ in range(2)]
99
+ self.log_btns = [QPushButton() for _ in range(2)]
100
100
 
101
101
  for i in range(2):
102
102
  hbox_feat = QHBoxLayout()
@@ -106,7 +106,7 @@ class ClassifierWidget(QWidget, Styles):
106
106
  layout.addLayout(hbox_feat)
107
107
 
108
108
  self.features_cb[i].clear()
109
- self.features_cb[i].addItems(sorted(list(self.cols),key=str.lower))
109
+ self.features_cb[i].addItems(sorted(list(self.cols), key=str.lower))
110
110
  self.features_cb[i].currentTextChanged.connect(self.update_props_scatter)
111
111
  self.features_cb[i].setCurrentIndex(i)
112
112
 
@@ -134,15 +134,15 @@ class ClassifierWidget(QWidget, Styles):
134
134
  self.time_corr.setEnabled(False)
135
135
 
136
136
  time_prop_hbox = QHBoxLayout()
137
- time_prop_hbox.addWidget(self.time_corr,alignment=Qt.AlignCenter)
137
+ time_prop_hbox.addWidget(self.time_corr, alignment=Qt.AlignCenter)
138
138
 
139
139
  self.help_propagate_btn = QPushButton()
140
- self.help_propagate_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
140
+ self.help_propagate_btn.setIcon(icon(MDI6.help_circle, color=self.help_color))
141
141
  self.help_propagate_btn.setIconSize(QSize(20, 20))
142
142
  self.help_propagate_btn.clicked.connect(self.help_propagate)
143
143
  self.help_propagate_btn.setStyleSheet(self.button_select_all)
144
144
  self.help_propagate_btn.setToolTip("Help.")
145
- time_prop_hbox.addWidget(self.help_propagate_btn,5,alignment=Qt.AlignRight)
145
+ time_prop_hbox.addWidget(self.help_propagate_btn, 5, alignment=Qt.AlignRight)
146
146
 
147
147
  layout.addLayout(time_prop_hbox)
148
148
 
@@ -154,23 +154,23 @@ class ClassifierWidget(QWidget, Styles):
154
154
 
155
155
  time_corr_layout = QHBoxLayout()
156
156
  time_corr_layout.addWidget(self.unique_state_btn, 33, alignment=Qt.AlignCenter)
157
- time_corr_layout.addWidget(self.irreversible_event_btn, 33,alignment=Qt.AlignCenter)
158
- time_corr_layout.addWidget(self.transient_event_btn, 33,alignment=Qt.AlignCenter)
157
+ time_corr_layout.addWidget(self.irreversible_event_btn, 33, alignment=Qt.AlignCenter)
158
+ time_corr_layout.addWidget(self.transient_event_btn, 33, alignment=Qt.AlignCenter)
159
159
  layout.addLayout(time_corr_layout)
160
160
 
161
161
  self.prereq_event_check = QCheckBox('prerequisite event:')
162
162
  self.prereq_event_check.toggled.connect(self.activate_prereq_cb)
163
163
  self.prereq_event_cb = QComboBox()
164
- event_cols = ['--'] + [c.replace('t_','') for c in self.cols if c.startswith('t_')]
164
+ event_cols = ['--'] + [c.replace('t_', '') for c in self.cols if c.startswith('t_')]
165
165
  self.prereq_event_cb.addItems(event_cols)
166
166
  self.prereq_event_check.setEnabled(False)
167
167
  self.prereq_event_cb.setEnabled(False)
168
168
 
169
169
  self.r2_slider = QLabeledDoubleSlider()
170
170
  self.r2_slider.setValue(0.75)
171
- self.r2_slider.setRange(0,1)
171
+ self.r2_slider.setRange(0, 1)
172
172
  self.r2_slider.setSingleStep(0.01)
173
- self.r2_slider.setOrientation(1)
173
+ self.r2_slider.setOrientation(Qt.Horizontal)
174
174
  self.r2_label = QLabel('R2 tolerance:')
175
175
  self.r2_label.setToolTip('Minimum R2 between the fit sigmoid and the binary response to the filters to accept the event.')
176
176
 
@@ -196,7 +196,7 @@ class ClassifierWidget(QWidget, Styles):
196
196
  wg.setEnabled(False)
197
197
 
198
198
  prereq_layout = QHBoxLayout()
199
- prereq_layout.setContentsMargins(30,0,0,0)
199
+ prereq_layout.setContentsMargins(30, 0, 0, 0)
200
200
  prereq_layout.addWidget(self.prereq_event_check, 20)
201
201
  prereq_layout.addWidget(self.prereq_event_cb, 80)
202
202
  layout.addLayout(prereq_layout)
@@ -212,7 +212,6 @@ class ClassifierWidget(QWidget, Styles):
212
212
  self.frame_slider.valueChanged.connect(self.set_frame)
213
213
  self.alpha_slider.valueChanged.connect(self.set_transparency)
214
214
 
215
- self.setAttribute(Qt.WA_DeleteOnClose)
216
215
 
217
216
  def activate_prereq_cb(self):
218
217
  if self.prereq_event_check.isChecked():
@@ -270,11 +269,10 @@ class ClassifierWidget(QWidget, Styles):
270
269
  Define properties scatter.
271
270
  """
272
271
 
273
- self.fig_props, self.ax_props = plt.subplots(figsize=(4,4),tight_layout=True)
272
+ self.fig_props, self.ax_props = plt.subplots(figsize=(4, 4), tight_layout=True)
274
273
  self.propscanvas = FigureCanvas(self.fig_props, interactive=True)
275
274
  self.fig_props.set_facecolor('none')
276
- self.fig_props.canvas.setStyleSheet("background-color: transparent;")
277
- self.scat_props = self.ax_props.scatter([],[], color="k", alpha=self.currentAlpha)
275
+ self.scat_props = self.ax_props.scatter([], [], color="k", alpha=self.currentAlpha)
278
276
  self.propscanvas.canvas.draw_idle()
279
277
  self.propscanvas.canvas.setMinimumHeight(self.screen_height//5)
280
278
 
@@ -295,25 +293,24 @@ class ClassifierWidget(QWidget, Styles):
295
293
  self.log_btns[0].setEnabled(True)
296
294
 
297
295
  if np.any(self.df[self.features_cb[1].currentText()].to_numpy() <= 0.):
298
- if self.ax_props.get_xscale()=='log':
296
+ if self.ax_props.get_xscale() == 'log':
299
297
  self.log_btns[1].click()
300
298
  self.log_btns[1].setEnabled(False)
301
299
  else:
302
300
  self.log_btns[1].setEnabled(True)
303
301
  except Exception as e:
304
- #print(e)
305
- pass
302
+ print(e)
306
303
 
307
304
  class_name = self.class_name
308
305
 
309
306
  try:
310
307
 
311
308
  if not self.project_times:
312
- self.scat_props.set_offsets(self.df.loc[self.df['FRAME']==self.currentFrame,[self.features_cb[1].currentText(),self.features_cb[0].currentText()]].to_numpy())
313
- colors = [color_from_status(c) for c in self.df.loc[self.df['FRAME']==self.currentFrame,class_name].to_numpy()]
309
+ self.scat_props.set_offsets(self.df.loc[self.df['FRAME'] == self.currentFrame, [self.features_cb[1].currentText(), self.features_cb[0].currentText()]].to_numpy())
310
+ colors = [color_from_status(c) for c in self.df.loc[self.df['FRAME'] == self.currentFrame, class_name].to_numpy()]
314
311
  self.scat_props.set_facecolor(colors)
315
312
  else:
316
- self.scat_props.set_offsets(self.df[[self.features_cb[1].currentText(),self.features_cb[0].currentText()]].to_numpy())
313
+ self.scat_props.set_offsets(self.df[[self.features_cb[1].currentText(), self.features_cb[0].currentText()]].to_numpy())
317
314
  colors = [color_from_status(c) for c in self.df[class_name].to_numpy()]
318
315
  self.scat_props.set_facecolor(colors)
319
316
 
@@ -333,18 +330,18 @@ class ClassifierWidget(QWidget, Styles):
333
330
 
334
331
  x_padding = (max_x - min_x) * 0.05
335
332
  y_padding = (max_y - min_y) * 0.05
336
- if x_padding==0:
333
+ if x_padding == 0:
337
334
  x_padding = 0.05
338
- if y_padding==0:
335
+ if y_padding == 0:
339
336
  y_padding = 0.05
340
337
 
341
- if min_x==min_x and max_x==max_x:
342
- if self.ax_props.get_xscale()=='linear':
338
+ if min_x == min_x and max_x == max_x:
339
+ if self.ax_props.get_xscale() == 'linear':
343
340
  self.ax_props.set_xlim(min_x - x_padding, max_x + x_padding)
344
341
  else:
345
342
  self.ax_props.set_xlim(min_x, max_x)
346
- if min_y==min_y and max_y==max_y:
347
- if self.ax_props.get_yscale()=='linear':
343
+ if min_y == min_y and max_y == max_y:
344
+ if self.ax_props.get_yscale() == 'linear':
348
345
  self.ax_props.set_ylim(min_y - y_padding, max_y + y_padding)
349
346
  else:
350
347
  self.ax_props.set_ylim(min_y, max_y)
@@ -379,7 +376,7 @@ class ClassifierWidget(QWidget, Styles):
379
376
  if self.df is None:
380
377
  msgBox = QMessageBox()
381
378
  msgBox.setIcon(QMessageBox.Warning)
382
- msgBox.setText(f"The query could not be understood. No filtering was applied. {e}")
379
+ msgBox.setText(f"The query could not be understood. No filtering was applied.")
383
380
  msgBox.setWindowTitle("Warning")
384
381
  msgBox.setStandardButtons(QMessageBox.Ok)
385
382
  returnValue = msgBox.exec()
@@ -390,22 +387,18 @@ class ClassifierWidget(QWidget, Styles):
390
387
  self.update_props_scatter(feature_changed=False)
391
388
 
392
389
  def set_frame(self, value):
393
- xlim=self.ax_props.get_xlim()
394
- ylim=self.ax_props.get_ylim()
390
+ xlim = self.ax_props.get_xlim()
391
+ ylim = self.ax_props.get_ylim()
395
392
  self.currentFrame = value
396
393
  self.update_props_scatter(feature_changed=False)
397
394
  self.ax_props.set_xlim(xlim)
398
395
  self.ax_props.set_ylim(ylim)
399
396
 
400
-
401
397
  def set_transparency(self, value):
402
- xlim=self.ax_props.get_xlim()
403
- ylim=self.ax_props.get_ylim()
398
+ xlim = self.ax_props.get_xlim()
399
+ ylim = self.ax_props.get_ylim()
404
400
  self.currentAlpha = value
405
- #fc = self.scat_props.get_facecolors()
406
- #fc[:, 3] = value
407
- #self.scat_props.set_facecolors(fc)
408
- #self.propscanvas.canvas.draw_idle()
401
+
409
402
  self.update_props_scatter(feature_changed=False)
410
403
  self.ax_props.set_xlim(xlim)
411
404
  self.ax_props.set_ylim(ylim)
@@ -413,12 +406,12 @@ class ClassifierWidget(QWidget, Styles):
413
406
  def switch_projection(self):
414
407
  if self.project_times:
415
408
  self.project_times = False
416
- self.project_times_btn.setIcon(icon(MDI6.math_integral,color="black"))
409
+ self.project_times_btn.setIcon(icon(MDI6.math_integral, color="black"))
417
410
  self.project_times_btn.setIconSize(QSize(20, 20))
418
411
  self.frame_slider.setEnabled(True)
419
412
  else:
420
413
  self.project_times = True
421
- self.project_times_btn.setIcon(icon(MDI6.math_integral_box,color="black"))
414
+ self.project_times_btn.setIcon(icon(MDI6.math_integral_box, color="black"))
422
415
  self.project_times_btn.setIconSize(QSize(20, 20))
423
416
  self.frame_slider.setEnabled(False)
424
417
  self.update_props_scatter(feature_changed=False)
@@ -432,12 +425,13 @@ class ClassifierWidget(QWidget, Styles):
432
425
 
433
426
  if self.time_corr.isChecked():
434
427
  self.class_name_user = 'class_'+self.name_le.text()
435
- print(f'User defined class name: {self.class_name_user}.')
428
+ print(f'User defined class name: {self.class_name_user}...')
436
429
  if self.class_name_user in self.df.columns:
437
430
 
438
431
  msgBox = QMessageBox()
439
432
  msgBox.setIcon(QMessageBox.Information)
440
- msgBox.setText(f"The class column {self.class_name_user} already exists in the table.\nProceeding will reclassify. Do you want to continue?")
433
+ msgBox.setText(f"The class column {self.class_name_user} already exists in the table.\nProceeding will "
434
+ f"reclassify. Do you want to continue?")
441
435
  msgBox.setWindowTitle("Warning")
442
436
  msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
443
437
  returnValue = msgBox.exec()
@@ -447,7 +441,6 @@ class ClassifierWidget(QWidget, Styles):
447
441
  return None
448
442
 
449
443
  name_map = {self.class_name: self.class_name_user}
450
- print(f"{name_map=}")
451
444
  self.df = self.df.drop(list(set(name_map.values()) & set(self.df.columns)), axis=1).rename(columns=name_map)
452
445
  self.df.reset_index(inplace=True, drop=True)
453
446
 
@@ -455,7 +448,7 @@ class ClassifierWidget(QWidget, Styles):
455
448
  if self.prereq_event_check.isChecked() and "t_"+self.prereq_event_cb.currentText() in self.cols:
456
449
  pre_event = self.prereq_event_cb.currentText()
457
450
 
458
- self.df = interpret_track_classification(self.df, self.class_name_user, irreversible_event=self.irreversible_event_btn.isChecked(), unique_state=self.unique_state_btn.isChecked(), transient_event=self.transient_event_btn.isChecked(),r2_threshold=self.r2_slider.value(), pre_event=pre_event)
451
+ self.df = interpret_track_classification(self.df, self.class_name_user, irreversible_event=self.irreversible_event_btn.isChecked(), unique_state=self.unique_state_btn.isChecked(), transient_event=self.transient_event_btn.isChecked(), r2_threshold=self.r2_slider.value(), pre_event=pre_event)
459
452
 
460
453
  else:
461
454
  self.group_name_user = 'group_' + self.name_le.text()
@@ -465,7 +458,8 @@ class ClassifierWidget(QWidget, Styles):
465
458
  msgBox = QMessageBox()
466
459
  msgBox.setIcon(QMessageBox.Information)
467
460
  msgBox.setText(
468
- f"The group column {self.group_name_user} already exists in the table.\nProceeding will reclassify. Do you want to continue?")
461
+ f"The group column {self.group_name_user} already exists in the table.\nProceeding will "
462
+ f"reclassify. Do you want to continue?")
469
463
  msgBox.setWindowTitle("Warning")
470
464
  msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
471
465
  returnValue = msgBox.exec()
@@ -477,18 +471,18 @@ class ClassifierWidget(QWidget, Styles):
477
471
  name_map = {self.class_name: self.group_name_user}
478
472
  self.df = self.df.drop(list(set(name_map.values()) & set(self.df.columns)), axis=1).rename(columns=name_map)
479
473
  print(self.df.columns)
480
- #self.df[self.group_name_user] = self.df[self.group_name_user].replace({0: 1, 1: 0})
474
+ # self.df[self.group_name_user] = self.df[self.group_name_user].replace({0: 1, 1: 0})
481
475
  self.df.reset_index(inplace=True, drop=True)
482
476
 
483
477
  if 'custom' in list(self.df.columns):
484
- self.df = self.df.drop(['custom'],axis=1)
478
+ self.df = self.df.drop(['custom'], axis=1)
485
479
 
486
- self.fig_props.set_size_inches(4,3)
480
+ self.fig_props.set_size_inches(4, 3)
487
481
  self.fig_props.suptitle(self.property_query_le.text(), fontsize=10)
488
482
  self.fig_props.tight_layout()
489
- for pos,pos_group in self.df.groupby('position'):
490
- self.fig_props.savefig(pos+os.sep.join(['output',f'{self.class_name}.png']), bbox_inches='tight', dpi=300)
491
- pos_group.to_csv(pos+os.sep.join(['output', 'tables', f'trajectories_{self.mode}.csv']), index=False)
483
+ for pos, pos_group in self.df.groupby('position'):
484
+ self.fig_props.savefig(str(pos)+os.sep.join(['output', f'{self.class_name}.png']), bbox_inches='tight', dpi=300)
485
+ pos_group.to_csv(str(pos)+os.sep.join(['output', 'tables', f'trajectories_{self.mode}.csv']), index=False)
492
486
 
493
487
  self.parent_window.parent_window.update_position_options()
494
488
  self.close()
@@ -500,7 +494,7 @@ class ClassifierWidget(QWidget, Styles):
500
494
  Helper for segmentation strategy between threshold-based and Deep learning.
501
495
  """
502
496
 
503
- dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','propagate-classification.json'])
497
+ dict_path = os.sep.join([get_software_location(), 'celldetective', 'gui', 'help', 'propagate-classification.json'])
504
498
 
505
499
  with open(dict_path) as f:
506
500
  d = json.load(f)
@@ -524,53 +518,46 @@ class ClassifierWidget(QWidget, Styles):
524
518
  Switch threshold histogram to log scale. Auto adjust.
525
519
  """
526
520
 
527
- if i==1:
521
+ if i == 1:
528
522
  try:
529
523
  feat_x = self.features_cb[1].currentText()
530
524
  min_x = self.df.dropna(subset=feat_x)[feat_x].min()
531
525
  max_x = self.df.dropna(subset=feat_x)[feat_x].max()
532
526
  x_padding = (max_x - min_x) * 0.05
533
- if x_padding==0:
527
+ if x_padding == 0:
534
528
  x_padding = 0.05
535
529
 
536
- if self.ax_props.get_xscale()=='linear':
530
+ if self.ax_props.get_xscale() == 'linear':
537
531
  self.ax_props.set_xlim(min_x, max_x)
538
532
  self.ax_props.set_xscale('log')
539
- self.log_btns[i].setIcon(icon(MDI6.math_log,color="#1565c0"))
533
+ self.log_btns[i].setIcon(icon(MDI6.math_log, color="#1565c0"))
540
534
  else:
541
535
  self.ax_props.set_xscale('linear')
542
536
  self.ax_props.set_xlim(min_x - x_padding, max_x + x_padding)
543
- self.log_btns[i].setIcon(icon(MDI6.math_log,color="black"))
537
+ self.log_btns[i].setIcon(icon(MDI6.math_log, color="black"))
544
538
  except Exception as e:
545
539
  print(e)
546
- elif i==0:
540
+ elif i == 0:
547
541
  try:
548
542
  feat_y = self.features_cb[0].currentText()
549
543
  min_y = self.df.dropna(subset=feat_y)[feat_y].min()
550
544
  max_y = self.df.dropna(subset=feat_y)[feat_y].max()
551
545
  y_padding = (max_y - min_y) * 0.05
552
- if y_padding==0:
546
+ if y_padding == 0:
553
547
  y_padding = 0.05
554
548
 
555
- if self.ax_props.get_yscale()=='linear':
549
+ if self.ax_props.get_yscale() == 'linear':
556
550
  self.ax_props.set_ylim(min_y, max_y)
557
551
  self.ax_props.set_yscale('log')
558
- self.log_btns[i].setIcon(icon(MDI6.math_log,color="#1565c0"))
552
+ self.log_btns[i].setIcon(icon(MDI6.math_log, color="#1565c0"))
559
553
  else:
560
554
  self.ax_props.set_yscale('linear')
561
555
  self.ax_props.set_ylim(min_y - y_padding, max_y + y_padding)
562
- self.log_btns[i].setIcon(icon(MDI6.math_log,color="black"))
556
+ self.log_btns[i].setIcon(icon(MDI6.math_log, color="black"))
563
557
  except Exception as e:
564
558
  print(e)
565
559
 
566
560
  self.ax_props.autoscale()
567
561
  self.propscanvas.canvas.draw_idle()
568
562
 
569
- print('Done.')
570
-
571
-
572
-
573
-
574
-
575
-
576
-
563
+ print('Done.')