celldetective 1.1.1.post3__py3-none-any.whl → 1.2.0__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/__init__.py +2 -1
- celldetective/__main__.py +17 -0
- celldetective/extra_properties.py +62 -34
- celldetective/gui/__init__.py +1 -0
- celldetective/gui/analyze_block.py +2 -1
- celldetective/gui/classifier_widget.py +18 -10
- celldetective/gui/control_panel.py +57 -6
- celldetective/gui/layouts.py +14 -11
- celldetective/gui/neighborhood_options.py +21 -13
- celldetective/gui/plot_signals_ui.py +39 -11
- celldetective/gui/process_block.py +413 -95
- celldetective/gui/retrain_segmentation_model_options.py +17 -4
- celldetective/gui/retrain_signal_model_options.py +106 -6
- celldetective/gui/signal_annotator.py +110 -30
- celldetective/gui/signal_annotator2.py +2708 -0
- celldetective/gui/signal_annotator_options.py +3 -1
- celldetective/gui/survival_ui.py +15 -6
- celldetective/gui/tableUI.py +248 -43
- celldetective/io.py +598 -416
- celldetective/measure.py +919 -969
- celldetective/models/pair_signal_detection/blank +0 -0
- celldetective/neighborhood.py +482 -340
- celldetective/preprocessing.py +81 -61
- celldetective/relative_measurements.py +648 -0
- celldetective/scripts/analyze_signals.py +1 -1
- celldetective/scripts/measure_cells.py +28 -8
- celldetective/scripts/measure_relative.py +103 -0
- celldetective/scripts/segment_cells.py +5 -5
- celldetective/scripts/track_cells.py +4 -1
- celldetective/scripts/train_segmentation_model.py +23 -18
- celldetective/scripts/train_signal_model.py +33 -0
- celldetective/segmentation.py +67 -29
- celldetective/signals.py +402 -8
- celldetective/tracking.py +8 -2
- celldetective/utils.py +144 -12
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/METADATA +8 -8
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/RECORD +42 -38
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/WHEEL +1 -1
- tests/test_segmentation.py +1 -1
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/LICENSE +0 -0
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/entry_points.txt +0 -0
- {celldetective-1.1.1.post3.dist-info → celldetective-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -34,7 +34,9 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
34
34
|
self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_targets.json"
|
|
35
35
|
elif self.mode=="effectors":
|
|
36
36
|
self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_effectors.json"
|
|
37
|
-
|
|
37
|
+
elif self.mode == "neighborhood":
|
|
38
|
+
self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_neighborhood.json"
|
|
39
|
+
|
|
38
40
|
exp_config = self.exp_dir +"config.ini"
|
|
39
41
|
#self.config_path = self.exp_dir + self.config_name
|
|
40
42
|
self.channel_names, self.channels = extract_experiment_channels(exp_config)
|
celldetective/gui/survival_ui.py
CHANGED
|
@@ -109,9 +109,10 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
109
109
|
main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
labels = [QLabel('population: '), QLabel('time of\nreference: '), QLabel('time of\ninterest: '), QLabel('
|
|
113
|
-
self.cb_options = [['targets','effectors'], ['0'
|
|
112
|
+
labels = [QLabel('population: '), QLabel('time of\nreference: '), QLabel('time of\ninterest: '), QLabel('cmap: ')] #QLabel('class: '),
|
|
113
|
+
self.cb_options = [['targets','effectors'], ['0'], [], list(plt.colormaps())] #['class'],
|
|
114
114
|
self.cbs = [QComboBox() for i in range(len(labels))]
|
|
115
|
+
|
|
115
116
|
self.cbs[-1] = QColormapComboBox()
|
|
116
117
|
self.cbs[0].currentIndexChanged.connect(self.set_classes_and_times)
|
|
117
118
|
|
|
@@ -133,6 +134,12 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
133
134
|
|
|
134
135
|
main_layout.addLayout(choice_layout)
|
|
135
136
|
|
|
137
|
+
select_layout = QHBoxLayout()
|
|
138
|
+
select_layout.addWidget(QLabel('select cells\nwith query: '), 33)
|
|
139
|
+
self.query_le = QLineEdit()
|
|
140
|
+
select_layout.addWidget(self.query_le, 66)
|
|
141
|
+
main_layout.addLayout(select_layout)
|
|
142
|
+
|
|
136
143
|
self.cbs[0].setCurrentIndex(0)
|
|
137
144
|
self.cbs[1].setCurrentText('t_firstdetection')
|
|
138
145
|
|
|
@@ -218,10 +225,12 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
218
225
|
|
|
219
226
|
if self.df is not None:
|
|
220
227
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
228
|
+
try:
|
|
229
|
+
query_text = self.query_le.text()
|
|
230
|
+
if query_text != '':
|
|
231
|
+
self.df = self.df.query(query_text)
|
|
232
|
+
except Exception as e:
|
|
233
|
+
print(e, ' The query is misunderstood and will not be applied...')
|
|
225
234
|
|
|
226
235
|
self.compute_survival_functions()
|
|
227
236
|
# prepare survival
|
celldetective/gui/tableUI.py
CHANGED
|
@@ -20,6 +20,10 @@ from matplotlib import colormaps
|
|
|
20
20
|
|
|
21
21
|
class PandasModel(QAbstractTableModel):
|
|
22
22
|
|
|
23
|
+
"""
|
|
24
|
+
from https://stackoverflow.com/questions/31475965/fastest-way-to-populate-qtableview-from-pandas-data-frame
|
|
25
|
+
"""
|
|
26
|
+
|
|
23
27
|
def __init__(self, data):
|
|
24
28
|
QAbstractTableModel.__init__(self)
|
|
25
29
|
self._data = data
|
|
@@ -65,9 +69,9 @@ class QueryWidget(QWidget):
|
|
|
65
69
|
|
|
66
70
|
def filter_table(self):
|
|
67
71
|
try:
|
|
68
|
-
query_text = self.query_le.text()
|
|
72
|
+
query_text = self.query_le.text() #.replace('class', '`class`')
|
|
69
73
|
tab = self.parent_window.data.query(query_text)
|
|
70
|
-
self.subtable = TableUI(tab, query_text, plot_mode="
|
|
74
|
+
self.subtable = TableUI(tab, query_text, plot_mode="static", population=self.parent_window.population)
|
|
71
75
|
self.subtable.show()
|
|
72
76
|
self.close()
|
|
73
77
|
except Exception as e:
|
|
@@ -236,7 +240,47 @@ class DifferentiateColWidget(QWidget, Styles):
|
|
|
236
240
|
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
237
241
|
self.close()
|
|
238
242
|
|
|
243
|
+
class AbsColWidget(QWidget, Styles):
|
|
244
|
+
|
|
245
|
+
def __init__(self, parent_window, column=None):
|
|
246
|
+
|
|
247
|
+
super().__init__()
|
|
248
|
+
self.parent_window = parent_window
|
|
249
|
+
self.column = column
|
|
250
|
+
|
|
251
|
+
self.setWindowTitle("abs(.)")
|
|
252
|
+
# Create the QComboBox and add some items
|
|
253
|
+
center_window(self)
|
|
254
|
+
|
|
255
|
+
layout = QVBoxLayout(self)
|
|
256
|
+
layout.setContentsMargins(30,30,30,30)
|
|
257
|
+
|
|
258
|
+
self.measurements_cb = QComboBox()
|
|
259
|
+
self.measurements_cb.addItems(list(self.parent_window.data.columns))
|
|
260
|
+
if self.column is not None:
|
|
261
|
+
idx = self.measurements_cb.findText(self.column)
|
|
262
|
+
self.measurements_cb.setCurrentIndex(idx)
|
|
239
263
|
|
|
264
|
+
measurement_layout = QHBoxLayout()
|
|
265
|
+
measurement_layout.addWidget(QLabel('measurements: '), 25)
|
|
266
|
+
measurement_layout.addWidget(self.measurements_cb, 75)
|
|
267
|
+
layout.addLayout(measurement_layout)
|
|
268
|
+
|
|
269
|
+
self.submit_btn = QPushButton('Compute')
|
|
270
|
+
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
271
|
+
self.submit_btn.clicked.connect(self.compute_abs_and_add_new_column)
|
|
272
|
+
layout.addWidget(self.submit_btn, 30)
|
|
273
|
+
|
|
274
|
+
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def compute_abs_and_add_new_column(self):
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
self.parent_window.data['|'+self.measurements_cb.currentText()+'|'] = self.parent_window.data[self.measurements_cb.currentText()].abs()
|
|
281
|
+
self.parent_window.model = PandasModel(self.parent_window.data)
|
|
282
|
+
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
283
|
+
self.close()
|
|
240
284
|
|
|
241
285
|
class RenameColWidget(QWidget):
|
|
242
286
|
|
|
@@ -268,7 +312,6 @@ class RenameColWidget(QWidget):
|
|
|
268
312
|
old_name = self.column
|
|
269
313
|
new_name = self.new_col_name.text()
|
|
270
314
|
self.parent_window.data = self.parent_window.data.rename(columns={old_name: new_name})
|
|
271
|
-
print(self.parent.data.columns)
|
|
272
315
|
|
|
273
316
|
self.parent_window.model = PandasModel(self.parent_window.data)
|
|
274
317
|
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
@@ -276,6 +319,7 @@ class RenameColWidget(QWidget):
|
|
|
276
319
|
|
|
277
320
|
|
|
278
321
|
class TableUI(QMainWindow, Styles):
|
|
322
|
+
|
|
279
323
|
def __init__(self, data, title, population='targets',plot_mode="plot_track_signals", *args, **kwargs):
|
|
280
324
|
|
|
281
325
|
QMainWindow.__init__(self, *args, **kwargs)
|
|
@@ -287,6 +331,16 @@ class TableUI(QMainWindow, Styles):
|
|
|
287
331
|
self.plot_mode = plot_mode
|
|
288
332
|
self.population = population
|
|
289
333
|
self.numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
|
|
334
|
+
self.groupby_cols = ['position', 'TRACK_ID']
|
|
335
|
+
self.tracks = False
|
|
336
|
+
|
|
337
|
+
if self.population=='pairs':
|
|
338
|
+
self.groupby_cols = ['position','reference_population', 'neighbor_population','REFERENCE_ID', 'NEIGHBOR_ID', 'FRAME']
|
|
339
|
+
self.tracks = True # for now
|
|
340
|
+
else:
|
|
341
|
+
if 'TRACK_ID' in data.columns:
|
|
342
|
+
if not np.all(data['TRACK_ID'].isnull()):
|
|
343
|
+
self.tracks = True
|
|
290
344
|
|
|
291
345
|
self._createMenuBar()
|
|
292
346
|
self._createActions()
|
|
@@ -329,6 +383,18 @@ class TableUI(QMainWindow, Styles):
|
|
|
329
383
|
self.groupby_action.triggered.connect(self.set_projection_mode_tracks)
|
|
330
384
|
self.groupby_action.setShortcut("Ctrl+g")
|
|
331
385
|
self.fileMenu.addAction(self.groupby_action)
|
|
386
|
+
if not self.tracks:
|
|
387
|
+
self.groupby_action.setEnabled(False)
|
|
388
|
+
|
|
389
|
+
if self.population=='pairs':
|
|
390
|
+
self.groupby_neigh_action = QAction("&Group by neighbors...", self)
|
|
391
|
+
self.groupby_neigh_action.triggered.connect(self.set_projection_mode_neigh)
|
|
392
|
+
self.fileMenu.addAction(self.groupby_neigh_action)
|
|
393
|
+
|
|
394
|
+
self.groupby_ref_action = QAction("&Group by reference...", self)
|
|
395
|
+
self.groupby_ref_action.triggered.connect(self.set_projection_mode_ref)
|
|
396
|
+
self.fileMenu.addAction(self.groupby_ref_action)
|
|
397
|
+
|
|
332
398
|
|
|
333
399
|
self.groupby_time_action = QAction("&Group by frames...", self)
|
|
334
400
|
self.groupby_time_action.triggered.connect(self.groupby_time_table)
|
|
@@ -349,16 +415,76 @@ class TableUI(QMainWindow, Styles):
|
|
|
349
415
|
#self.rename_col_action.setShortcut(Qt.Key_Delete)
|
|
350
416
|
self.editMenu.addAction(self.rename_col_action)
|
|
351
417
|
|
|
418
|
+
if self.population=='pairs':
|
|
419
|
+
self.merge_action = QAction('&Merge...', self)
|
|
420
|
+
self.merge_action.triggered.connect(self.merge_tables)
|
|
421
|
+
#self.rename_col_action.setShortcut(Qt.Key_Delete)
|
|
422
|
+
self.editMenu.addAction(self.merge_action)
|
|
423
|
+
|
|
352
424
|
self.derivative_action = QAction('&Differentiate...', self)
|
|
353
425
|
self.derivative_action.triggered.connect(self.differenciate_selected_feature)
|
|
354
426
|
self.derivative_action.setShortcut("Ctrl+D")
|
|
355
427
|
self.mathMenu.addAction(self.derivative_action)
|
|
356
428
|
|
|
429
|
+
self.abs_action = QAction('&Absolute value...', self)
|
|
430
|
+
self.abs_action.triggered.connect(self.take_abs_of_selected_feature)
|
|
431
|
+
#self.derivative_action.setShortcut("Ctrl+D")
|
|
432
|
+
self.mathMenu.addAction(self.abs_action)
|
|
433
|
+
|
|
357
434
|
self.onehot_action = QAction('&One hot to categorical...', self)
|
|
358
435
|
self.onehot_action.triggered.connect(self.transform_one_hot_cols_to_categorical)
|
|
359
436
|
#self.onehot_action.setShortcut("Ctrl+D")
|
|
360
437
|
self.mathMenu.addAction(self.onehot_action)
|
|
361
438
|
|
|
439
|
+
def merge_tables(self):
|
|
440
|
+
|
|
441
|
+
expanded_table = []
|
|
442
|
+
|
|
443
|
+
for neigh, group in self.data.groupby(['reference_population','neighbor_population']):
|
|
444
|
+
print(f'{neigh=}')
|
|
445
|
+
ref_pop = neigh[0]; neigh_pop = neigh[1];
|
|
446
|
+
for pos,pos_group in group.groupby('position'):
|
|
447
|
+
print(f'{pos=}')
|
|
448
|
+
|
|
449
|
+
ref_tab = os.sep.join([pos,'output','tables',f'trajectories_{ref_pop}.csv'])
|
|
450
|
+
neigh_tab = os.sep.join([pos,'output','tables',f'trajectories_{neigh_pop}.csv'])
|
|
451
|
+
if os.path.exists(ref_tab):
|
|
452
|
+
df_ref = pd.read_csv(ref_tab)
|
|
453
|
+
if 'TRACK_ID' in df_ref.columns:
|
|
454
|
+
if not np.all(df_ref['TRACK_ID'].isnull()):
|
|
455
|
+
ref_merge_cols = ['TRACK_ID','FRAME']
|
|
456
|
+
else:
|
|
457
|
+
ref_merge_cols = ['ID','FRAME']
|
|
458
|
+
else:
|
|
459
|
+
ref_merge_cols = ['ID','FRAME']
|
|
460
|
+
if os.path.exists(neigh_tab):
|
|
461
|
+
df_neigh = pd.read_csv(neigh_tab)
|
|
462
|
+
if 'TRACK_ID' in df_neigh.columns:
|
|
463
|
+
if not np.all(df_neigh['TRACK_ID'].isnull()):
|
|
464
|
+
neigh_merge_cols = ['TRACK_ID','FRAME']
|
|
465
|
+
else:
|
|
466
|
+
neigh_merge_cols = ['ID','FRAME']
|
|
467
|
+
else:
|
|
468
|
+
neigh_merge_cols = ['ID','FRAME']
|
|
469
|
+
|
|
470
|
+
df_ref = df_ref.add_prefix('reference_',axis=1)
|
|
471
|
+
df_neigh = df_neigh.add_prefix('neighbor_',axis=1)
|
|
472
|
+
ref_merge_cols = ['reference_'+c for c in ref_merge_cols]
|
|
473
|
+
neigh_merge_cols = ['neighbor_'+c for c in neigh_merge_cols]
|
|
474
|
+
|
|
475
|
+
merge_ref = pos_group.merge(df_ref, how='outer', left_on=['REFERENCE_ID','FRAME'], right_on=ref_merge_cols, suffixes=('', '_reference'))
|
|
476
|
+
print(f'{merge_ref.columns=}')
|
|
477
|
+
merge_neigh = merge_ref.merge(df_neigh, how='outer', left_on=['NEIGHBOR_ID','FRAME'], right_on=neigh_merge_cols, suffixes=('_reference', '_neighbor'))
|
|
478
|
+
print(f'{merge_neigh.columns=}')
|
|
479
|
+
expanded_table.append(merge_neigh)
|
|
480
|
+
|
|
481
|
+
df_expanded = pd.concat(expanded_table, axis=0, ignore_index = True)
|
|
482
|
+
df_expanded = df_expanded.sort_values(by=['position', 'reference_population','neighbor_population','REFERENCE_ID','NEIGHBOR_ID','FRAME'])
|
|
483
|
+
df_expanded = df_expanded.dropna(axis=0, subset=['REFERENCE_ID','NEIGHBOR_ID','reference_population','neighbor_population'])
|
|
484
|
+
self.subtable = TableUI(df_expanded, 'merge', plot_mode = "static", population='pairs')
|
|
485
|
+
self.subtable.show()
|
|
486
|
+
|
|
487
|
+
|
|
362
488
|
def delete_columns(self):
|
|
363
489
|
|
|
364
490
|
x = self.table_view.selectedIndexes()
|
|
@@ -408,8 +534,6 @@ class TableUI(QMainWindow, Styles):
|
|
|
408
534
|
pos_group.to_csv(pos+os.sep.join(['output', 'tables', f'trajectories_{self.population}.csv']), index=False)
|
|
409
535
|
print("Done...")
|
|
410
536
|
|
|
411
|
-
|
|
412
|
-
|
|
413
537
|
def differenciate_selected_feature(self):
|
|
414
538
|
|
|
415
539
|
# check only one col selected and assert is numerical
|
|
@@ -427,6 +551,24 @@ class TableUI(QMainWindow, Styles):
|
|
|
427
551
|
self.diffWidget = DifferentiateColWidget(self, selected_col)
|
|
428
552
|
self.diffWidget.show()
|
|
429
553
|
|
|
554
|
+
def take_abs_of_selected_feature(self):
|
|
555
|
+
|
|
556
|
+
# check only one col selected and assert is numerical
|
|
557
|
+
# open widget to select window parameters, directionality
|
|
558
|
+
# create new col
|
|
559
|
+
|
|
560
|
+
x = self.table_view.selectedIndexes()
|
|
561
|
+
col_idx = np.unique(np.array([l.column() for l in x]))
|
|
562
|
+
if col_idx!=0:
|
|
563
|
+
cols = np.array(list(self.data.columns))
|
|
564
|
+
selected_col = str(cols[col_idx][0])
|
|
565
|
+
else:
|
|
566
|
+
selected_col = None
|
|
567
|
+
|
|
568
|
+
self.absWidget = AbsColWidget(self, selected_col)
|
|
569
|
+
self.absWidget.show()
|
|
570
|
+
|
|
571
|
+
|
|
430
572
|
def transform_one_hot_cols_to_categorical(self):
|
|
431
573
|
|
|
432
574
|
x = self.table_view.selectedIndexes()
|
|
@@ -451,7 +593,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
451
593
|
|
|
452
594
|
num_df = self.data.select_dtypes(include=self.numerics)
|
|
453
595
|
|
|
454
|
-
timeseries = num_df.groupby("FRAME").
|
|
596
|
+
timeseries = num_df.groupby("FRAME").sum().copy()
|
|
455
597
|
timeseries["timeline"] = timeseries.index
|
|
456
598
|
self.subtable = TableUI(timeseries,"Group by frames", plot_mode="plot_timeseries")
|
|
457
599
|
self.subtable.show()
|
|
@@ -473,6 +615,16 @@ class TableUI(QMainWindow, Styles):
|
|
|
473
615
|
# self.subtable = TableUI(timeseries,"Group by frames", plot_mode="plot_timeseries")
|
|
474
616
|
# self.subtable.show()
|
|
475
617
|
|
|
618
|
+
def set_projection_mode_neigh(self):
|
|
619
|
+
|
|
620
|
+
self.groupby_cols = ['position', 'reference_population', 'neighbor_population', 'NEIGHBOR_ID', 'FRAME']
|
|
621
|
+
self.set_projection_mode_tracks()
|
|
622
|
+
|
|
623
|
+
def set_projection_mode_ref(self):
|
|
624
|
+
|
|
625
|
+
self.groupby_cols = ['position', 'reference_population', 'neighbor_population', 'REFERENCE_ID', 'FRAME']
|
|
626
|
+
self.set_projection_mode_tracks()
|
|
627
|
+
|
|
476
628
|
def set_projection_mode_tracks(self):
|
|
477
629
|
|
|
478
630
|
self.projectionWidget = QWidget()
|
|
@@ -484,6 +636,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
484
636
|
|
|
485
637
|
self.projection_option = QRadioButton('global operation: ')
|
|
486
638
|
self.projection_option.setToolTip('Collapse the cell track measurements with an operation over each track.')
|
|
639
|
+
self.projection_option.setChecked(True)
|
|
487
640
|
self.projection_option.toggled.connect(self.enable_projection_options)
|
|
488
641
|
self.projection_op_cb = QComboBox()
|
|
489
642
|
self.projection_op_cb.addItems(['mean','median','min','max', 'prod', 'sum'])
|
|
@@ -583,18 +736,20 @@ class TableUI(QMainWindow, Styles):
|
|
|
583
736
|
layout.addWidget(QLabel('Representations: '))
|
|
584
737
|
self.hist_check = QCheckBox('histogram')
|
|
585
738
|
self.kde_check = QCheckBox('KDE plot')
|
|
586
|
-
self.count_check = QCheckBox('
|
|
739
|
+
self.count_check = QCheckBox('countplot')
|
|
587
740
|
self.ecdf_check = QCheckBox('ECDF plot')
|
|
741
|
+
self.scat_check = QCheckBox('scatter plot')
|
|
588
742
|
self.swarm_check = QCheckBox('swarm')
|
|
589
743
|
self.violin_check = QCheckBox('violin')
|
|
590
744
|
self.strip_check = QCheckBox('strip')
|
|
591
|
-
self.box_check = QCheckBox('
|
|
592
|
-
self.boxenplot_check = QCheckBox('
|
|
745
|
+
self.box_check = QCheckBox('boxplot')
|
|
746
|
+
self.boxenplot_check = QCheckBox('boxenplot')
|
|
593
747
|
|
|
594
748
|
layout.addWidget(self.hist_check)
|
|
595
749
|
layout.addWidget(self.kde_check)
|
|
596
750
|
layout.addWidget(self.count_check)
|
|
597
751
|
layout.addWidget(self.ecdf_check)
|
|
752
|
+
layout.addWidget(self.scat_check)
|
|
598
753
|
layout.addWidget(self.swarm_check)
|
|
599
754
|
layout.addWidget(self.violin_check)
|
|
600
755
|
layout.addWidget(self.strip_check)
|
|
@@ -695,18 +850,49 @@ class TableUI(QMainWindow, Styles):
|
|
|
695
850
|
self.x = self.x_cb.currentText()
|
|
696
851
|
|
|
697
852
|
legend=True
|
|
853
|
+
|
|
698
854
|
if self.hist_check.isChecked():
|
|
699
|
-
|
|
700
|
-
|
|
855
|
+
if self.x is not None:
|
|
856
|
+
sns.histplot(data=self.data, x=self.x, hue=hue_variable, legend=legend, ax=self.ax, palette=colors, kde=True, common_norm=False, stat='density')
|
|
857
|
+
legend = False
|
|
858
|
+
elif self.x is None and self.y is not None:
|
|
859
|
+
sns.histplot(data=self.data, x=self.y, hue=hue_variable, legend=legend, ax=self.ax, palette=colors, kde=True, common_norm=False, stat='density')
|
|
860
|
+
legend = False
|
|
861
|
+
else:
|
|
862
|
+
pass
|
|
863
|
+
|
|
701
864
|
if self.kde_check.isChecked():
|
|
702
|
-
|
|
703
|
-
|
|
865
|
+
if self.x is not None:
|
|
866
|
+
sns.kdeplot(data=self.data, x=self.x, hue=hue_variable, legend=legend, ax=self.ax, palette=colors, cut=0)
|
|
867
|
+
legend = False
|
|
868
|
+
elif self.x is None and self.y is not None:
|
|
869
|
+
sns.kdeplot(data=self.data, x=self.y, hue=hue_variable, legend=legend, ax=self.ax, palette=colors, cut=0)
|
|
870
|
+
legend = False
|
|
871
|
+
else:
|
|
872
|
+
pass
|
|
873
|
+
|
|
704
874
|
if self.count_check.isChecked():
|
|
705
875
|
sns.countplot(data=self.data, x=self.x, hue=hue_variable, legend=legend, ax=self.ax, palette=colors)
|
|
706
876
|
legend = False
|
|
877
|
+
|
|
878
|
+
|
|
707
879
|
if self.ecdf_check.isChecked():
|
|
708
|
-
|
|
709
|
-
|
|
880
|
+
if self.x is not None:
|
|
881
|
+
sns.ecdfplot(data=self.data, x=self.x, hue=hue_variable, legend=legend, ax=self.ax, palette=colors)
|
|
882
|
+
legend = False
|
|
883
|
+
elif self.x is None and self.y is not None:
|
|
884
|
+
sns.ecdfplot(data=self.data, x=self.y, hue=hue_variable, legend=legend, ax=self.ax, palette=colors)
|
|
885
|
+
legend = False
|
|
886
|
+
else:
|
|
887
|
+
pass
|
|
888
|
+
|
|
889
|
+
if self.scat_check.isChecked():
|
|
890
|
+
if self.x_option:
|
|
891
|
+
sns.scatterplot(data=self.data, x=self.x,y=self.y, hue=hue_variable,legend=legend, ax=self.ax, palette=colors)
|
|
892
|
+
legend = False
|
|
893
|
+
else:
|
|
894
|
+
print('please provide a -x variable...')
|
|
895
|
+
pass
|
|
710
896
|
|
|
711
897
|
if self.swarm_check.isChecked():
|
|
712
898
|
if self.x_option:
|
|
@@ -718,7 +904,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
718
904
|
|
|
719
905
|
if self.violin_check.isChecked():
|
|
720
906
|
if self.x_option:
|
|
721
|
-
sns.
|
|
907
|
+
sns.violinplot(data=self.data,x=self.x, y=self.y,dodge=True, ax=self.ax, hue=hue_variable, legend=legend, palette=colors)
|
|
722
908
|
legend = False
|
|
723
909
|
else:
|
|
724
910
|
sns.violinplot(data=self.data, y=self.y,dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors, cut=0)
|
|
@@ -757,32 +943,39 @@ class TableUI(QMainWindow, Styles):
|
|
|
757
943
|
|
|
758
944
|
def set_proj_mode(self):
|
|
759
945
|
|
|
760
|
-
self.static_columns = ['well_index', 'well_name', 'pos_name', 'position', 'well', 'status', 't0', 'class','cell_type','concentration', 'antibody', 'pharmaceutical_agent','TRACK_ID','position']
|
|
946
|
+
self.static_columns = ['well_index', 'well_name', 'pos_name', 'position', 'well', 'status', 't0', 'class','cell_type','concentration', 'antibody', 'pharmaceutical_agent','TRACK_ID','position', 'neighbor_population', 'reference_population', 'NEIGHBOR_ID', 'REFERENCE_ID', 'FRAME']
|
|
761
947
|
|
|
762
948
|
if self.projection_option.isChecked():
|
|
763
949
|
|
|
764
950
|
self.projection_mode = self.projection_op_cb.currentText()
|
|
765
|
-
op = getattr(self.data.groupby(
|
|
766
|
-
group_table = op(self.data.groupby(
|
|
951
|
+
op = getattr(self.data.groupby(self.groupby_cols), self.projection_mode)
|
|
952
|
+
group_table = op(self.data.groupby(self.groupby_cols))
|
|
767
953
|
|
|
768
954
|
for c in self.static_columns:
|
|
769
955
|
try:
|
|
770
|
-
group_table[c] = self.data.groupby(
|
|
956
|
+
group_table[c] = self.data.groupby(self.groupby_cols)[c].apply(lambda x: x.unique()[0])
|
|
771
957
|
except Exception as e:
|
|
772
958
|
print(e)
|
|
773
959
|
pass
|
|
774
960
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
961
|
+
if self.population=='pairs':
|
|
962
|
+
for col in self.groupby_cols[1:]: #['neighbor_population', 'reference_population', 'NEIGHBOR_ID', 'REFERENCE_ID']
|
|
963
|
+
if col in group_table:
|
|
964
|
+
first_column = group_table.pop(col)
|
|
965
|
+
group_table.insert(0, col, first_column)
|
|
966
|
+
else:
|
|
967
|
+
for col in ['TRACK_ID']:
|
|
968
|
+
first_column = group_table.pop(col)
|
|
969
|
+
group_table.insert(0, col, first_column)
|
|
970
|
+
group_table.pop('FRAME')
|
|
779
971
|
|
|
780
972
|
|
|
781
973
|
elif self.event_time_option.isChecked():
|
|
974
|
+
|
|
782
975
|
time_of_interest = self.event_times_cb.currentText()
|
|
783
976
|
self.projection_mode = f"measurements at {time_of_interest}"
|
|
784
977
|
new_table = []
|
|
785
|
-
for tid,group in self.data.groupby(
|
|
978
|
+
for tid,group in self.data.groupby(self.groupby_cols):
|
|
786
979
|
time = group[time_of_interest].values[0]
|
|
787
980
|
if time==time:
|
|
788
981
|
time = floor(time) # floor for onset
|
|
@@ -792,16 +985,21 @@ class TableUI(QMainWindow, Styles):
|
|
|
792
985
|
values = group.loc[group['FRAME']==time,:].to_numpy()
|
|
793
986
|
if len(values)>0:
|
|
794
987
|
values = dict(zip(list(self.data.columns), values[0]))
|
|
795
|
-
|
|
796
|
-
|
|
988
|
+
for k,c in enumerate(self.groupby_cols):
|
|
989
|
+
values.update({c: tid[k]})
|
|
797
990
|
new_table.append(values)
|
|
798
991
|
|
|
799
992
|
group_table = pd.DataFrame(new_table)
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
993
|
+
if self.population=='pairs':
|
|
994
|
+
for col in self.groupby_cols[1:]:
|
|
995
|
+
first_column = group_table.pop(col)
|
|
996
|
+
group_table.insert(0, col, first_column)
|
|
997
|
+
else:
|
|
998
|
+
for col in ['TRACK_ID']:
|
|
999
|
+
first_column = group_table.pop(col)
|
|
1000
|
+
group_table.insert(0, col, first_column)
|
|
1001
|
+
|
|
1002
|
+
group_table = group_table.sort_values(by=self.groupby_cols+['FRAME'],ignore_index=True)
|
|
805
1003
|
group_table = group_table.reset_index(drop=True)
|
|
806
1004
|
|
|
807
1005
|
|
|
@@ -815,12 +1013,12 @@ class TableUI(QMainWindow, Styles):
|
|
|
815
1013
|
df_sections = []
|
|
816
1014
|
for s in unique_statuses:
|
|
817
1015
|
subtab = self.data.loc[self.data[status_of_interest]==s,:]
|
|
818
|
-
op = getattr(subtab.groupby(
|
|
819
|
-
subtab_projected = op(subtab.groupby(
|
|
820
|
-
frame_duration = subtab.groupby(
|
|
1016
|
+
op = getattr(subtab.groupby(self.groupby_cols), self.status_operation.currentText())
|
|
1017
|
+
subtab_projected = op(subtab.groupby(self.groupby_cols))
|
|
1018
|
+
frame_duration = subtab.groupby(self.groupby_cols).size().to_numpy()
|
|
821
1019
|
for c in self.static_columns:
|
|
822
1020
|
try:
|
|
823
|
-
subtab_projected[c] = subtab.groupby(
|
|
1021
|
+
subtab_projected[c] = subtab.groupby(self.groupby_cols)[c].apply(lambda x: x.unique()[0])
|
|
824
1022
|
except Exception as e:
|
|
825
1023
|
print(e)
|
|
826
1024
|
pass
|
|
@@ -828,11 +1026,18 @@ class TableUI(QMainWindow, Styles):
|
|
|
828
1026
|
df_sections.append(subtab_projected)
|
|
829
1027
|
|
|
830
1028
|
group_table = pd.concat(df_sections,axis=0,ignore_index=True)
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1029
|
+
|
|
1030
|
+
if self.population=='pairs':
|
|
1031
|
+
for col in ['duration_in_state',status_of_interest, 'neighbor_population', 'reference_population', 'NEIGHBOR_ID', 'REFERENCE_ID']:
|
|
1032
|
+
first_column = group_table.pop(col)
|
|
1033
|
+
group_table.insert(0, col, first_column)
|
|
1034
|
+
else:
|
|
1035
|
+
for col in ['duration_in_state',status_of_interest,'TRACK_ID']:
|
|
1036
|
+
first_column = group_table.pop(col)
|
|
1037
|
+
group_table.insert(0, col, first_column)
|
|
1038
|
+
|
|
834
1039
|
group_table.pop('FRAME')
|
|
835
|
-
group_table = group_table.sort_values(by=[
|
|
1040
|
+
group_table = group_table.sort_values(by=self.groupby_cols + [status_of_interest],ignore_index=True)
|
|
836
1041
|
group_table = group_table.reset_index(drop=True)
|
|
837
1042
|
|
|
838
1043
|
|
|
@@ -963,7 +1168,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
963
1168
|
print(unique_cols[k])
|
|
964
1169
|
for w,well_group in self.data.groupby('well_name'):
|
|
965
1170
|
for pos,pos_group in well_group.groupby('pos_name'):
|
|
966
|
-
for tid,group_track in pos_group.groupby(
|
|
1171
|
+
for tid,group_track in pos_group.groupby(self.groupby_cols[1:]):
|
|
967
1172
|
ax.plot(group_track["FRAME"], group_track[column_names[unique_cols[k]]],label=column_names[unique_cols[k]])
|
|
968
1173
|
#ax.plot(self.data["FRAME"][row_idx_i], y, label=column_names[unique_cols[k]])
|
|
969
1174
|
ax.legend()
|
|
@@ -977,7 +1182,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
977
1182
|
self.fig, self.ax = plt.subplots(1, 1, figsize=(4, 3))
|
|
978
1183
|
self.scatter_wdw = FigureCanvas(self.fig, title="scatter")
|
|
979
1184
|
self.ax.clear()
|
|
980
|
-
for tid,group in self.data.groupby(
|
|
1185
|
+
for tid,group in self.data.groupby(self.groupby_cols[1:]):
|
|
981
1186
|
self.ax.plot(group[column_names[unique_cols[0]]], group[column_names[unique_cols[1]]], marker="o")
|
|
982
1187
|
self.ax.set_xlabel(column_names[unique_cols[0]])
|
|
983
1188
|
self.ax.set_ylabel(column_names[unique_cols[1]])
|
|
@@ -1000,7 +1205,7 @@ class TableUI(QMainWindow, Styles):
|
|
|
1000
1205
|
|
|
1001
1206
|
for w,well_group in self.data.groupby('well_name'):
|
|
1002
1207
|
for pos,pos_group in well_group.groupby('pos_name'):
|
|
1003
|
-
for tid,group_track in pos_group.groupby(
|
|
1208
|
+
for tid,group_track in pos_group.groupby(self.groupby_cols[1:]):
|
|
1004
1209
|
self.ax.plot(group_track["FRAME"], group_track[column_names[unique_cols[0]]],c="k", alpha = 0.1)
|
|
1005
1210
|
self.ax.set_xlabel(r"$t$ [frame]")
|
|
1006
1211
|
self.ax.set_ylabel(column_names[unique_cols[0]])
|