celldetective 1.3.2__py3-none-any.whl → 1.3.4__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 (41) hide show
  1. celldetective/__main__.py +30 -4
  2. celldetective/_version.py +1 -1
  3. celldetective/extra_properties.py +21 -0
  4. celldetective/filters.py +15 -2
  5. celldetective/gui/InitWindow.py +28 -34
  6. celldetective/gui/analyze_block.py +3 -498
  7. celldetective/gui/classifier_widget.py +1 -1
  8. celldetective/gui/control_panel.py +100 -29
  9. celldetective/gui/generic_signal_plot.py +35 -18
  10. celldetective/gui/gui_utils.py +143 -2
  11. celldetective/gui/layouts.py +7 -6
  12. celldetective/gui/measurement_options.py +38 -43
  13. celldetective/gui/plot_measurements.py +5 -13
  14. celldetective/gui/plot_signals_ui.py +30 -30
  15. celldetective/gui/process_block.py +66 -197
  16. celldetective/gui/retrain_segmentation_model_options.py +3 -1
  17. celldetective/gui/signal_annotator.py +50 -32
  18. celldetective/gui/signal_annotator2.py +7 -4
  19. celldetective/gui/styles.py +13 -0
  20. celldetective/gui/survival_ui.py +8 -21
  21. celldetective/gui/tableUI.py +1 -2
  22. celldetective/gui/thresholds_gui.py +195 -205
  23. celldetective/gui/viewers.py +262 -12
  24. celldetective/io.py +85 -11
  25. celldetective/measure.py +128 -88
  26. celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +79 -0
  27. celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  28. celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +37 -0
  29. celldetective/models/segmentation_effectors/test-transfer/config_input.json +39 -0
  30. celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  31. celldetective/neighborhood.py +0 -2
  32. celldetective/scripts/measure_cells.py +21 -9
  33. celldetective/signals.py +77 -66
  34. celldetective/tracking.py +19 -13
  35. {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/METADATA +12 -10
  36. {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/RECORD +41 -36
  37. {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/WHEEL +1 -1
  38. tests/test_qt.py +5 -3
  39. {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/LICENSE +0 -0
  40. {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/entry_points.txt +0 -0
  41. {celldetective-1.3.2.dist-info → celldetective-1.3.4.dist-info}/top_level.txt +0 -0
@@ -10,7 +10,7 @@ from superqt import QLabeledDoubleSlider
10
10
  from superqt.fonticon import icon
11
11
  from fonticon_mdi6 import MDI6
12
12
 
13
- from celldetective.gui.thresholds_gui import ThresholdSpot
13
+ #from celldetective.gui.thresholds_gui import ThresholdSpot
14
14
  from celldetective.utils import extract_experiment_channels, get_software_location
15
15
  from celldetective.io import load_frames, auto_load_number_of_frames
16
16
  from celldetective.measure import compute_haralick_features
@@ -24,9 +24,8 @@ from glob import glob
24
24
  from natsort import natsorted
25
25
  from tifffile import imread
26
26
  from pathlib import Path
27
- import gc
28
27
 
29
- from celldetective.gui.viewers import CellEdgeVisualizer
28
+ from celldetective.gui.viewers import CellEdgeVisualizer, SpotDetectionVisualizer
30
29
  from celldetective.gui.layouts import ProtocolDesignerLayout, BackgroundFitCorrectionLayout, LocalCorrectionLayout
31
30
  from celldetective.gui.gui_utils import ThresholdLineEdit
32
31
  from celldetective.gui import Styles
@@ -726,18 +725,10 @@ class ConfigMeasurements(QMainWindow, Styles):
726
725
  else:
727
726
  self.current_stack = movies[0]
728
727
  self.stack_length = auto_load_number_of_frames(self.current_stack)
729
-
730
- if self.stack_length is None:
731
- stack = imread(self.current_stack)
732
- self.stack_length = len(stack)
733
- del stack
734
- gc.collect()
735
-
736
728
  self.mid_time = self.stack_length // 2
737
- indices = self.mid_time + np.arange(len(self.channel_names))
729
+ indices = len(self.channel_names) * self.mid_time + np.arange(len(self.channel_names))
738
730
  self.test_frame = load_frames(list(indices.astype(int)),self.current_stack, normalize_input=False)
739
731
 
740
-
741
732
  def control_haralick_digitalization(self):
742
733
 
743
734
  """
@@ -746,9 +737,10 @@ class ConfigMeasurements(QMainWindow, Styles):
746
737
 
747
738
  """
748
739
 
749
- self.locate_image()
740
+ self.locate_image() # pb here
750
741
  self.extract_haralick_options()
751
742
  if self.test_frame is not None:
743
+
752
744
  digitized_img = compute_haralick_features(self.test_frame, np.zeros(self.test_frame.shape[:2]),
753
745
  channels=self.channel_names, return_digit_image_only=True,
754
746
  **self.haralick_options
@@ -951,51 +943,54 @@ class ConfigMeasurements(QMainWindow, Styles):
951
943
 
952
944
  layout.addWidget(self.threshold_lbl, 4, 0)
953
945
  layout.addWidget(self.threshold_value, 4, 1)
954
- self.preview_spot = QPushButton('Preview')
955
- self.preview_spot.clicked.connect(self.spot_preview)
956
- self.preview_spot.setStyleSheet(self.button_style_sheet_2)
957
- layout.addWidget(self.preview_spot, 5, 0, 1, 2)
958
- self.spot_channel.setEnabled(False)
959
- self.spot_channel_lbl.setEnabled(False)
960
- self.diameter_value.setEnabled(False)
961
- self.diameter_lbl.setEnabled(False)
962
- self.threshold_value.setEnabled(False)
963
- self.threshold_lbl.setEnabled(False)
964
- self.preview_spot.setEnabled(False)
965
946
 
947
+ self.spot_viewer_btn = QPushButton()
948
+ self.spot_viewer_btn.clicked.connect(self.spot_preview)
949
+ self.spot_viewer_btn.setIcon(icon(MDI6.image_check, color="k"))
950
+ self.spot_viewer_btn.setStyleSheet(self.button_select_all)
951
+ self.spot_viewer_btn.setToolTip('Set detection parameters visually.')
952
+ layout.addWidget(self.spot_viewer_btn, 1, 1, 1, 1, alignment=Qt.AlignRight)
953
+
954
+ self.spot_detection_widgets = [self.spot_channel, self.spot_channel_lbl, self.diameter_value, self.diameter_lbl, self.threshold_value, self.threshold_lbl, self.spot_viewer_btn]
955
+ for wg in self.spot_detection_widgets:
956
+ wg.setEnabled(False)
966
957
 
967
958
  def enable_spot_preview(self):
968
959
 
969
960
  diam = self.diameter_value.text().replace(',','').replace('.','')
970
961
  thresh = self.threshold_value.text().replace(',','').replace('.','')
971
962
  if diam.isnumeric() and thresh.isnumeric():
972
- self.preview_spot.setEnabled(True)
963
+ self.spot_viewer_btn.setEnabled(True)
973
964
  else:
974
- self.preview_spot.setEnabled(False)
965
+ self.spot_viewer_btn.setEnabled(False)
975
966
 
976
967
  def spot_preview(self):
977
968
  self.locate_image()
978
969
  if self.test_frame is not None:
979
970
  self.locate_mask()
980
971
  if self.test_mask is not None:
981
- self.spot_visual = ThresholdSpot(current_channel=self.spot_channel.currentIndex(), img=self.test_frame,
982
- mask=self.test_mask, parent_window=self)
972
+ self.spot_visual = SpotDetectionVisualizer(frame_slider=True,
973
+ contrast_slider=True,
974
+ cell_type=self.mode,
975
+ channel_cb=True,
976
+ channel_names = self.channel_names,
977
+ stack_path=self.current_stack,
978
+ n_channels=len(self.channel_names),
979
+ target_channel=self.spot_channel.currentIndex(),
980
+ window_title='Detect spots',
981
+ parent_channel_cb=self.spot_channel,
982
+ parent_diameter_le=self.diameter_value,
983
+ parent_threshold_le=self.threshold_value,
984
+ PxToUm = 1,)
985
+ self.spot_visual.show()
986
+ #self.spot_visual = ThresholdSpot(current_channel=self.spot_channel.currentIndex(), img=self.test_frame,
987
+ # mask=self.test_mask, parent_window=self)
983
988
 
984
989
  def enable_spot_detection(self):
985
- if self.spot_check.isChecked():
986
- self.spot_channel.setEnabled(True)
987
- self.spot_channel_lbl.setEnabled(True)
988
- self.diameter_value.setEnabled(True)
989
- self.diameter_lbl.setEnabled(True)
990
- self.threshold_value.setEnabled(True)
991
- self.threshold_lbl.setEnabled(True)
992
- self.preview_spot.setEnabled(True)
993
990
 
991
+ if self.spot_check.isChecked():
992
+ for wg in self.spot_detection_widgets:
993
+ wg.setEnabled(True)
994
994
  else:
995
- self.spot_channel.setEnabled(False)
996
- self.spot_channel_lbl.setEnabled(False)
997
- self.diameter_value.setEnabled(False)
998
- self.diameter_lbl.setEnabled(False)
999
- self.threshold_value.setEnabled(False)
1000
- self.threshold_lbl.setEnabled(False)
1001
- self.preview_spot.setEnabled(False)
995
+ for wg in self.spot_detection_widgets:
996
+ wg.setEnabled(False)
@@ -56,8 +56,8 @@ class ConfigMeasurementsPlot(QWidget,Styles):
56
56
 
57
57
  print('Parent wells: ', self.wells)
58
58
 
59
- self.well_option = self.parent_window.parent_window.well_list.currentIndex()
60
- self.position_option = self.parent_window.parent_window.position_list.currentIndex()
59
+ self.well_option = self.parent_window.parent_window.well_list.getSelectedIndices()
60
+ self.position_option = self.parent_window.parent_window.position_list.getSelectedIndices()
61
61
  self.interpret_pos_location()
62
62
  # self.load_available_tables()
63
63
  # self.config_path = self.exp_dir + self.config_name
@@ -526,18 +526,10 @@ class ConfigMeasurementsPlot(QWidget,Styles):
526
526
 
527
527
  """
528
528
 
529
- self.well_option = self.parent_window.parent_window.well_list.currentIndex()
530
- if self.well_option == len(self.wells):
531
- wo = '*'
532
- else:
533
- wo = self.well_option
534
- self.position_option = self.parent_window.parent_window.position_list.currentIndex()
535
- if self.position_option == 0:
536
- po = '*'
537
- else:
538
- po = self.position_option - 1
529
+ self.well_option = self.parent_window.parent_window.well_list.getSelectedIndices()
530
+ self.position_option = self.parent_window.parent_window.position_list.getSelectedIndices()
539
531
 
540
- self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=wo, position_option=po,
532
+ self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=self.well_option, position_option=self.position_option,
541
533
  population=self.cbs[0].currentText(), return_pos_info=True)
542
534
 
543
535
  if self.df is None:
@@ -47,8 +47,8 @@ class ConfigSignalPlot(QWidget, Styles):
47
47
  self.ax2=None
48
48
  self.auto_close = False
49
49
 
50
- self.well_option = self.parent_window.parent_window.well_list.currentIndex()
51
- self.position_option = self.parent_window.parent_window.position_list.currentIndex()
50
+ self.well_option = self.parent_window.parent_window.well_list.getSelectedIndices()
51
+ self.position_option = self.parent_window.parent_window.position_list.getSelectedIndices()
52
52
  self.interpret_pos_location()
53
53
 
54
54
  self.screen_height = self.parent_window.parent_window.parent_window.screen_height
@@ -67,15 +67,11 @@ class ConfigSignalPlot(QWidget, Styles):
67
67
 
68
68
  """
69
69
 
70
- if self.well_option==len(self.wells):
71
- self.well_indices = np.arange(len(self.wells))
72
- else:
73
- self.well_indices = np.array([self.well_option],dtype=int)
74
-
75
- if self.position_option==0:
70
+ self.well_indices = self.parent_window.parent_window.well_list.getSelectedIndices()
71
+ self.position_indices = self.parent_window.parent_window.position_list.getSelectedIndices()
72
+ if not self.parent_window.parent_window.position_list.isAnySelected():
76
73
  self.position_indices = None
77
- else:
78
- self.position_indices = np.array([self.position_option],dtype=int)
74
+
79
75
 
80
76
  def populate_widget(self):
81
77
 
@@ -188,11 +184,21 @@ class ConfigSignalPlot(QWidget, Styles):
188
184
  if 't0' in self.all_columns:
189
185
  time_columns.append('t0')
190
186
 
187
+ self.class_columns = np.unique(class_columns)
188
+ self.time_columns = np.unique(time_columns)
189
+ thresh = 18
190
+ self.class_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.class_columns]
191
+ self.time_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.time_columns]
192
+
191
193
  self.cbs[2].clear()
192
- self.cbs[2].addItems(np.unique(self.cb_options[2]+time_columns))
194
+ self.cbs[2].addItems(self.time_truncated)
195
+ for i in range(len(self.time_columns)):
196
+ self.cbs[2].setItemData(i, self.time_columns[i], Qt.ToolTipRole)
193
197
 
194
198
  self.cbs[1].clear()
195
- self.cbs[1].addItems(np.unique(self.cb_options[1]+class_columns))
199
+ self.cbs[1].addItems(self.class_truncated)
200
+ for i in range(len(self.class_columns)):
201
+ self.cbs[1].setItemData(i, self.class_columns[i], Qt.ToolTipRole)
196
202
 
197
203
  def ask_for_feature(self):
198
204
 
@@ -273,7 +279,8 @@ class ConfigSignalPlot(QWidget, Styles):
273
279
 
274
280
  # read instructions from combobox options
275
281
  self.load_available_tables()
276
- class_col = self.cbs[1].currentText()
282
+ class_col = self.class_columns[self.cbs[1].currentIndex()]
283
+ print(f"{class_col=}")
277
284
 
278
285
  if self.df is not None:
279
286
 
@@ -300,18 +307,10 @@ class ConfigSignalPlot(QWidget, Styles):
300
307
 
301
308
  """
302
309
 
303
- self.well_option = self.parent_window.parent_window.well_list.currentIndex()
304
- if self.well_option==len(self.wells):
305
- wo = '*'
306
- else:
307
- wo = self.well_option
308
- self.position_option = self.parent_window.parent_window.position_list.currentIndex()
309
- if self.position_option==0:
310
- po = '*'
311
- else:
312
- po = self.position_option - 1
310
+ self.well_option = self.parent_window.parent_window.well_list.getSelectedIndices()
311
+ self.position_option = self.parent_window.parent_window.position_list.getSelectedIndices()
313
312
 
314
- self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=wo, position_option=po, population=self.cbs[0].currentText(), return_pos_info=True)
313
+ self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=self.well_option, position_option=self.position_option, population=self.cbs[0].currentText(), return_pos_info=True)
315
314
 
316
315
  if self.df is None:
317
316
 
@@ -337,8 +336,8 @@ class ConfigSignalPlot(QWidget, Styles):
337
336
 
338
337
  # Per position signal
339
338
  max_time = int(self.df.FRAME.max()) + 1
340
- class_col = self.cbs[1].currentText()
341
- time_col = self.cbs[2].currentText()
339
+ class_col = self.class_columns[self.cbs[1].currentIndex()]
340
+ time_col = self.time_columns[self.cbs[2].currentIndex()]
342
341
  if self.abs_time_checkbox.isChecked():
343
342
  time_col = self.frame_slider.value()
344
343
 
@@ -375,6 +374,9 @@ class ConfigSignalPlot(QWidget, Styles):
375
374
  if isinstance(cclass,int):
376
375
  cclass = [cclass]
377
376
 
377
+ class_col = self.class_columns[self.cbs[1].currentIndex()]
378
+ time_col = self.time_columns[self.cbs[2].currentIndex()]
379
+
378
380
  n_cells = len(well_group.groupby(['position','TRACK_ID']))
379
381
  depth = int(2*max_time + 3)
380
382
  matrix = np.zeros((n_cells, depth))
@@ -382,14 +384,14 @@ class ConfigSignalPlot(QWidget, Styles):
382
384
  mapping = np.arange(-max_time-1, max_time+2)
383
385
  cid=0
384
386
  for block,movie_group in well_group.groupby('position'):
385
- for tid,track_group in movie_group.loc[movie_group[self.cbs[1].currentText()].isin(cclass)].groupby('TRACK_ID'):
387
+ for tid,track_group in movie_group.loc[movie_group[class_col].isin(cclass)].groupby('TRACK_ID'):
386
388
  try:
387
389
  timeline = track_group['FRAME'].to_numpy().astype(int)
388
390
  feature = track_group[feature_selected].to_numpy()
389
391
  if self.checkBox_feature.isChecked():
390
392
  second_feature=track_group[self.second_feature_selected].to_numpy()
391
393
  if self.cbs[2].currentText().startswith('t') and not self.abs_time_checkbox.isChecked():
392
- t0 = math.floor(track_group[self.cbs[2].currentText()].to_numpy()[0])
394
+ t0 = math.floor(track_group[time_col].to_numpy()[0])
393
395
  timeline -= t0
394
396
  elif self.cbs[2].currentText()=='first detection' and not self.abs_time_checkbox.isChecked():
395
397
 
@@ -401,7 +403,6 @@ class ConfigSignalPlot(QWidget, Styles):
401
403
 
402
404
  first_detection = timeline[feat==feat][0]
403
405
  timeline -= first_detection
404
- print(first_detection, timeline)
405
406
 
406
407
  elif self.abs_time_checkbox.isChecked():
407
408
  timeline -= int(self.frame_slider.value())
@@ -410,7 +411,6 @@ class ConfigSignalPlot(QWidget, Styles):
410
411
  matrix[cid,loc_t] = feature
411
412
  if second_feature:
412
413
  matrix[cid,loc_t+1]=second_feature
413
- print(timeline, loc_t)
414
414
 
415
415
  cid+=1
416
416
  except: