celldetective 1.0.2__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 (66) hide show
  1. celldetective/__init__.py +2 -0
  2. celldetective/__main__.py +432 -0
  3. celldetective/datasets/segmentation_annotations/blank +0 -0
  4. celldetective/datasets/signal_annotations/blank +0 -0
  5. celldetective/events.py +149 -0
  6. celldetective/extra_properties.py +100 -0
  7. celldetective/filters.py +89 -0
  8. celldetective/gui/__init__.py +20 -0
  9. celldetective/gui/about.py +44 -0
  10. celldetective/gui/analyze_block.py +563 -0
  11. celldetective/gui/btrack_options.py +898 -0
  12. celldetective/gui/classifier_widget.py +386 -0
  13. celldetective/gui/configure_new_exp.py +532 -0
  14. celldetective/gui/control_panel.py +438 -0
  15. celldetective/gui/gui_utils.py +495 -0
  16. celldetective/gui/json_readers.py +113 -0
  17. celldetective/gui/measurement_options.py +1425 -0
  18. celldetective/gui/neighborhood_options.py +452 -0
  19. celldetective/gui/plot_signals_ui.py +1042 -0
  20. celldetective/gui/process_block.py +1055 -0
  21. celldetective/gui/retrain_segmentation_model_options.py +706 -0
  22. celldetective/gui/retrain_signal_model_options.py +643 -0
  23. celldetective/gui/seg_model_loader.py +460 -0
  24. celldetective/gui/signal_annotator.py +2388 -0
  25. celldetective/gui/signal_annotator_options.py +340 -0
  26. celldetective/gui/styles.py +217 -0
  27. celldetective/gui/survival_ui.py +903 -0
  28. celldetective/gui/tableUI.py +608 -0
  29. celldetective/gui/thresholds_gui.py +1300 -0
  30. celldetective/icons/logo-large.png +0 -0
  31. celldetective/icons/logo.png +0 -0
  32. celldetective/icons/signals_icon.png +0 -0
  33. celldetective/icons/splash-test.png +0 -0
  34. celldetective/icons/splash.png +0 -0
  35. celldetective/icons/splash0.png +0 -0
  36. celldetective/icons/survival2.png +0 -0
  37. celldetective/icons/vignette_signals2.png +0 -0
  38. celldetective/icons/vignette_signals2.svg +114 -0
  39. celldetective/io.py +2050 -0
  40. celldetective/links/zenodo.json +561 -0
  41. celldetective/measure.py +1258 -0
  42. celldetective/models/segmentation_effectors/blank +0 -0
  43. celldetective/models/segmentation_generic/blank +0 -0
  44. celldetective/models/segmentation_targets/blank +0 -0
  45. celldetective/models/signal_detection/blank +0 -0
  46. celldetective/models/tracking_configs/mcf7.json +68 -0
  47. celldetective/models/tracking_configs/ricm.json +203 -0
  48. celldetective/models/tracking_configs/ricm2.json +203 -0
  49. celldetective/neighborhood.py +717 -0
  50. celldetective/scripts/analyze_signals.py +51 -0
  51. celldetective/scripts/measure_cells.py +275 -0
  52. celldetective/scripts/segment_cells.py +212 -0
  53. celldetective/scripts/segment_cells_thresholds.py +140 -0
  54. celldetective/scripts/track_cells.py +206 -0
  55. celldetective/scripts/train_segmentation_model.py +246 -0
  56. celldetective/scripts/train_signal_model.py +49 -0
  57. celldetective/segmentation.py +712 -0
  58. celldetective/signals.py +2826 -0
  59. celldetective/tracking.py +974 -0
  60. celldetective/utils.py +1681 -0
  61. celldetective-1.0.2.dist-info/LICENSE +674 -0
  62. celldetective-1.0.2.dist-info/METADATA +192 -0
  63. celldetective-1.0.2.dist-info/RECORD +66 -0
  64. celldetective-1.0.2.dist-info/WHEEL +5 -0
  65. celldetective-1.0.2.dist-info/entry_points.txt +2 -0
  66. celldetective-1.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1042 @@
1
+ from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QScrollArea, QButtonGroup, QComboBox, QFrame, \
2
+ QCheckBox, QFileDialog, QGridLayout, QTextEdit, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton, \
3
+ QRadioButton, QSpacerItem, QSizePolicy
4
+ from PyQt5.QtCore import Qt, QSize, QRect
5
+ from PyQt5.QtGui import QIcon, QDoubleValidator
6
+ from sklearn.preprocessing import MinMaxScaler
7
+
8
+ from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, GeometryChoice, OperationChoice
9
+ from superqt import QLabeledSlider
10
+ from superqt.fonticon import icon
11
+ from fonticon_mdi6 import MDI6
12
+ from celldetective.utils import extract_experiment_channels, get_software_location, _extract_labels_from_config
13
+ from celldetective.io import interpret_tracking_configuration, load_frames, auto_load_number_of_frames, load_experiment_tables
14
+ from celldetective.measure import compute_haralick_features, contour_of_instance_segmentation
15
+ from celldetective.signals import columnwise_mean, mean_signal
16
+ import numpy as np
17
+ from tifffile import imread
18
+ import json
19
+ from shutil import copyfile
20
+ import os
21
+ import matplotlib.pyplot as plt
22
+ plt.rcParams['svg.fonttype'] = 'none'
23
+ from mpl_toolkits.axes_grid1 import make_axes_locatable
24
+ from glob import glob
25
+ from natsort import natsorted
26
+ from tifffile import imread
27
+ from pathlib import Path, PurePath
28
+ import gc
29
+ import pandas as pd
30
+ from tqdm import tqdm
31
+ from lifelines import KaplanMeierFitter
32
+ from matplotlib.cm import viridis, tab10
33
+ import math
34
+
35
+
36
+
37
+ class ConfigSignalPlot(QWidget):
38
+
39
+ """
40
+ UI to set survival instructions.
41
+
42
+ """
43
+
44
+ def __init__(self, parent=None):
45
+
46
+ super().__init__()
47
+ self.parent = parent
48
+ self.setWindowTitle("Configure signal plot")
49
+ self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','mexican-hat.png'])))
50
+ self.exp_dir = self.parent.exp_dir
51
+ self.soft_path = get_software_location()
52
+ self.exp_config = self.exp_dir +"config.ini"
53
+ self.wells = np.array(self.parent.parent.wells,dtype=str)
54
+ self.well_labels = _extract_labels_from_config(self.exp_config,len(self.wells))
55
+ self.FrameToMin = self.parent.parent.FrameToMin
56
+ self.float_validator = QDoubleValidator()
57
+ self.target_class = [0,1]
58
+ self.show_ci = True
59
+ self.show_cell_lines = False
60
+ self.ax2=None
61
+ self.auto_close = False
62
+
63
+
64
+ print('Parent wells: ', self.wells)
65
+
66
+
67
+ self.well_option = self.parent.parent.well_list.currentIndex()
68
+ self.position_option = self.parent.parent.position_list.currentIndex()
69
+ self.interpret_pos_location()
70
+ #self.load_available_tables()
71
+ #self.config_path = self.exp_dir + self.config_name
72
+
73
+ self.screen_height = self.parent.parent.parent.screen_height
74
+ center_window(self)
75
+ #self.setMinimumHeight(int(0.8*self.screen_height))
76
+ #self.setMaximumHeight(int(0.8*self.screen_height))
77
+ self.populate_widget()
78
+ #self.load_previous_measurement_instructions()
79
+ if self.auto_close:
80
+ self.close()
81
+
82
+ def interpret_pos_location(self):
83
+
84
+ """
85
+ Read the well/position selection from the control panel to decide which data to load
86
+ Set position_indices to None if all positions must be taken
87
+
88
+ """
89
+
90
+ if self.well_option==len(self.wells):
91
+ self.well_indices = np.arange(len(self.wells))
92
+ else:
93
+ self.well_indices = np.array([self.well_option],dtype=int)
94
+
95
+ if self.position_option==0:
96
+ self.position_indices = None
97
+ else:
98
+ self.position_indices = np.array([self.position_option],dtype=int)
99
+
100
+
101
+ def populate_widget(self):
102
+
103
+ """
104
+ Create the multibox design.
105
+
106
+ """
107
+
108
+ # Create button widget and layout
109
+ main_layout = QVBoxLayout()
110
+ self.setLayout(main_layout)
111
+ main_layout.setContentsMargins(30,30,30,30)
112
+ panel_title = QLabel('Options')
113
+ panel_title.setStyleSheet("""
114
+ font-weight: bold;
115
+ padding: 0px;
116
+ """)
117
+ main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
118
+
119
+ labels = [QLabel('population: '), QLabel('class: '), QLabel('time of\ninterest: ')]
120
+ self.cb_options = [['targets','effectors'],['class'], ['t0','first detection']]
121
+ self.cbs = [QComboBox() for i in range(len(labels))]
122
+ self.cbs[0].currentIndexChanged.connect(self.set_classes_and_times)
123
+
124
+ choice_layout = QVBoxLayout()
125
+ choice_layout.setContentsMargins(20,20,20,20)
126
+ for i in range(len(labels)):
127
+ hbox = QHBoxLayout()
128
+ hbox.addWidget(labels[i], 33)
129
+ hbox.addWidget(self.cbs[i],66)
130
+ self.cbs[i].addItems(self.cb_options[i])
131
+ choice_layout.addLayout(hbox)
132
+
133
+
134
+ self.cbs[0].setCurrentIndex(1)
135
+ self.cbs[0].setCurrentIndex(0)
136
+
137
+ self.abs_time_checkbox = QCheckBox('absolute time')
138
+ self.frame_slider = QLabeledSlider()
139
+ self.frame_slider.setSingleStep(1)
140
+ self.frame_slider.setOrientation(1)
141
+ self.frame_slider.setRange(0,self.parent.parent.len_movie)
142
+ self.frame_slider.setValue(0)
143
+ self.frame_slider.setEnabled(False)
144
+ slider_hbox = QHBoxLayout()
145
+ slider_hbox.addWidget(self.abs_time_checkbox, 33)
146
+ slider_hbox.addWidget(self.frame_slider, 66)
147
+ choice_layout.addLayout(slider_hbox)
148
+ main_layout.addLayout(choice_layout)
149
+
150
+ self.abs_time_checkbox.stateChanged.connect(self.switch_ref_time_mode)
151
+
152
+
153
+ time_calib_layout = QHBoxLayout()
154
+ time_calib_layout.setContentsMargins(20,20,20,20)
155
+ time_calib_layout.addWidget(QLabel('time calibration\n(frame to min)'), 33)
156
+ self.time_calibration_le = QLineEdit(str(self.FrameToMin).replace('.',','))
157
+ self.time_calibration_le.setValidator(self.float_validator)
158
+ time_calib_layout.addWidget(self.time_calibration_le, 66)
159
+ #time_calib_layout.addWidget(QLabel(' min'))
160
+ main_layout.addLayout(time_calib_layout)
161
+
162
+ self.submit_btn = QPushButton('Submit')
163
+ self.submit_btn.setStyleSheet(self.parent.parent.parent.button_style_sheet)
164
+ self.submit_btn.clicked.connect(self.process_signal)
165
+ main_layout.addWidget(self.submit_btn)
166
+
167
+ #self.populate_left_panel()
168
+ #grid.addLayout(self.left_side, 0, 0, 1, 1)
169
+
170
+ # self.setCentralWidget(self.scroll_area)
171
+ # self.show()
172
+
173
+ def set_classes_and_times(self):
174
+
175
+ # Look for all classes and times
176
+ tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_*']))
177
+ self.all_columns = []
178
+ for tab in tables:
179
+ cols = pd.read_csv(tab, nrows=1).columns.tolist()
180
+ self.all_columns.extend(cols)
181
+ self.all_columns = np.unique(self.all_columns)
182
+ class_idx = np.array([s.startswith('class_') for s in self.all_columns])
183
+ time_idx = np.array([s.startswith('t_') for s in self.all_columns])
184
+
185
+ try:
186
+ class_columns = list(self.all_columns[class_idx])
187
+ time_columns = list(self.all_columns[time_idx])
188
+ except:
189
+ print('columns not found')
190
+ self.auto_close = True
191
+ return None
192
+
193
+ self.cbs[2].clear()
194
+ self.cbs[2].addItems(np.unique(self.cb_options[2]+time_columns))
195
+
196
+ self.cbs[1].clear()
197
+ self.cbs[1].addItems(np.unique(self.cb_options[1]+class_columns))
198
+
199
+ def ask_for_feature(self):
200
+
201
+ cols = np.array(list(self.df.columns))
202
+ is_number = np.vectorize(lambda x: np.issubdtype(x, np.number))
203
+ feats = cols[is_number(self.df.dtypes)]
204
+
205
+ self.feature_choice_widget = QWidget()
206
+ self.feature_choice_widget.setWindowTitle("Select numeric feature")
207
+ layout = QVBoxLayout()
208
+ self.feature_choice_widget.setLayout(layout)
209
+ self.feature_cb = QComboBox()
210
+ self.feature_cb.addItems(feats)
211
+ hbox = QHBoxLayout()
212
+ hbox.addWidget(QLabel('feature: '), 33)
213
+ hbox.addWidget(self.feature_cb, 66)
214
+ layout.addLayout(hbox)
215
+
216
+ self.set_feature_btn = QPushButton('set')
217
+ self.set_feature_btn.clicked.connect(self.compute_signals)
218
+ layout.addWidget(self.set_feature_btn)
219
+ self.feature_choice_widget.show()
220
+ center_window(self.feature_choice_widget)
221
+
222
+ def ask_for_features(self):
223
+
224
+ cols = np.array(list(self.df.columns))
225
+ is_number = np.vectorize(lambda x: np.issubdtype(x, np.number))
226
+ feats = cols[is_number(self.df.dtypes)]
227
+
228
+ self.feature_choice_widget = QWidget()
229
+ self.feature_choice_widget.setWindowTitle("Select numeric feature")
230
+ layout = QVBoxLayout()
231
+ self.feature_choice_widget.setLayout(layout)
232
+ self.feature_cb = QComboBox()
233
+ self.feature_cb.addItems(feats)
234
+ hbox = QHBoxLayout()
235
+ hbox.addWidget(QLabel('feature: '), 33)
236
+ hbox.addWidget(self.feature_cb, 66)
237
+ #hbox.addWidget((QLabel('Plot two features')))
238
+ layout.addLayout(hbox)
239
+ self.checkBox_feature = QCheckBox(self.feature_choice_widget)
240
+ self.checkBox_feature.setGeometry(QRect(170, 120, 81, 20))
241
+ self.checkBox_feature.setText('Plot two features')
242
+ #hbox.addWidget(self.checkBox_feature)
243
+ layout.addWidget(self.checkBox_feature, alignment=Qt.AlignCenter)
244
+ self.checkBox_feature.stateChanged.connect(self.enable_second_feature)
245
+
246
+ #layout = QVBoxLayout()
247
+ #self.feature_two_choice_widget.setLayout(layout)
248
+ self.feature_two_cb = QComboBox()
249
+ self.feature_two_cb.addItems(feats)
250
+ self.feature_two_cb.setEnabled(False)
251
+ hbox_two = QHBoxLayout()
252
+ hbox_two.addWidget(QLabel('feature two: '), 33)
253
+ hbox_two.addWidget(self.feature_two_cb, 66)
254
+ layout.addLayout(hbox_two)
255
+
256
+
257
+ self.set_feature_btn = QPushButton('set')
258
+ self.set_feature_btn.clicked.connect(self.compute_signals)
259
+ layout.addWidget(self.set_feature_btn)
260
+ self.feature_choice_widget.show()
261
+ center_window(self.feature_choice_widget)
262
+
263
+ def enable_second_feature(self):
264
+ if self.checkBox_feature.isChecked():
265
+ self.feature_two_cb.setEnabled(True)
266
+ else:
267
+ self.feature_two_cb.setEnabled(False)
268
+ def compute_signals(self):
269
+
270
+ if self.df is not None:
271
+ self.feature_selected = self.feature_cb.currentText()
272
+ if self.checkBox_feature.isChecked():
273
+ self.second_feature_selected=self.feature_two_cb.currentText()
274
+ print(self.second_feature_selected)
275
+ self.feature_choice_widget.close()
276
+ self.compute_signal_functions()
277
+ # prepare survival
278
+
279
+ # plot survival
280
+ self.survivalWidget = QWidget()
281
+ self.scroll = QScrollArea()
282
+ self.survivalWidget.setMinimumHeight(int(0.8*self.screen_height))
283
+ self.survivalWidget.setWindowTitle('signals')
284
+ self.plotvbox = QVBoxLayout(self.survivalWidget)
285
+ self.plotvbox.setContentsMargins(30,30,30,30)
286
+ self.survival_title = QLabel('Signal function')
287
+ self.survival_title.setStyleSheet("""
288
+ font-weight: bold;
289
+ padding: 0px;
290
+ """)
291
+ self.plotvbox.addWidget(self.survival_title, alignment=Qt.AlignCenter)
292
+
293
+ plot_buttons_hbox = QHBoxLayout()
294
+ plot_buttons_hbox.addWidget(QLabel(''),80, alignment=Qt.AlignLeft)
295
+
296
+ self.legend_btn = QPushButton('')
297
+ self.legend_btn.setIcon(icon(MDI6.text_box,color="black"))
298
+ self.legend_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
299
+ self.legend_btn.setToolTip('Show or hide the legend')
300
+ self.legend_visible = True
301
+ self.legend_btn.clicked.connect(self.show_hide_legend)
302
+ plot_buttons_hbox.addWidget(self.legend_btn, 5,alignment=Qt.AlignRight)
303
+
304
+
305
+ self.log_btn = QPushButton('')
306
+ self.log_btn.setIcon(icon(MDI6.math_log,color="black"))
307
+ self.log_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
308
+ self.log_btn.clicked.connect(self.switch_to_log)
309
+ self.log_btn.setToolTip('Enable or disable log scale')
310
+ plot_buttons_hbox.addWidget(self.log_btn, 5, alignment=Qt.AlignRight)
311
+
312
+
313
+ self.ci_btn = QPushButton('')
314
+ self.ci_btn.setIcon(icon(MDI6.arrow_expand_horizontal,color="blue"))
315
+ self.ci_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
316
+ self.ci_btn.clicked.connect(self.switch_ci)
317
+ self.ci_btn.setToolTip('Show or hide confidence intervals.')
318
+ plot_buttons_hbox.addWidget(self.ci_btn, 5, alignment=Qt.AlignRight)
319
+
320
+ self.cell_lines_btn = QPushButton('')
321
+ self.cell_lines_btn.setIcon(icon(MDI6.view_headline,color="black"))
322
+ self.cell_lines_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
323
+ self.cell_lines_btn.clicked.connect(self.switch_cell_lines)
324
+ self.cell_lines_btn.setToolTip('Show or hide individual cell signals.')
325
+ plot_buttons_hbox.addWidget(self.cell_lines_btn, 5, alignment=Qt.AlignRight)
326
+
327
+
328
+ self.fig, self.ax = plt.subplots(1,1,figsize=(4,3))
329
+ #self.setMinimumHeight(100)
330
+ self.survival_window = FigureCanvas(self.fig, title="Survival")
331
+ self.survival_window.setContentsMargins(0,0,0,0)
332
+ if self.df is not None:
333
+ self.initialize_axis()
334
+ plt.tight_layout()
335
+
336
+
337
+ self.fig.set_facecolor('none') # or 'None'
338
+ self.fig.canvas.setStyleSheet("background-color: transparent;")
339
+ self.survival_window.canvas.draw()
340
+
341
+ #self.survival_window.layout.addWidget(QLabel('WHAAAAATTT???'))
342
+
343
+ self.plot_options = [QRadioButton() for i in range(3)]
344
+ self.radio_labels = ['well', 'pos', 'both']
345
+ radio_hbox = QHBoxLayout()
346
+ radio_hbox.setContentsMargins(30,30,30,30)
347
+ self.plot_btn_group = QButtonGroup()
348
+ for i in range(3):
349
+ self.plot_options[i].setText(self.radio_labels[i])
350
+ #self.plot_options[i].toggled.connect(self.plot_survivals)
351
+ self.plot_btn_group.addButton(self.plot_options[i])
352
+ radio_hbox.addWidget(self.plot_options[i], 33, alignment=Qt.AlignCenter)
353
+ self.plot_btn_group.buttonClicked[int].connect(self.plot_survivals)
354
+
355
+ print(self.well_indices, self.position_indices)
356
+ if self.position_indices is not None:
357
+ if len(self.well_indices)>1 and len(self.position_indices)==1:
358
+ self.plot_btn_group.buttons()[0].click()
359
+ for i in [1,2]:
360
+ self.plot_options[i].setEnabled(False)
361
+ elif len(self.well_indices)>1:
362
+ self.plot_btn_group.buttons()[0].click()
363
+ elif len(self.well_indices)==1 and len(self.position_indices)==1:
364
+ self.plot_btn_group.buttons()[1].click()
365
+ for i in [0,2]:
366
+ self.plot_options[i].setEnabled(False)
367
+ else:
368
+ if len(self.well_indices)>1:
369
+ self.plot_btn_group.buttons()[0].click()
370
+ elif len(self.well_indices)==1:
371
+ self.plot_btn_group.buttons()[2].click()
372
+
373
+
374
+ # elif len(self.well_indices)>1:
375
+ # self.plot_btn_group.buttons()[0].click()
376
+ # else:
377
+ # self.plot_btn_group.buttons()[1].click()
378
+
379
+ # if self.position_indices is not None:
380
+ # for i in [0,2]:
381
+ # self.plot_options[i].setEnabled(False)
382
+
383
+
384
+ #self.plot_options[0].setChecked(True)
385
+ self.plotvbox.addLayout(radio_hbox)
386
+ self.plotvbox.addLayout(plot_buttons_hbox)
387
+ self.plotvbox.addWidget(self.survival_window)
388
+ self.class_selection_lbl = QLabel('Select class')
389
+ self.class_selection_lbl.setStyleSheet("""
390
+ font-weight: bold;
391
+ padding: 0px;
392
+ """)
393
+ self.plotvbox.addWidget(self.class_selection_lbl, alignment=Qt.AlignCenter)
394
+ class_selection_hbox = QHBoxLayout()
395
+ class_selection_hbox.setContentsMargins(30,30,30,30)
396
+ self.all_btn = QRadioButton('*')
397
+ self.all_btn.setChecked(True)
398
+ self.event_btn = QRadioButton('event')
399
+ self.no_event_btn = QRadioButton('no event')
400
+ self.class_btn_group = QButtonGroup()
401
+ for btn in [self.all_btn, self.event_btn, self.no_event_btn]:
402
+ self.class_btn_group.addButton(btn)
403
+
404
+ self.class_btn_group.buttonClicked[int].connect(self.set_class_to_plot)
405
+
406
+ class_selection_hbox.addWidget(self.all_btn, 33, alignment=Qt.AlignLeft)
407
+ class_selection_hbox.addWidget(self.event_btn, 33, alignment=Qt.AlignCenter)
408
+ class_selection_hbox.addWidget(self.no_event_btn, 33, alignment=Qt.AlignRight)
409
+ self.plotvbox.addLayout(class_selection_hbox)
410
+
411
+
412
+ self.select_pos_label = QLabel('Select positions')
413
+ self.select_pos_label.setStyleSheet("""
414
+ font-weight: bold;
415
+ padding: 0px;
416
+ """)
417
+ self.plotvbox.addWidget(self.select_pos_label, alignment=Qt.AlignCenter)
418
+
419
+ self.select_option = [QRadioButton() for i in range(2)]
420
+ self.select_label = ['name', 'spatial']
421
+ select_hbox = QHBoxLayout()
422
+ select_hbox.setContentsMargins(30,30,30,30)
423
+ self.select_btn_group = QButtonGroup()
424
+ for i in range(2):
425
+ self.select_option[i].setText(self.select_label[i])
426
+ #self.select_option[i].toggled.connect(self.switch_selection_mode)
427
+ self.select_btn_group.addButton(self.select_option[i])
428
+ select_hbox.addWidget(self.select_option[i],33, alignment=Qt.AlignCenter)
429
+ self.select_btn_group.buttonClicked[int].connect(self.switch_selection_mode)
430
+ self.plotvbox.addLayout(select_hbox)
431
+
432
+ self.look_for_metadata()
433
+ if self.metadata_found:
434
+ self.fig_scatter, self.ax_scatter = plt.subplots(1,1,figsize=(4,3))
435
+ self.position_scatter = FigureCanvas(self.fig_scatter)
436
+ self.load_coordinates()
437
+ self.plot_spatial_location()
438
+ #self.plot_positions()
439
+ self.ax_scatter.spines['top'].set_visible(False)
440
+ self.ax_scatter.spines['right'].set_visible(False)
441
+ self.ax_scatter.set_aspect('equal')
442
+ self.ax_scatter.set_xticks([])
443
+ self.ax_scatter.set_yticks([])
444
+ plt.tight_layout()
445
+
446
+ self.fig_scatter.set_facecolor('none') # or 'None'
447
+ self.fig_scatter.canvas.setStyleSheet("background-color: transparent;")
448
+ self.plotvbox.addWidget(self.position_scatter)
449
+
450
+
451
+
452
+ self.generate_pos_selection_widget()
453
+
454
+ # if self.df is not None and len(self.ks_estimators_per_position)>0:
455
+ # self.plot_survivals()
456
+ self.select_btn_group.buttons()[0].click()
457
+ self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
458
+ self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
459
+ #self.scroll.setWidgetResizable(True)
460
+ self.scroll.setWidget(self.survivalWidget)
461
+
462
+ self.scroll.setMinimumHeight(int(0.8*self.screen_height))
463
+ self.survivalWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
464
+ self.scroll.show()
465
+
466
+
467
+ def process_signal(self):
468
+
469
+ print('you clicked!!')
470
+ self.FrameToMin = float(self.time_calibration_le.text().replace(',','.'))
471
+ print(self.FrameToMin, 'set')
472
+
473
+ # read instructions from combobox options
474
+ self.load_available_tables()
475
+ if self.df is not None:
476
+ self.ask_for_features()
477
+ else:
478
+ return None
479
+
480
+ def generate_pos_selection_widget(self):
481
+
482
+ self.well_names = self.df['well_name'].unique()
483
+ self.pos_names = self.df_pos_info['pos_name'].unique() #pd.DataFrame(self.ks_estimators_per_position)['position_name'].unique()
484
+ print(f'POSITION NAMES: ',self.pos_names)
485
+ self.usable_well_labels = []
486
+ for name in self.well_names:
487
+ for lbl in self.well_labels:
488
+ if name+':' in lbl:
489
+ self.usable_well_labels.append(lbl)
490
+
491
+ self.line_choice_widget = QWidget()
492
+ self.line_check_vbox = QVBoxLayout()
493
+ self.line_choice_widget.setLayout(self.line_check_vbox)
494
+ if len(self.well_indices)>1:
495
+ self.well_display_options = [QCheckBox(self.usable_well_labels[i]) for i in range(len(self.usable_well_labels))]
496
+ for i in range(len(self.well_names)):
497
+ self.line_check_vbox.addWidget(self.well_display_options[i], alignment=Qt.AlignLeft)
498
+ self.well_display_options[i].setChecked(True)
499
+ self.well_display_options[i].toggled.connect(self.select_survival_lines)
500
+ else:
501
+ self.pos_display_options = [QCheckBox(self.pos_names[i]) for i in range(len(self.pos_names))]
502
+ for i in range(len(self.pos_names)):
503
+ self.line_check_vbox.addWidget(self.pos_display_options[i], alignment=Qt.AlignLeft)
504
+ self.pos_display_options[i].setChecked(True)
505
+ self.pos_display_options[i].toggled.connect(self.select_survival_lines)
506
+
507
+ self.plotvbox.addWidget(self.line_choice_widget, alignment=Qt.AlignCenter)
508
+
509
+ def load_available_tables(self):
510
+
511
+ """
512
+ Load the tables of the selected wells/positions from the control Panel for the population of interest
513
+
514
+ """
515
+
516
+ self.well_option = self.parent.parent.well_list.currentIndex()
517
+ if self.well_option==len(self.wells):
518
+ wo = '*'
519
+ else:
520
+ wo = self.well_option
521
+ self.position_option = self.parent.parent.position_list.currentIndex()
522
+ if self.position_option==0:
523
+ po = '*'
524
+ else:
525
+ po = self.position_option - 1
526
+
527
+ 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)
528
+
529
+ if self.df is None:
530
+
531
+ print('No table could be found...')
532
+ msgBox = QMessageBox()
533
+ msgBox.setIcon(QMessageBox.Warning)
534
+ msgBox.setText("No table could be found to compute survival...")
535
+ msgBox.setWindowTitle("Warning")
536
+ msgBox.setStandardButtons(QMessageBox.Ok)
537
+ returnValue = msgBox.exec()
538
+ if returnValue == QMessageBox.Ok:
539
+ self.close()
540
+ return None
541
+ else:
542
+ self.close()
543
+ return None
544
+ else:
545
+ self.df_well_info = self.df_pos_info.loc[:,['well_path', 'well_index', 'well_name', 'well_number', 'well_alias']].drop_duplicates()
546
+
547
+ def compute_signal_functions(self):
548
+
549
+ # REPLACE EVRYTHING WITH MEAN_SIGNAL FUNCTION
550
+
551
+ # Per position signal
552
+ max_time = int(self.df.FRAME.max()) + 1
553
+ class_col = self.cbs[1].currentText()
554
+ time_col = self.cbs[2].currentText()
555
+
556
+
557
+ for block,movie_group in self.df.groupby(['well','position']):
558
+
559
+ 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=[0,1], return_matrix=True, forced_max_duration=max_time)
560
+ 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)
561
+ 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)
562
+ self.mean_plots_timeline = timeline_all
563
+ # self.df_pos_info.loc[self.df_pos_info['pos_path']==block[1],'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,
564
+ # '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}]
565
+
566
+ if self.checkBox_feature.isChecked():
567
+ second_well_signal_mean, second_well_std_mean, second_timeline_all, second_matrix_all = mean_signal(movie_group, self.second_feature_selected, class_col, time_col=time_col, class_value=[0,1], return_matrix=True, forced_max_duration=max_time)
568
+ second_well_signal_event, second_well_std_event, second_timeline_event, second_matrix_event = mean_signal(movie_group, self.second_feature_selected, class_col, time_col=time_col, class_value=[0], return_matrix=True, forced_max_duration=max_time)
569
+ second_well_signal_no_event, second_well_std_no_event, second_timeline_no_event, second_matrix_no_event = mean_signal(movie_group, self.second_feature_selected, class_col, time_col=time_col, class_value=[1], return_matrix=True, forced_max_duration=max_time)
570
+ self.second_mean_plots_timeline = second_timeline_all
571
+ self.df_pos_info.loc[self.df_pos_info['pos_path'] == block[1], 'signal'] = [
572
+ {'mean_all': well_signal_mean, 'std_all': well_std_mean,'matrix_all': matrix_all,'mean_event': well_signal_event, 'std_event': well_std_event,
573
+ '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,'second_mean_all': second_well_signal_mean, 'second_std_all': second_well_std_mean, 'second_matrix_all': second_matrix_all,
574
+ 'second_mean_event': second_well_signal_event, 'second_std_event': second_well_std_event,
575
+ 'second_matrix_event': second_matrix_event, 'second_mean_no_event': second_well_signal_no_event,
576
+ 'second_std_no_event': second_well_std_no_event, 'second_matrix_no_event': second_matrix_no_event,
577
+ 'second_timeline': self.second_mean_plots_timeline}]
578
+ else:
579
+ self.df_pos_info.loc[self.df_pos_info['pos_path'] == block[1], 'signal'] = [
580
+ {'mean_all': well_signal_mean, 'std_all': well_std_mean, 'matrix_all': matrix_all,
581
+ 'mean_event': well_signal_event, 'std_event': well_std_event,
582
+ 'matrix_event': matrix_event, 'mean_no_event': well_signal_no_event,
583
+ 'std_no_event': well_std_no_event, 'matrix_no_event': matrix_no_event,
584
+ 'timeline': self.mean_plots_timeline}]
585
+
586
+ # Per well
587
+ for well,well_group in self.df.groupby('well'):
588
+
589
+ 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=[0,1], return_matrix=True, forced_max_duration=max_time)
590
+ 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)
591
+ 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)
592
+ if self.checkBox_feature.isChecked():
593
+ second_well_signal_mean, second_well_std_mean, second_timeline_all, second_matrix_all = mean_signal(movie_group, self.second_feature_selected, class_col, time_col=time_col, class_value=[0,1], return_matrix=True, forced_max_duration=max_time)
594
+ second_well_signal_event, second_well_std_event, second_timeline_event, second_matrix_event = mean_signal(movie_group, self.second_feature_selected, class_col, time_col=time_col, class_value=[0], return_matrix=True, forced_max_duration=max_time)
595
+ second_well_signal_no_event, second_well_std_no_event, second_timeline_no_event, second_matrix_no_event = mean_signal(movie_group, self.second_feature_selected, class_col, time_col=time_col, class_value=[1], return_matrix=True, forced_max_duration=max_time)
596
+ self.df_well_info.loc[self.df_well_info['well_path'] == well, 'signal'] = [
597
+ {'mean_all': well_signal_mean, 'std_all': well_std_mean,'matrix_all': matrix_all,'mean_event': well_signal_event, 'std_event': well_std_event,
598
+ '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,'second_mean_all': second_well_signal_mean, 'second_std_all': second_well_std_mean, 'second_matrix_all': second_matrix_all,
599
+ 'second_mean_event': second_well_signal_event, 'second_std_event': second_well_std_event,
600
+ 'second_matrix_event': second_matrix_event, 'second_mean_no_event': second_well_signal_no_event,
601
+ 'second_std_no_event': second_well_std_no_event, 'second_matrix_no_event': second_matrix_no_event,
602
+ 'second_timeline': self.second_mean_plots_timeline}]
603
+ else:
604
+ 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,
605
+ '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}]
606
+
607
+ self.df_pos_info.loc[:,'select'] = True
608
+ self.df_well_info.loc[:,'select'] = True
609
+ self.df_pos_info.to_csv('pos_info.csv')
610
+
611
+
612
+ def generate_synchronized_matrix(self, well_group, feature_selected, cclass, max_time):
613
+
614
+ if isinstance(cclass,int):
615
+ cclass = [cclass]
616
+
617
+ n_cells = len(well_group.groupby(['position','TRACK_ID']))
618
+ depth = int(2*max_time + 3)
619
+ matrix = np.zeros((n_cells, depth))
620
+ matrix[:,:] = np.nan
621
+ mapping = np.arange(-max_time-1, max_time+2)
622
+ cid=0
623
+ for block,movie_group in well_group.groupby('position'):
624
+ for tid,track_group in movie_group.loc[movie_group[self.cbs[1].currentText()].isin(cclass)].groupby('TRACK_ID'):
625
+ try:
626
+ timeline = track_group['FRAME'].to_numpy().astype(int)
627
+ feature = track_group[feature_selected].to_numpy()
628
+ if self.checkBox_feature.isChecked():
629
+ second_feature=track_group[self.second_feature_selected].to_numpy()
630
+ if self.cbs[2].currentText().startswith('t') and not self.abs_time_checkbox.isChecked():
631
+ t0 = math.floor(track_group[self.cbs[2].currentText()].to_numpy()[0])
632
+ timeline -= t0
633
+ elif self.cbs[2].currentText()=='first detection' and not self.abs_time_checkbox.isChecked():
634
+
635
+ if 'area' in list(track_group.columns):
636
+ print('area in list')
637
+ feat = track_group['area'].values
638
+ else:
639
+ feat = feature
640
+
641
+ first_detection = timeline[feat==feat][0]
642
+ timeline -= first_detection
643
+ print(first_detection, timeline)
644
+
645
+ elif self.abs_time_checkbox.isChecked():
646
+ timeline -= int(self.frame_slider.value())
647
+
648
+ loc_t = [np.where(mapping==t)[0][0] for t in timeline]
649
+ matrix[cid,loc_t] = feature
650
+ if second_feature:
651
+ matrix[cid,loc_t+1]=second_feature
652
+ print(timeline, loc_t)
653
+
654
+ cid+=1
655
+ except:
656
+ pass
657
+ return matrix
658
+
659
+ def col_mean(self, matrix):
660
+
661
+ mean_line = np.zeros(matrix.shape[1])
662
+ mean_line[:] = np.nan
663
+ std_line = np.copy(mean_line)
664
+
665
+ for k in range(matrix.shape[1]):
666
+ values = matrix[:,k]
667
+ #values = values[values!=0]
668
+ if len(values[values==values])>2:
669
+ mean_line[k] = np.nanmean(values)
670
+ std_line[k] = np.nanstd(values)
671
+
672
+ return mean_line, std_line
673
+
674
+ def initialize_axis(self):
675
+
676
+ self.ax.clear()
677
+ self.ax.plot([],[])
678
+ self.ax.spines['top'].set_visible(False)
679
+ self.ax.spines['right'].set_visible(False)
680
+ self.ax.set_ylim(self.df[self.feature_selected].min(),self.df[self.feature_selected].max())
681
+ self.ax.set_xlim(-(self.df['FRAME'].max()+2)*self.FrameToMin,(self.df['FRAME'].max()+2)*self.FrameToMin)
682
+ self.ax.set_xlabel('time [min]')
683
+ self.ax.set_ylabel(self.feature_selected)
684
+ if self.checkBox_feature.isChecked():
685
+ if self.ax2:
686
+ self.ax2.clear()
687
+ self.ax2.get_yaxis().set_visible(False)
688
+ self.ax2 = self.ax.twinx()
689
+ #self.ax2.plot([], color='red', label='Feature 2')
690
+ self.ax2.set_ylim(self.df[self.second_feature_selected].min(), self.df[self.second_feature_selected].max())
691
+ self.ax2.set_ylabel(self.second_feature_selected, color='red')
692
+ self.ax2.get_yaxis().set_visible(True)
693
+ #self.ax2.tick_params('y', colors='red')
694
+
695
+ def plot_survivals(self, id):
696
+
697
+ for i in range(3):
698
+ if self.plot_options[i].isChecked():
699
+ self.plot_mode = self.radio_labels[i]
700
+
701
+ if self.target_class==[0,1]:
702
+ mean_signal = 'mean_all'
703
+ std_signal = 'std_all'
704
+ matrix = 'matrix_all'
705
+ if self.checkBox_feature.isChecked():
706
+ second_mean_signal='second_mean_all'
707
+ second_std_signal='second_std_all'
708
+ second_matrix='second_matrix_all'
709
+ elif self.target_class==[0]:
710
+ mean_signal = 'mean_event'
711
+ std_signal = 'std_event'
712
+ matrix = 'matrix_event'
713
+ if self.checkBox_feature.isChecked():
714
+ second_mean_signal='second_mean_event'
715
+ second_std_signal='second_std_event'
716
+ second_matrix='second_matrix_event'
717
+ else:
718
+ mean_signal = 'mean_no_event'
719
+ std_signal = 'std_no_event'
720
+ matrix = 'matrix_no_event'
721
+ if self.checkBox_feature.isChecked():
722
+ second_mean_signal='second_mean_no_event'
723
+ second_std_signal='second_std_no_event'
724
+ second_matrix='second_matrix_no_event'
725
+
726
+
727
+ colors = np.array([tab10(i / len(self.df_pos_info)) for i in range(len(self.df_pos_info))])
728
+ if self.checkBox_feature.isChecked():
729
+ second_colors = tab10(np.linspace(0.5, 1.5, len(self.df_pos_info)))
730
+ well_color = [tab10(i / len(self.df_well_info)) for i in range(len(self.df_well_info))]
731
+
732
+ if self.plot_mode=='pos':
733
+ self.initialize_axis()
734
+ lines = self.df_pos_info.loc[self.df_pos_info['select'],'signal'].values
735
+ pos_labels = self.df_pos_info.loc[self.df_pos_info['select'],'pos_name'].values
736
+ pos_indices = self.df_pos_info.loc[self.df_pos_info['select'],'pos_index'].values
737
+ well_index = self.df_pos_info.loc[self.df_pos_info['select'],'well_index'].values
738
+ for i in range(len(lines)):
739
+ if len(self.well_indices)<=1:
740
+ self.plot_line(lines[i], colors[pos_indices[i]], pos_labels[i], mean_signal, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines, matrix=matrix)
741
+ if self.checkBox_feature.isChecked():
742
+ self.plot_line(lines[i],second_colors[pos_indices[i]],pos_labels[i],second_mean_signal,std_signal=second_std_signal,ci_option=self.show_ci, cell_lines_option=self.show_cell_lines, matrix=second_matrix)
743
+
744
+
745
+ else:
746
+ self.plot_line(lines[i], well_color[well_index[i]], pos_labels[i], mean_signal, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines, matrix=matrix)
747
+ if self.checkBox_feature.isChecked():
748
+ self.plot_line(lines[i],second_colors[pos_indices[i]],pos_labels[i],second_mean_signal,std_signal=second_std_signal,ci_option=self.show_ci, cell_lines_option=self.show_cell_lines, matrix=second_matrix)
749
+
750
+ elif self.plot_mode=='well':
751
+ self.initialize_axis()
752
+ lines = self.df_well_info.loc[self.df_well_info['select'],'signal'].values
753
+ well_index = self.df_well_info.loc[self.df_well_info['select'],'well_index'].values
754
+ well_labels = self.df_well_info.loc[self.df_well_info['select'],'well_name'].values
755
+ for i in range(len(lines)):
756
+ if len(self.well_indices)<=1:
757
+ self.plot_line(lines[i], 'k', well_labels[i], mean_signal, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines,matrix=matrix)
758
+ if self.checkBox_feature.isChecked():
759
+ self.plot_line(lines[i], 'k', well_labels[i], second_mean_signal, std_signal=second_std_signal,
760
+ ci_option=self.show_ci, cell_lines_option=self.show_cell_lines, matrix=second_matrix)
761
+ else:
762
+ self.plot_line(lines[i], well_color[well_index[i]], well_labels[i], mean_signal, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines,matrix=matrix)
763
+ if self.checkBox_feature.isChecked():
764
+ self.plot_line(lines[i], well_color[well_index[i]], well_labels[i], second_mean_signal, std_signal=second_std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines,matrix=second_matrix)
765
+
766
+ elif self.plot_mode=='both':
767
+ self.initialize_axis()
768
+ lines_pos = self.df_pos_info.loc[self.df_pos_info['select'],'signal'].values
769
+ lines_well = self.df_well_info.loc[self.df_well_info['select'],'signal'].values
770
+
771
+ pos_indices = self.df_pos_info.loc[self.df_pos_info['select'],'pos_index'].values
772
+ well_index_pos = self.df_pos_info.loc[self.df_pos_info['select'],'well_index'].values
773
+ well_index = self.df_well_info.loc[self.df_well_info['select'],'well_index'].values
774
+ well_labels = self.df_well_info.loc[self.df_well_info['select'],'well_name'].values
775
+ pos_labels = self.df_pos_info.loc[self.df_pos_info['select'],'pos_name'].values
776
+
777
+ for i in range(len(lines_pos)):
778
+ if len(self.well_indices)<=1:
779
+ self.plot_line(lines_pos[i], colors[pos_indices[i]], pos_labels[i], mean_signal, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines,matrix=matrix)
780
+ if self.checkBox_feature.isChecked():
781
+ self.plot_line(lines_pos[i], second_colors[pos_indices[i]], pos_labels[i], second_mean_signal,
782
+ std_signal=second_std_signal, ci_option=self.show_ci,
783
+ cell_lines_option=self.show_cell_lines, matrix=second_matrix)
784
+
785
+ else:
786
+ self.plot_line(lines_pos[i], well_color[well_index_pos[i]], None, mean_signal, std_signal=std_signal, ci_option=False)
787
+ if self.checkBox_feature.isChecked():
788
+ self.plot_line(lines_pos[i], well_color[well_index_pos[i]], None, second_mean_signal,
789
+ std_signal=second_std_signal, ci_option=False)
790
+
791
+ for i in range(len(lines_well)):
792
+ if len(self.well_indices)<=1:
793
+ self.plot_line(lines_well[i], 'k', 'pool', mean_signal, std_signal=std_signal, ci_option=False)
794
+ else:
795
+ self.plot_line(lines_well[i], well_color[well_index[i]], well_labels[i], mean_signal, std_signal=std_signal, ci_option=False)
796
+ self.survival_window.setMinimumHeight(int(0.5*self.screen_height))
797
+ self.survival_window.setMinimumWidth(int(0.8 * self.survivalWidget.width()))
798
+ self.survival_window.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
799
+
800
+ self.survival_window.canvas.draw()
801
+
802
+ def plot_line(self, line, color, label, mean_signal, ci_option=True, cell_lines_option=False, alpha_ci=0.5, alpha_cell_lines=0.5, std_signal=None, matrix=None):
803
+ try:
804
+ if 'second' in str(mean_signal):
805
+ self.ax2.plot(line['timeline'] * self.FrameToMin, line[mean_signal], color=color, label=label)
806
+ else:
807
+ self.ax.plot(line['timeline']*self.FrameToMin, line[mean_signal], color=color, label=label)
808
+ if ci_option and std_signal is not None:
809
+ if 'second' in str(mean_signal):
810
+ self.ax2.fill_between(line['timeline'] * self.FrameToMin,
811
+ [a - b for a, b in zip(line[mean_signal], line[std_signal])],
812
+ [a + b for a, b in zip(line[mean_signal], line[std_signal])],
813
+ color=color,
814
+ alpha=alpha_ci,
815
+ )
816
+ else:
817
+ self.ax.fill_between(line['timeline']*self.FrameToMin,
818
+ [a-b for a,b in zip(line[mean_signal], line[std_signal])],
819
+ [a+b for a,b in zip(line[mean_signal], line[std_signal])],
820
+ color=color,
821
+ alpha=alpha_ci,
822
+ )
823
+ if cell_lines_option and matrix is not None:
824
+ print(mean_signal)
825
+ mat = line[matrix]
826
+ if 'second' in str(mean_signal):
827
+ for i in range(mat.shape[0]):
828
+ self.ax2.plot(line['timeline'] * self.FrameToMin, mat[i, :], color=color, alpha=alpha_cell_lines)
829
+ else:
830
+ for i in range(mat.shape[0]):
831
+ self.ax.plot(line['timeline']*self.FrameToMin, mat[i,:], color=color, alpha=alpha_cell_lines)
832
+
833
+ except Exception as e:
834
+ print(f'Exception {e}')
835
+
836
+ def switch_to_log(self):
837
+
838
+ """
839
+ Switch threshold histogram to log scale. Auto adjust.
840
+ """
841
+
842
+ if self.ax.get_yscale()=='linear':
843
+ self.ax.set_yscale('log')
844
+ #self.ax.set_ylim(0.01,1.05)
845
+ else:
846
+ self.ax.set_yscale('linear')
847
+ #self.ax.set_ylim(0.01,1.05)
848
+
849
+ #self.ax.autoscale()
850
+ self.survival_window.canvas.draw_idle()
851
+
852
+ def show_hide_legend(self):
853
+ if self.legend_visible:
854
+ self.ax.legend().set_visible(False)
855
+ self.legend_visible = False
856
+ self.legend_btn.setIcon(icon(MDI6.text_box_outline,color="black"))
857
+ else:
858
+ self.ax.legend().set_visible(True)
859
+ self.legend_visible = True
860
+ self.legend_btn.setIcon(icon(MDI6.text_box,color="black"))
861
+
862
+ self.survival_window.canvas.draw_idle()
863
+
864
+ def look_for_metadata(self):
865
+
866
+ self.metadata_found = False
867
+ self.metafiles = glob(self.exp_dir+os.sep.join([f'W*','*','movie','*metadata.txt'])) \
868
+ + glob(self.exp_dir+os.sep.join([f'W*','*','*metadata.txt'])) \
869
+ + glob(self.exp_dir+os.sep.join([f'W*','*metadata.txt'])) \
870
+ + glob(self.exp_dir+'*metadata.txt')
871
+ print(f'Found {len(self.metafiles)} metadata files...')
872
+ if len(self.metafiles)>0:
873
+ self.metadata_found = True
874
+
875
+ def switch_selection_mode(self, id):
876
+ print(f'button {id} was clicked')
877
+ for i in range(2):
878
+ if self.select_option[i].isChecked():
879
+ self.selection_mode = self.select_label[i]
880
+ if self.selection_mode=='name':
881
+ if len(self.metafiles)>0:
882
+ self.position_scatter.hide()
883
+ self.line_choice_widget.show()
884
+ else:
885
+ if len(self.metafiles)>0:
886
+ self.position_scatter.show()
887
+ self.line_choice_widget.hide()
888
+
889
+
890
+ def load_coordinates(self):
891
+
892
+ """
893
+ Read metadata and try to extract position coordinates
894
+ """
895
+
896
+ self.no_meta = False
897
+ try:
898
+ with open(self.metafiles[0], 'r') as f:
899
+ data = json.load(f)
900
+ positions = data['Summary']['InitialPositionList']
901
+ except Exception as e:
902
+ print(f'Trouble loading metadata: error {e}...')
903
+ return None
904
+
905
+ for k in range(len(positions)):
906
+ pos_label = positions[k]['Label']
907
+ try:
908
+ coords = positions[k]['DeviceCoordinatesUm']['XYStage']
909
+ except:
910
+ try:
911
+ coords = positions[k]['DeviceCoordinatesUm']['PIXYStage']
912
+ except:
913
+ self.no_meta = True
914
+
915
+ if not self.no_meta:
916
+ files = self.df_pos_info['stack_path'].values
917
+ pos_loc = [pos_label in f for f in files]
918
+ self.df_pos_info.loc[pos_loc, 'x'] = coords[0]
919
+ self.df_pos_info.loc[pos_loc, 'y'] = coords[1]
920
+ self.df_pos_info.loc[pos_loc, 'metadata_tag'] = pos_label
921
+
922
+
923
+ def update_annot(self, ind):
924
+
925
+ pos = self.sc.get_offsets()[ind["ind"][0]]
926
+ self.annot.xy = pos
927
+ text = self.scat_labels[ind["ind"][0]]
928
+ self.annot.set_text(text)
929
+ self.annot.get_bbox_patch().set_facecolor('k')
930
+ self.annot.get_bbox_patch().set_alpha(0.4)
931
+
932
+ def hover(self, event):
933
+ vis = self.annot.get_visible()
934
+ if event.inaxes == self.ax_scatter:
935
+ cont, ind = self.sc.contains(event)
936
+ if cont:
937
+ self.update_annot(ind)
938
+ self.annot.set_visible(True)
939
+ self.fig_scatter.canvas.draw_idle()
940
+ else:
941
+ if vis:
942
+ self.annot.set_visible(False)
943
+ self.fig_scatter.canvas.draw_idle()
944
+
945
+ def unselect_position(self, event):
946
+
947
+ ind = event.ind # index of selected position
948
+ well_idx = self.df_pos_info.iloc[ind]['well_index'].values[0]
949
+ selectedPos = self.df_pos_info.iloc[ind]['pos_path'].values[0]
950
+ currentSelState = self.df_pos_info.iloc[ind]['select'].values[0]
951
+ if self.plot_options[0].isChecked() or self.plot_options[2].isChecked():
952
+ self.df_pos_info.loc[self.df_pos_info['well_index']==well_idx,'select'] = not currentSelState
953
+ self.df_well_info.loc[self.df_well_info['well_index']==well_idx, 'select'] = not currentSelState
954
+ if len(self.well_indices)>1:
955
+ self.well_display_options[well_idx].setChecked(not currentSelState)
956
+ else:
957
+ for p in self.pos_display_options:
958
+ p.setChecked(not currentSelState)
959
+ else:
960
+ self.df_pos_info.loc[self.df_pos_info['pos_path']==selectedPos,'select'] = not currentSelState
961
+ if len(self.well_indices)<=1:
962
+ self.pos_display_options[ind[0]].setChecked(not currentSelState)
963
+
964
+ self.sc.set_color(self.select_color(self.df_pos_info["select"].values))
965
+ self.position_scatter.canvas.draw_idle()
966
+ self.plot_survivals(0)
967
+
968
+ def select_survival_lines(self):
969
+
970
+ if len(self.well_indices)>1:
971
+ for i in range(len(self.well_display_options)):
972
+ self.df_well_info.loc[self.df_well_info['well_index']==i,'select'] = self.well_display_options[i].isChecked()
973
+ self.df_pos_info.loc[self.df_pos_info['well_index']==i,'select'] = self.well_display_options[i].isChecked()
974
+ else:
975
+ for i in range(len(self.pos_display_options)):
976
+ self.df_pos_info.loc[self.df_pos_info['pos_index']==i,'select'] = self.pos_display_options[i].isChecked()
977
+
978
+ if len(self.metafiles)>0:
979
+ self.sc.set_color(self.select_color(self.df_pos_info["select"].values))
980
+ self.position_scatter.canvas.draw_idle()
981
+ self.plot_survivals(0)
982
+
983
+
984
+ def select_color(self, selection):
985
+ colors = [tab10(0) if s else tab10(0.1) for s in selection]
986
+ return colors
987
+
988
+ def plot_spatial_location(self):
989
+
990
+ try:
991
+ self.sc = self.ax_scatter.scatter(self.df_pos_info["x"].values, self.df_pos_info["y"].values, picker=True, pickradius=1, color=self.select_color(self.df_pos_info["select"].values))
992
+ self.scat_labels = self.df_pos_info['metadata_tag'].values
993
+ self.ax_scatter.invert_xaxis()
994
+ self.annot = self.ax_scatter.annotate("", xy=(0,0), xytext=(10,10),textcoords="offset points",
995
+ bbox=dict(boxstyle="round", fc="w"),
996
+ arrowprops=dict(arrowstyle="->"))
997
+ self.annot.set_visible(False)
998
+ self.fig_scatter.canvas.mpl_connect("motion_notify_event", self.hover)
999
+ self.fig_scatter.canvas.mpl_connect("pick_event", self.unselect_position)
1000
+ except Exception as e:
1001
+ pass
1002
+
1003
+
1004
+ def switch_ref_time_mode(self):
1005
+ if self.abs_time_checkbox.isChecked():
1006
+ self.frame_slider.setEnabled(True)
1007
+ self.cbs[-1].setEnabled(False)
1008
+ else:
1009
+ self.frame_slider.setEnabled(False)
1010
+ self.cbs[-1].setEnabled(True)
1011
+
1012
+ def switch_ci(self):
1013
+
1014
+ if self.show_ci:
1015
+ self.ci_btn.setIcon(icon(MDI6.arrow_expand_horizontal,color="black"))
1016
+ else:
1017
+ self.ci_btn.setIcon(icon(MDI6.arrow_expand_horizontal,color="blue"))
1018
+ self.show_ci = not self.show_ci
1019
+ self.plot_survivals(0)
1020
+
1021
+ def switch_cell_lines(self):
1022
+
1023
+ if self.show_cell_lines:
1024
+ self.cell_lines_btn.setIcon(icon(MDI6.view_headline,color="black"))
1025
+ else:
1026
+ self.cell_lines_btn.setIcon(icon(MDI6.view_headline,color="blue"))
1027
+ self.show_cell_lines = not self.show_cell_lines
1028
+ self.plot_survivals(0)
1029
+
1030
+
1031
+ def set_class_to_plot(self):
1032
+
1033
+ if self.all_btn.isChecked():
1034
+ self.target_class=[0,1]
1035
+ elif self.event_btn.isChecked():
1036
+ self.target_class = [0]
1037
+ else:
1038
+ self.target_class = [1]
1039
+
1040
+ self.plot_survivals(0)
1041
+
1042
+