celldetective 1.2.0__py3-none-any.whl → 1.2.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 (54) hide show
  1. celldetective/__main__.py +12 -5
  2. celldetective/events.py +28 -2
  3. celldetective/gui/about.py +0 -1
  4. celldetective/gui/analyze_block.py +3 -18
  5. celldetective/gui/btrack_options.py +126 -21
  6. celldetective/gui/classifier_widget.py +68 -107
  7. celldetective/gui/configure_new_exp.py +37 -4
  8. celldetective/gui/control_panel.py +14 -30
  9. celldetective/gui/generic_signal_plot.py +793 -0
  10. celldetective/gui/gui_utils.py +401 -226
  11. celldetective/gui/json_readers.py +0 -2
  12. celldetective/gui/layouts.py +269 -25
  13. celldetective/gui/measurement_options.py +14 -23
  14. celldetective/gui/neighborhood_options.py +6 -16
  15. celldetective/gui/plot_measurements.py +10 -23
  16. celldetective/gui/plot_signals_ui.py +53 -687
  17. celldetective/gui/process_block.py +320 -186
  18. celldetective/gui/retrain_segmentation_model_options.py +30 -47
  19. celldetective/gui/retrain_signal_model_options.py +5 -14
  20. celldetective/gui/seg_model_loader.py +129 -113
  21. celldetective/gui/signal_annotator.py +93 -103
  22. celldetective/gui/signal_annotator2.py +9 -13
  23. celldetective/gui/styles.py +32 -0
  24. celldetective/gui/survival_ui.py +49 -712
  25. celldetective/gui/tableUI.py +4 -39
  26. celldetective/gui/thresholds_gui.py +38 -11
  27. celldetective/gui/viewers.py +6 -7
  28. celldetective/io.py +62 -84
  29. celldetective/measure.py +374 -15
  30. celldetective/models/segmentation_effectors/ricm-bimodal/config_input.json +130 -0
  31. celldetective/models/segmentation_effectors/ricm-bimodal/ricm-bimodal +0 -0
  32. celldetective/models/segmentation_effectors/ricm-bimodal/training_instructions.json +37 -0
  33. celldetective/neighborhood.py +3 -7
  34. celldetective/preprocessing.py +2 -4
  35. celldetective/relative_measurements.py +0 -3
  36. celldetective/scripts/analyze_signals.py +0 -1
  37. celldetective/scripts/measure_cells.py +1 -3
  38. celldetective/scripts/measure_relative.py +1 -2
  39. celldetective/scripts/segment_cells.py +16 -12
  40. celldetective/scripts/segment_cells_thresholds.py +17 -10
  41. celldetective/scripts/track_cells.py +18 -18
  42. celldetective/scripts/train_segmentation_model.py +1 -2
  43. celldetective/scripts/train_signal_model.py +0 -3
  44. celldetective/segmentation.py +1 -1
  45. celldetective/signals.py +20 -8
  46. celldetective/tracking.py +2 -1
  47. celldetective/utils.py +126 -18
  48. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/METADATA +19 -12
  49. celldetective-1.2.2.dist-info/RECORD +92 -0
  50. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/WHEEL +1 -1
  51. celldetective-1.2.0.dist-info/RECORD +0 -88
  52. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/LICENSE +0 -0
  53. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/entry_points.txt +0 -0
  54. {celldetective-1.2.0.dist-info → celldetective-1.2.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,793 @@
1
+ from PyQt5.QtWidgets import QMessageBox,QGridLayout, QButtonGroup, \
2
+ QCheckBox, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton, \
3
+ QRadioButton
4
+ from PyQt5.QtCore import Qt, QSize
5
+ from PyQt5.QtGui import QDoubleValidator
6
+
7
+ from celldetective.gui.gui_utils import center_window, FigureCanvas, ExportPlotBtn
8
+ from superqt.fonticon import icon
9
+ from fonticon_mdi6 import MDI6
10
+ import numpy as np
11
+ import json
12
+ import os
13
+ import matplotlib.pyplot as plt
14
+ plt.rcParams['svg.fonttype'] = 'none'
15
+ from glob import glob
16
+ from matplotlib.cm import tab10
17
+ from celldetective.gui import Styles
18
+ import matplotlib.cm as mcm
19
+
20
+
21
+ class GenericSignalPlotWidget(QWidget, Styles):
22
+
23
+ def __init__(self, df = None, df_pos_info = None, df_well_info = None, feature_selected = None, parent_window=None, title='plot', *args, **kwargs):
24
+
25
+ super().__init__()
26
+ center_window(self)
27
+
28
+ self.parent_window = parent_window
29
+ self.setWindowTitle(title)
30
+ self.setWindowIcon(self.celldetective_icon)
31
+
32
+ self.show_ci = False
33
+ self.legend_visible = True
34
+ self.show_cell_lines = False
35
+ self.alpha_setting = 0.5
36
+ self.scaling_factor = 1
37
+ self.target_class = [0]
38
+ self.float_validator = QDoubleValidator()
39
+
40
+ cmap_lbl = self.parent_window.cbs[-1].currentText()
41
+ self.cmap = getattr(mcm, cmap_lbl)
42
+
43
+ self.feature_selected = feature_selected
44
+ self.df = df
45
+ self.df_pos_info = df_pos_info
46
+ self.df_well_info = df_well_info
47
+
48
+ self.layout = QVBoxLayout()
49
+ self.layout.setSpacing(3)
50
+ self.populate_widget()
51
+
52
+ self.ci_btn.click()
53
+ #self.legend_btn.click()
54
+
55
+ self.fig.tight_layout()
56
+ self.setLayout(self.layout)
57
+ self.setAttribute(Qt.WA_DeleteOnClose)
58
+
59
+ def populate_widget(self):
60
+
61
+ self.plot_options = [QRadioButton() for i in range(3)]
62
+ self.radio_labels = ['well', 'position', 'both']
63
+ radio_hbox = QHBoxLayout()
64
+ radio_hbox.setContentsMargins(15,15,15,0)
65
+
66
+ self.group_lbl = QLabel('grouping: ')
67
+ radio_hbox.addWidget(self.group_lbl, 25)
68
+ radio_subhbox = QHBoxLayout()
69
+ radio_hbox.addLayout(radio_subhbox, 75)
70
+
71
+ self.plot_btn_group = QButtonGroup()
72
+ for i in range(3):
73
+ self.plot_options[i].setText(self.radio_labels[i])
74
+ self.plot_btn_group.addButton(self.plot_options[i])
75
+ radio_subhbox.addWidget(self.plot_options[i], 33, alignment=Qt.AlignCenter)
76
+
77
+ if self.parent_window.position_indices is not None:
78
+ if len(self.parent_window.well_indices)>1 and len(self.parent_window.position_indices)==1:
79
+ self.plot_btn_group.buttons()[0].click()
80
+ for i in [1,2]:
81
+ self.plot_options[i].setEnabled(False)
82
+ elif len(self.parent_window.well_indices)>1:
83
+ self.plot_btn_group.buttons()[0].click()
84
+ elif len(self.parent_window.well_indices)==1 and len(self.parent_window.position_indices)==1:
85
+ self.plot_btn_group.buttons()[1].click()
86
+ for i in [0,2]:
87
+ self.plot_options[i].setEnabled(False)
88
+ else:
89
+ if len(self.parent_window.well_indices)>1:
90
+ self.plot_btn_group.buttons()[0].click()
91
+ elif len(self.parent_window.well_indices)==1:
92
+ self.plot_btn_group.buttons()[2].click()
93
+
94
+ self.layout.addLayout(radio_hbox)
95
+
96
+
97
+ plot_buttons_hbox = QHBoxLayout()
98
+ plot_buttons_hbox.setContentsMargins(10,10,5,0)
99
+ plot_buttons_hbox.addWidget(QLabel(''),80, alignment=Qt.AlignLeft)
100
+
101
+ self.legend_btn = QPushButton('')
102
+ self.legend_btn.setIcon(icon(MDI6.text_box,color=self.help_color))
103
+ self.legend_btn.setStyleSheet(self.button_select_all)
104
+ self.legend_btn.setToolTip('Show or hide the legend')
105
+ self.legend_btn.setIconSize(QSize(20, 20))
106
+ plot_buttons_hbox.addWidget(self.legend_btn, 5,alignment=Qt.AlignRight)
107
+
108
+ self.log_btn = QPushButton('')
109
+ self.log_btn.setIcon(icon(MDI6.math_log,color="black"))
110
+ self.log_btn.setStyleSheet(self.button_select_all)
111
+ self.log_btn.setIconSize(QSize(20, 20))
112
+ self.log_btn.setToolTip('Enable or disable log scale')
113
+ plot_buttons_hbox.addWidget(self.log_btn, 5, alignment=Qt.AlignRight)
114
+
115
+ self.ci_btn = QPushButton('')
116
+ self.ci_btn.setIcon(icon(MDI6.arrow_expand_horizontal,color="black"))
117
+ self.ci_btn.setStyleSheet(self.button_select_all)
118
+ self.ci_btn.setIconSize(QSize(20, 20))
119
+ self.ci_btn.setToolTip('Show or hide confidence intervals.')
120
+ plot_buttons_hbox.addWidget(self.ci_btn, 5, alignment=Qt.AlignRight)
121
+
122
+ self.cell_lines_btn = QPushButton('')
123
+ self.cell_lines_btn.setIcon(icon(MDI6.view_headline,color="black"))
124
+ self.cell_lines_btn.setStyleSheet(self.button_select_all)
125
+ self.cell_lines_btn.setToolTip('Show or hide individual cell signals.')
126
+ self.cell_lines_btn.setIconSize(QSize(20, 20))
127
+ plot_buttons_hbox.addWidget(self.cell_lines_btn, 5, alignment=Qt.AlignRight)
128
+
129
+ self.fig, self.ax = plt.subplots(1,1,figsize=(4,3))
130
+ self.plot_widget = FigureCanvas(self.fig, title="")
131
+ self.plot_widget.setContentsMargins(0,0,0,0)
132
+ self.initialize_axis()
133
+ plt.tight_layout()
134
+
135
+ self.export_btn = ExportPlotBtn(self.fig, export_dir=self.parent_window.exp_dir)
136
+ plot_buttons_hbox.addWidget(self.export_btn, 5, alignment=Qt.AlignRight)
137
+ self.layout.addLayout(plot_buttons_hbox)
138
+
139
+ self.ax.set_prop_cycle('color',[self.cmap(i) for i in np.linspace(0, 1, len(self.parent_window.well_indices))])
140
+
141
+ self.fig.set_facecolor('none') # or 'None'
142
+ self.fig.canvas.setStyleSheet("background-color: transparent;")
143
+ self.plot_widget.canvas.draw()
144
+
145
+ self.layout.addWidget(self.plot_widget)
146
+
147
+ self.plot_btn_group.buttonClicked[int].connect(self.plot_signals)
148
+ self.legend_btn.clicked.connect(self.show_hide_legend)
149
+ self.log_btn.clicked.connect(self.switch_to_log)
150
+ self.ci_btn.clicked.connect(self.switch_ci)
151
+ self.cell_lines_btn.clicked.connect(self.switch_cell_lines)
152
+
153
+ self.class_selection_widget = QWidget()
154
+
155
+ self.class_selection_lbl = QLabel('class of interest:')
156
+ class_hbox = QHBoxLayout()
157
+ self.class_selection_widget.setLayout(class_hbox)
158
+ class_hbox.addWidget(self.class_selection_lbl, 25, alignment=Qt.AlignLeft)
159
+
160
+ class_subhbox = QHBoxLayout()
161
+ class_hbox.addLayout(class_subhbox, 75)
162
+
163
+ self.all_btn = QRadioButton('*')
164
+ self.event_btn = QRadioButton('event')
165
+ self.event_btn.setChecked(True)
166
+ self.no_event_btn = QRadioButton('no event')
167
+ self.class_btn_group = QButtonGroup()
168
+ for btn in [self.all_btn, self.event_btn, self.no_event_btn]:
169
+ self.class_btn_group.addButton(btn)
170
+
171
+ self.class_btn_group.buttonClicked[int].connect(self.set_class_to_plot)
172
+
173
+ class_subhbox.addWidget(self.all_btn, 33, alignment=Qt.AlignCenter)
174
+ class_subhbox.addWidget(self.event_btn, 33, alignment=Qt.AlignCenter)
175
+ class_subhbox.addWidget(self.no_event_btn, 33, alignment=Qt.AlignCenter)
176
+
177
+ self.layout.addWidget(self.class_selection_widget) #Layout(class_hbox)
178
+
179
+ # Rescale
180
+ self.rescale_widget = QWidget()
181
+
182
+ scale_hbox = QHBoxLayout()
183
+ self.rescale_widget.setLayout(scale_hbox)
184
+
185
+ scale_hbox.addWidget(QLabel('scaling factor: '), 25)
186
+ self.scaling_factor_le = QLineEdit('1')
187
+ self.scaling_factor_le.setValidator(self.float_validator)
188
+ scale_hbox.addWidget(self.scaling_factor_le, 65)
189
+
190
+ self.rescale_btn = QPushButton('rescale')
191
+ self.rescale_btn.setStyleSheet(self.button_style_sheet_2)
192
+ self.rescale_btn.clicked.connect(self.rescale_y_axis)
193
+ scale_hbox.addWidget(self.rescale_btn, 10)
194
+ #self.layout.addLayout(scale_hbox)
195
+ self.layout.addWidget(self.rescale_widget)
196
+
197
+
198
+ # Rescale
199
+ self.cell_lines_alpha_wdg = QWidget()
200
+ alpha_hbox = QHBoxLayout()
201
+ self.cell_lines_alpha_wdg.setLayout(alpha_hbox)
202
+
203
+ alpha_hbox.addWidget(QLabel('single-cell\nsignal alpha: '), 25)
204
+ self.alpha_le = QLineEdit('0,8')
205
+ self.alpha_le.setValidator(self.float_validator)
206
+ alpha_hbox.addWidget(self.alpha_le, 65)
207
+
208
+ self.submit_alpha_btn = QPushButton('submit')
209
+ self.submit_alpha_btn.setStyleSheet(self.button_style_sheet_2)
210
+ self.submit_alpha_btn.clicked.connect(self.submit_alpha)
211
+ alpha_hbox.addWidget(self.submit_alpha_btn, 10)
212
+ self.layout.addWidget(self.cell_lines_alpha_wdg)
213
+
214
+ self.select_option = [QRadioButton() for i in range(2)]
215
+ self.select_label = ['by name', 'spatially']
216
+
217
+ select_hbox = QHBoxLayout()
218
+ select_hbox.addWidget(QLabel('select position: '), 25)
219
+
220
+ select_subhbox = QHBoxLayout()
221
+ select_hbox.addLayout(select_subhbox, 75)
222
+
223
+ self.select_btn_group = QButtonGroup()
224
+ for i in range(2):
225
+ self.select_option[i].setText(self.select_label[i])
226
+ self.select_btn_group.addButton(self.select_option[i])
227
+ select_subhbox.addWidget(self.select_option[i],33, alignment=Qt.AlignCenter)
228
+ self.select_option[0].setChecked(True)
229
+ self.select_btn_group.buttonClicked[int].connect(self.switch_selection_mode)
230
+ self.layout.addLayout(select_hbox)
231
+
232
+ self.look_for_metadata()
233
+ if self.metadata_found:
234
+ self.fig_scatter, self.ax_scatter = plt.subplots(1,1,figsize=(4,2)) #,figsize=(4,3)
235
+ self.position_scatter = FigureCanvas(self.fig_scatter)
236
+ self.load_coordinates()
237
+ self.plot_spatial_location()
238
+ self.ax_scatter.spines['top'].set_visible(False)
239
+ self.ax_scatter.spines['right'].set_visible(False)
240
+ self.ax_scatter.set_aspect('equal')
241
+ self.ax_scatter.set_xticks([])
242
+ self.ax_scatter.set_yticks([])
243
+ plt.tight_layout()
244
+
245
+ self.fig_scatter.set_facecolor('none') # or 'None'
246
+ self.fig_scatter.canvas.setStyleSheet("background-color: transparent;")
247
+ self.layout.addWidget(self.position_scatter)
248
+
249
+ self.generate_pos_selection_widget()
250
+ self.select_btn_group.buttons()[0].click()
251
+
252
+ def submit_alpha(self):
253
+
254
+ alpha = self.alpha_le.text().replace(',','.')
255
+ try:
256
+ alpha = float(alpha)
257
+ except:
258
+ return None
259
+ if alpha>1.0:
260
+ alpha = 1.0
261
+ elif alpha<0.0:
262
+ alpha = 0.0
263
+ self.alpha_setting = alpha
264
+ self.plot_signals(0)
265
+
266
+ def rescale_y_axis(self):
267
+ new_scale = self.scaling_factor_le.text().replace(',','.')
268
+ if new_scale=='':
269
+ msgBox = QMessageBox()
270
+ msgBox.setIcon(QMessageBox.Warning)
271
+ msgBox.setText("Please set a valid scaling factor...")
272
+ msgBox.setWindowTitle("Warning")
273
+ msgBox.setStandardButtons(QMessageBox.Ok)
274
+ returnValue = msgBox.exec()
275
+ if returnValue == QMessageBox.Ok:
276
+ return None
277
+ else:
278
+ self.scaling_factor = float(new_scale)
279
+ self.plot_signals(0)
280
+
281
+
282
+ def switch_selection_mode(self, id):
283
+
284
+ for i in range(2):
285
+ if self.select_option[i].isChecked():
286
+ self.selection_mode = self.select_label[i]
287
+ if self.selection_mode=='by name':
288
+ if len(self.metafiles)>0:
289
+ self.position_scatter.hide()
290
+ self.line_choice_widget.show()
291
+ else:
292
+ if len(self.metafiles)>0:
293
+ self.position_scatter.show()
294
+ self.line_choice_widget.hide()
295
+
296
+ def set_class_to_plot(self):
297
+
298
+ if self.all_btn.isChecked():
299
+ self.target_class=[0,1]
300
+ elif self.event_btn.isChecked():
301
+ self.target_class = [0]
302
+ else:
303
+ self.target_class = [1]
304
+
305
+ self.plot_signals(0)
306
+
307
+ def generate_pos_selection_widget(self):
308
+
309
+ self.well_names = self.df['well_name'].unique()
310
+ self.pos_names = self.df_pos_info['pos_name'].unique() #pd.DataFrame(self.ks_estimators_per_position)['position_name'].unique()
311
+
312
+ self.usable_well_labels = []
313
+ for name in self.well_names:
314
+ for lbl in self.parent_window.well_labels:
315
+ if name+':' in lbl:
316
+ self.usable_well_labels.append(lbl)
317
+
318
+ self.line_choice_widget = QWidget()
319
+ self.line_check_vbox = QGridLayout()
320
+ self.line_choice_widget.setLayout(self.line_check_vbox)
321
+
322
+ if len(self.parent_window.well_indices)>1:
323
+ self.well_display_options = [QCheckBox(self.usable_well_labels[i]) for i in range(len(self.usable_well_labels))]
324
+ for i in range(len(self.well_names)):
325
+ self.line_check_vbox.addWidget(self.well_display_options[i], i, 0, 1, 1, alignment=Qt.AlignLeft)
326
+ self.well_display_options[i].setChecked(True)
327
+ self.well_display_options[i].setStyleSheet("font-size: 12px;")
328
+ self.well_display_options[i].toggled.connect(self.select_lines)
329
+ else:
330
+ self.pos_display_options = [QCheckBox(self.pos_names[i]) for i in range(len(self.pos_names))]
331
+ for i in range(len(self.pos_names)):
332
+ self.line_check_vbox.addWidget(self.pos_display_options[i], i%4, i//4, 1, 1, alignment=Qt.AlignCenter)
333
+ self.pos_display_options[i].setChecked(True)
334
+ self.pos_display_options[i].setStyleSheet("font-size: 12px;")
335
+ self.pos_display_options[i].toggled.connect(self.select_lines)
336
+
337
+ self.layout.addWidget(self.line_choice_widget)
338
+ #self.layout.addLayout(self.line_check_vbox)
339
+
340
+ def look_for_metadata(self):
341
+ self.metadata_found = False
342
+ self.metafiles = glob(self.parent_window.exp_dir+os.sep.join([f'W*','*','movie','*metadata.txt'])) \
343
+ + glob(self.parent_window.exp_dir+os.sep.join([f'W*','*','*metadata.txt'])) \
344
+ + glob(self.parent_window.exp_dir+os.sep.join([f'W*','*metadata.txt'])) \
345
+ + glob(self.parent_window.exp_dir+'*metadata.txt')
346
+ print(f'Found {len(self.metafiles)} metadata files...')
347
+ if len(self.metafiles)>0:
348
+ self.metadata_found = True
349
+
350
+ def load_coordinates(self):
351
+
352
+ """
353
+ Read metadata and try to extract position coordinates
354
+ """
355
+
356
+ self.no_meta = False
357
+ try:
358
+ with open(self.metafiles[0], 'r') as f:
359
+ data = json.load(f)
360
+ positions = data['Summary']['InitialPositionList']
361
+ except Exception as e:
362
+ print(f'Trouble loading metadata: error {e}...')
363
+ return None
364
+
365
+ for k in range(len(positions)):
366
+ pos_label = positions[k]['Label']
367
+ try:
368
+ coords = positions[k]['DeviceCoordinatesUm']['XYStage']
369
+ except:
370
+ try:
371
+ coords = positions[k]['DeviceCoordinatesUm']['PIXYStage']
372
+ except:
373
+ self.no_meta = True
374
+
375
+ if not self.no_meta:
376
+ files = self.df_pos_info['stack_path'].values
377
+ pos_loc = [pos_label in f for f in files]
378
+ self.df_pos_info.loc[pos_loc, 'x'] = coords[0]
379
+ self.df_pos_info.loc[pos_loc, 'y'] = coords[1]
380
+ self.df_pos_info.loc[pos_loc, 'metadata_tag'] = pos_label
381
+
382
+
383
+ def plot_spatial_location(self):
384
+
385
+ try:
386
+ 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))
387
+ self.scat_labels = self.df_pos_info['metadata_tag'].values
388
+ self.ax_scatter.invert_xaxis()
389
+
390
+ self.annot = self.ax_scatter.annotate("", xy=(0,0), xytext=(10,10),textcoords="offset points",
391
+ bbox=dict(boxstyle="round", fc="w"),
392
+ arrowprops=dict(arrowstyle="->"))
393
+ self.annot.set_visible(False)
394
+
395
+ xmin,xmax = self.ax_scatter.get_xlim()
396
+ ymin,ymax = self.ax_scatter.get_ylim()
397
+ xdatarange = xmax - xmin
398
+ ydatarange = ymax - ymin
399
+
400
+ self.ax_scatter.set_xlim(xmin-0.1*xdatarange, xmax + 0.1*xdatarange)
401
+ self.ax_scatter.set_ylim(ymin-0.1*ydatarange, ymax + 0.1*ydatarange)
402
+
403
+ #xmin,xmax = self.ax_scatter.get_xlim()
404
+ #ymin,ymax = self.ax_scatter.get_ylim()
405
+ #desired_a = 4
406
+ #new_x_max = xmin + desired_a * (ymax - ymin)
407
+ #self.ax_scatter.set_xlim(xmin - (new_x_max - xmin)/2.0, new_x_max - (new_x_max - xmin)/2.0)
408
+
409
+ self.fig_scatter.tight_layout()
410
+ self.fig_scatter.canvas.mpl_connect("motion_notify_event", self.hover)
411
+ self.fig_scatter.canvas.mpl_connect("pick_event", self.unselect_position)
412
+ except Exception as e:
413
+ pass
414
+
415
+ def update_annot(self, ind):
416
+
417
+ pos = self.sc.get_offsets()[ind["ind"][0]]
418
+ self.annot.xy = pos
419
+ text = self.scat_labels[ind["ind"][0]]
420
+ self.annot.set_text(text)
421
+ self.annot.get_bbox_patch().set_facecolor('k')
422
+ self.annot.get_bbox_patch().set_alpha(0.4)
423
+
424
+
425
+ def hover(self, event):
426
+ vis = self.annot.get_visible()
427
+ if event.inaxes == self.ax_scatter:
428
+ cont, ind = self.sc.contains(event)
429
+ if cont:
430
+ self.update_annot(ind)
431
+ self.annot.set_visible(True)
432
+ self.fig_scatter.canvas.draw_idle()
433
+ else:
434
+ if vis:
435
+ self.annot.set_visible(False)
436
+ self.fig_scatter.canvas.draw_idle()
437
+
438
+ def unselect_position(self, event):
439
+
440
+ ind = event.ind # index of selected position
441
+ well_idx = self.df_pos_info.iloc[ind]['well_index'].values[0]
442
+ selectedPos = self.df_pos_info.iloc[ind]['pos_path'].values[0]
443
+ currentSelState = self.df_pos_info.iloc[ind]['select'].values[0]
444
+ if self.plot_options[0].isChecked() or self.plot_options[2].isChecked():
445
+ self.df_pos_info.loc[self.df_pos_info['well_index']==well_idx,'select'] = not currentSelState
446
+ self.df_well_info.loc[self.df_well_info['well_index']==well_idx, 'select'] = not currentSelState
447
+ if len(self.parent_window.well_indices)>1:
448
+ self.well_display_options[well_idx].setChecked(not currentSelState)
449
+ else:
450
+ for p in self.pos_display_options:
451
+ p.setChecked(not currentSelState)
452
+ else:
453
+ self.df_pos_info.loc[self.df_pos_info['pos_path']==selectedPos,'select'] = not currentSelState
454
+ if len(self.parent_window.well_indices)<=1:
455
+ self.pos_display_options[ind[0]].setChecked(not currentSelState)
456
+
457
+ self.sc.set_color(self.select_color(self.df_pos_info["select"].values))
458
+ self.position_scatter.canvas.draw_idle()
459
+ self.plot_signals(0)
460
+
461
+ def select_color(self, selection):
462
+ colors = [tab10(0) if s else tab10(0.1) for s in selection]
463
+ return colors
464
+
465
+ def initialize_axis(self):
466
+
467
+ previous_ymin, previous_ymax = self.ax.get_ylim()
468
+ previous_legend = self.legend_visible
469
+ is_log = self.ax.get_yscale()
470
+
471
+ self.ax.clear()
472
+ self.ax.plot([],[])
473
+
474
+ # Labels
475
+ self.ax.set_xlabel('time [min]')
476
+ self.ax.set_ylabel(self.feature_selected)
477
+
478
+ # Spines
479
+ self.ax.spines['top'].set_visible(False)
480
+ self.ax.spines['right'].set_visible(False)
481
+
482
+ # Lims
483
+ safe_df = self.df.dropna(subset=self.feature_selected)
484
+ values = safe_df[self.feature_selected].values
485
+ if len(values)>0:
486
+ self.ax.set_ylim(np.percentile(values, 1)*self.scaling_factor, np.percentile(values, 99)*self.scaling_factor)
487
+ self.ax.set_xlim(-(self.df['FRAME'].max()+2)*self.parent_window.FrameToMin,(self.df['FRAME'].max()+2)*self.parent_window.FrameToMin)
488
+
489
+ if is_log=='log':
490
+ self.ax.set_yscale('log')
491
+ if previous_legend:
492
+ leg = self.ax.get_legend()
493
+ if leg is not None:
494
+ leg.set_visible(True)
495
+
496
+ def show_hide_legend(self):
497
+
498
+ if self.legend_visible:
499
+ leg = self.ax.get_legend()
500
+ leg.set_visible(False)
501
+ self.legend_visible = False
502
+ self.legend_btn.setIcon(icon(MDI6.text_box,color="black"))
503
+ else:
504
+ leg = self.ax.get_legend()
505
+ leg.set_visible(True)
506
+ self.legend_visible = True
507
+ self.legend_btn.setIcon(icon(MDI6.text_box,color=self.help_color))
508
+
509
+ self.plot_widget.canvas.draw_idle()
510
+
511
+ def switch_to_log(self):
512
+
513
+ """
514
+ Switch threshold histogram to log scale. Auto adjust.
515
+ """
516
+
517
+ if self.ax.get_yscale()=='linear':
518
+ self.ax.set_yscale('log')
519
+ self.log_btn.setIcon(icon(MDI6.math_log,color=self.help_color))
520
+ #self.ax.set_ylim(0.01,1.05)
521
+ else:
522
+ self.ax.set_yscale('linear')
523
+ self.log_btn.setIcon(icon(MDI6.math_log,color="black"))
524
+ #self.ax.set_ylim(0.01,1.05)
525
+
526
+ #self.ax.autoscale()
527
+ self.plot_widget.canvas.draw_idle()
528
+
529
+ def plot_signals(self, id):
530
+
531
+ for i in range(3):
532
+ if self.plot_options[i].isChecked():
533
+ self.plot_mode = self.radio_labels[i]
534
+
535
+ if self.target_class==[0,1]:
536
+ mean_signal_type = 'mean_all'
537
+ std_signal = 'std_all'
538
+ matrix = 'matrix_all'
539
+ elif self.target_class==[0]:
540
+ mean_signal_type = 'mean_event'
541
+ std_signal = 'std_event'
542
+ matrix = 'matrix_event'
543
+ else:
544
+ mean_signal_type = 'mean_no_event'
545
+ std_signal = 'std_no_event'
546
+ matrix = 'matrix_no_event'
547
+
548
+
549
+ colors = np.array([self.cmap(i / len(self.df_pos_info)) for i in range(len(self.df_pos_info))])
550
+ well_color = [self.cmap(i / len(self.df_well_info)) for i in range(len(self.df_well_info))]
551
+
552
+ if self.plot_mode=='position':
553
+ self.initialize_axis()
554
+ lines = self.df_pos_info.loc[self.df_pos_info['select'],'signal'].values
555
+ pos_labels = self.df_pos_info.loc[self.df_pos_info['select'],'pos_name'].values
556
+ pos_indices = self.df_pos_info.loc[self.df_pos_info['select'],'pos_index'].values
557
+ well_index = self.df_pos_info.loc[self.df_pos_info['select'],'well_index'].values
558
+ for i in range(len(lines)):
559
+ if len(self.parent_window.well_indices)<=1:
560
+ self.plot_line(lines[i], colors[pos_indices[i]], pos_labels[i], mean_signal_type, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines, matrix=matrix)
561
+ else:
562
+ self.plot_line(lines[i], well_color[well_index[i]], pos_labels[i], mean_signal_type, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines, matrix=matrix)
563
+ if self.legend_visible:
564
+ self.ax.legend(ncols=3,fontsize='x-small')
565
+
566
+ elif self.plot_mode=='well':
567
+ self.initialize_axis()
568
+ lines = self.df_well_info.loc[self.df_well_info['select'],'signal'].values
569
+ well_index = self.df_well_info.loc[self.df_well_info['select'],'well_index'].values
570
+ well_labels = self.df_well_info.loc[self.df_well_info['select'],'well_name'].values
571
+ for i in range(len(lines)):
572
+ if len(self.parent_window.well_indices)<=1:
573
+ self.plot_line(lines[i], 'k', well_labels[i], mean_signal_type, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines,matrix=matrix)
574
+ else:
575
+ self.plot_line(lines[i], well_color[well_index[i]], well_labels[i], mean_signal_type, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines,matrix=matrix)
576
+ if self.legend_visible:
577
+ self.ax.legend(ncols=2, fontsize='x-small')
578
+
579
+ elif self.plot_mode=='both':
580
+
581
+ self.initialize_axis()
582
+ lines_pos = self.df_pos_info.loc[self.df_pos_info['select'],'signal'].values
583
+ lines_well = self.df_well_info.loc[self.df_well_info['select'],'signal'].values
584
+
585
+ pos_indices = self.df_pos_info.loc[self.df_pos_info['select'],'pos_index'].values
586
+ well_index_pos = self.df_pos_info.loc[self.df_pos_info['select'],'well_index'].values
587
+ well_index = self.df_well_info.loc[self.df_well_info['select'],'well_index'].values
588
+ well_labels = self.df_well_info.loc[self.df_well_info['select'],'well_name'].values
589
+ pos_labels = self.df_pos_info.loc[self.df_pos_info['select'],'pos_name'].values
590
+
591
+ for i in range(len(lines_pos)):
592
+ if len(self.parent_window.well_indices)<=1:
593
+ self.plot_line(lines_pos[i], colors[pos_indices[i]], pos_labels[i], mean_signal_type, std_signal=std_signal, ci_option=self.show_ci, cell_lines_option=self.show_cell_lines,matrix=matrix)
594
+ else:
595
+ self.plot_line(lines_pos[i], well_color[well_index_pos[i]], None, mean_signal_type, std_signal=std_signal, ci_option=False)
596
+
597
+ for i in range(len(lines_well)):
598
+ if len(self.parent_window.well_indices)<=1:
599
+ self.plot_line(lines_well[i], 'k', 'pool', mean_signal_type, std_signal=std_signal, ci_option=False)
600
+ else:
601
+ self.plot_line(lines_well[i], well_color[well_index[i]], well_labels[i], mean_signal_type, std_signal=std_signal, ci_option=False)
602
+ if self.legend_visible:
603
+ self.ax.legend(ncols=3,fontsize='x-small')
604
+
605
+ self.plot_widget.canvas.draw()
606
+
607
+ def plot_line(self, line, color, label, mean_signal_type, ci_option=True, cell_lines_option=False, alpha_ci=0.5, std_signal=None, matrix=None):
608
+
609
+ # Plot a signal
610
+ if line==line:
611
+ self.ax.plot(line['timeline']*self.parent_window.FrameToMin, line[mean_signal_type]*self.scaling_factor, color=color, label=label)
612
+
613
+ if ci_option and std_signal is not None:
614
+
615
+ self.ax.fill_between(line['timeline']*self.parent_window.FrameToMin,
616
+ [a-b for a,b in zip(line[mean_signal_type]*self.scaling_factor, line[std_signal]*self.scaling_factor)],
617
+ [a+b for a,b in zip(line[mean_signal_type]*self.scaling_factor, line[std_signal]*self.scaling_factor)],
618
+ color=color,
619
+ alpha=alpha_ci,
620
+ )
621
+ if cell_lines_option and matrix is not None:
622
+ # Show individual cell signals
623
+ mat = line[matrix]
624
+ for i in range(mat.shape[0]):
625
+ self.ax.plot(line['timeline']*self.parent_window.FrameToMin, mat[i,:]*self.scaling_factor, color=color, alpha=self.alpha_setting)
626
+
627
+
628
+ def switch_ci(self):
629
+
630
+ # Show the confidence interval / STD
631
+
632
+ if self.show_ci:
633
+ self.ci_btn.setIcon(icon(MDI6.arrow_expand_horizontal,color="black"))
634
+ else:
635
+ self.ci_btn.setIcon(icon(MDI6.arrow_expand_horizontal,color=self.help_color))
636
+ self.show_ci = not self.show_ci
637
+ self.plot_signals(0)
638
+
639
+ def switch_cell_lines(self):
640
+
641
+ # Show individual cell signals
642
+
643
+ if self.show_cell_lines:
644
+ self.cell_lines_btn.setIcon(icon(MDI6.view_headline,color="black"))
645
+ else:
646
+ self.cell_lines_btn.setIcon(icon(MDI6.view_headline,color=self.help_color))
647
+ self.show_cell_lines = not self.show_cell_lines
648
+ self.plot_signals(0)
649
+
650
+ def select_lines(self):
651
+
652
+ if len(self.parent_window.well_indices)>1:
653
+ for i in range(len(self.well_display_options)):
654
+ self.df_well_info.loc[self.df_well_info['well_index']==i,'select'] = self.well_display_options[i].isChecked()
655
+ self.df_pos_info.loc[self.df_pos_info['well_index']==i,'select'] = self.well_display_options[i].isChecked()
656
+ else:
657
+ for i in range(len(self.pos_display_options)):
658
+ self.df_pos_info.loc[self.df_pos_info['pos_index']==i,'select'] = self.pos_display_options[i].isChecked()
659
+
660
+ if len(self.metafiles)>0:
661
+ self.sc.set_color(self.select_color(self.df_pos_info["select"].values))
662
+ self.position_scatter.canvas.draw_idle()
663
+ self.plot_signals(0)
664
+
665
+ class SurvivalPlotWidget(GenericSignalPlotWidget):
666
+
667
+ def __init__(self, *args, **kwargs):
668
+
669
+ super(SurvivalPlotWidget, self).__init__(*args, **kwargs)
670
+ self.cell_lines_btn.hide()
671
+ self.class_selection_widget.hide()
672
+ self.rescale_widget.hide()
673
+ self.cell_lines_alpha_wdg.hide()
674
+
675
+ def switch_to_log(self):
676
+
677
+ """
678
+ Switch threshold histogram to log scale. Auto adjust.
679
+ """
680
+
681
+ if self.ax.get_yscale()=='linear':
682
+ ymin,_ = self.ax.get_ylim()
683
+ self.ax.set_ylim(max(ymin,0.01),1.05)
684
+ self.ax.set_yscale('log')
685
+ self.log_btn.setIcon(icon(MDI6.math_log,color=self.help_color))
686
+ else:
687
+ self.ax.set_yscale('linear')
688
+ self.log_btn.setIcon(icon(MDI6.math_log,color="black"))
689
+ #self.ax.set_ylim(0.01,1.05)
690
+
691
+ #self.ax.autoscale()
692
+ self.plot_widget.canvas.draw_idle()
693
+
694
+ def initialize_axis(self):
695
+
696
+ previous_legend = self.legend_visible
697
+ is_log = self.ax.get_yscale()
698
+
699
+ self.ax.clear()
700
+ self.ax.plot([],[])
701
+
702
+ # Labels
703
+ self.ax.set_xlabel('time [min]')
704
+ self.ax.set_ylabel('survival')
705
+
706
+ # Spines
707
+ self.ax.spines['top'].set_visible(False)
708
+ self.ax.spines['right'].set_visible(False)
709
+
710
+ # Lims
711
+ self.ax.set_xlim(0*self.parent_window.FrameToMin,(self.df['FRAME'].max()+2)*self.parent_window.FrameToMin)
712
+ if is_log=='log':
713
+ ymin = 0.1
714
+ else:
715
+ ymin = 0.0
716
+ self.ax.set_ylim(ymin,1.05)
717
+
718
+ if is_log=='log':
719
+ self.ax.set_yscale('log')
720
+ if previous_legend:
721
+ leg = self.ax.get_legend()
722
+ if leg is not None:
723
+ leg.set_visible(True)
724
+
725
+ def plot_signals(self, id):
726
+
727
+ for i in range(3):
728
+ if self.plot_options[i].isChecked():
729
+ self.plot_mode = self.radio_labels[i]
730
+
731
+ colors = np.array([self.cmap(i / len(self.df_pos_info)) for i in range(len(self.df_pos_info))])
732
+ well_color = [self.cmap(i / len(self.df_well_info)) for i in range(len(self.df_well_info))]
733
+
734
+ if self.plot_mode=='position':
735
+ self.initialize_axis()
736
+ lines = self.df_pos_info.loc[self.df_pos_info['select'],'survival_fit'].values
737
+ pos_labels = self.df_pos_info.loc[self.df_pos_info['select'],'pos_name'].values
738
+ pos_indices = self.df_pos_info.loc[self.df_pos_info['select'],'pos_index'].values
739
+ well_index = self.df_pos_info.loc[self.df_pos_info['select'],'well_index'].values
740
+ for i in range(len(lines)):
741
+ if len(self.parent_window.well_indices)<=1:
742
+ self.plot_line(lines[i], colors[pos_indices[i]], pos_labels[i], ci_option=self.show_ci)
743
+ else:
744
+ self.plot_line(lines[i], well_color[well_index[i]], pos_labels[i], ci_option=self.show_ci)
745
+ if self.legend_visible:
746
+ self.ax.legend(ncols=3,fontsize='x-small')
747
+
748
+ elif self.plot_mode=='well':
749
+ self.initialize_axis()
750
+ lines = self.df_well_info.loc[self.df_well_info['select'],'survival_fit'].values
751
+ well_index = self.df_well_info.loc[self.df_well_info['select'],'well_index'].values
752
+ well_labels = self.df_well_info.loc[self.df_well_info['select'],'well_name'].values
753
+ for i in range(len(lines)):
754
+ if len(self.parent_window.well_indices)<=1:
755
+ self.plot_line(lines[i], 'k', well_labels[i], ci_option=self.show_ci, legend=True)
756
+ else:
757
+ self.plot_line(lines[i], well_color[well_index[i]], well_labels[i], ci_option=self.show_ci, legend=True)
758
+ if self.legend_visible:
759
+ self.ax.legend(ncols=2, fontsize='x-small')
760
+
761
+ elif self.plot_mode=='both':
762
+
763
+ self.initialize_axis()
764
+ lines_pos = self.df_pos_info.loc[self.df_pos_info['select'],'survival_fit'].values
765
+ lines_well = self.df_well_info.loc[self.df_well_info['select'],'survival_fit'].values
766
+
767
+ pos_indices = self.df_pos_info.loc[self.df_pos_info['select'],'pos_index'].values
768
+ well_index_pos = self.df_pos_info.loc[self.df_pos_info['select'],'well_index'].values
769
+ well_index = self.df_well_info.loc[self.df_well_info['select'],'well_index'].values
770
+ well_labels = self.df_well_info.loc[self.df_well_info['select'],'well_name'].values
771
+ pos_labels = self.df_pos_info.loc[self.df_pos_info['select'],'pos_name'].values
772
+
773
+ for i in range(len(lines_pos)):
774
+ if len(self.parent_window.well_indices)<=1:
775
+ self.plot_line(lines_pos[i], colors[pos_indices[i]], pos_labels[i], ci_option=self.show_ci, legend=True)
776
+ else:
777
+ self.plot_line(lines_pos[i], well_color[well_index_pos[i]], None, ci_option=False)
778
+
779
+ for i in range(len(lines_well)):
780
+ if len(self.parent_window.well_indices)<=1:
781
+ self.plot_line(lines_well[i], 'k', 'pool', ci_option=False, legend=True)
782
+ else:
783
+ self.plot_line(lines_well[i], well_color[well_index[i]], well_labels[i], ci_option=False, legend=True)
784
+ if self.legend_visible:
785
+ self.ax.legend(ncols=3,fontsize='x-small')
786
+
787
+ self.plot_widget.canvas.draw()
788
+
789
+ def plot_line(self, line, color, label, ci_option=True, legend=None, alpha_ci=0.5):
790
+
791
+ # Plot a signal
792
+ if line==line:
793
+ line.plot_survival_function(ci_show=ci_option, ax=self.ax, legend=legend, color=color, label=label, xlabel='timeline [min]')