celldetective 1.3.4.post1__tar.gz → 1.3.6.post1__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.post1 → celldetective-1.3.6.post1}/PKG-INFO +3 -2
  2. celldetective-1.3.6.post1/celldetective/_version.py +1 -0
  3. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/events.py +10 -5
  4. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/filters.py +11 -0
  5. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/btrack_options.py +151 -1
  6. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/classifier_widget.py +44 -15
  7. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/configure_new_exp.py +13 -0
  8. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/control_panel.py +4 -2
  9. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/generic_signal_plot.py +2 -6
  10. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/gui_utils.py +170 -12
  11. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/measurement_options.py +85 -54
  12. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/neighborhood_options.py +1 -1
  13. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/plot_signals_ui.py +3 -4
  14. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/process_block.py +8 -6
  15. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/signal_annotator.py +10 -3
  16. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/signal_annotator2.py +146 -193
  17. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/survival_ui.py +121 -34
  18. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/tableUI.py +26 -12
  19. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/thresholds_gui.py +9 -52
  20. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/viewers.py +58 -21
  21. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/io.py +1087 -161
  22. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/measure.py +175 -102
  23. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/preprocessing.py +2 -2
  24. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/relative_measurements.py +6 -9
  25. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/scripts/measure_cells.py +13 -3
  26. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/scripts/segment_cells.py +0 -1
  27. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/scripts/track_cells.py +25 -1
  28. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/signals.py +9 -7
  29. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/tracking.py +130 -81
  30. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/utils.py +28 -7
  31. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective.egg-info/PKG-INFO +3 -2
  32. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective.egg-info/requires.txt +2 -1
  33. celldetective-1.3.4.post1/celldetective/_version.py +0 -1
  34. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/LICENSE +0 -0
  35. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/README.md +0 -0
  36. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/__init__.py +0 -0
  37. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/__main__.py +0 -0
  38. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/datasets/segmentation_annotations/blank +0 -0
  39. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/datasets/signal_annotations/blank +0 -0
  40. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/extra_properties.py +0 -0
  41. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/InitWindow.py +0 -0
  42. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/__init__.py +0 -0
  43. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/about.py +0 -0
  44. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/analyze_block.py +0 -0
  45. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
  46. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
  47. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/cell-populations.json +0 -0
  48. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/exp-structure.json +0 -0
  49. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/feature-btrack.json +0 -0
  50. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/neighborhood.json +0 -0
  51. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
  52. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/preprocessing.json +0 -0
  53. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/propagate-classification.json +0 -0
  54. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/track-postprocessing.json +0 -0
  55. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/help/tracking.json +0 -0
  56. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/json_readers.py +0 -0
  57. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/layouts.py +0 -0
  58. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/plot_measurements.py +0 -0
  59. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/retrain_segmentation_model_options.py +0 -0
  60. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/retrain_signal_model_options.py +0 -0
  61. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/seg_model_loader.py +0 -0
  62. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/signal_annotator_options.py +0 -0
  63. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/gui/styles.py +0 -0
  64. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/icons/logo-large.png +0 -0
  65. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/icons/logo.png +0 -0
  66. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/icons/signals_icon.png +0 -0
  67. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/icons/splash-test.png +0 -0
  68. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/icons/splash.png +0 -0
  69. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/icons/splash0.png +0 -0
  70. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/icons/survival2.png +0 -0
  71. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/icons/vignette_signals2.png +0 -0
  72. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/icons/vignette_signals2.svg +0 -0
  73. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/links/zenodo.json +0 -0
  74. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/pair_signal_detection/blank +0 -0
  75. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/segmentation_effectors/blank +0 -0
  76. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -0
  77. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  78. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -0
  79. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -0
  80. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  81. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/segmentation_generic/blank +0 -0
  82. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/segmentation_targets/blank +0 -0
  83. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/signal_detection/blank +0 -0
  84. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/tracking_configs/biased_motion.json +0 -0
  85. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/tracking_configs/mcf7.json +0 -0
  86. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
  87. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/tracking_configs/ricm.json +0 -0
  88. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/models/tracking_configs/ricm2.json +0 -0
  89. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/neighborhood.py +0 -0
  90. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/scripts/analyze_signals.py +0 -0
  91. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/scripts/measure_relative.py +0 -0
  92. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/scripts/segment_cells_thresholds.py +0 -0
  93. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/scripts/train_segmentation_model.py +0 -0
  94. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/scripts/train_signal_model.py +0 -0
  95. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective/segmentation.py +0 -0
  96. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective.egg-info/SOURCES.txt +0 -0
  97. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective.egg-info/dependency_links.txt +0 -0
  98. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective.egg-info/entry_points.txt +0 -0
  99. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective.egg-info/not-zip-safe +0 -0
  100. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/celldetective.egg-info/top_level.txt +0 -0
  101. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/setup.cfg +0 -0
  102. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/setup.py +0 -0
  103. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/__init__.py +0 -0
  104. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_events.py +0 -0
  105. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_filters.py +0 -0
  106. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_io.py +0 -0
  107. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_measure.py +0 -0
  108. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_neighborhood.py +0 -0
  109. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_preprocessing.py +0 -0
  110. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_qt.py +0 -0
  111. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_segmentation.py +0 -0
  112. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_signals.py +0 -0
  113. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/tests/test_tracking.py +0 -0
  114. {celldetective-1.3.4.post1 → celldetective-1.3.6.post1}/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.post1
3
+ Version: 1.3.6.post1
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
@@ -42,6 +42,7 @@ Requires-Dist: pytest-qt
42
42
  Requires-Dist: h5py
43
43
  Requires-Dist: cliffs_delta
44
44
  Requires-Dist: requests
45
+ Requires-Dist: trackpy
45
46
 
46
47
  # Celldetective
47
48
 
@@ -0,0 +1 @@
1
+ __version__ = "1.3.6.post1"
@@ -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()
@@ -127,3 +127,14 @@ def tophat_filter(img, size, connectivity=4, interpolate=True, *kwargs):
127
127
  structure = snd.generate_binary_structure(rank=2, connectivity=connectivity)
128
128
  img = snd.white_tophat(img.astype(float), structure=structure, size=size, *kwargs)
129
129
  return img
130
+
131
+ def invert_filter(img, value=65535, *kwargs):
132
+
133
+ img = img.astype(float)
134
+
135
+ image_fill = np.zeros_like(img)
136
+ image_fill[:,:] = value
137
+
138
+ inverted = np.subtract(image_fill, img, where=img==img)
139
+ return inverted
140
+
@@ -1,5 +1,7 @@
1
- from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QTextEdit, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
1
+ from PyQt5.QtWidgets import QRadioButton, QButtonGroup, QMainWindow, QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QTextEdit, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
2
2
  from PyQt5.QtCore import Qt, QSize
3
+ from PyQt5.QtGui import QDoubleValidator
4
+
3
5
  from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, help_generic
4
6
  from superqt import QLabeledDoubleSlider,QLabeledSlider
5
7
  from superqt.fonticon import icon
@@ -30,6 +32,8 @@ class ConfigTracking(QMainWindow, Styles):
30
32
  self.setWindowTitle("Configure tracking")
31
33
  self.mode = self.parent_window.mode
32
34
  self.exp_dir = self.parent_window.exp_dir
35
+ self.floatValidator = QDoubleValidator()
36
+
33
37
  if self.mode=="targets":
34
38
  self.config_name = os.sep.join(["configs", "btrack_config_targets.json"])
35
39
  self.track_instructions_write_path = self.parent_window.exp_dir + os.sep.join(["configs","tracking_instructions_targets.json"])
@@ -68,9 +72,25 @@ class ConfigTracking(QMainWindow, Styles):
68
72
  main_layout.setContentsMargins(30,30,30,30)
69
73
 
70
74
  # First collapsable Frame CONFIG
75
+
76
+ self.btrack_option = QRadioButton('bTrack')
77
+ self.btrack_option.setChecked(True)
78
+
79
+ self.trackpy_option = QRadioButton('trackpy')
80
+ self.tracker_option_group = QButtonGroup()
81
+ self.tracker_option_group.addButton(self.btrack_option)
82
+ self.tracker_option_group.addButton(self.trackpy_option)
83
+
71
84
  self.config_frame = QFrame()
72
85
  self.config_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
73
86
  self.populate_config_frame()
87
+
88
+ tracker_hbox = QHBoxLayout()
89
+ tracker_hbox.setContentsMargins(15,15,15,15)
90
+ tracker_hbox.addWidget(self.btrack_option, 50, alignment=Qt.AlignCenter)
91
+ tracker_hbox.addWidget(self.trackpy_option, 50, alignment=Qt.AlignCenter)
92
+ main_layout.addLayout(tracker_hbox)
93
+
74
94
  main_layout.addWidget(self.config_frame)
75
95
 
76
96
  # Second collapsable frame FEATURES
@@ -79,6 +99,12 @@ class ConfigTracking(QMainWindow, Styles):
79
99
  self.populate_features_frame()
80
100
  main_layout.addWidget(self.features_frame)
81
101
 
102
+ self.config_trackpy_frame = QFrame()
103
+ self.config_trackpy_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
104
+ self.populate_config_trackpy_frame()
105
+ main_layout.addWidget(self.config_trackpy_frame)
106
+ self.config_trackpy_frame.hide()
107
+
82
108
  # Third collapsable frame POST-PROCESSING
83
109
  self.post_proc_frame = QFrame()
84
110
  self.post_proc_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
@@ -102,9 +128,27 @@ class ConfigTracking(QMainWindow, Styles):
102
128
  self.setCentralWidget(self.scroll_area)
103
129
  self.show()
104
130
 
131
+ self.btrack_option.toggled.connect(self.show_tracking_options)
132
+ self.trackpy_option.toggled.connect(self.show_tracking_options)
133
+
105
134
  QApplication.processEvents()
106
135
  self.adjustScrollArea()
107
136
 
137
+ def show_tracking_options(self):
138
+
139
+ if self.btrack_option.isChecked():
140
+ self.config_frame.show()
141
+ self.features_frame.show()
142
+ self.config_trackpy_frame.hide()
143
+ #self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
144
+ #self.adjustSize()
145
+ else:
146
+ self.config_frame.hide()
147
+ self.features_frame.hide()
148
+ self.config_trackpy_frame.show()
149
+ #self.scroll_area.setMinimumHeight(self.minimum_height)
150
+ #self.adjustSize()
151
+
108
152
 
109
153
  def populate_post_proc_frame(self):
110
154
 
@@ -539,6 +583,29 @@ class ConfigTracking(QMainWindow, Styles):
539
583
  self.collapse_config_btn.clicked.connect(self.collapse_config_advanced)
540
584
  #self.ContentsConfig.hide()
541
585
 
586
+ def populate_config_trackpy_frame(self):
587
+
588
+ grid = QGridLayout(self.config_trackpy_frame)
589
+ panel_title = QLabel(f"CONFIGURATION")
590
+ panel_title.setStyleSheet("""
591
+ font-weight: bold;
592
+ padding: 0px;
593
+ """)
594
+
595
+ grid.addWidget(panel_title, 0, 0, 1, 4, alignment=Qt.AlignCenter)
596
+
597
+ self.collapse_config_trackpy_btn = QPushButton()
598
+ self.collapse_config_trackpy_btn.setIcon(icon(MDI6.chevron_down,color="black"))
599
+ self.collapse_config_trackpy_btn.setIconSize(QSize(20, 20))
600
+ self.collapse_config_trackpy_btn.setStyleSheet(self.button_select_all)
601
+ grid.addWidget(self.collapse_config_trackpy_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
602
+ self.generate_config_trackpy_panel_contents()
603
+ grid.addWidget(self.ContentsConfigTrackpy, 1, 0, 1, 4, alignment=Qt.AlignTop)
604
+ self.collapse_config_trackpy_btn.clicked.connect(lambda: self.ContentsConfigTrackpy.setHidden(not self.ContentsConfigTrackpy.isHidden()))
605
+ self.collapse_config_trackpy_btn.clicked.connect(self.collapse_config_trackpy_advanced)
606
+ #self.ContentsConfig.hide()
607
+
608
+
542
609
  def collapse_config_advanced(self):
543
610
 
544
611
  """
@@ -561,6 +628,56 @@ class ConfigTracking(QMainWindow, Styles):
561
628
  self.collapse_config_btn.setIconSize(QSize(20, 20))
562
629
  self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
563
630
 
631
+ def collapse_config_trackpy_advanced(self):
632
+
633
+ """
634
+ Switch the chevron icon and adjust the size for the CONFIG frame.
635
+ """
636
+
637
+
638
+ post_open = not self.ContentsPostProc.isHidden()
639
+ is_open = np.array([post_open])
640
+
641
+ if self.ContentsConfigTrackpy.isHidden():
642
+ self.collapse_config_trackpy_btn.setIcon(icon(MDI6.chevron_down,color="black"))
643
+ self.collapse_config_trackpy_btn.setIconSize(QSize(20, 20))
644
+ if len(is_open[is_open])==0:
645
+ self.scroll_area.setMinimumHeight(int(self.minimum_height))
646
+ self.adjustSize()
647
+ else:
648
+ self.collapse_config_trackpy_btn.setIcon(icon(MDI6.chevron_up,color="black"))
649
+ self.collapse_config_trackpy_btn.setIconSize(QSize(20, 20))
650
+ self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
651
+
652
+
653
+ def generate_config_trackpy_panel_contents(self):
654
+
655
+ self.ContentsConfigTrackpy = QFrame()
656
+ layout = QVBoxLayout(self.ContentsConfigTrackpy)
657
+ layout.setContentsMargins(0,0,0,0)
658
+
659
+ sr_layout = QHBoxLayout()
660
+ self.search_range_lbl = QLabel("search range [px]: ")
661
+ self.search_range_le = QLineEdit('30')
662
+ self.search_range_le.setPlaceholderText('search distance in pixels')
663
+ self.search_range_le.setValidator(self.floatValidator)
664
+ sr_layout.addWidget(self.search_range_lbl, 30)
665
+ sr_layout.addWidget(self.search_range_le, 70)
666
+ layout.addLayout(sr_layout)
667
+
668
+ memory_layout = QHBoxLayout()
669
+ self.memory_lbl = QLabel("memory [# frames]: ")
670
+ self.memory_slider = QLabeledSlider()
671
+ self.memory_slider.setSingleStep(1)
672
+ self.memory_slider.setTickInterval(1)
673
+ self.memory_slider.setSingleStep(1)
674
+ self.memory_slider.setOrientation(1)
675
+ self.memory_slider.setRange(0,self.parent_window.parent_window.len_movie)
676
+ self.memory_slider.setValue(0)
677
+ memory_layout.addWidget(self.memory_lbl, 30)
678
+ memory_layout.addWidget(self.memory_slider, 70)
679
+ layout.addLayout(memory_layout)
680
+
564
681
 
565
682
  def generate_config_panel_contents(self):
566
683
 
@@ -741,7 +858,23 @@ class ConfigTracking(QMainWindow, Styles):
741
858
  """
742
859
 
743
860
  print('Writing instructions...')
861
+
862
+ if self.btrack_option.isChecked():
863
+ btrack_option = True
864
+ else:
865
+ btrack_option = False
866
+
867
+ # Fetch trackpky params
868
+ if not btrack_option:
869
+ search_range = int(self.search_range_le.text().replace(',','.'))
870
+ memory = self.memory_slider.value()
871
+ else:
872
+ search_range = None
873
+ memory = None
874
+
744
875
  tracking_options = {'btrack_config_path': self.config_path}
876
+ tracking_options.update({'btrack_option': btrack_option, 'search_range': search_range, 'memory': memory})
877
+
745
878
  if not self.features_ticked:
746
879
  features = None
747
880
  masked_channels = None
@@ -850,6 +983,23 @@ class ConfigTracking(QMainWindow, Styles):
850
983
  self.ContentsFeatures.hide()
851
984
  self.uncheck_features()
852
985
 
986
+ btrack_option = True
987
+ if 'btrack_option' in tracking_instructions:
988
+ btrack_option = tracking_instructions['btrack_option']
989
+ if btrack_option:
990
+ self.btrack_option.click()
991
+ else:
992
+ self.trackpy_option.click()
993
+
994
+ if 'search_range' in tracking_instructions:
995
+ search_range = tracking_instructions['search_range']
996
+ if search_range is not None:
997
+ self.search_range_le.setText(str(search_range).replace('.',','))
998
+ if 'memory' in tracking_instructions:
999
+ memory = tracking_instructions['memory']
1000
+ if memory is not None:
1001
+ self.memory_slider.setValue(memory)
1002
+
853
1003
  # Uncheck channels that are masked
854
1004
  mask_channels = tracking_instructions['mask_channels']
855
1005
  if (mask_channels is not None) and len(mask_channels)>0:
@@ -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
@@ -95,7 +95,6 @@ class ClassifierWidget(QWidget, Styles):
95
95
  layout.addLayout(slider_alpha_hbox)
96
96
 
97
97
 
98
-
99
98
  self.features_cb = [QSearchableComboBox() for i in range(2)]
100
99
  self.log_btns = [QPushButton() for i in range(2)]
101
100
 
@@ -129,7 +128,6 @@ class ClassifierWidget(QWidget, Styles):
129
128
  layout.addLayout(hbox_classify)
130
129
 
131
130
  self.time_corr = QCheckBox('Time correlated')
132
- self.time_corr.toggled.connect(self.activate_time_corr_options)
133
131
  if "TRACK_ID" in self.df.columns:
134
132
  self.time_corr.setEnabled(True)
135
133
  else:
@@ -150,19 +148,24 @@ class ClassifierWidget(QWidget, Styles):
150
148
 
151
149
  self.irreversible_event_btn = QRadioButton('irreversible event')
152
150
  self.unique_state_btn = QRadioButton('unique state')
151
+ self.transient_event_btn = QRadioButton('transient event')
153
152
  time_corr_btn_group = QButtonGroup()
154
153
  self.unique_state_btn.click()
155
- self.time_corr_options = [self.irreversible_event_btn, self.unique_state_btn]
156
-
157
- for btn in self.time_corr_options:
158
- time_corr_btn_group.addButton(btn)
159
- btn.setEnabled(False)
160
154
 
161
155
  time_corr_layout = QHBoxLayout()
162
- time_corr_layout.addWidget(self.unique_state_btn, 50, alignment=Qt.AlignCenter)
163
- time_corr_layout.addWidget(self.irreversible_event_btn, 50,alignment=Qt.AlignCenter)
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)
164
159
  layout.addLayout(time_corr_layout)
165
160
 
161
+ self.prereq_event_check = QCheckBox('prerequisite event:')
162
+ self.prereq_event_check.toggled.connect(self.activate_prereq_cb)
163
+ self.prereq_event_cb = QComboBox()
164
+ event_cols = ['--'] + [c.replace('t_','') for c in self.cols if c.startswith('t_')]
165
+ self.prereq_event_cb.addItems(event_cols)
166
+ self.prereq_event_check.setEnabled(False)
167
+ self.prereq_event_cb.setEnabled(False)
168
+
166
169
  self.r2_slider = QLabeledDoubleSlider()
167
170
  self.r2_slider.setValue(0.75)
168
171
  self.r2_slider.setRange(0,1)
@@ -170,18 +173,34 @@ class ClassifierWidget(QWidget, Styles):
170
173
  self.r2_slider.setOrientation(1)
171
174
  self.r2_label = QLabel('R2 tolerance:')
172
175
  self.r2_label.setToolTip('Minimum R2 between the fit sigmoid and the binary response to the filters to accept the event.')
176
+
173
177
  r2_threshold_layout = QHBoxLayout()
174
- r2_threshold_layout.addWidget(QLabel(''), 50)
175
- r2_threshold_layout.addWidget(self.r2_label, 15)
176
- r2_threshold_layout.addWidget(self.r2_slider, 35)
177
- layout.addLayout(r2_threshold_layout)
178
+ r2_threshold_layout.addWidget(QLabel(''), 33)
179
+ r2_threshold_layout.addWidget(self.r2_label, 13)
180
+ r2_threshold_layout.addWidget(self.r2_slider, 20)
181
+ r2_threshold_layout.addWidget(QLabel(''), 33)
182
+
183
+ layout.addLayout(r2_threshold_layout)
178
184
 
185
+ self.time_corr_options = [self.irreversible_event_btn, self.unique_state_btn, self.prereq_event_check, self.prereq_event_cb, self.transient_event_btn]
186
+ for btn in [self.irreversible_event_btn, self.unique_state_btn, self.transient_event_btn]:
187
+ time_corr_btn_group.addButton(btn)
188
+ btn.setEnabled(False)
189
+ self.time_corr.toggled.connect(self.activate_time_corr_options)
190
+
179
191
  self.irreversible_event_btn.clicked.connect(self.activate_r2)
180
192
  self.unique_state_btn.clicked.connect(self.activate_r2)
193
+ self.transient_event_btn.clicked.connect(self.activate_r2)
181
194
 
182
195
  for wg in [self.r2_slider, self.r2_label]:
183
196
  wg.setEnabled(False)
184
197
 
198
+ prereq_layout = QHBoxLayout()
199
+ prereq_layout.setContentsMargins(30,0,0,0)
200
+ prereq_layout.addWidget(self.prereq_event_check, 20)
201
+ prereq_layout.addWidget(self.prereq_event_cb, 80)
202
+ layout.addLayout(prereq_layout)
203
+
185
204
  layout.addWidget(QLabel())
186
205
 
187
206
  self.submit_btn = QPushButton('apply')
@@ -193,6 +212,12 @@ class ClassifierWidget(QWidget, Styles):
193
212
  self.frame_slider.valueChanged.connect(self.set_frame)
194
213
  self.alpha_slider.valueChanged.connect(self.set_transparency)
195
214
 
215
+ def activate_prereq_cb(self):
216
+ if self.prereq_event_check.isChecked():
217
+ self.prereq_event_cb.setEnabled(True)
218
+ else:
219
+ self.prereq_event_cb.setEnabled(False)
220
+
196
221
  def activate_submit_btn(self):
197
222
 
198
223
  if self.property_query_le.text()=='':
@@ -416,7 +441,11 @@ class ClassifierWidget(QWidget, Styles):
416
441
  self.df = self.df.drop(list(set(name_map.values()) & set(self.df.columns)), axis=1).rename(columns=name_map)
417
442
  self.df.reset_index(inplace=True, drop=True)
418
443
 
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())
444
+ pre_event = None
445
+ if self.prereq_event_check.isChecked() and "t_"+self.prereq_event_cb.currentText() in self.cols:
446
+ pre_event = self.prereq_event_cb.currentText()
447
+
448
+ 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)
420
449
 
421
450
  else:
422
451
  self.group_name_user = 'group_' + self.name_le.text()
@@ -453,6 +453,9 @@ class ConfigNewExperiment(QMainWindow, Styles):
453
453
  config.set('Labels', 'concentrations', self.concentrations)
454
454
  config.set('Labels', 'pharmaceutical_agents', self.pharmaceutical_agents)
455
455
 
456
+ config.add_section('Metadata')
457
+ config.set('Metadata', 'concentration_units', self.concentration_units)
458
+
456
459
  # save to a file
457
460
  with open('config.ini', 'w') as configfile:
458
461
  config.write(configfile)
@@ -480,6 +483,8 @@ class SetupConditionLabels(QWidget, Styles):
480
483
  self.antibodies_cbs = [QLineEdit() for i in range(self.n_wells)]
481
484
  self.concentrations_cbs = [QLineEdit() for i in range(self.n_wells)]
482
485
  self.pharmaceutical_agents_cbs = [QLineEdit() for i in range(self.n_wells)]
486
+ self.concentration_units_le = QLineEdit('pM')
487
+ self.concentration_units_le.setPlaceholderText('concentration units')
483
488
 
484
489
  for i in range(self.n_wells):
485
490
  hbox = QHBoxLayout()
@@ -504,6 +509,12 @@ class SetupConditionLabels(QWidget, Styles):
504
509
 
505
510
  self.layout.addLayout(hbox)
506
511
 
512
+ concentration_units_layout = QHBoxLayout()
513
+ concentration_units_layout.addWidget(QLabel('concentration\nunits: '),5,alignment=Qt.AlignLeft)
514
+ concentration_units_layout.addWidget(self.concentration_units_le,10)
515
+ concentration_units_layout.addWidget(QLabel(''), 85)
516
+ self.layout.addLayout(concentration_units_layout)
517
+
507
518
  btn_hbox = QHBoxLayout()
508
519
  btn_hbox.setContentsMargins(0,20,0,0)
509
520
  self.skip_btn = QPushButton('Skip')
@@ -556,6 +567,8 @@ class SetupConditionLabels(QWidget, Styles):
556
567
  pharamaceutical_text = [c.text() for c in self.pharmaceutical_agents_cbs]
557
568
  self.parent_window.pharmaceutical_agents = ','.join(pharamaceutical_text)
558
569
 
570
+ self.parent_window.concentration_units = self.concentration_units_le.text()
571
+
559
572
 
560
573
 
561
574
 
@@ -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)
@@ -337,6 +338,7 @@ class ControlPanel(QMainWindow, Styles):
337
338
  self.antibodies = get_experiment_antibodies(self.exp_dir)
338
339
  self.pharmaceutical_agents = get_experiment_pharmaceutical_agents(self.exp_dir)
339
340
 
341
+ self.metadata = ConfigSectionMap(self.exp_config,"Metadata")
340
342
  print('Experiment configuration successfully read...')
341
343
 
342
344
  def closeEvent(self, event):
@@ -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)]