celldetective 1.3.9.post5__py3-none-any.whl → 1.4.1__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 (94) hide show
  1. celldetective/__init__.py +0 -3
  2. celldetective/_version.py +1 -1
  3. celldetective/events.py +2 -4
  4. celldetective/exceptions.py +11 -0
  5. celldetective/extra_properties.py +132 -0
  6. celldetective/filters.py +7 -1
  7. celldetective/gui/InitWindow.py +37 -46
  8. celldetective/gui/__init__.py +3 -9
  9. celldetective/gui/about.py +19 -15
  10. celldetective/gui/analyze_block.py +34 -19
  11. celldetective/gui/base_annotator.py +786 -0
  12. celldetective/gui/base_components.py +23 -0
  13. celldetective/gui/classifier_widget.py +86 -94
  14. celldetective/gui/configure_new_exp.py +163 -46
  15. celldetective/gui/control_panel.py +76 -146
  16. celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
  17. celldetective/gui/generic_signal_plot.py +11 -13
  18. celldetective/gui/gui_utils.py +54 -23
  19. celldetective/gui/help/neighborhood.json +2 -2
  20. celldetective/gui/json_readers.py +5 -4
  21. celldetective/gui/layouts.py +265 -31
  22. celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
  23. celldetective/gui/plot_measurements.py +21 -17
  24. celldetective/gui/plot_signals_ui.py +125 -72
  25. celldetective/gui/process_block.py +283 -188
  26. celldetective/gui/processes/compute_neighborhood.py +594 -0
  27. celldetective/gui/processes/downloader.py +37 -34
  28. celldetective/gui/processes/measure_cells.py +19 -8
  29. celldetective/gui/processes/segment_cells.py +47 -11
  30. celldetective/gui/processes/track_cells.py +18 -13
  31. celldetective/gui/seg_model_loader.py +21 -62
  32. celldetective/gui/settings/__init__.py +7 -0
  33. celldetective/gui/settings/_settings_base.py +70 -0
  34. celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
  35. celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
  36. celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
  37. celldetective/gui/settings/_settings_segmentation.py +49 -0
  38. celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
  39. celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
  40. celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
  41. celldetective/gui/styles.py +2 -1
  42. celldetective/gui/survival_ui.py +49 -95
  43. celldetective/gui/tableUI.py +53 -25
  44. celldetective/gui/table_ops/__init__.py +0 -0
  45. celldetective/gui/table_ops/merge_groups.py +118 -0
  46. celldetective/gui/thresholds_gui.py +617 -1221
  47. celldetective/gui/viewers.py +107 -42
  48. celldetective/gui/workers.py +8 -4
  49. celldetective/io.py +137 -57
  50. celldetective/links/zenodo.json +145 -144
  51. celldetective/measure.py +94 -53
  52. celldetective/neighborhood.py +342 -268
  53. celldetective/preprocessing.py +56 -35
  54. celldetective/regionprops/_regionprops.py +16 -5
  55. celldetective/relative_measurements.py +50 -29
  56. celldetective/scripts/analyze_signals.py +4 -1
  57. celldetective/scripts/measure_cells.py +5 -5
  58. celldetective/scripts/measure_relative.py +20 -12
  59. celldetective/scripts/segment_cells.py +4 -10
  60. celldetective/scripts/segment_cells_thresholds.py +3 -3
  61. celldetective/scripts/track_cells.py +10 -8
  62. celldetective/scripts/train_segmentation_model.py +18 -6
  63. celldetective/signals.py +29 -14
  64. celldetective/tracking.py +14 -3
  65. celldetective/utils.py +91 -62
  66. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
  67. celldetective-1.4.1.dist-info/RECORD +123 -0
  68. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
  69. tests/gui/__init__.py +0 -0
  70. tests/gui/test_new_project.py +228 -0
  71. tests/gui/test_project.py +99 -0
  72. tests/test_preprocessing.py +2 -2
  73. celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
  74. celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  75. celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
  76. celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
  77. celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  78. celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
  79. celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
  80. celldetective/models/signal_detection/NucCond/config_input.json +0 -1
  81. celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
  82. celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
  83. celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
  84. celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
  85. celldetective/models/signal_detection/NucCond/scores.npy +0 -0
  86. celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
  87. celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
  88. celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
  89. celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
  90. celldetective-1.3.9.post5.dist-info/RECORD +0 -129
  91. tests/test_qt.py +0 -103
  92. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
  93. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
  94. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,10 @@
1
1
  from PyQt5.QtWidgets import QMessageBox, QScrollArea, QButtonGroup, QComboBox, \
2
- QCheckBox, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton, \
2
+ QCheckBox, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, \
3
3
  QRadioButton, QSizePolicy
4
4
  from PyQt5.QtCore import Qt, QRect
5
- from PyQt5.QtGui import QIcon, QDoubleValidator
5
+ from PyQt5.QtGui import QDoubleValidator
6
6
 
7
- from celldetective.gui import Styles
7
+ from celldetective.gui import CelldetectiveWidget
8
8
  from celldetective.gui.gui_utils import center_window, FigureCanvas
9
9
 
10
10
  from superqt.fonticon import icon
@@ -12,7 +12,6 @@ from fonticon_mdi6 import MDI6
12
12
  from celldetective.utils import get_software_location, _extract_labels_from_config
13
13
  from celldetective.io import load_experiment_tables, get_experiment_antibodies, get_experiment_cell_types, get_experiment_concentrations, \
14
14
  get_positions_in_well, get_experiment_wells
15
- from celldetective.signals import mean_signal
16
15
  import numpy as np
17
16
  import json
18
17
  import os
@@ -26,7 +25,7 @@ import math
26
25
  import seaborn as sns
27
26
 
28
27
 
29
- class ConfigMeasurementsPlot(QWidget,Styles):
28
+ class ConfigMeasurementsPlot(CelldetectiveWidget):
30
29
  """
31
30
  UI to set survival instructions.
32
31
 
@@ -37,7 +36,6 @@ class ConfigMeasurementsPlot(QWidget,Styles):
37
36
  super().__init__()
38
37
  self.parent_window = parent_window
39
38
  self.setWindowTitle("Configure signal plot")
40
- self.setWindowIcon(QIcon(os.sep.join(['celldetective', 'icons', 'mexican-hat.png'])))
41
39
  self.exp_dir = self.parent_window.exp_dir
42
40
  self.soft_path = get_software_location()
43
41
  self.exp_config = self.exp_dir + "config.ini"
@@ -109,7 +107,7 @@ class ConfigMeasurementsPlot(QWidget,Styles):
109
107
  main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
110
108
 
111
109
  labels = [QLabel('population: '), QLabel('class: '), QLabel('group: ')] # , QLabel('time of\ninterest: ')]
112
- self.cb_options = [['targets', 'effectors'], ['class'], ['group']] # , ['t0','first detection']]
110
+ self.cb_options = [self.parent_window.parent_window.populations, ['class'], ['group']] # , ['t0','first detection']]
113
111
  self.cbs = [QComboBox() for i in range(len(labels))]
114
112
  self.cbs[0].currentIndexChanged.connect(self.set_classes_and_times)
115
113
 
@@ -145,7 +143,7 @@ class ConfigMeasurementsPlot(QWidget,Styles):
145
143
  # self.abs_time_checkbox = QCheckBox('absolute time')
146
144
  # self.frame_slider = QLabeledSlider()
147
145
  # self.frame_slider.setSingleStep(1)
148
- # self.frame_slider.setOrientation(1)
146
+ # self.frame_slider.setOrientation(Qt.Horizontal)
149
147
  # self.frame_slider.setRange(0,self.parent.parent.len_movie)
150
148
  # self.frame_slider.setValue(0)
151
149
  # self.frame_slider.setEnabled(False)
@@ -202,14 +200,20 @@ class ConfigMeasurementsPlot(QWidget,Styles):
202
200
  class_idx = np.array([s.startswith('class_') for s in self.all_columns])
203
201
  group_idx = np.array([s.startswith('group_') for s in self.all_columns])
204
202
 
203
+ print(f'{class_idx=} {group_idx=} {self.all_columns=}')
205
204
  # time_idx = np.array([s.startswith('t_') for s in self.all_columns])
206
-
207
205
  try:
208
- class_columns = list(self.all_columns[class_idx])
209
- group_columns = list(self.all_columns[group_idx])
206
+ if len(class_idx)>0:
207
+ class_columns = list(self.all_columns[class_idx])
208
+ else:
209
+ class_columns = []
210
+ if len(group_idx)>0:
211
+ group_columns = list(self.all_columns[group_idx])
212
+ else:
213
+ group_columns = []
210
214
  # time_columns = list(self.all_columns[time_idx])
211
- except:
212
- print('columns not found')
215
+ except Exception as e:
216
+ print(f'L210 columns not found {e}')
213
217
  self.auto_close = True
214
218
  return None
215
219
 
@@ -227,7 +231,7 @@ class ConfigMeasurementsPlot(QWidget,Styles):
227
231
  is_number = np.vectorize(lambda x: np.issubdtype(x, np.number))
228
232
  feats = cols[is_number(self.df.dtypes)]
229
233
 
230
- self.feature_choice_widget = QWidget()
234
+ self.feature_choice_widget = CelldetectiveWidget()
231
235
  self.feature_choice_widget.setWindowTitle("Select numeric feature")
232
236
  layout = QVBoxLayout()
233
237
  self.feature_choice_widget.setLayout(layout)
@@ -250,7 +254,7 @@ class ConfigMeasurementsPlot(QWidget,Styles):
250
254
  is_number = np.vectorize(lambda x: np.issubdtype(x, np.number))
251
255
  feats = cols[is_number(self.df.dtypes)]
252
256
 
253
- self.feature_choice_widget = QWidget()
257
+ self.feature_choice_widget = CelldetectiveWidget()
254
258
  self.feature_choice_widget.setWindowTitle("Select numeric feature")
255
259
  layout = QVBoxLayout()
256
260
  self.feature_choice_widget.setLayout(layout)
@@ -299,7 +303,7 @@ class ConfigMeasurementsPlot(QWidget,Styles):
299
303
  # prepare survival
300
304
 
301
305
  # plot survival
302
- self.survivalWidget = QWidget()
306
+ self.survivalWidget = CelldetectiveWidget()
303
307
  self.scroll = QScrollArea()
304
308
  self.survivalWidget.setMinimumHeight(int(0.8 * self.screen_height))
305
309
  self.survivalWidget.setWindowTitle('signals')
@@ -500,7 +504,7 @@ class ConfigMeasurementsPlot(QWidget,Styles):
500
504
  if name + ':' in lbl:
501
505
  self.usable_well_labels.append(lbl)
502
506
 
503
- self.line_choice_widget = QWidget()
507
+ self.line_choice_widget = CelldetectiveWidget()
504
508
  self.line_check_vbox = QVBoxLayout()
505
509
  self.line_choice_widget.setLayout(self.line_check_vbox)
506
510
  if len(self.well_indices) > 1:
@@ -1,9 +1,9 @@
1
- from PyQt5.QtWidgets import QMessageBox, QComboBox, \
2
- QCheckBox, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
1
+ from PyQt5.QtWidgets import QComboBox, \
2
+ QCheckBox, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton
3
3
  from PyQt5.QtCore import Qt
4
- from PyQt5.QtGui import QIcon, QDoubleValidator
4
+ from PyQt5.QtGui import QDoubleValidator
5
5
 
6
- from celldetective.gui.gui_utils import center_window
6
+ from celldetective.gui.gui_utils import center_window, generic_message
7
7
  from celldetective.gui.generic_signal_plot import GenericSignalPlotWidget
8
8
  from superqt import QLabeledSlider, QColormapComboBox, QSearchableComboBox
9
9
  from celldetective.utils import get_software_location, _extract_labels_from_config, extract_cols_from_table_list
@@ -16,12 +16,14 @@ plt.rcParams['svg.fonttype'] = 'none'
16
16
  from glob import glob
17
17
  from natsort import natsorted
18
18
  import math
19
- from celldetective.gui import Styles
19
+ from celldetective.gui import CelldetectiveWidget
20
20
  from matplotlib import colormaps
21
21
  import matplotlib.cm
22
+ from celldetective.relative_measurements import expand_pair_table
23
+ from celldetective.neighborhood import extract_neighborhood_in_pair_table
22
24
 
23
25
 
24
- class ConfigSignalPlot(QWidget, Styles):
26
+ class ConfigSignalPlot(CelldetectiveWidget):
25
27
 
26
28
  """
27
29
  UI to set survival instructions.
@@ -33,7 +35,6 @@ class ConfigSignalPlot(QWidget, Styles):
33
35
  super().__init__()
34
36
  self.parent_window = parent_window
35
37
  self.setWindowTitle("Configure signal plot")
36
- self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','mexican-hat.png'])))
37
38
  self.exp_dir = self.parent_window.exp_dir
38
39
  self.soft_path = get_software_location()
39
40
  self.exp_config = self.exp_dir +"config.ini"
@@ -57,7 +58,6 @@ class ConfigSignalPlot(QWidget, Styles):
57
58
 
58
59
  if self.auto_close:
59
60
  self.close()
60
- self.setAttribute(Qt.WA_DeleteOnClose)
61
61
 
62
62
  def interpret_pos_location(self):
63
63
 
@@ -92,10 +92,30 @@ class ConfigSignalPlot(QWidget, Styles):
92
92
  main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
93
93
 
94
94
  pops = []
95
- for population in ['effectors','targets','pairs']:
95
+ self.cols_per_pop = {}
96
+ for population in self.parent_window.parent_window.populations:
96
97
  tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{population}.csv']))
97
98
  if len(tables)>0:
98
99
  pops.append(population)
100
+ cols = extract_cols_from_table_list(tables)
101
+
102
+ # check for neighbor pairs
103
+ neigh_cols = [c for c in cols if c.startswith('inclusive_count_neighborhood')]
104
+ neigh_pairs = [c.split('_(')[-1].split(')_')[0].split('-') for c in neigh_cols]
105
+ neigh_pairs = ['-'.join(c) for c in neigh_pairs]
106
+ for k in range(len(neigh_pairs)):
107
+ if "_self_" in neigh_pairs[k]:
108
+ neigh_pairs[k] = '-'.join([population, population])
109
+ pops.extend(neigh_pairs)
110
+
111
+ self.cols_per_pop.update({population: cols})
112
+
113
+ # pops = []
114
+ # for population in self.parent_window.parent_window.populations+['pairs']:
115
+ # tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{population}.csv']))
116
+ # if len(tables)>0:
117
+ # pops.append(population)
118
+
99
119
 
100
120
  labels = [QLabel('population: '), QLabel('class: '), QLabel('time of\ninterest: '), QLabel('cmap: ')]
101
121
  self.cb_options = [pops,[], [], []]
@@ -128,7 +148,7 @@ class ConfigSignalPlot(QWidget, Styles):
128
148
  self.abs_time_checkbox = QCheckBox('absolute time')
129
149
  self.frame_slider = QLabeledSlider()
130
150
  self.frame_slider.setSingleStep(1)
131
- self.frame_slider.setOrientation(1)
151
+ self.frame_slider.setOrientation(Qt.Horizontal)
132
152
  self.frame_slider.setRange(0,self.parent_window.parent_window.len_movie)
133
153
  self.frame_slider.setValue(0)
134
154
  self.frame_slider.setEnabled(False)
@@ -168,7 +188,7 @@ class ConfigSignalPlot(QWidget, Styles):
168
188
  n_cells_layout.setContentsMargins(20,3,20,3)
169
189
  self.n_cells_slider = QLabeledSlider()
170
190
  self.n_cells_slider.setSingleStep(1)
171
- self.n_cells_slider.setOrientation(1)
191
+ self.n_cells_slider.setOrientation(Qt.Horizontal)
172
192
  self.n_cells_slider.setRange(1,100)
173
193
  self.n_cells_slider.setValue(2)
174
194
  n_cells_layout.addWidget(QLabel('min # cells\nfor pool:'), 33)
@@ -188,35 +208,83 @@ class ConfigSignalPlot(QWidget, Styles):
188
208
  # self.show()
189
209
 
190
210
  def set_classes_and_times(self):
191
-
192
- # Look for all classes and times
193
- population = self.cbs[0].currentText()
194
- tables = natsorted(glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{population}.csv'])))
195
211
 
196
- self.all_columns = extract_cols_from_table_list(tables)
212
+ # Look for all classes and times
213
+ self.neighborhood_keys = None
214
+ self.population = self.cbs[0].currentText()
215
+ pop_split = self.population.split('-')
216
+
217
+ if len(pop_split)==2:
218
+
219
+ self.population = 'pairs'
220
+ tables_pairs = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_pairs.csv']))
221
+ if not tables_pairs:
222
+ print('No pair table found... please compute the pair measurements...')
223
+ return None
224
+ self.cols_pairs = extract_cols_from_table_list(tables_pairs)
225
+
226
+ self.population_reference = pop_split[0]
227
+ self.population_neigh = pop_split[1]
228
+
229
+ cols_ref = self.cols_per_pop[self.population_reference]
230
+ cols_neigh = self.cols_per_pop[self.population_neigh]
231
+
232
+ time_cols_ref = np.array([s.startswith('t_') or s=='t0' for s in cols_ref])
233
+ if len(time_cols_ref)>0:
234
+ time_cols_ref = list(cols_ref[time_cols_ref])
235
+ time_cols_ref = ['reference_'+t for t in time_cols_ref]
236
+
237
+ time_cols_neigh = np.array([s.startswith('t_') or s=='t0' for s in cols_neigh])
238
+ if len(time_cols_neigh)>0:
239
+ time_cols_neigh = list(cols_neigh[time_cols_neigh])
240
+ time_cols_neigh = ['neighbor_'+t for t in time_cols_neigh]
241
+
242
+ if self.population_reference!=self.population_neigh:
243
+ self.neighborhood_keys = [c[16:] for c in cols_ref if c.startswith('inclusive_count_neighborhood') and str(self.population_neigh) in c]
244
+ else:
245
+ self.neighborhood_keys = [c[16:] for c in cols_ref if c.startswith('inclusive_count_neighborhood') and str(self.population_neigh) not in c]
246
+
247
+ time_idx = np.array([s.startswith('t_') or s.startswith('t0') for s in self.cols_pairs])
248
+ time_cols_pairs = list(self.cols_pairs[time_idx])
249
+ time_columns = time_cols_ref + time_cols_neigh + time_cols_pairs
250
+
251
+ class_cols_ref = [c.replace('reference_t_','reference_class_') for c in time_cols_ref]
252
+ class_cols_neigh = [c.replace('neighbor_t_','neighbor_class_') for c in time_cols_neigh]
253
+ class_cols_pairs = [c.replace('t_','class_') for c in time_cols_neigh if c.startswith('t_')]
254
+ class_columns = class_cols_ref + class_cols_neigh + class_cols_pairs
255
+ else:
256
+ tables = natsorted(glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_{self.population}.csv'])))
257
+ self.all_columns = extract_cols_from_table_list(tables)
258
+
259
+ class_idx = np.array([s.startswith('class_') for s in self.all_columns])
260
+ time_idx = np.array([s.startswith('t_') or s.startswith('t0_') for s in self.all_columns])
261
+ print(f'{class_idx=} {time_idx=} {self.all_columns=}')
262
+
263
+ try:
264
+ if len(class_idx)>0:
265
+ class_columns = list(self.all_columns[class_idx])
266
+ else:
267
+ class_columns = []
268
+ if len(time_idx)>0:
269
+ time_columns = list(self.all_columns[time_idx])
270
+ else:
271
+ time_columns = []
272
+ except Exception as e:
273
+ print(f'L266 columns not found {e}')
274
+ self.auto_close = True
275
+ return None
276
+
277
+ if 'class' in self.all_columns:
278
+ class_columns.append("class")
279
+ if 't0' in self.all_columns:
280
+ time_columns.append('t0')
197
281
 
198
- class_idx = np.array([s.startswith('class_') for s in self.all_columns])
199
- time_idx = np.array([s.startswith('t_') for s in self.all_columns])
200
-
201
- try:
202
- class_columns = list(self.all_columns[class_idx])
203
- time_columns = list(self.all_columns[time_idx])
204
- except:
205
- print('columns not found')
206
- self.auto_close = True
207
- return None
208
-
209
- if 'class' in self.all_columns:
210
- class_columns.append("class")
211
- if 't0' in self.all_columns:
212
- time_columns.append('t0')
213
-
214
282
  self.class_columns = np.unique(class_columns)
215
283
  self.time_columns = np.unique(time_columns)
216
- thresh = 18
284
+ thresh = 30
217
285
  self.class_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.class_columns]
218
286
  self.time_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.time_columns]
219
-
287
+
220
288
  self.cbs[2].clear()
221
289
  self.cbs[2].addItems(self.time_truncated)
222
290
  for i in range(len(self.time_columns)):
@@ -233,7 +301,7 @@ class ConfigSignalPlot(QWidget, Styles):
233
301
  is_number = np.vectorize(lambda x: np.issubdtype(x, np.number))
234
302
  feats = cols[is_number(self.df.dtypes)]
235
303
 
236
- self.feature_choice_widget = QWidget()
304
+ self.feature_choice_widget = CelldetectiveWidget()
237
305
  self.feature_choice_widget.setWindowTitle("Select numeric feature")
238
306
  layout = QVBoxLayout()
239
307
  self.feature_choice_widget.setLayout(layout)
@@ -256,7 +324,7 @@ class ConfigSignalPlot(QWidget, Styles):
256
324
  is_number = np.vectorize(lambda x: np.issubdtype(x, np.number))
257
325
  feats = cols[is_number(self.df.dtypes)]
258
326
 
259
- self.feature_choice_widget = QWidget()
327
+ self.feature_choice_widget = CelldetectiveWidget()
260
328
  self.feature_choice_widget.setWindowTitle("Select numeric feature")
261
329
  layout = QVBoxLayout()
262
330
  self.feature_choice_widget.setLayout(layout)
@@ -316,14 +384,8 @@ class ConfigSignalPlot(QWidget, Styles):
316
384
  if self.df is not None:
317
385
 
318
386
  if class_col not in list(self.df.columns):
319
- msgBox = QMessageBox()
320
- msgBox.setIcon(QMessageBox.Warning)
321
- msgBox.setText("The class of interest could not be found in the data. Abort.")
322
- msgBox.setWindowTitle("Warning")
323
- msgBox.setStandardButtons(QMessageBox.Ok)
324
- returnValue = msgBox.exec()
325
- if returnValue == QMessageBox.Ok:
326
- return None
387
+ generic_message("The class of interest could not be found in the data. Abort.")
388
+ return None
327
389
  else:
328
390
  self.ask_for_features()
329
391
  else:
@@ -341,23 +403,17 @@ class ConfigSignalPlot(QWidget, Styles):
341
403
  self.well_option = self.parent_window.parent_window.well_list.getSelectedIndices()
342
404
  self.position_option = self.parent_window.parent_window.position_list.getSelectedIndices()
343
405
 
344
- 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)
406
+ self.df, self.df_pos_info = load_experiment_tables(self.exp_dir, well_option=self.well_option, position_option=self.position_option, population=self.population, return_pos_info=True)
407
+
408
+ if self.population=='pairs':
409
+ self.df = expand_pair_table(self.df)
410
+ self.df = extract_neighborhood_in_pair_table(self.df, reference_population=self.population_reference, neighbor_population=self.population_neigh, neighborhood_key=self.neighborhood_keys[0], contact_only=True)
345
411
 
346
412
  if self.df is None:
347
-
348
413
  print('No table could be found...')
349
- msgBox = QMessageBox()
350
- msgBox.setIcon(QMessageBox.Warning)
351
- msgBox.setText("No table could be found to compute survival...")
352
- msgBox.setWindowTitle("Warning")
353
- msgBox.setStandardButtons(QMessageBox.Ok)
354
- returnValue = msgBox.exec()
355
- if returnValue == QMessageBox.Ok:
356
- self.close()
357
- return None
358
- else:
359
- self.close()
360
- return None
414
+ generic_message("No table could be found to compute survival...")
415
+ self.close()
416
+ return None
361
417
  else:
362
418
  self.df_well_info = self.df_pos_info.loc[:,['well_path', 'well_index', 'well_name', 'well_number', 'well_alias']].drop_duplicates()
363
419
 
@@ -366,14 +422,7 @@ class ConfigSignalPlot(QWidget, Styles):
366
422
  # Check to move at the beginning
367
423
  self.open_widget = True
368
424
  if len(self.time_columns)==0:
369
- msgBox = QMessageBox()
370
- msgBox.setIcon(QMessageBox.Warning)
371
- msgBox.setText("No synchronizing time is available...")
372
- msgBox.setWindowTitle("Warning")
373
- msgBox.setStandardButtons(QMessageBox.Ok)
374
- returnValue = msgBox.exec()
375
- if returnValue == QMessageBox.Ok:
376
- pass
425
+ generic_message("No synchronizing time is available...")
377
426
  self.open_widget = False
378
427
  return None
379
428
 
@@ -383,6 +432,10 @@ class ConfigSignalPlot(QWidget, Styles):
383
432
  print('Warning... The dataset is empty. Please check your filters. Abort...')
384
433
  return None
385
434
 
435
+ pairs=False
436
+ if self.population=='pairs':
437
+ pairs=True
438
+
386
439
  max_time = int(self.df.FRAME.max()) + 1
387
440
  class_col = self.class_columns[self.cbs[1].currentIndex()]
388
441
  time_col = self.time_columns[self.cbs[2].currentIndex()]
@@ -391,9 +444,9 @@ class ConfigSignalPlot(QWidget, Styles):
391
444
 
392
445
  for block,movie_group in self.df.groupby(['well','position']):
393
446
 
394
- well_signal_mean, well_std_mean, timeline_all, matrix_all = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=None, return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
395
- well_signal_event, well_std_event, timeline_event, matrix_event = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=[0], return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
396
- well_signal_no_event, well_std_no_event, timeline_no_event, matrix_no_event = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=[1], return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
447
+ well_signal_mean, well_std_mean, timeline_all, matrix_all = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=None, return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value(),pairs=pairs)
448
+ well_signal_event, well_std_event, timeline_event, matrix_event = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=[0], return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value(),pairs=pairs)
449
+ well_signal_no_event, well_std_no_event, timeline_no_event, matrix_no_event = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=[1], return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value(),pairs=pairs)
397
450
  self.mean_plots_timeline = timeline_all
398
451
 
399
452
  self.df_pos_info.loc[self.df_pos_info['pos_path'] == block[1], 'signal'] = [
@@ -406,9 +459,9 @@ class ConfigSignalPlot(QWidget, Styles):
406
459
  # Per well
407
460
  for well,well_group in self.df.groupby('well'):
408
461
 
409
- well_signal_mean, well_std_mean, timeline_all, matrix_all = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=None, return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
410
- well_signal_event, well_std_event, timeline_event, matrix_event = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=[0], return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
411
- well_signal_no_event, well_std_no_event, timeline_no_event, matrix_no_event = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=[1], return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
462
+ well_signal_mean, well_std_mean, timeline_all, matrix_all = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=None, return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value(),pairs=pairs)
463
+ well_signal_event, well_std_event, timeline_event, matrix_event = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=[0], return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value(),pairs=pairs)
464
+ well_signal_no_event, well_std_no_event, timeline_no_event, matrix_no_event = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=[1], return_matrix=True, forced_max_duration=max_time, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value(),pairs=pairs)
412
465
 
413
466
  self.df_well_info.loc[self.df_well_info['well_path']==well,'signal'] = [{'mean_all': well_signal_mean, 'std_all': well_std_mean,'matrix_all': matrix_all,'mean_event': well_signal_event, 'std_event': well_std_event,
414
467
  'matrix_event': matrix_event,'mean_no_event': well_signal_no_event, 'std_no_event': well_std_no_event, 'matrix_no_event': matrix_no_event, 'timeline': self.mean_plots_timeline}]