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.
Files changed (63) hide show
  1. celldetective/__main__.py +7 -21
  2. celldetective/events.py +2 -44
  3. celldetective/extra_properties.py +62 -52
  4. celldetective/filters.py +4 -5
  5. celldetective/gui/__init__.py +1 -1
  6. celldetective/gui/analyze_block.py +37 -10
  7. celldetective/gui/btrack_options.py +24 -23
  8. celldetective/gui/classifier_widget.py +62 -19
  9. celldetective/gui/configure_new_exp.py +32 -35
  10. celldetective/gui/control_panel.py +120 -81
  11. celldetective/gui/gui_utils.py +674 -396
  12. celldetective/gui/json_readers.py +7 -6
  13. celldetective/gui/layouts.py +756 -0
  14. celldetective/gui/measurement_options.py +98 -513
  15. celldetective/gui/neighborhood_options.py +322 -270
  16. celldetective/gui/plot_measurements.py +1114 -0
  17. celldetective/gui/plot_signals_ui.py +21 -20
  18. celldetective/gui/process_block.py +449 -169
  19. celldetective/gui/retrain_segmentation_model_options.py +27 -26
  20. celldetective/gui/retrain_signal_model_options.py +25 -24
  21. celldetective/gui/seg_model_loader.py +31 -27
  22. celldetective/gui/signal_annotator.py +2326 -2295
  23. celldetective/gui/signal_annotator_options.py +18 -16
  24. celldetective/gui/styles.py +16 -1
  25. celldetective/gui/survival_ui.py +67 -39
  26. celldetective/gui/tableUI.py +337 -48
  27. celldetective/gui/thresholds_gui.py +75 -71
  28. celldetective/gui/viewers.py +743 -0
  29. celldetective/io.py +247 -27
  30. celldetective/measure.py +43 -263
  31. celldetective/models/segmentation_effectors/primNK_cfse/config_input.json +29 -0
  32. celldetective/models/segmentation_effectors/primNK_cfse/cp-cfse-transfer +0 -0
  33. celldetective/models/segmentation_effectors/primNK_cfse/training_instructions.json +37 -0
  34. celldetective/neighborhood.py +498 -27
  35. celldetective/preprocessing.py +1023 -0
  36. celldetective/scripts/analyze_signals.py +7 -0
  37. celldetective/scripts/measure_cells.py +12 -0
  38. celldetective/scripts/segment_cells.py +20 -4
  39. celldetective/scripts/track_cells.py +11 -0
  40. celldetective/scripts/train_segmentation_model.py +35 -34
  41. celldetective/segmentation.py +14 -9
  42. celldetective/signals.py +234 -329
  43. celldetective/tracking.py +2 -2
  44. celldetective/utils.py +602 -49
  45. celldetective-1.1.1.dist-info/METADATA +305 -0
  46. celldetective-1.1.1.dist-info/RECORD +84 -0
  47. {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/top_level.txt +1 -0
  48. tests/__init__.py +0 -0
  49. tests/test_events.py +28 -0
  50. tests/test_filters.py +24 -0
  51. tests/test_io.py +70 -0
  52. tests/test_measure.py +141 -0
  53. tests/test_neighborhood.py +70 -0
  54. tests/test_preprocessing.py +37 -0
  55. tests/test_segmentation.py +93 -0
  56. tests/test_signals.py +135 -0
  57. tests/test_tracking.py +164 -0
  58. tests/test_utils.py +118 -0
  59. celldetective-1.0.2.post1.dist-info/METADATA +0 -221
  60. celldetective-1.0.2.post1.dist-info/RECORD +0 -66
  61. {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/LICENSE +0 -0
  62. {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/WHEEL +0 -0
  63. {celldetective-1.0.2.post1.dist-info → celldetective-1.1.1.dist-info}/entry_points.txt +0 -0
@@ -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, parent):
45
+ def __init__(self, parent_window):
40
46
 
41
47
  super().__init__()
42
- self.parent = parent
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.parent.data.query(query_text)
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, parent, column=None):
155
+ def __init__(self, parent_window, column=None):
71
156
 
72
157
  super().__init__()
73
- self.parent = parent
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.parent.data = self.parent.data.rename(columns={old_name: new_name})
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.parent.model = PandasModel(self.parent.data)
100
- self.parent.table_view.setModel(self.parent.model)
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
- print('you want to differentiate? cool but I"m too tired to code it now...')
233
- pass
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
- self.set_projection_btn = QPushButton('set')
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
- layout.addWidget(self.set_projection_btn)
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.hue_cb = QComboBox()
317
- self.hue_cb.addItems(list(self.data.columns))
318
- idx = self.hue_cb.findText('well_index')
319
- self.hue_cb.setCurrentIndex(idx)
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
- self.cmap_cb = QComboBox()
327
- self.cmap_cb.addItems(list(plt.colormaps()))
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
- colors = [cmap(i / len(self.data[hue_variable].unique())) for i in range(len(self.data[hue_variable].unique()))]
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
- sns.swarmplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors)
375
- legend = False
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
- sns.violinplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors, cut=0)
379
- legend = False
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
- 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,)
383
- legend = False
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
- 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,)
387
- legend = False
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
- sns.stripplot(data=self.data, y=column_names[unique_cols],dodge=True, ax=self.ax, hue=hue_variable, legend=legend, palette=colors)
391
- legend = False
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
- self.projection_mode = self.projection_op_cb.currentText()
402
- #eval(self.projection_mode)
403
- op = getattr(self.data.groupby(['position', 'TRACK_ID']), self.projection_mode)
404
- group_table = op(self.data.groupby(['position', 'TRACK_ID']))
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