celldetective 1.3.4__tar.gz → 1.3.5__tar.gz

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 (114) hide show
  1. {celldetective-1.3.4 → celldetective-1.3.5}/PKG-INFO +2 -2
  2. celldetective-1.3.5/celldetective/_version.py +1 -0
  3. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/events.py +10 -5
  4. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/classifier_widget.py +29 -4
  5. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/control_panel.py +3 -2
  6. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/generic_signal_plot.py +2 -6
  7. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/gui_utils.py +34 -6
  8. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/measurement_options.py +1 -30
  9. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/neighborhood_options.py +1 -1
  10. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/plot_signals_ui.py +3 -4
  11. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/process_block.py +8 -6
  12. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/signal_annotator.py +4 -2
  13. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/signal_annotator2.py +141 -191
  14. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/survival_ui.py +122 -33
  15. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/tableUI.py +26 -12
  16. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/io.py +1059 -156
  17. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/measure.py +151 -53
  18. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/preprocessing.py +2 -2
  19. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/relative_measurements.py +6 -9
  20. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/scripts/measure_cells.py +13 -3
  21. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/scripts/segment_cells.py +0 -1
  22. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/signals.py +10 -7
  23. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/tracking.py +52 -28
  24. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/utils.py +23 -5
  25. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective.egg-info/PKG-INFO +2 -2
  26. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective.egg-info/requires.txt +1 -1
  27. celldetective-1.3.4/celldetective/_version.py +0 -1
  28. {celldetective-1.3.4 → celldetective-1.3.5}/LICENSE +0 -0
  29. {celldetective-1.3.4 → celldetective-1.3.5}/README.md +0 -0
  30. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/__init__.py +0 -0
  31. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/__main__.py +0 -0
  32. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/datasets/segmentation_annotations/blank +0 -0
  33. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/datasets/signal_annotations/blank +0 -0
  34. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/extra_properties.py +0 -0
  35. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/filters.py +0 -0
  36. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/InitWindow.py +0 -0
  37. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/__init__.py +0 -0
  38. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/about.py +0 -0
  39. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/analyze_block.py +0 -0
  40. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/btrack_options.py +0 -0
  41. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/configure_new_exp.py +0 -0
  42. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
  43. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
  44. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/cell-populations.json +0 -0
  45. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/exp-structure.json +0 -0
  46. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/feature-btrack.json +0 -0
  47. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/neighborhood.json +0 -0
  48. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
  49. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/preprocessing.json +0 -0
  50. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/propagate-classification.json +0 -0
  51. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/track-postprocessing.json +0 -0
  52. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/help/tracking.json +0 -0
  53. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/json_readers.py +0 -0
  54. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/layouts.py +0 -0
  55. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/plot_measurements.py +0 -0
  56. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/retrain_segmentation_model_options.py +0 -0
  57. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/retrain_signal_model_options.py +0 -0
  58. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/seg_model_loader.py +0 -0
  59. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/signal_annotator_options.py +0 -0
  60. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/styles.py +0 -0
  61. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/thresholds_gui.py +0 -0
  62. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/gui/viewers.py +0 -0
  63. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/icons/logo-large.png +0 -0
  64. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/icons/logo.png +0 -0
  65. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/icons/signals_icon.png +0 -0
  66. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/icons/splash-test.png +0 -0
  67. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/icons/splash.png +0 -0
  68. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/icons/splash0.png +0 -0
  69. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/icons/survival2.png +0 -0
  70. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/icons/vignette_signals2.png +0 -0
  71. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/icons/vignette_signals2.svg +0 -0
  72. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/links/zenodo.json +0 -0
  73. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/pair_signal_detection/blank +0 -0
  74. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/blank +0 -0
  75. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -0
  76. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  77. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -0
  78. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -0
  79. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  80. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/segmentation_generic/blank +0 -0
  81. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/segmentation_targets/blank +0 -0
  82. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/signal_detection/blank +0 -0
  83. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/tracking_configs/biased_motion.json +0 -0
  84. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/tracking_configs/mcf7.json +0 -0
  85. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
  86. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/tracking_configs/ricm.json +0 -0
  87. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/models/tracking_configs/ricm2.json +0 -0
  88. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/neighborhood.py +0 -0
  89. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/scripts/analyze_signals.py +0 -0
  90. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/scripts/measure_relative.py +0 -0
  91. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/scripts/segment_cells_thresholds.py +0 -0
  92. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/scripts/track_cells.py +0 -0
  93. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/scripts/train_segmentation_model.py +0 -0
  94. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/scripts/train_signal_model.py +0 -0
  95. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective/segmentation.py +0 -0
  96. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective.egg-info/SOURCES.txt +0 -0
  97. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective.egg-info/dependency_links.txt +0 -0
  98. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective.egg-info/entry_points.txt +0 -0
  99. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective.egg-info/not-zip-safe +0 -0
  100. {celldetective-1.3.4 → celldetective-1.3.5}/celldetective.egg-info/top_level.txt +0 -0
  101. {celldetective-1.3.4 → celldetective-1.3.5}/setup.cfg +0 -0
  102. {celldetective-1.3.4 → celldetective-1.3.5}/setup.py +0 -0
  103. {celldetective-1.3.4 → celldetective-1.3.5}/tests/__init__.py +0 -0
  104. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_events.py +0 -0
  105. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_filters.py +0 -0
  106. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_io.py +0 -0
  107. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_measure.py +0 -0
  108. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_neighborhood.py +0 -0
  109. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_preprocessing.py +0 -0
  110. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_qt.py +0 -0
  111. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_segmentation.py +0 -0
  112. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_signals.py +0 -0
  113. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_tracking.py +0 -0
  114. {celldetective-1.3.4 → celldetective-1.3.5}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: celldetective
3
- Version: 1.3.4
3
+ Version: 1.3.5
4
4
  Summary: description
5
5
  Home-page: http://github.com/remyeltorro/celldetective
6
6
  Author: Rémy Torro
@@ -20,7 +20,7 @@ Requires-Dist: cellpose<3
20
20
  Requires-Dist: scikit-learn
21
21
  Requires-Dist: btrack
22
22
  Requires-Dist: tensorflow~=2.15.0
23
- Requires-Dist: napari
23
+ Requires-Dist: napari<0.6.0
24
24
  Requires-Dist: tqdm
25
25
  Requires-Dist: mahotas
26
26
  Requires-Dist: fonticon-materialdesignicons6
@@ -0,0 +1 @@
1
+ __version__ = "1.3.5"
@@ -143,7 +143,7 @@ def switch_to_events(classes, event_times, max_times, origin_times=None, left_ce
143
143
  survival_times = [s*FrameToMin for s in survival_times]
144
144
  return events, survival_times
145
145
 
146
- def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMin=1, cut_observation_time=None):
146
+ def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMin=1, cut_observation_time=None, pairs=False):
147
147
 
148
148
  """
149
149
  Computes survival analysis for a specific class of interest within a dataset, returning a fitted Kaplan-Meier
@@ -190,9 +190,14 @@ def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMi
190
190
  assert t_event in cols,"The event time cannot be found in the dataframe..."
191
191
  left_censored = False
192
192
 
193
- classes = df.groupby(['position','TRACK_ID'])[class_of_interest].min().values
194
- event_times = df.groupby(['position','TRACK_ID'])[t_event].min().values
195
- max_times = df.groupby(['position','TRACK_ID'])['FRAME'].max().values
193
+ if not pairs:
194
+ groupby_cols = ['position','TRACK_ID']
195
+ else:
196
+ groupby_cols = ['position','REFERENCE_ID','NEIGHBOR_ID']
197
+
198
+ classes = df.groupby(groupby_cols)[class_of_interest].min().values
199
+ event_times = df.groupby(groupby_cols)[t_event].min().values
200
+ max_times = df.groupby(groupby_cols)['FRAME'].max().values
196
201
 
197
202
  if t_reference=="0" or t_reference==0:
198
203
  t_reference = None
@@ -202,7 +207,7 @@ def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMi
202
207
  if t_reference is not None:
203
208
  left_censored = True
204
209
  assert t_reference in cols,"The reference time cannot be found in the dataframe..."
205
- first_detections = df.groupby(['position','TRACK_ID'])[t_reference].max().values
210
+ first_detections = df.groupby(groupby_cols)[t_reference].max().values
206
211
 
207
212
  events, survival_times = switch_to_events(classes, event_times, max_times, origin_times=first_detections, left_censored=left_censored, FrameToMin=FrameToMin, cut_observation_time=cut_observation_time)
208
213
  ks = KaplanMeierFitter()
@@ -1,5 +1,5 @@
1
1
  from PyQt5.QtWidgets import QWidget, QLineEdit, QMessageBox, QHBoxLayout, QVBoxLayout, QPushButton, QLabel, \
2
- QCheckBox, QRadioButton, QButtonGroup
2
+ QCheckBox, QRadioButton, QButtonGroup, QComboBox
3
3
  from PyQt5.QtCore import Qt, QSize
4
4
  from superqt import QLabeledSlider,QLabeledDoubleSlider, QSearchableComboBox
5
5
  from superqt.fonticon import icon
@@ -163,6 +163,20 @@ class ClassifierWidget(QWidget, Styles):
163
163
  time_corr_layout.addWidget(self.irreversible_event_btn, 50,alignment=Qt.AlignCenter)
164
164
  layout.addLayout(time_corr_layout)
165
165
 
166
+ self.prereq_event_check = QCheckBox('prerequisite event:')
167
+ self.prereq_event_check.toggled.connect(self.activate_prereq_cb)
168
+ self.prereq_event_cb = QComboBox()
169
+ event_cols = ['--'] + [c.replace('t_','') for c in self.cols if c.startswith('t_')]
170
+ self.prereq_event_cb.addItems(event_cols)
171
+ self.prereq_event_check.setEnabled(False)
172
+ self.prereq_event_cb.setEnabled(False)
173
+
174
+ prereq_layout = QHBoxLayout()
175
+ prereq_layout.addWidget(QLabel(''), 50)
176
+ prereq_layout.addWidget(self.prereq_event_check, 15)
177
+ prereq_layout.addWidget(self.prereq_event_cb, 35)
178
+ layout.addLayout(prereq_layout)
179
+
166
180
  self.r2_slider = QLabeledDoubleSlider()
167
181
  self.r2_slider.setValue(0.75)
168
182
  self.r2_slider.setRange(0,1)
@@ -170,6 +184,7 @@ class ClassifierWidget(QWidget, Styles):
170
184
  self.r2_slider.setOrientation(1)
171
185
  self.r2_label = QLabel('R2 tolerance:')
172
186
  self.r2_label.setToolTip('Minimum R2 between the fit sigmoid and the binary response to the filters to accept the event.')
187
+
173
188
  r2_threshold_layout = QHBoxLayout()
174
189
  r2_threshold_layout.addWidget(QLabel(''), 50)
175
190
  r2_threshold_layout.addWidget(self.r2_label, 15)
@@ -193,6 +208,12 @@ class ClassifierWidget(QWidget, Styles):
193
208
  self.frame_slider.valueChanged.connect(self.set_frame)
194
209
  self.alpha_slider.valueChanged.connect(self.set_transparency)
195
210
 
211
+ def activate_prereq_cb(self):
212
+ if self.prereq_event_check.isChecked():
213
+ self.prereq_event_cb.setEnabled(True)
214
+ else:
215
+ self.prereq_event_cb.setEnabled(False)
216
+
196
217
  def activate_submit_btn(self):
197
218
 
198
219
  if self.property_query_le.text()=='':
@@ -204,10 +225,10 @@ class ClassifierWidget(QWidget, Styles):
204
225
 
205
226
  def activate_r2(self):
206
227
  if self.irreversible_event_btn.isChecked() and self.time_corr.isChecked():
207
- for wg in [self.r2_slider, self.r2_label]:
228
+ for wg in [self.r2_slider, self.r2_label, self.prereq_event_check]:
208
229
  wg.setEnabled(True)
209
230
  else:
210
- for wg in [self.r2_slider, self.r2_label]:
231
+ for wg in [self.r2_slider, self.r2_label, self.prereq_event_check]:
211
232
  wg.setEnabled(False)
212
233
 
213
234
  def activate_time_corr_options(self):
@@ -416,7 +437,11 @@ class ClassifierWidget(QWidget, Styles):
416
437
  self.df = self.df.drop(list(set(name_map.values()) & set(self.df.columns)), axis=1).rename(columns=name_map)
417
438
  self.df.reset_index(inplace=True, drop=True)
418
439
 
419
- 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(), r2_threshold=self.r2_slider.value())
440
+ pre_event = None
441
+ if self.prereq_event_check.isChecked() and "t_"+self.prereq_event_cb.currentText() in self.cols:
442
+ pre_event = self.prereq_event_cb.currentText()
443
+
444
+ 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(), r2_threshold=self.r2_slider.value(), pre_event=pre_event)
420
445
 
421
446
  else:
422
447
  self.group_name_user = 'group_' + self.name_le.text()
@@ -93,6 +93,9 @@ class ControlPanel(QMainWindow, Styles):
93
93
  self.screen_width = desktop.screenGeometry().width()
94
94
  self.scroll.setMinimumWidth(440)
95
95
 
96
+ self.well_list.setCurrentIndex(0)
97
+ #self.position_list.setCurrentIndex(0)
98
+
96
99
  def init_wells_and_positions(self):
97
100
 
98
101
  """
@@ -151,10 +154,8 @@ class ControlPanel(QMainWindow, Styles):
151
154
  #self.locate_selected_position()
152
155
 
153
156
  self.well_list.activated.connect(self.display_positions)
154
- self.well_list.setCurrentIndex(0)
155
157
 
156
158
  self.position_list.activated.connect(self.update_position_options)
157
- self.position_list.setCurrentIndex(0)
158
159
 
159
160
  self.view_stack_btn = QPushButton()
160
161
  self.view_stack_btn.setStyleSheet(self.button_select_all)
@@ -62,6 +62,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
62
62
  self.setLayout(self.layout)
63
63
  self.setAttribute(Qt.WA_DeleteOnClose)
64
64
 
65
+
65
66
  def populate_widget(self):
66
67
 
67
68
  self.plot_options = [QRadioButton() for i in range(3)]
@@ -221,18 +222,13 @@ class GenericSignalPlotWidget(QWidget, Styles):
221
222
  self.alpha_slider = QLabeledDoubleSlider()
222
223
  alpha_hbox = QuickSliderLayout(label='single-cell\nsignal alpha: ',
223
224
  slider=self.alpha_slider,
224
- slider_initial_value=0.8,
225
+ slider_initial_value=self.alpha_setting,
225
226
  slider_range=(0,1),
226
227
  decimal_option=True,
227
228
  precision=1.0E-05,
228
229
  )
229
230
  self.alpha_slider.valueChanged.connect(self.submit_alpha)
230
231
  self.cell_lines_alpha_wdg.setLayout(alpha_hbox)
231
-
232
- # self.submit_alpha_btn = QPushButton('submit')
233
- # self.submit_alpha_btn.setStyleSheet(self.button_style_sheet_2)
234
- # self.submit_alpha_btn.clicked.connect(self.submit_alpha)
235
- # alpha_hbox.addWidget(self.submit_alpha_btn, 10)
236
232
  self.layout.addWidget(self.cell_lines_alpha_wdg)
237
233
 
238
234
  self.select_option = [QRadioButton() for i in range(2)]
@@ -1,7 +1,7 @@
1
1
  import numpy as np
2
2
  from PyQt5.QtWidgets import QApplication, QMessageBox, QFrame, QSizePolicy, QWidget, QLineEdit, QListWidget, QVBoxLayout, QComboBox, \
3
3
  QPushButton, QLabel, QHBoxLayout, QCheckBox, QFileDialog, QToolButton, QMenu, QStylePainter, QStyleOptionComboBox, QStyle
4
- from PyQt5.QtCore import Qt, QSize, QAbstractTableModel
4
+ from PyQt5.QtCore import Qt, QSize, QAbstractTableModel, QEvent, pyqtSignal
5
5
  from PyQt5.QtGui import QDoubleValidator, QIntValidator, QStandardItemModel, QPalette
6
6
 
7
7
  from celldetective.gui import Styles
@@ -23,12 +23,13 @@ class QCheckableComboBox(QComboBox):
23
23
  adapted from https://stackoverflow.com/questions/22775095/pyqt-how-to-set-combobox-items-be-checkable
24
24
  """
25
25
 
26
+ activated = pyqtSignal(str)
27
+
26
28
  def __init__(self, obj='', parent_window=None, *args, **kwargs):
27
29
 
28
30
  super().__init__(parent_window, *args, **kwargs)
29
31
 
30
32
  self.setTitle('')
31
- self.view().pressed.connect(self.handleItemPressed)
32
33
  self.setModel(QStandardItemModel(self))
33
34
  self.obj = obj
34
35
  self.toolButton = QToolButton(parent_window)
@@ -38,6 +39,9 @@ class QCheckableComboBox(QComboBox):
38
39
  self.toolButton.setPopupMode(QToolButton.InstantPopup)
39
40
  self.anySelected = False
40
41
 
42
+ self.view().viewport().installEventFilter(self)
43
+ self.view().pressed.connect(self.handleItemPressed)
44
+
41
45
  def clear(self):
42
46
 
43
47
  self.unselectAll()
@@ -70,6 +74,8 @@ class QCheckableComboBox(QComboBox):
70
74
  elif len(options_checked[options_checked])==0:
71
75
  self.setTitle(f"No {self.obj} selected...")
72
76
  self.anySelected = False
77
+
78
+ self.activated.emit(self.title())
73
79
 
74
80
  def setCurrentIndex(self, index):
75
81
 
@@ -101,6 +107,7 @@ class QCheckableComboBox(QComboBox):
101
107
 
102
108
  def setTitle(self, title):
103
109
  self._title = title
110
+ self.update()
104
111
  self.repaint()
105
112
 
106
113
  def paintEvent(self, event):
@@ -155,7 +162,12 @@ class QCheckableComboBox(QComboBox):
155
162
 
156
163
  def isAnySelected(self):
157
164
  return not self.title().startswith('No')
158
-
165
+
166
+ def eventFilter(self, source, event):
167
+ if source is self.view().viewport():
168
+ if event.type() == QEvent.MouseButtonRelease:
169
+ return True # Prevent the popup from closing
170
+ return super().eventFilter(source, event)
159
171
 
160
172
  class PandasModel(QAbstractTableModel):
161
173
 
@@ -503,7 +515,11 @@ class FilterChoice(QWidget):
503
515
  self.combo_box.currentTextChanged.connect(self.update_arguments)
504
516
  layout.addWidget(self.combo_box)
505
517
 
518
+ self.floatValidator = QDoubleValidator()
506
519
  self.arguments_le = [QLineEdit() for i in range(3)]
520
+ for i in range(3):
521
+ self.arguments_le[i].setValidator(self.floatValidator)
522
+
507
523
  self.arguments_labels = [QLabel('') for i in range(3)]
508
524
  for i in range(2):
509
525
  hbox = QHBoxLayout()
@@ -525,8 +541,10 @@ class FilterChoice(QWidget):
525
541
 
526
542
  filter_instructions = [filtername.split('_')[0]]
527
543
  for a in self.arguments_le:
528
- arg = a.text()
544
+
545
+ arg = a.text().replace(',','.')
529
546
  arg_num = arg
547
+
530
548
  if (arg != '') and arg_num.replace('.', '').replace(',', '').isnumeric():
531
549
  num = float(arg)
532
550
  if num.is_integer():
@@ -666,12 +684,14 @@ class DistanceChoice(QWidget):
666
684
  super().__init__()
667
685
  self.parent_window = parent_window
668
686
  self.setWindowTitle("Set distances")
687
+ self.floatValidator = QDoubleValidator()
669
688
  center_window(self)
670
689
 
671
690
  # Create the QComboBox and add some items
672
691
 
673
692
  self.dist_label = QLabel('Distance [px]: ')
674
693
  self.dist_le = QLineEdit('10')
694
+ self.dist_le.setValidator(self.floatValidator)
675
695
 
676
696
  self.add_btn = QPushButton("Add")
677
697
  self.add_btn.clicked.connect(self.add_current_feature)
@@ -686,7 +706,7 @@ class DistanceChoice(QWidget):
686
706
  layout.addWidget(self.add_btn)
687
707
 
688
708
  def add_current_feature(self):
689
- value = self.dist_le.text()
709
+ value = self.dist_le.text().replace(',','.')
690
710
  values = [value]
691
711
  self.parent_window.list_widget.addItems(values)
692
712
  self.close()
@@ -827,13 +847,21 @@ class FigureCanvas(QWidget):
827
847
  if interactive:
828
848
  self.toolbar = NavigationToolbar2QT(self.canvas)
829
849
  self.layout = QVBoxLayout(self)
830
- self.layout.addWidget(self.canvas)
850
+ self.layout.addWidget(self.canvas,90)
831
851
  if interactive:
832
852
  self.layout.addWidget(self.toolbar)
833
853
 
834
854
  center_window(self)
835
855
  self.setAttribute(Qt.WA_DeleteOnClose)
836
856
 
857
+ def resizeEvent(self, event):
858
+
859
+ super().resizeEvent(event)
860
+ try:
861
+ self.fig.tight_layout()
862
+ except:
863
+ pass
864
+
837
865
  def draw(self):
838
866
  self.canvas.draw()
839
867
 
@@ -261,7 +261,7 @@ class ConfigMeasurements(QMainWindow, Styles):
261
261
  self.add_feature_btn.setToolTip("Add feature")
262
262
  self.add_feature_btn.setIconSize(QSize(20, 20))
263
263
 
264
- self.features_list = ListWidget(FeatureChoice, initial_features=['area', 'intensity_nanmean', ])
264
+ self.features_list = ListWidget(FeatureChoice, initial_features=['area', 'intensity_mean', ])
265
265
 
266
266
  self.del_feature_btn.clicked.connect(self.features_list.removeSel)
267
267
  self.add_feature_btn.clicked.connect(self.features_list.addItem)
@@ -313,25 +313,6 @@ class ConfigMeasurements(QMainWindow, Styles):
313
313
 
314
314
  self.feat_sep3 = QHSeperationLine()
315
315
  layout.addWidget(self.feat_sep3)
316
- # self.radial_intensity_btn = QCheckBox('Measure radial intensity distribution')
317
- # layout.addWidget(self.radial_intensity_btn)
318
- # self.radial_intensity_btn.clicked.connect(self.enable_step_size)
319
- # self.channel_chechkboxes=[]
320
- # for channel in self.channel_names:
321
- # channel_checkbox=QCheckBox(channel)
322
- # self.channel_chechkboxes.append(channel_checkbox)
323
- # layout.addWidget(channel_checkbox)
324
- # channel_checkbox.setEnabled(False)
325
- # step_box=QHBoxLayout()
326
- # self.step_lbl=QLabel("Step size (in px)")
327
- # self.step_size=QLineEdit()
328
- # self.step_lbl.setEnabled(False)
329
- # self.step_size.setEnabled(False)
330
- # step_box.addWidget(self.step_lbl)
331
- # step_box.addWidget(self.step_size)
332
- # layout.addLayout(step_box)
333
- # self.feat_sep4 = QHSeperationLine()
334
- # layout.addWidget(self.feat_sep4)
335
316
 
336
317
  # Haralick features parameters
337
318
  self.activate_haralick_btn = QCheckBox('Measure Haralick texture features')
@@ -511,16 +492,6 @@ class ConfigMeasurements(QMainWindow, Styles):
511
492
  if not border_distances:
512
493
  border_distances = None
513
494
  measurement_options.update({'border_distances': border_distances})
514
- # radial_intensity = {}
515
- # radial_step = int(self.step_size.text())
516
- # radial_channels = []
517
- # for checkbox in self.channel_chechkboxes:
518
- # if checkbox.isChecked():
519
- # radial_channels.append(checkbox.text())
520
- # radial_intensity={'radial_step': radial_step, 'radial_channels': radial_channels}
521
- # if not self.radial_intensity_btn.isChecked():
522
- # radial_intensity = None
523
- # measurement_options.update({'radial_intensity' : radial_intensity})
524
495
 
525
496
  self.extract_haralick_options()
526
497
  measurement_options.update({'haralick_options': self.haralick_options})
@@ -174,7 +174,7 @@ class ConfigNeighborhoods(QWidget, Styles):
174
174
  self.attr_parent.locate_image()
175
175
  if self.attr_parent.current_stack is not None:
176
176
  self.viewer = CellEdgeVisualizer(
177
- cell_type='effectors',
177
+ cell_type=self.reference_population_cb.currentText(),
178
178
  edge_range=(1,30),
179
179
  invert=True,
180
180
  initial_edge=3,
@@ -19,6 +19,7 @@ import pandas as pd
19
19
  import math
20
20
  from celldetective.gui import Styles
21
21
  from matplotlib import colormaps
22
+ import matplotlib.cm
22
23
 
23
24
 
24
25
  class ConfigSignalPlot(QWidget, Styles):
@@ -110,10 +111,8 @@ class ConfigSignalPlot(QWidget, Styles):
110
111
 
111
112
  all_cms = list(colormaps)
112
113
  for cm in all_cms:
113
- try:
114
- self.cbs[-1].addColormap(cm)
115
- except:
116
- pass
114
+ if hasattr(matplotlib.cm, str(cm).lower()):
115
+ self.cbs[-1].addColormap(cm.lower())
117
116
 
118
117
  self.cbs[0].setCurrentIndex(1)
119
118
  self.cbs[0].setCurrentIndex(0)
@@ -9,7 +9,7 @@ from PyQt5.QtGui import QDoubleValidator, QIntValidator
9
9
  from celldetective.gui.signal_annotator import MeasureAnnotator
10
10
  from celldetective.gui.signal_annotator2 import SignalAnnotator2
11
11
  from celldetective.io import get_segmentation_models_list, control_segmentation_napari, get_signal_models_list, \
12
- control_tracking_btrack, load_experiment_tables, get_pair_signal_models_list
12
+ control_tracks, load_experiment_tables, get_pair_signal_models_list
13
13
  from celldetective.io import locate_segmentation_model, fix_missing_labels, auto_load_number_of_frames, load_frames, locate_signal_model
14
14
  from celldetective.gui import SegmentationModelLoader, ClassifierWidget, ConfigNeighborhoods, ConfigSegmentationModelTraining, ConfigTracking, SignalAnnotator, ConfigSignalModelTraining, ConfigMeasurements, ConfigSignalAnnotator, TableUI
15
15
  from celldetective.gui.gui_utils import QHSeperationLine
@@ -291,7 +291,7 @@ class ProcessPanel(QFrame, Styles):
291
291
  self.track_action.setStyleSheet(self.menu_check_style)
292
292
  self.track_action.setIcon(icon(MDI6.chart_timeline_variant,color="black"))
293
293
  self.track_action.setIconSize(QSize(20, 20))
294
- self.track_action.setToolTip("Track the target cells using bTrack.")
294
+ self.track_action.setToolTip(f"Track the {self.mode[:-1]} cells.")
295
295
  grid_track.addWidget(self.track_action, 75)
296
296
 
297
297
  self.delete_tracks_btn = QPushButton()
@@ -307,7 +307,7 @@ class ProcessPanel(QFrame, Styles):
307
307
  self.check_tracking_result_btn = QPushButton()
308
308
  self.check_tracking_result_btn.setIcon(icon(MDI6.eye_check_outline,color="black"))
309
309
  self.check_tracking_result_btn.setIconSize(QSize(20, 20))
310
- self.check_tracking_result_btn.setToolTip("View raw bTrack output in napari.")
310
+ self.check_tracking_result_btn.setToolTip("View tracking output in napari.")
311
311
  self.check_tracking_result_btn.setStyleSheet(self.button_select_all)
312
312
  self.check_tracking_result_btn.clicked.connect(self.open_napari_tracking)
313
313
  self.check_tracking_result_btn.setEnabled(False)
@@ -845,14 +845,16 @@ class ProcessPanel(QFrame, Styles):
845
845
 
846
846
  # self.stack = None
847
847
  self.parent_window.update_position_options()
848
- if self.segment_action.isChecked():
849
- self.segment_action.setChecked(False)
848
+
849
+ for action in [self.segment_action, self.track_action, self.measure_action, self.signal_analysis_action]:
850
+ if action.isChecked():
851
+ action.setChecked(False)
850
852
 
851
853
  self.cellpose_calibrated = False
852
854
 
853
855
  def open_napari_tracking(self):
854
856
  print(f'View the tracks before post-processing for position {self.parent_window.pos} in napari...')
855
- control_tracking_btrack(self.parent_window.pos, prefix=self.parent_window.movie_prefix, population=self.mode, threads=self.parent_window.parent_window.n_threads)
857
+ control_tracks(self.parent_window.pos, prefix=self.parent_window.movie_prefix, population=self.mode, threads=self.parent_window.parent_window.n_threads)
856
858
 
857
859
  def view_table_ui(self):
858
860
 
@@ -457,8 +457,10 @@ class SignalAnnotator(QMainWindow, Styles):
457
457
  cols = np.array(self.df_tracks.columns)
458
458
  self.class_cols = np.array([c.startswith('class') for c in list(self.df_tracks.columns)])
459
459
  self.class_cols = list(cols[self.class_cols])
460
- self.class_cols.remove('class_id')
461
- self.class_cols.remove('class_color')
460
+ if 'class_id' in self.class_cols:
461
+ self.class_cols.remove('class_id')
462
+ if 'class_color' in self.class_cols:
463
+ self.class_cols.remove('class_color')
462
464
  self.class_choice_cb.addItems(self.class_cols)
463
465
  idx = self.class_choice_cb.findText(self.target_class)
464
466
  self.class_choice_cb.setCurrentIndex(idx)