celldetective 1.0.2.post1__py3-none-any.whl → 1.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- celldetective/__main__.py +7 -21
- celldetective/events.py +2 -44
- celldetective/extra_properties.py +62 -52
- celldetective/filters.py +4 -5
- celldetective/gui/__init__.py +1 -1
- celldetective/gui/analyze_block.py +37 -10
- celldetective/gui/btrack_options.py +24 -23
- celldetective/gui/classifier_widget.py +62 -19
- celldetective/gui/configure_new_exp.py +32 -35
- celldetective/gui/control_panel.py +120 -81
- celldetective/gui/gui_utils.py +674 -396
- celldetective/gui/json_readers.py +7 -6
- celldetective/gui/layouts.py +756 -0
- celldetective/gui/measurement_options.py +98 -513
- celldetective/gui/neighborhood_options.py +322 -270
- celldetective/gui/plot_measurements.py +1114 -0
- celldetective/gui/plot_signals_ui.py +21 -20
- celldetective/gui/process_block.py +449 -169
- celldetective/gui/retrain_segmentation_model_options.py +27 -26
- celldetective/gui/retrain_signal_model_options.py +25 -24
- celldetective/gui/seg_model_loader.py +31 -27
- celldetective/gui/signal_annotator.py +2326 -2295
- celldetective/gui/signal_annotator_options.py +18 -16
- celldetective/gui/styles.py +16 -1
- celldetective/gui/survival_ui.py +67 -39
- celldetective/gui/tableUI.py +337 -48
- celldetective/gui/thresholds_gui.py +75 -71
- celldetective/gui/viewers.py +743 -0
- celldetective/io.py +247 -27
- celldetective/measure.py +43 -263
- celldetective/models/segmentation_effectors/primNK_cfse/config_input.json +29 -0
- celldetective/models/segmentation_effectors/primNK_cfse/cp-cfse-transfer +0 -0
- celldetective/models/segmentation_effectors/primNK_cfse/training_instructions.json +37 -0
- celldetective/neighborhood.py +498 -27
- celldetective/preprocessing.py +1023 -0
- celldetective/scripts/analyze_signals.py +7 -0
- celldetective/scripts/measure_cells.py +12 -0
- celldetective/scripts/segment_cells.py +20 -4
- celldetective/scripts/track_cells.py +11 -0
- celldetective/scripts/train_segmentation_model.py +35 -34
- celldetective/segmentation.py +14 -9
- celldetective/signals.py +234 -329
- celldetective/tracking.py +2 -2
- celldetective/utils.py +602 -49
- celldetective-1.1.1.dist-info/METADATA +305 -0
- celldetective-1.1.1.dist-info/RECORD +84 -0
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/top_level.txt +1 -0
- tests/__init__.py +0 -0
- tests/test_events.py +28 -0
- tests/test_filters.py +24 -0
- tests/test_io.py +70 -0
- tests/test_measure.py +141 -0
- tests/test_neighborhood.py +70 -0
- tests/test_preprocessing.py +37 -0
- tests/test_segmentation.py +93 -0
- tests/test_signals.py +135 -0
- tests/test_tracking.py +164 -0
- tests/test_utils.py +118 -0
- celldetective-1.0.2.post1.dist-info/METADATA +0 -221
- celldetective-1.0.2.post1.dist-info/RECORD +0 -66
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/LICENSE +0 -0
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/WHEEL +0 -0
- {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/entry_points.txt +0 -0
celldetective/gui/tableUI.py
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QMainWindow, QTableView, QAction, QMenu,QFileDialog, QLineEdit, QHBoxLayout, QWidget, QPushButton, QVBoxLayout, QComboBox, QLabel, QCheckBox, QMessageBox
|
|
1
|
+
from PyQt5.QtWidgets import QRadioButton, QButtonGroup, QMainWindow, QTableView, QAction, QMenu,QFileDialog, QLineEdit, QHBoxLayout, QWidget, QPushButton, QVBoxLayout, QComboBox, QLabel, QCheckBox, QMessageBox
|
|
2
2
|
from PyQt5.QtCore import Qt, QAbstractTableModel
|
|
3
3
|
import pandas as pd
|
|
4
4
|
import matplotlib.pyplot as plt
|
|
5
5
|
from matplotlib.cm import viridis
|
|
6
6
|
plt.rcParams['svg.fonttype'] = 'none'
|
|
7
7
|
from celldetective.gui.gui_utils import FigureCanvas, center_window
|
|
8
|
+
from celldetective.utils import differentiate_per_track
|
|
8
9
|
import numpy as np
|
|
9
10
|
import seaborn as sns
|
|
10
11
|
import matplotlib.cm as mcm
|
|
11
12
|
import os
|
|
13
|
+
from celldetective.gui import Styles
|
|
14
|
+
from superqt import QColormapComboBox, QLabeledSlider, QSearchableComboBox
|
|
15
|
+
from math import floor
|
|
16
|
+
|
|
17
|
+
from matplotlib import colormaps
|
|
12
18
|
|
|
13
19
|
class PandasModel(QAbstractTableModel):
|
|
14
20
|
|
|
@@ -36,10 +42,10 @@ class PandasModel(QAbstractTableModel):
|
|
|
36
42
|
|
|
37
43
|
class QueryWidget(QWidget):
|
|
38
44
|
|
|
39
|
-
def __init__(self,
|
|
45
|
+
def __init__(self, parent_window):
|
|
40
46
|
|
|
41
47
|
super().__init__()
|
|
42
|
-
self.
|
|
48
|
+
self.parent_window = parent_window
|
|
43
49
|
self.setWindowTitle("Filter table")
|
|
44
50
|
# Create the QComboBox and add some items
|
|
45
51
|
center_window(self)
|
|
@@ -53,11 +59,12 @@ class QueryWidget(QWidget):
|
|
|
53
59
|
self.submit_btn = QPushButton('submit')
|
|
54
60
|
self.submit_btn.clicked.connect(self.filter_table)
|
|
55
61
|
layout.addWidget(self.submit_btn, 30)
|
|
62
|
+
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
56
63
|
|
|
57
64
|
def filter_table(self):
|
|
58
65
|
try:
|
|
59
66
|
query_text = self.query_le.text().replace('class', '`class`')
|
|
60
|
-
tab = self.
|
|
67
|
+
tab = self.parent_window.data.query(query_text)
|
|
61
68
|
self.subtable = TableUI(tab, query_text, plot_mode="scatter")
|
|
62
69
|
self.subtable.show()
|
|
63
70
|
self.close()
|
|
@@ -65,12 +72,90 @@ class QueryWidget(QWidget):
|
|
|
65
72
|
print(e)
|
|
66
73
|
return None
|
|
67
74
|
|
|
75
|
+
class DifferentiateColWidget(QWidget, Styles):
|
|
76
|
+
|
|
77
|
+
def __init__(self, parent_window, column=None):
|
|
78
|
+
|
|
79
|
+
super().__init__()
|
|
80
|
+
self.parent_window = parent_window
|
|
81
|
+
self.column = column
|
|
82
|
+
|
|
83
|
+
self.setWindowTitle("d/dt")
|
|
84
|
+
# Create the QComboBox and add some items
|
|
85
|
+
center_window(self)
|
|
86
|
+
|
|
87
|
+
layout = QVBoxLayout(self)
|
|
88
|
+
layout.setContentsMargins(30,30,30,30)
|
|
89
|
+
|
|
90
|
+
self.measurements_cb = QComboBox()
|
|
91
|
+
self.measurements_cb.addItems(list(self.parent_window.data.columns))
|
|
92
|
+
if self.column is not None:
|
|
93
|
+
idx = self.measurements_cb.findText(self.column)
|
|
94
|
+
self.measurements_cb.setCurrentIndex(idx)
|
|
95
|
+
|
|
96
|
+
measurement_layout = QHBoxLayout()
|
|
97
|
+
measurement_layout.addWidget(QLabel('measurements: '), 25)
|
|
98
|
+
measurement_layout.addWidget(self.measurements_cb, 75)
|
|
99
|
+
layout.addLayout(measurement_layout)
|
|
100
|
+
|
|
101
|
+
self.window_size_slider = QLabeledSlider()
|
|
102
|
+
self.window_size_slider.setRange(1,np.nanmax(self.parent_window.data.FRAME.to_numpy()))
|
|
103
|
+
self.window_size_slider.setValue(3)
|
|
104
|
+
window_layout = QHBoxLayout()
|
|
105
|
+
window_layout.addWidget(QLabel('window size: '), 25)
|
|
106
|
+
window_layout.addWidget(self.window_size_slider, 75)
|
|
107
|
+
layout.addLayout(window_layout)
|
|
108
|
+
|
|
109
|
+
self.backward_btn = QRadioButton('backward')
|
|
110
|
+
self.bi_btn = QRadioButton('bi')
|
|
111
|
+
self.bi_btn.click()
|
|
112
|
+
self.forward_btn = QRadioButton('forward')
|
|
113
|
+
self.mode_btn_group = QButtonGroup()
|
|
114
|
+
self.mode_btn_group.addButton(self.backward_btn)
|
|
115
|
+
self.mode_btn_group.addButton(self.bi_btn)
|
|
116
|
+
self.mode_btn_group.addButton(self.forward_btn)
|
|
117
|
+
|
|
118
|
+
mode_layout = QHBoxLayout()
|
|
119
|
+
mode_layout.addWidget(QLabel('mode: '),25)
|
|
120
|
+
mode_sublayout = QHBoxLayout()
|
|
121
|
+
mode_sublayout.addWidget(self.backward_btn, 33, alignment=Qt.AlignCenter)
|
|
122
|
+
mode_sublayout.addWidget(self.bi_btn, 33, alignment=Qt.AlignCenter)
|
|
123
|
+
mode_sublayout.addWidget(self.forward_btn, 33, alignment=Qt.AlignCenter)
|
|
124
|
+
mode_layout.addLayout(mode_sublayout, 75)
|
|
125
|
+
layout.addLayout(mode_layout)
|
|
126
|
+
|
|
127
|
+
self.submit_btn = QPushButton('Compute')
|
|
128
|
+
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
129
|
+
self.submit_btn.clicked.connect(self.compute_derivative_and_add_new_column)
|
|
130
|
+
layout.addWidget(self.submit_btn, 30)
|
|
131
|
+
|
|
132
|
+
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def compute_derivative_and_add_new_column(self):
|
|
136
|
+
|
|
137
|
+
if self.bi_btn.isChecked():
|
|
138
|
+
mode = 'bi'
|
|
139
|
+
elif self.forward_btn.isChecked():
|
|
140
|
+
mode = 'forward'
|
|
141
|
+
elif self.backward_btn.isChecked():
|
|
142
|
+
mode = 'backward'
|
|
143
|
+
self.parent_window.data = differentiate_per_track(self.parent_window.data,
|
|
144
|
+
self.measurements_cb.currentText(),
|
|
145
|
+
window_size=self.window_size_slider.value(),
|
|
146
|
+
mode=mode)
|
|
147
|
+
self.parent_window.model = PandasModel(self.parent_window.data)
|
|
148
|
+
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
149
|
+
self.close()
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
68
153
|
class RenameColWidget(QWidget):
|
|
69
154
|
|
|
70
|
-
def __init__(self,
|
|
155
|
+
def __init__(self, parent_window, column=None):
|
|
71
156
|
|
|
72
157
|
super().__init__()
|
|
73
|
-
self.
|
|
158
|
+
self.parent_window = parent_window
|
|
74
159
|
self.column = column
|
|
75
160
|
if self.column is None:
|
|
76
161
|
self.column = ''
|
|
@@ -88,20 +173,21 @@ class RenameColWidget(QWidget):
|
|
|
88
173
|
self.submit_btn = QPushButton('rename')
|
|
89
174
|
self.submit_btn.clicked.connect(self.rename_col)
|
|
90
175
|
layout.addWidget(self.submit_btn, 30)
|
|
176
|
+
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
91
177
|
|
|
92
178
|
def rename_col(self):
|
|
93
179
|
|
|
94
180
|
old_name = self.column
|
|
95
181
|
new_name = self.new_col_name.text()
|
|
96
|
-
self.
|
|
182
|
+
self.parent_window.data = self.parent_window.data.rename(columns={old_name: new_name})
|
|
97
183
|
print(self.parent.data.columns)
|
|
98
184
|
|
|
99
|
-
self.
|
|
100
|
-
self.
|
|
185
|
+
self.parent_window.model = PandasModel(self.parent_window.data)
|
|
186
|
+
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
101
187
|
self.close()
|
|
102
188
|
|
|
103
189
|
|
|
104
|
-
class TableUI(QMainWindow):
|
|
190
|
+
class TableUI(QMainWindow, Styles):
|
|
105
191
|
def __init__(self, data, title, population='targets',plot_mode="plot_track_signals", *args, **kwargs):
|
|
106
192
|
|
|
107
193
|
QMainWindow.__init__(self, *args, **kwargs)
|
|
@@ -126,6 +212,8 @@ class TableUI(QMainWindow):
|
|
|
126
212
|
self.model = PandasModel(data)
|
|
127
213
|
self.table_view.setModel(self.model)
|
|
128
214
|
self.table_view.resizeColumnsToContents()
|
|
215
|
+
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
216
|
+
|
|
129
217
|
|
|
130
218
|
def _createActions(self):
|
|
131
219
|
|
|
@@ -229,8 +317,17 @@ class TableUI(QMainWindow):
|
|
|
229
317
|
# check only one col selected and assert is numerical
|
|
230
318
|
# open widget to select window parameters, directionality
|
|
231
319
|
# create new col
|
|
232
|
-
|
|
233
|
-
|
|
320
|
+
|
|
321
|
+
x = self.table_view.selectedIndexes()
|
|
322
|
+
col_idx = np.unique(np.array([l.column() for l in x]))
|
|
323
|
+
if col_idx!=0:
|
|
324
|
+
cols = np.array(list(self.data.columns))
|
|
325
|
+
selected_col = str(cols[col_idx][0])
|
|
326
|
+
else:
|
|
327
|
+
selected_col = None
|
|
328
|
+
|
|
329
|
+
self.diffWidget = DifferentiateColWidget(self, selected_col)
|
|
330
|
+
self.diffWidget.show()
|
|
234
331
|
|
|
235
332
|
|
|
236
333
|
def groupby_time_table(self):
|
|
@@ -268,24 +365,102 @@ class TableUI(QMainWindow):
|
|
|
268
365
|
def set_projection_mode_tracks(self):
|
|
269
366
|
|
|
270
367
|
self.projectionWidget = QWidget()
|
|
368
|
+
self.projectionWidget.setMinimumWidth(500)
|
|
271
369
|
self.projectionWidget.setWindowTitle('Set projection mode')
|
|
272
370
|
|
|
273
371
|
layout = QVBoxLayout()
|
|
274
372
|
self.projectionWidget.setLayout(layout)
|
|
373
|
+
|
|
374
|
+
self.projection_option = QRadioButton('global operation: ')
|
|
375
|
+
self.projection_option.setToolTip('Collapse the cell track measurements with an operation over each track.')
|
|
376
|
+
self.projection_option.toggled.connect(self.enable_projection_options)
|
|
275
377
|
self.projection_op_cb = QComboBox()
|
|
276
378
|
self.projection_op_cb.addItems(['mean','median','min','max', 'prod', 'sum'])
|
|
277
|
-
hbox = QHBoxLayout()
|
|
278
|
-
hbox.addWidget(QLabel('operation: '), 33)
|
|
279
|
-
hbox.addWidget(self.projection_op_cb, 66)
|
|
280
|
-
layout.addLayout(hbox)
|
|
281
379
|
|
|
282
|
-
|
|
380
|
+
projection_layout = QHBoxLayout()
|
|
381
|
+
projection_layout.addWidget(self.projection_option, 33)
|
|
382
|
+
projection_layout.addWidget(self.projection_op_cb, 66)
|
|
383
|
+
layout.addLayout(projection_layout)
|
|
384
|
+
|
|
385
|
+
self.event_time_option = QRadioButton('@event time: ')
|
|
386
|
+
self.event_time_option.setToolTip('Pick the measurements at a specific event time.')
|
|
387
|
+
self.event_time_option.toggled.connect(self.enable_projection_options)
|
|
388
|
+
self.event_times_cb = QComboBox()
|
|
389
|
+
cols = np.array(self.data.columns)
|
|
390
|
+
time_cols = np.array([c.startswith('t_') for c in cols])
|
|
391
|
+
time_cols = list(cols[time_cols])
|
|
392
|
+
if 't0' in list(self.data.columns):
|
|
393
|
+
time_cols.append('t0')
|
|
394
|
+
self.event_times_cb.addItems(time_cols)
|
|
395
|
+
self.event_times_cb.setEnabled(False)
|
|
396
|
+
|
|
397
|
+
event_time_layout = QHBoxLayout()
|
|
398
|
+
event_time_layout.addWidget(self.event_time_option, 33)
|
|
399
|
+
event_time_layout.addWidget(self.event_times_cb, 66)
|
|
400
|
+
layout.addLayout(event_time_layout)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
self.per_status_option = QRadioButton('per status: ')
|
|
404
|
+
self.per_status_option.setToolTip('Collapse the cell track measurements independently for each of the cell state.')
|
|
405
|
+
self.per_status_option.toggled.connect(self.enable_projection_options)
|
|
406
|
+
self.per_status_cb = QComboBox()
|
|
407
|
+
self.status_operation = QComboBox()
|
|
408
|
+
self.status_operation.setEnabled(False)
|
|
409
|
+
self.status_operation.addItems(['mean','median','min','max', 'prod', 'sum'])
|
|
410
|
+
|
|
411
|
+
status_cols = np.array([c.startswith('status_') for c in cols])
|
|
412
|
+
status_cols = list(cols[status_cols])
|
|
413
|
+
if 'status' in list(self.data.columns):
|
|
414
|
+
status_cols.append('status')
|
|
415
|
+
self.per_status_cb.addItems(status_cols)
|
|
416
|
+
self.per_status_cb.setEnabled(False)
|
|
417
|
+
|
|
418
|
+
per_status_layout = QHBoxLayout()
|
|
419
|
+
per_status_layout.addWidget(self.per_status_option, 33)
|
|
420
|
+
per_status_layout.addWidget(self.per_status_cb, 66)
|
|
421
|
+
layout.addLayout(per_status_layout)
|
|
422
|
+
|
|
423
|
+
status_operation_layout = QHBoxLayout()
|
|
424
|
+
status_operation_layout.addWidget(QLabel('operation: '), 33, alignment=Qt.AlignRight)
|
|
425
|
+
status_operation_layout.addWidget(self.status_operation, 66)
|
|
426
|
+
layout.addLayout(status_operation_layout)
|
|
427
|
+
|
|
428
|
+
self.btn_projection_group = QButtonGroup()
|
|
429
|
+
self.btn_projection_group.addButton(self.projection_option)
|
|
430
|
+
self.btn_projection_group.addButton(self.event_time_option)
|
|
431
|
+
self.btn_projection_group.addButton(self.per_status_option)
|
|
432
|
+
|
|
433
|
+
apply_layout = QHBoxLayout()
|
|
434
|
+
|
|
435
|
+
self.set_projection_btn = QPushButton('Apply')
|
|
436
|
+
self.set_projection_btn.setStyleSheet(self.button_style_sheet)
|
|
283
437
|
self.set_projection_btn.clicked.connect(self.set_proj_mode)
|
|
284
|
-
|
|
438
|
+
apply_layout.addWidget(QLabel(''), 33)
|
|
439
|
+
apply_layout.addWidget(self.set_projection_btn,33)
|
|
440
|
+
apply_layout.addWidget(QLabel(''),33)
|
|
441
|
+
layout.addLayout(apply_layout)
|
|
285
442
|
|
|
286
443
|
self.projectionWidget.show()
|
|
287
444
|
center_window(self.projectionWidget)
|
|
288
445
|
|
|
446
|
+
def enable_projection_options(self):
|
|
447
|
+
|
|
448
|
+
if self.projection_option.isChecked():
|
|
449
|
+
self.projection_op_cb.setEnabled(True)
|
|
450
|
+
self.event_times_cb.setEnabled(False)
|
|
451
|
+
self.per_status_cb.setEnabled(False)
|
|
452
|
+
self.status_operation.setEnabled(False)
|
|
453
|
+
elif self.event_time_option.isChecked():
|
|
454
|
+
self.projection_op_cb.setEnabled(False)
|
|
455
|
+
self.event_times_cb.setEnabled(True)
|
|
456
|
+
self.per_status_cb.setEnabled(False)
|
|
457
|
+
self.status_operation.setEnabled(False)
|
|
458
|
+
elif self.per_status_option.isChecked():
|
|
459
|
+
self.projection_op_cb.setEnabled(False)
|
|
460
|
+
self.event_times_cb.setEnabled(False)
|
|
461
|
+
self.per_status_cb.setEnabled(True)
|
|
462
|
+
self.status_operation.setEnabled(True)
|
|
463
|
+
|
|
289
464
|
def set_1D_plot_params(self):
|
|
290
465
|
|
|
291
466
|
self.plot1Dparams = QWidget()
|
|
@@ -313,24 +488,38 @@ class TableUI(QMainWindow):
|
|
|
313
488
|
layout.addWidget(self.box_check)
|
|
314
489
|
layout.addWidget(self.boxenplot_check)
|
|
315
490
|
|
|
316
|
-
self.
|
|
317
|
-
self.
|
|
318
|
-
|
|
319
|
-
self.hue_cb
|
|
491
|
+
self.x_cb = QSearchableComboBox()
|
|
492
|
+
self.x_cb.addItems(['--']+list(self.data.columns))
|
|
493
|
+
|
|
494
|
+
self.hue_cb = QSearchableComboBox()
|
|
495
|
+
self.hue_cb.addItems(['--']+list(self.data.columns))
|
|
496
|
+
idx = self.hue_cb.findText('--')
|
|
497
|
+
|
|
498
|
+
self.x_cb.findText('--')
|
|
499
|
+
hbox = QHBoxLayout()
|
|
500
|
+
hbox.addWidget(QLabel('x: '), 33)
|
|
501
|
+
hbox.addWidget(self.x_cb, 66)
|
|
502
|
+
layout.addLayout(hbox)
|
|
503
|
+
|
|
320
504
|
hbox = QHBoxLayout()
|
|
321
505
|
hbox.addWidget(QLabel('hue: '), 33)
|
|
322
506
|
hbox.addWidget(self.hue_cb, 66)
|
|
323
507
|
layout.addLayout(hbox)
|
|
324
508
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
509
|
+
self.cmap_cb = QColormapComboBox()
|
|
510
|
+
for cm in list(colormaps):
|
|
511
|
+
try:
|
|
512
|
+
self.cmap_cb.addColormap(cm)
|
|
513
|
+
except:
|
|
514
|
+
pass
|
|
515
|
+
|
|
328
516
|
hbox = QHBoxLayout()
|
|
329
517
|
hbox.addWidget(QLabel('colormap: '), 33)
|
|
330
518
|
hbox.addWidget(self.cmap_cb, 66)
|
|
331
519
|
layout.addLayout(hbox)
|
|
332
520
|
|
|
333
521
|
self.plot1d_btn = QPushButton('set')
|
|
522
|
+
self.plot1d_btn.setStyleSheet(self.button_style_sheet)
|
|
334
523
|
self.plot1d_btn.clicked.connect(self.plot1d)
|
|
335
524
|
layout.addWidget(self.plot1d_btn)
|
|
336
525
|
|
|
@@ -340,6 +529,11 @@ class TableUI(QMainWindow):
|
|
|
340
529
|
|
|
341
530
|
def plot1d(self):
|
|
342
531
|
|
|
532
|
+
self.x_option = False
|
|
533
|
+
if self.x_cb.currentText()!='--':
|
|
534
|
+
self.x_option = True
|
|
535
|
+
self.x = self.x_cb.currentText()
|
|
536
|
+
|
|
343
537
|
x = self.table_view.selectedIndexes()
|
|
344
538
|
col_idx = np.array([l.column() for l in x])
|
|
345
539
|
row_idx = np.array([l.row() for l in x])
|
|
@@ -353,9 +547,16 @@ class TableUI(QMainWindow):
|
|
|
353
547
|
y = self.data.iloc[row_idx_i, unique_cols]
|
|
354
548
|
|
|
355
549
|
cmap = getattr(mcm, self.cmap_cb.currentText())
|
|
356
|
-
hue_variable = self.hue_cb.currentText()
|
|
357
550
|
|
|
358
|
-
|
|
551
|
+
try:
|
|
552
|
+
hue_variable = self.hue_cb.currentText()
|
|
553
|
+
colors = [cmap(i / len(self.data[hue_variable].unique())) for i in range(len(self.data[hue_variable].unique()))]
|
|
554
|
+
except:
|
|
555
|
+
colors = None
|
|
556
|
+
|
|
557
|
+
if self.hue_cb.currentText()=='--':
|
|
558
|
+
hue_variable = None
|
|
559
|
+
|
|
359
560
|
#for w,well_group in self.data.groupby('well_index'):
|
|
360
561
|
|
|
361
562
|
legend=True
|
|
@@ -371,24 +572,44 @@ class TableUI(QMainWindow):
|
|
|
371
572
|
legend = False
|
|
372
573
|
|
|
373
574
|
if self.swarm_check.isChecked():
|
|
374
|
-
|
|
375
|
-
|
|
575
|
+
if self.x_option:
|
|
576
|
+
sns.swarmplot(data=self.data, x=self.x,y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors)
|
|
577
|
+
legend = False
|
|
578
|
+
else:
|
|
579
|
+
sns.swarmplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors)
|
|
580
|
+
legend = False
|
|
376
581
|
|
|
377
582
|
if self.violin_check.isChecked():
|
|
378
|
-
|
|
379
|
-
|
|
583
|
+
if self.x_option:
|
|
584
|
+
sns.stripplot(data=self.data,x=self.x, y=column_names[unique_cols],dodge=True, ax=self.ax, hue=hue_variable, legend=legend, palette=colors)
|
|
585
|
+
legend = False
|
|
586
|
+
else:
|
|
587
|
+
sns.violinplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors, cut=0)
|
|
588
|
+
legend = False
|
|
380
589
|
|
|
381
590
|
if self.box_check.isChecked():
|
|
382
|
-
|
|
383
|
-
|
|
591
|
+
if self.x_option:
|
|
592
|
+
sns.boxplot(data=self.data, x=self.x, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, fill=False,palette=colors, linewidth=2,)
|
|
593
|
+
legend = False
|
|
594
|
+
else:
|
|
595
|
+
sns.boxplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, fill=False,palette=colors, linewidth=2,)
|
|
596
|
+
legend = False
|
|
384
597
|
|
|
385
598
|
if self.boxenplot_check.isChecked():
|
|
386
|
-
|
|
387
|
-
|
|
599
|
+
if self.x_option:
|
|
600
|
+
sns.boxenplot(data=self.data, x = self.x, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, fill=False,palette=colors, linewidth=2,)
|
|
601
|
+
legend = False
|
|
602
|
+
else:
|
|
603
|
+
sns.boxenplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, fill=False,palette=colors, linewidth=2,)
|
|
604
|
+
legend = False
|
|
388
605
|
|
|
389
606
|
if self.strip_check.isChecked():
|
|
390
|
-
|
|
391
|
-
|
|
607
|
+
if self.x_option:
|
|
608
|
+
sns.stripplot(data=self.data, x = self.x, y=column_names[unique_cols],dodge=True, ax=self.ax, hue=hue_variable, legend=legend, palette=colors)
|
|
609
|
+
legend = False
|
|
610
|
+
else:
|
|
611
|
+
sns.stripplot(data=self.data, y=column_names[unique_cols],dodge=True, ax=self.ax, hue=hue_variable, legend=legend, palette=colors)
|
|
612
|
+
legend = False
|
|
392
613
|
|
|
393
614
|
plt.tight_layout()
|
|
394
615
|
self.fig.set_facecolor('none') # or 'None'
|
|
@@ -398,18 +619,86 @@ class TableUI(QMainWindow):
|
|
|
398
619
|
|
|
399
620
|
|
|
400
621
|
def set_proj_mode(self):
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
622
|
+
|
|
623
|
+
self.static_columns = ['well_index', 'well_name', 'pos_name', 'position', 'well', 'status', 't0', 'class','cell_type','concentration', 'antibody', 'pharmaceutical_agent','TRACK_ID','position']
|
|
624
|
+
|
|
625
|
+
if self.projection_option.isChecked():
|
|
626
|
+
|
|
627
|
+
self.projection_mode = self.projection_op_cb.currentText()
|
|
628
|
+
op = getattr(self.data.groupby(['position', 'TRACK_ID']), self.projection_mode)
|
|
629
|
+
group_table = op(self.data.groupby(['position', 'TRACK_ID']))
|
|
630
|
+
|
|
631
|
+
for c in self.static_columns:
|
|
632
|
+
try:
|
|
633
|
+
group_table[c] = self.data.groupby(['position','TRACK_ID'])[c].apply(lambda x: x.unique()[0])
|
|
634
|
+
except Exception as e:
|
|
635
|
+
print(e)
|
|
636
|
+
pass
|
|
637
|
+
|
|
638
|
+
for col in ['TRACK_ID']:
|
|
639
|
+
first_column = group_table.pop(col)
|
|
640
|
+
group_table.insert(0, col, first_column)
|
|
641
|
+
group_table.pop('FRAME')
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
elif self.event_time_option.isChecked():
|
|
645
|
+
time_of_interest = self.event_times_cb.currentText()
|
|
646
|
+
self.projection_mode = f"measurements at {time_of_interest}"
|
|
647
|
+
new_table = []
|
|
648
|
+
for tid,group in self.data.groupby(['position','TRACK_ID']):
|
|
649
|
+
time = group[time_of_interest].values[0]
|
|
650
|
+
if time==time:
|
|
651
|
+
time = floor(time) # floor for onset
|
|
652
|
+
else:
|
|
653
|
+
continue
|
|
654
|
+
frames = group['FRAME'].values
|
|
655
|
+
values = group.loc[group['FRAME']==time,:].to_numpy()
|
|
656
|
+
if len(values)>0:
|
|
657
|
+
values = dict(zip(list(self.data.columns), values[0]))
|
|
658
|
+
values.update({'TRACK_ID': tid[1]})
|
|
659
|
+
values.update({'position': tid[0]})
|
|
660
|
+
new_table.append(values)
|
|
661
|
+
|
|
662
|
+
group_table = pd.DataFrame(new_table)
|
|
663
|
+
for col in ['TRACK_ID']:
|
|
664
|
+
first_column = group_table.pop(col)
|
|
665
|
+
group_table.insert(0, col, first_column)
|
|
666
|
+
|
|
667
|
+
group_table = group_table.sort_values(by=['position','TRACK_ID','FRAME'],ignore_index=True)
|
|
668
|
+
group_table = group_table.reset_index(drop=True)
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
elif self.per_status_option.isChecked():
|
|
672
|
+
|
|
673
|
+
status_of_interest = self.per_status_cb.currentText()
|
|
674
|
+
self.projection_mode = f'{self.status_operation.currentText()} per {status_of_interest}'
|
|
675
|
+
self.data = self.data.dropna(subset=status_of_interest,ignore_index=True)
|
|
676
|
+
unique_statuses = np.unique(self.data[status_of_interest].to_numpy())
|
|
677
|
+
|
|
678
|
+
df_sections = []
|
|
679
|
+
for s in unique_statuses:
|
|
680
|
+
subtab = self.data.loc[self.data[status_of_interest]==s,:]
|
|
681
|
+
op = getattr(subtab.groupby(['position', 'TRACK_ID']), self.status_operation.currentText())
|
|
682
|
+
subtab_projected = op(subtab.groupby(['position', 'TRACK_ID']))
|
|
683
|
+
frame_duration = subtab.groupby(['position','TRACK_ID']).size().to_numpy()
|
|
684
|
+
for c in self.static_columns:
|
|
685
|
+
try:
|
|
686
|
+
subtab_projected[c] = subtab.groupby(['position', 'TRACK_ID'])[c].apply(lambda x: x.unique()[0])
|
|
687
|
+
except Exception as e:
|
|
688
|
+
print(e)
|
|
689
|
+
pass
|
|
690
|
+
subtab_projected['duration_in_state'] = frame_duration
|
|
691
|
+
df_sections.append(subtab_projected)
|
|
692
|
+
|
|
693
|
+
group_table = pd.concat(df_sections,axis=0,ignore_index=True)
|
|
694
|
+
for col in ['duration_in_state',status_of_interest,'TRACK_ID']:
|
|
695
|
+
first_column = group_table.pop(col)
|
|
696
|
+
group_table.insert(0, col, first_column)
|
|
697
|
+
group_table.pop('FRAME')
|
|
698
|
+
group_table = group_table.sort_values(by=['position','TRACK_ID',status_of_interest],ignore_index=True)
|
|
699
|
+
group_table = group_table.reset_index(drop=True)
|
|
700
|
+
|
|
405
701
|
|
|
406
|
-
self.static_columns = ['well_index', 'well_name', 'pos_name', 'position', 'well', 'status', 't0', 'class', 'concentration', 'antibody', 'pharmaceutical_agent']
|
|
407
|
-
for c in self.static_columns:
|
|
408
|
-
try:
|
|
409
|
-
group_table[c] = self.data.groupby(['position','TRACK_ID'])[c].apply(lambda x: x.unique()[0])
|
|
410
|
-
except Exception as e:
|
|
411
|
-
print(e)
|
|
412
|
-
pass
|
|
413
702
|
self.subtable = TableUI(group_table,f"Group by tracks: {self.projection_mode}", plot_mode="static")
|
|
414
703
|
self.subtable.show()
|
|
415
704
|
|