celldetective 1.3.1__tar.gz → 1.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {celldetective-1.3.1 → celldetective-1.3.2}/PKG-INFO +1 -1
- celldetective-1.3.2/celldetective/_version.py +1 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/events.py +2 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/classifier_widget.py +51 -3
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/control_panel.py +7 -1
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/generic_signal_plot.py +161 -2
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/gui_utils.py +90 -1
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/plot_signals_ui.py +8 -3
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/process_block.py +31 -20
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/signal_annotator.py +53 -26
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/signal_annotator2.py +17 -30
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/survival_ui.py +7 -3
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/tableUI.py +300 -183
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/io.py +56 -3
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/measure.py +3 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/neighborhood.py +154 -69
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/relative_measurements.py +128 -4
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/measure_cells.py +3 -3
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/signals.py +207 -213
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/utils.py +16 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/PKG-INFO +1 -1
- celldetective-1.3.1/celldetective/_version.py +0 -1
- {celldetective-1.3.1 → celldetective-1.3.2}/LICENSE +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/README.md +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/__init__.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/__main__.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/datasets/segmentation_annotations/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/datasets/signal_annotations/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/extra_properties.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/filters.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/InitWindow.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/__init__.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/about.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/analyze_block.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/btrack_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/configure_new_exp.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/cell-populations.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/exp-structure.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/feature-btrack.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/neighborhood.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/preprocessing.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/propagate-classification.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/track-postprocessing.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/tracking.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/json_readers.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/layouts.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/measurement_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/neighborhood_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/plot_measurements.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/retrain_segmentation_model_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/retrain_signal_model_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/seg_model_loader.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/signal_annotator_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/styles.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/thresholds_gui.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/viewers.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/logo-large.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/logo.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/signals_icon.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/splash-test.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/splash.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/splash0.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/survival2.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/vignette_signals2.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/vignette_signals2.svg +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/links/zenodo.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/pair_signal_detection/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/segmentation_effectors/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/segmentation_generic/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/segmentation_targets/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/signal_detection/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/biased_motion.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/mcf7.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/ricm.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/ricm2.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/preprocessing.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/analyze_signals.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/measure_relative.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/segment_cells.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/segment_cells_thresholds.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/track_cells.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/train_segmentation_model.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/train_signal_model.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/segmentation.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/tracking.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/SOURCES.txt +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/dependency_links.txt +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/entry_points.txt +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/not-zip-safe +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/requires.txt +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/top_level.txt +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/setup.cfg +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/setup.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/__init__.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_events.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_filters.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_io.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_measure.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_neighborhood.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_preprocessing.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_qt.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_segmentation.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_signals.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_tracking.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_utils.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.2"
|
|
@@ -104,6 +104,8 @@ def switch_to_events(classes, event_times, max_times, origin_times=None, left_ce
|
|
|
104
104
|
pass
|
|
105
105
|
elif c==1:
|
|
106
106
|
delta_t = mt - ot
|
|
107
|
+
if cut_observation_time is not None:
|
|
108
|
+
delta_t = cut_observation_time - ot
|
|
107
109
|
if delta_t>0:
|
|
108
110
|
events.append(0)
|
|
109
111
|
survival_times.append(delta_t)
|
|
@@ -253,6 +253,24 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
253
253
|
|
|
254
254
|
def update_props_scatter(self, feature_changed=True):
|
|
255
255
|
|
|
256
|
+
try:
|
|
257
|
+
if np.any(self.df[self.features_cb[0].currentText()].to_numpy() <= 0.):
|
|
258
|
+
if self.ax_props.get_yscale()=='log':
|
|
259
|
+
self.log_btns[0].click()
|
|
260
|
+
self.log_btns[0].setEnabled(False)
|
|
261
|
+
else:
|
|
262
|
+
self.log_btns[0].setEnabled(True)
|
|
263
|
+
|
|
264
|
+
if np.any(self.df[self.features_cb[1].currentText()].to_numpy() <= 0.):
|
|
265
|
+
if self.ax_props.get_xscale()=='log':
|
|
266
|
+
self.log_btns[1].click()
|
|
267
|
+
self.log_btns[1].setEnabled(False)
|
|
268
|
+
else:
|
|
269
|
+
self.log_btns[1].setEnabled(True)
|
|
270
|
+
except Exception as e:
|
|
271
|
+
#print(e)
|
|
272
|
+
pass
|
|
273
|
+
|
|
256
274
|
class_name = self.class_name
|
|
257
275
|
|
|
258
276
|
try:
|
|
@@ -279,11 +297,24 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
279
297
|
max_x = self.df.dropna(subset=feat_x)[feat_x].max()
|
|
280
298
|
min_y = self.df.dropna(subset=feat_y)[feat_y].min()
|
|
281
299
|
max_y = self.df.dropna(subset=feat_y)[feat_y].max()
|
|
300
|
+
|
|
301
|
+
x_padding = (max_x - min_x) * 0.05
|
|
302
|
+
y_padding = (max_y - min_y) * 0.05
|
|
303
|
+
if x_padding==0:
|
|
304
|
+
x_padding = 0.05
|
|
305
|
+
if y_padding==0:
|
|
306
|
+
y_padding = 0.05
|
|
282
307
|
|
|
283
308
|
if min_x==min_x and max_x==max_x:
|
|
284
|
-
self.ax_props.
|
|
309
|
+
if self.ax_props.get_xscale()=='linear':
|
|
310
|
+
self.ax_props.set_xlim(min_x - x_padding, max_x + x_padding)
|
|
311
|
+
else:
|
|
312
|
+
self.ax_props.set_xlim(min_x, max_x)
|
|
285
313
|
if min_y==min_y and max_y==max_y:
|
|
286
|
-
self.ax_props.
|
|
314
|
+
if self.ax_props.get_yscale()=='linear':
|
|
315
|
+
self.ax_props.set_ylim(min_y - y_padding, max_y + y_padding)
|
|
316
|
+
else:
|
|
317
|
+
self.ax_props.set_ylim(min_y, max_y)
|
|
287
318
|
|
|
288
319
|
self.propscanvas.canvas.toolbar.update()
|
|
289
320
|
|
|
@@ -452,22 +483,39 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
452
483
|
|
|
453
484
|
if i==1:
|
|
454
485
|
try:
|
|
486
|
+
feat_x = self.features_cb[1].currentText()
|
|
487
|
+
min_x = self.df.dropna(subset=feat_x)[feat_x].min()
|
|
488
|
+
max_x = self.df.dropna(subset=feat_x)[feat_x].max()
|
|
489
|
+
x_padding = (max_x - min_x) * 0.05
|
|
490
|
+
if x_padding==0:
|
|
491
|
+
x_padding = 0.05
|
|
492
|
+
|
|
455
493
|
if self.ax_props.get_xscale()=='linear':
|
|
494
|
+
self.ax_props.set_xlim(min_x, max_x)
|
|
456
495
|
self.ax_props.set_xscale('log')
|
|
457
496
|
self.log_btns[i].setIcon(icon(MDI6.math_log,color="#1565c0"))
|
|
458
497
|
else:
|
|
459
498
|
self.ax_props.set_xscale('linear')
|
|
499
|
+
self.ax_props.set_xlim(min_x - x_padding, max_x + x_padding)
|
|
460
500
|
self.log_btns[i].setIcon(icon(MDI6.math_log,color="black"))
|
|
461
501
|
except Exception as e:
|
|
462
502
|
print(e)
|
|
463
503
|
elif i==0:
|
|
464
504
|
try:
|
|
505
|
+
feat_y = self.features_cb[0].currentText()
|
|
506
|
+
min_y = self.df.dropna(subset=feat_y)[feat_y].min()
|
|
507
|
+
max_y = self.df.dropna(subset=feat_y)[feat_y].max()
|
|
508
|
+
y_padding = (max_y - min_y) * 0.05
|
|
509
|
+
if y_padding==0:
|
|
510
|
+
y_padding = 0.05
|
|
511
|
+
|
|
465
512
|
if self.ax_props.get_yscale()=='linear':
|
|
466
|
-
|
|
513
|
+
self.ax_props.set_ylim(min_y, max_y)
|
|
467
514
|
self.ax_props.set_yscale('log')
|
|
468
515
|
self.log_btns[i].setIcon(icon(MDI6.math_log,color="#1565c0"))
|
|
469
516
|
else:
|
|
470
517
|
self.ax_props.set_yscale('linear')
|
|
518
|
+
self.ax_props.set_ylim(min_y - y_padding, max_y + y_padding)
|
|
471
519
|
self.log_btns[i].setIcon(icon(MDI6.math_log,color="black"))
|
|
472
520
|
except Exception as e:
|
|
473
521
|
print(e)
|
|
@@ -181,7 +181,13 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
181
181
|
exp_hbox = QHBoxLayout()
|
|
182
182
|
exp_hbox.addWidget(experiment_label, 25, alignment=Qt.AlignRight)
|
|
183
183
|
exp_subhbox = QHBoxLayout()
|
|
184
|
-
|
|
184
|
+
if len(name)>thresh:
|
|
185
|
+
name_cut = name[:thresh - 3]+'...'
|
|
186
|
+
else:
|
|
187
|
+
name_cut = name
|
|
188
|
+
exp_name_lbl = QLabel(name_cut)
|
|
189
|
+
exp_name_lbl.setToolTip(name)
|
|
190
|
+
exp_subhbox.addWidget(exp_name_lbl, 90, alignment=Qt.AlignLeft)
|
|
185
191
|
exp_subhbox.addWidget(self.folder_exp_btn, 5, alignment=Qt.AlignRight)
|
|
186
192
|
exp_subhbox.addWidget(self.edit_config_button, 5, alignment=Qt.AlignRight)
|
|
187
193
|
exp_hbox.addLayout(exp_subhbox, 75)
|
|
@@ -5,7 +5,11 @@ from PyQt5.QtCore import Qt, QSize
|
|
|
5
5
|
from PyQt5.QtGui import QDoubleValidator
|
|
6
6
|
|
|
7
7
|
from celldetective.gui.gui_utils import center_window, FigureCanvas, ExportPlotBtn
|
|
8
|
+
from celldetective.gui.tableUI import TableUI
|
|
9
|
+
from celldetective.io import collect_experiment_metadata
|
|
10
|
+
|
|
8
11
|
from superqt.fonticon import icon
|
|
12
|
+
from superqt import QLabeledSlider
|
|
9
13
|
from fonticon_mdi6 import MDI6
|
|
10
14
|
import numpy as np
|
|
11
15
|
import json
|
|
@@ -16,7 +20,9 @@ from glob import glob
|
|
|
16
20
|
from matplotlib.cm import tab10
|
|
17
21
|
from celldetective.gui import Styles
|
|
18
22
|
import matplotlib.cm as mcm
|
|
23
|
+
import pandas as pd
|
|
19
24
|
|
|
25
|
+
from lifelines.utils import qth_survival_times
|
|
20
26
|
|
|
21
27
|
class GenericSignalPlotWidget(QWidget, Styles):
|
|
22
28
|
|
|
@@ -136,6 +142,14 @@ class GenericSignalPlotWidget(QWidget, Styles):
|
|
|
136
142
|
plot_buttons_hbox.addWidget(self.export_btn, 5, alignment=Qt.AlignRight)
|
|
137
143
|
self.layout.addLayout(plot_buttons_hbox)
|
|
138
144
|
|
|
145
|
+
self.export_tabular_btn = QPushButton('')
|
|
146
|
+
self.export_tabular_btn.setIcon(icon(MDI6.table,color="black"))
|
|
147
|
+
self.export_tabular_btn.setStyleSheet(self.button_select_all)
|
|
148
|
+
self.export_tabular_btn.setToolTip('Tabulate survival values.')
|
|
149
|
+
self.export_tabular_btn.setIconSize(QSize(20, 20))
|
|
150
|
+
plot_buttons_hbox.addWidget(self.export_tabular_btn, 5, alignment=Qt.AlignRight)
|
|
151
|
+
self.export_tabular_btn.hide()
|
|
152
|
+
|
|
139
153
|
self.ax.set_prop_cycle('color',[self.cmap(i) for i in np.linspace(0, 1, len(self.parent_window.well_indices))])
|
|
140
154
|
|
|
141
155
|
self.fig.set_facecolor('none') # or 'None'
|
|
@@ -671,7 +685,9 @@ class SurvivalPlotWidget(GenericSignalPlotWidget):
|
|
|
671
685
|
self.class_selection_widget.hide()
|
|
672
686
|
self.rescale_widget.hide()
|
|
673
687
|
self.cell_lines_alpha_wdg.hide()
|
|
674
|
-
|
|
688
|
+
self.export_tabular_btn.show()
|
|
689
|
+
self.export_tabular_btn.clicked.connect(self.set_table_options)
|
|
690
|
+
|
|
675
691
|
def switch_to_log(self):
|
|
676
692
|
|
|
677
693
|
"""
|
|
@@ -790,4 +806,147 @@ class SurvivalPlotWidget(GenericSignalPlotWidget):
|
|
|
790
806
|
|
|
791
807
|
# Plot a signal
|
|
792
808
|
if line==line:
|
|
793
|
-
line.plot_survival_function(ci_show=ci_option, ax=self.ax, legend=legend, color=color, label=label, xlabel='timeline [min]')
|
|
809
|
+
line.plot_survival_function(ci_show=ci_option, ax=self.ax, legend=legend, color=color, label=label, xlabel='timeline [min]')
|
|
810
|
+
|
|
811
|
+
def set_table_options(self):
|
|
812
|
+
|
|
813
|
+
self.config_table_wg = QWidget()
|
|
814
|
+
self.config_table_wg.setMinimumWidth(480)
|
|
815
|
+
self.config_table_wg.setWindowTitle('Survival data')
|
|
816
|
+
|
|
817
|
+
layout = QVBoxLayout()
|
|
818
|
+
self.config_table_wg.setLayout(layout)
|
|
819
|
+
|
|
820
|
+
self.all_values_rb = QRadioButton('tabulate all values')
|
|
821
|
+
self.single_timepoint_rb = QRadioButton('survival at single timepoint [min]: ')
|
|
822
|
+
self.ec_rb = QRadioButton(r'EC N% survival: ')
|
|
823
|
+
self.all_values_rb.toggled.connect(self.activate_sliders)
|
|
824
|
+
self.single_timepoint_rb.toggled.connect(self.activate_sliders)
|
|
825
|
+
|
|
826
|
+
self.single_timepoint_slider = QLabeledSlider()
|
|
827
|
+
self.single_timepoint_slider.setRange(0, int(self.df['FRAME'].max()*self.parent_window.FrameToMin))
|
|
828
|
+
self.single_timepoint_slider.setValue(int(self.df['FRAME'].max()*self.parent_window.FrameToMin))
|
|
829
|
+
|
|
830
|
+
self.ec_slider = QLabeledSlider()
|
|
831
|
+
self.ec_slider.setRange(0, 100)
|
|
832
|
+
self.ec_slider.setValue(50)
|
|
833
|
+
|
|
834
|
+
self.ec_rb.toggled.connect(self.activate_sliders)
|
|
835
|
+
self.all_values_rb.click()
|
|
836
|
+
|
|
837
|
+
self.set_btn = QPushButton('Set')
|
|
838
|
+
self.set_btn.setStyleSheet(self.button_style_sheet)
|
|
839
|
+
self.set_btn.clicked.connect(self.assemble_survival_data)
|
|
840
|
+
|
|
841
|
+
layout.addWidget(self.all_values_rb)
|
|
842
|
+
|
|
843
|
+
single_tp_layout = QHBoxLayout()
|
|
844
|
+
single_tp_layout.addWidget(self.single_timepoint_rb, 33)
|
|
845
|
+
single_tp_layout.addWidget(self.single_timepoint_slider, 66)
|
|
846
|
+
layout.addLayout(single_tp_layout)
|
|
847
|
+
|
|
848
|
+
ec_layout = QHBoxLayout()
|
|
849
|
+
ec_layout.addWidget(self.ec_rb, 33)
|
|
850
|
+
ec_layout.addWidget(self.ec_slider, 66)
|
|
851
|
+
layout.addLayout(ec_layout)
|
|
852
|
+
|
|
853
|
+
layout.addWidget(self.set_btn)
|
|
854
|
+
center_window(self.config_table_wg)
|
|
855
|
+
self.config_table_wg.show()
|
|
856
|
+
|
|
857
|
+
def activate_sliders(self):
|
|
858
|
+
if self.all_values_rb.isChecked():
|
|
859
|
+
self.single_timepoint_slider.setEnabled(False)
|
|
860
|
+
self.ec_slider.setEnabled(False)
|
|
861
|
+
elif self.single_timepoint_rb.isChecked():
|
|
862
|
+
self.single_timepoint_slider.setEnabled(True)
|
|
863
|
+
self.ec_slider.setEnabled(False)
|
|
864
|
+
elif self.ec_rb.isChecked():
|
|
865
|
+
self.ec_slider.setEnabled(True)
|
|
866
|
+
self.single_timepoint_slider.setEnabled(False)
|
|
867
|
+
|
|
868
|
+
def assemble_survival_data(self):
|
|
869
|
+
|
|
870
|
+
if self.plot_options[0].isChecked():
|
|
871
|
+
data = self.df_well_info
|
|
872
|
+
groupby = ['well_path']
|
|
873
|
+
if self.plot_options[1].isChecked():
|
|
874
|
+
data = self.df_pos_info
|
|
875
|
+
groupby = ['pos_path']
|
|
876
|
+
if self.plot_options[2].isChecked():
|
|
877
|
+
print('Not implemented yet... Please select "well" or "position" as grouping...')
|
|
878
|
+
return None
|
|
879
|
+
|
|
880
|
+
if self.all_values_rb.isChecked():
|
|
881
|
+
|
|
882
|
+
survival_table = []
|
|
883
|
+
tid=0
|
|
884
|
+
for name,group in data.groupby(groupby):
|
|
885
|
+
print(name)
|
|
886
|
+
if groupby[0]=="pos_path":
|
|
887
|
+
metadata = collect_experiment_metadata(pos_path=name[0])
|
|
888
|
+
elif groupby[0]=="well_path":
|
|
889
|
+
metadata = collect_experiment_metadata(well_path=name[0])
|
|
890
|
+
ks_estimator = group['survival_fit'].values[0]
|
|
891
|
+
if ks_estimator!=ks_estimator:
|
|
892
|
+
continue
|
|
893
|
+
timeline = list(ks_estimator.survival_function_.index)
|
|
894
|
+
survival = ks_estimator.survival_function_['KM_estimate'].values
|
|
895
|
+
lower_error = ks_estimator.confidence_interval_['KM_estimate_lower_0.95'].values
|
|
896
|
+
upper_error = ks_estimator.confidence_interval_['KM_estimate_upper_0.95'].values
|
|
897
|
+
for k in range(len(timeline)):
|
|
898
|
+
dico = metadata.copy()
|
|
899
|
+
dico.update({'TRACK_ID': tid,'FRAME': int(timeline[k] / self.parent_window.FrameToMin),'timeline': timeline[k], 'survival': survival[k], "event_fraction": 1-survival[k], 'KM_estimate_lower_0.95': lower_error[k], 'KM_estimate_upper_0.95': upper_error[k]})
|
|
900
|
+
survival_table.append(dico)
|
|
901
|
+
tid+=1
|
|
902
|
+
|
|
903
|
+
survival_table = pd.DataFrame(survival_table)
|
|
904
|
+
self.table = TableUI(survival_table, f"Survival data", plot_mode="plot_track_signals")
|
|
905
|
+
self.table.show()
|
|
906
|
+
|
|
907
|
+
elif self.single_timepoint_rb.isChecked():
|
|
908
|
+
|
|
909
|
+
survival_table = []
|
|
910
|
+
tid=0
|
|
911
|
+
for name,group in data.groupby(groupby):
|
|
912
|
+
print(name)
|
|
913
|
+
if groupby[0]=="pos_path":
|
|
914
|
+
metadata = collect_experiment_metadata(pos_path=name[0])
|
|
915
|
+
elif groupby[0]=="well_path":
|
|
916
|
+
metadata = collect_experiment_metadata(well_path=name[0])
|
|
917
|
+
ks_estimator = group['survival_fit'].values[0]
|
|
918
|
+
if ks_estimator!=ks_estimator:
|
|
919
|
+
continue
|
|
920
|
+
survival = ks_estimator.survival_function_at_times(self.single_timepoint_slider.value()).values[0]
|
|
921
|
+
dico = metadata.copy()
|
|
922
|
+
dico.update({'timepoint': self.single_timepoint_slider.value(), 'survival': survival, 'event_fraction': 1 - survival})
|
|
923
|
+
survival_table.append(dico)
|
|
924
|
+
tid+=1
|
|
925
|
+
|
|
926
|
+
survival_table = pd.DataFrame(survival_table)
|
|
927
|
+
self.table = TableUI(survival_table, f"Survival data", plot_mode="static")
|
|
928
|
+
self.table.show()
|
|
929
|
+
|
|
930
|
+
elif self.ec_rb.isChecked():
|
|
931
|
+
|
|
932
|
+
survival_table = []
|
|
933
|
+
tid=0
|
|
934
|
+
for name,group in data.groupby(groupby):
|
|
935
|
+
print(name)
|
|
936
|
+
if groupby[0]=="pos_path":
|
|
937
|
+
metadata = collect_experiment_metadata(pos_path=name[0])
|
|
938
|
+
elif groupby[0]=="well_path":
|
|
939
|
+
metadata = collect_experiment_metadata(well_path=name[0])
|
|
940
|
+
ks_estimator = group['survival_fit'].values[0]
|
|
941
|
+
if ks_estimator!=ks_estimator:
|
|
942
|
+
continue
|
|
943
|
+
survival = ks_estimator.survival_function_
|
|
944
|
+
ecN = qth_survival_times(float(self.ec_slider.value())/100.0, survival)
|
|
945
|
+
dico = metadata.copy()
|
|
946
|
+
dico.update({"qth": int(self.ec_slider.value()), f'EC{int(self.ec_slider.value())}% [min]': ecN})
|
|
947
|
+
survival_table.append(dico)
|
|
948
|
+
tid+=1
|
|
949
|
+
|
|
950
|
+
survival_table = pd.DataFrame(survival_table)
|
|
951
|
+
self.table = TableUI(survival_table, f"Survival data", plot_mode="static")
|
|
952
|
+
self.table.show()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
from PyQt5.QtWidgets import QApplication, QMessageBox, QFrame, QSizePolicy, QWidget, QLineEdit, QListWidget, QVBoxLayout, QComboBox, \
|
|
3
3
|
QPushButton, QLabel, QHBoxLayout, QCheckBox, QFileDialog
|
|
4
|
-
from PyQt5.QtCore import Qt, QSize
|
|
4
|
+
from PyQt5.QtCore import Qt, QSize, QAbstractTableModel
|
|
5
5
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator
|
|
6
6
|
|
|
7
7
|
from celldetective.gui import Styles
|
|
@@ -16,6 +16,95 @@ from inspect import getmembers, isfunction
|
|
|
16
16
|
from celldetective.filters import *
|
|
17
17
|
from os import sep
|
|
18
18
|
|
|
19
|
+
class PandasModel(QAbstractTableModel):
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
from https://stackoverflow.com/questions/31475965/fastest-way-to-populate-qtableview-from-pandas-data-frame
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, data):
|
|
26
|
+
QAbstractTableModel.__init__(self)
|
|
27
|
+
self._data = data
|
|
28
|
+
self.colors = dict()
|
|
29
|
+
|
|
30
|
+
def rowCount(self, parent=None):
|
|
31
|
+
return self._data.shape[0]
|
|
32
|
+
|
|
33
|
+
def columnCount(self, parent=None):
|
|
34
|
+
return self._data.shape[1]
|
|
35
|
+
|
|
36
|
+
def data(self, index, role=Qt.DisplayRole):
|
|
37
|
+
if index.isValid():
|
|
38
|
+
if role == Qt.DisplayRole:
|
|
39
|
+
return str(self._data.iloc[index.row(), index.column()])
|
|
40
|
+
if role == Qt.BackgroundRole:
|
|
41
|
+
color = self.colors.get((index.row(), index.column()))
|
|
42
|
+
if color is not None:
|
|
43
|
+
return color
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
def headerData(self, rowcol, orientation, role):
|
|
47
|
+
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
|
|
48
|
+
return self._data.columns[rowcol]
|
|
49
|
+
if orientation == Qt.Vertical and role == Qt.DisplayRole:
|
|
50
|
+
return self._data.index[rowcol]
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
def change_color(self, row, column, color):
|
|
54
|
+
ix = self.index(row, column)
|
|
55
|
+
self.colors[(row, column)] = color
|
|
56
|
+
self.dataChanged.emit(ix, ix, (Qt.BackgroundRole,))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class GenericOpColWidget(QWidget, Styles):
|
|
60
|
+
|
|
61
|
+
def __init__(self, parent_window, column=None, title=''):
|
|
62
|
+
|
|
63
|
+
super().__init__()
|
|
64
|
+
|
|
65
|
+
self.parent_window = parent_window
|
|
66
|
+
self.column = column
|
|
67
|
+
self.title = title
|
|
68
|
+
|
|
69
|
+
self.setWindowTitle(self.title)
|
|
70
|
+
# Create the QComboBox and add some items
|
|
71
|
+
|
|
72
|
+
self.layout = QVBoxLayout(self)
|
|
73
|
+
self.layout.setContentsMargins(30,30,30,30)
|
|
74
|
+
|
|
75
|
+
self.sublayout = QVBoxLayout()
|
|
76
|
+
|
|
77
|
+
self.measurements_cb = QComboBox()
|
|
78
|
+
self.measurements_cb.addItems(list(self.parent_window.data.columns))
|
|
79
|
+
if self.column is not None:
|
|
80
|
+
idx = self.measurements_cb.findText(self.column)
|
|
81
|
+
self.measurements_cb.setCurrentIndex(idx)
|
|
82
|
+
|
|
83
|
+
measurement_layout = QHBoxLayout()
|
|
84
|
+
measurement_layout.addWidget(QLabel('measurements: '), 25)
|
|
85
|
+
measurement_layout.addWidget(self.measurements_cb, 75)
|
|
86
|
+
self.sublayout.addLayout(measurement_layout)
|
|
87
|
+
|
|
88
|
+
self.layout.addLayout(self.sublayout)
|
|
89
|
+
|
|
90
|
+
self.submit_btn = QPushButton('Compute')
|
|
91
|
+
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
92
|
+
self.submit_btn.clicked.connect(self.launch_operation)
|
|
93
|
+
self.layout.addWidget(self.submit_btn, 30)
|
|
94
|
+
|
|
95
|
+
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
96
|
+
center_window(self)
|
|
97
|
+
|
|
98
|
+
def launch_operation(self):
|
|
99
|
+
|
|
100
|
+
self.compute()
|
|
101
|
+
self.parent_window.model = PandasModel(self.parent_window.data)
|
|
102
|
+
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
103
|
+
self.close()
|
|
104
|
+
|
|
105
|
+
def compute(self):
|
|
106
|
+
pass
|
|
107
|
+
|
|
19
108
|
|
|
20
109
|
class QuickSliderLayout(QHBoxLayout):
|
|
21
110
|
|
|
@@ -96,7 +96,7 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
96
96
|
main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
|
|
97
97
|
|
|
98
98
|
labels = [QLabel('population: '), QLabel('class: '), QLabel('time of\ninterest: '), QLabel('cmap: ')]
|
|
99
|
-
self.cb_options = [['targets','effectors'],[
|
|
99
|
+
self.cb_options = [['targets','effectors'],[], [], []]
|
|
100
100
|
self.cbs = [QComboBox() for i in range(len(labels))]
|
|
101
101
|
self.cbs[-1] = QColormapComboBox()
|
|
102
102
|
|
|
@@ -183,6 +183,11 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
183
183
|
self.auto_close = True
|
|
184
184
|
return None
|
|
185
185
|
|
|
186
|
+
if 'class' in self.all_columns:
|
|
187
|
+
class_columns.append("class")
|
|
188
|
+
if 't0' in self.all_columns:
|
|
189
|
+
time_columns.append('t0')
|
|
190
|
+
|
|
186
191
|
self.cbs[2].clear()
|
|
187
192
|
self.cbs[2].addItems(np.unique(self.cb_options[2]+time_columns))
|
|
188
193
|
|
|
@@ -339,7 +344,7 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
339
344
|
|
|
340
345
|
for block,movie_group in self.df.groupby(['well','position']):
|
|
341
346
|
|
|
342
|
-
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=
|
|
347
|
+
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)
|
|
343
348
|
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)
|
|
344
349
|
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)
|
|
345
350
|
self.mean_plots_timeline = timeline_all
|
|
@@ -354,7 +359,7 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
354
359
|
# Per well
|
|
355
360
|
for well,well_group in self.df.groupby('well'):
|
|
356
361
|
|
|
357
|
-
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=
|
|
362
|
+
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)
|
|
358
363
|
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)
|
|
359
364
|
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)
|
|
360
365
|
|
|
@@ -920,7 +920,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
920
920
|
plot_mode = 'plot_track_signals'
|
|
921
921
|
if 'TRACK_ID' not in list(self.df.columns):
|
|
922
922
|
plot_mode = 'static'
|
|
923
|
-
self.tab_ui = TableUI(self.df, f"Well {self.parent_window.well_list.currentText()}; Position {self.parent_window.position_list.currentText()}", population=self.mode, plot_mode=plot_mode)
|
|
923
|
+
self.tab_ui = TableUI(self.df, f"Well {self.parent_window.well_list.currentText()}; Position {self.parent_window.position_list.currentText()}", population=self.mode, plot_mode=plot_mode, save_inplace_option=True)
|
|
924
924
|
self.tab_ui.show()
|
|
925
925
|
else:
|
|
926
926
|
print('Table could not be loaded...')
|
|
@@ -1207,28 +1207,19 @@ class NeighPanel(QFrame, Styles):
|
|
|
1207
1207
|
self.measure_pairs_action.setToolTip("Measure the relative quantities defined for the cell pairs, for all neighborhoods.")
|
|
1208
1208
|
rel_layout.addWidget(self.measure_pairs_action, 90)
|
|
1209
1209
|
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
# self.config_rel_annotator_btn = QPushButton()
|
|
1220
|
-
# self.config_rel_annotator_btn.setIcon(icon(MDI6.cog_outline, color="black"))
|
|
1221
|
-
# self.config_rel_annotator_btn.setIconSize(QSize(20, 20))
|
|
1222
|
-
# self.config_rel_annotator_btn.setToolTip("Configure the animation of the annotation tool.")
|
|
1223
|
-
# self.config_rel_annotator_btn.setStyleSheet(self.button_select_all)
|
|
1224
|
-
# self.config_rel_annotator_btn.clicked.connect(self.open_signal_annotator_configuration_ui)
|
|
1225
|
-
# # self.grid_contents.addWidget(self.config_rel_annotator_btn, 1,2,1,1, alignment=Qt.AlignRight)
|
|
1226
|
-
# rel_layout.addWidget(self.config_rel_annotator_btn, 6)
|
|
1210
|
+
self.classify_pairs_btn = QPushButton()
|
|
1211
|
+
self.classify_pairs_btn.setIcon(icon(MDI6.scatter_plot, color="black"))
|
|
1212
|
+
self.classify_pairs_btn.setIconSize(QSize(20, 20))
|
|
1213
|
+
self.classify_pairs_btn.setToolTip("Classify data.")
|
|
1214
|
+
self.classify_pairs_btn.setStyleSheet(self.button_select_all)
|
|
1215
|
+
self.classify_pairs_btn.clicked.connect(self.open_classifier_ui_pairs)
|
|
1216
|
+
rel_layout.addWidget(self.classify_pairs_btn, 5) #4,2,1,1, alignment=Qt.AlignRight
|
|
1217
|
+
|
|
1227
1218
|
self.grid_contents.addLayout(rel_layout, 6, 0, 1, 4)
|
|
1228
1219
|
|
|
1229
1220
|
signal_layout = QVBoxLayout()
|
|
1230
1221
|
signal_hlayout = QHBoxLayout()
|
|
1231
|
-
self.signal_analysis_action = QCheckBox("PAIR
|
|
1222
|
+
self.signal_analysis_action = QCheckBox("DETECT PAIR EVENTS")
|
|
1232
1223
|
self.signal_analysis_action.setStyleSheet("""
|
|
1233
1224
|
font-size: 10px;
|
|
1234
1225
|
padding-left: 10px;
|
|
@@ -1304,6 +1295,26 @@ class NeighPanel(QFrame, Styles):
|
|
|
1304
1295
|
self.neigh_action.setChecked(True)
|
|
1305
1296
|
self.neigh_action.setChecked(False)
|
|
1306
1297
|
|
|
1298
|
+
def open_classifier_ui_pairs(self):
|
|
1299
|
+
|
|
1300
|
+
self.mode = "pairs"
|
|
1301
|
+
self.load_available_tables()
|
|
1302
|
+
if self.df is None:
|
|
1303
|
+
|
|
1304
|
+
msgBox = QMessageBox()
|
|
1305
|
+
msgBox.setIcon(QMessageBox.Warning)
|
|
1306
|
+
msgBox.setText("No table was found...")
|
|
1307
|
+
msgBox.setWindowTitle("Warning")
|
|
1308
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
1309
|
+
returnValue = msgBox.exec()
|
|
1310
|
+
if returnValue == QMessageBox.Ok:
|
|
1311
|
+
return None
|
|
1312
|
+
else:
|
|
1313
|
+
return None
|
|
1314
|
+
else:
|
|
1315
|
+
self.ClassifierWidget = ClassifierWidget(self)
|
|
1316
|
+
self.ClassifierWidget.show()
|
|
1317
|
+
|
|
1307
1318
|
|
|
1308
1319
|
def help_neighborhood(self):
|
|
1309
1320
|
|
|
@@ -1360,7 +1371,7 @@ class NeighPanel(QFrame, Styles):
|
|
|
1360
1371
|
|
|
1361
1372
|
if self.df is not None:
|
|
1362
1373
|
plot_mode = 'static'
|
|
1363
|
-
self.tab_ui = TableUI(self.df, f"Well {self.parent_window.well_list.currentText()}; Position {self.parent_window.position_list.currentText()}", population='pairs', plot_mode=plot_mode)
|
|
1374
|
+
self.tab_ui = TableUI(self.df, f"Well {self.parent_window.well_list.currentText()}; Position {self.parent_window.position_list.currentText()}", population='pairs', plot_mode=plot_mode, save_inplace_option=True)
|
|
1364
1375
|
self.tab_ui.show()
|
|
1365
1376
|
else:
|
|
1366
1377
|
print('Table could not be loaded...')
|