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.
Files changed (109) hide show
  1. {celldetective-1.3.1 → celldetective-1.3.2}/PKG-INFO +1 -1
  2. celldetective-1.3.2/celldetective/_version.py +1 -0
  3. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/events.py +2 -0
  4. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/classifier_widget.py +51 -3
  5. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/control_panel.py +7 -1
  6. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/generic_signal_plot.py +161 -2
  7. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/gui_utils.py +90 -1
  8. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/plot_signals_ui.py +8 -3
  9. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/process_block.py +31 -20
  10. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/signal_annotator.py +53 -26
  11. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/signal_annotator2.py +17 -30
  12. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/survival_ui.py +7 -3
  13. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/tableUI.py +300 -183
  14. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/io.py +56 -3
  15. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/measure.py +3 -0
  16. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/neighborhood.py +154 -69
  17. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/relative_measurements.py +128 -4
  18. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/measure_cells.py +3 -3
  19. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/signals.py +207 -213
  20. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/utils.py +16 -0
  21. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/PKG-INFO +1 -1
  22. celldetective-1.3.1/celldetective/_version.py +0 -1
  23. {celldetective-1.3.1 → celldetective-1.3.2}/LICENSE +0 -0
  24. {celldetective-1.3.1 → celldetective-1.3.2}/README.md +0 -0
  25. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/__init__.py +0 -0
  26. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/__main__.py +0 -0
  27. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/datasets/segmentation_annotations/blank +0 -0
  28. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/datasets/signal_annotations/blank +0 -0
  29. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/extra_properties.py +0 -0
  30. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/filters.py +0 -0
  31. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/InitWindow.py +0 -0
  32. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/__init__.py +0 -0
  33. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/about.py +0 -0
  34. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/analyze_block.py +0 -0
  35. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/btrack_options.py +0 -0
  36. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/configure_new_exp.py +0 -0
  37. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
  38. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
  39. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/cell-populations.json +0 -0
  40. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/exp-structure.json +0 -0
  41. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/feature-btrack.json +0 -0
  42. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/neighborhood.json +0 -0
  43. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
  44. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/preprocessing.json +0 -0
  45. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/propagate-classification.json +0 -0
  46. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/track-postprocessing.json +0 -0
  47. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/help/tracking.json +0 -0
  48. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/json_readers.py +0 -0
  49. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/layouts.py +0 -0
  50. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/measurement_options.py +0 -0
  51. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/neighborhood_options.py +0 -0
  52. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/plot_measurements.py +0 -0
  53. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/retrain_segmentation_model_options.py +0 -0
  54. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/retrain_signal_model_options.py +0 -0
  55. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/seg_model_loader.py +0 -0
  56. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/signal_annotator_options.py +0 -0
  57. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/styles.py +0 -0
  58. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/thresholds_gui.py +0 -0
  59. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/gui/viewers.py +0 -0
  60. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/logo-large.png +0 -0
  61. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/logo.png +0 -0
  62. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/signals_icon.png +0 -0
  63. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/splash-test.png +0 -0
  64. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/splash.png +0 -0
  65. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/splash0.png +0 -0
  66. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/survival2.png +0 -0
  67. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/vignette_signals2.png +0 -0
  68. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/icons/vignette_signals2.svg +0 -0
  69. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/links/zenodo.json +0 -0
  70. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/pair_signal_detection/blank +0 -0
  71. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/segmentation_effectors/blank +0 -0
  72. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/segmentation_generic/blank +0 -0
  73. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/segmentation_targets/blank +0 -0
  74. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/signal_detection/blank +0 -0
  75. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/biased_motion.json +0 -0
  76. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/mcf7.json +0 -0
  77. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
  78. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/ricm.json +0 -0
  79. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/models/tracking_configs/ricm2.json +0 -0
  80. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/preprocessing.py +0 -0
  81. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/analyze_signals.py +0 -0
  82. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/measure_relative.py +0 -0
  83. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/segment_cells.py +0 -0
  84. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/segment_cells_thresholds.py +0 -0
  85. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/track_cells.py +0 -0
  86. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/train_segmentation_model.py +0 -0
  87. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/scripts/train_signal_model.py +0 -0
  88. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/segmentation.py +0 -0
  89. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective/tracking.py +0 -0
  90. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/SOURCES.txt +0 -0
  91. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/dependency_links.txt +0 -0
  92. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/entry_points.txt +0 -0
  93. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/not-zip-safe +0 -0
  94. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/requires.txt +0 -0
  95. {celldetective-1.3.1 → celldetective-1.3.2}/celldetective.egg-info/top_level.txt +0 -0
  96. {celldetective-1.3.1 → celldetective-1.3.2}/setup.cfg +0 -0
  97. {celldetective-1.3.1 → celldetective-1.3.2}/setup.py +0 -0
  98. {celldetective-1.3.1 → celldetective-1.3.2}/tests/__init__.py +0 -0
  99. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_events.py +0 -0
  100. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_filters.py +0 -0
  101. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_io.py +0 -0
  102. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_measure.py +0 -0
  103. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_neighborhood.py +0 -0
  104. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_preprocessing.py +0 -0
  105. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_qt.py +0 -0
  106. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_segmentation.py +0 -0
  107. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_signals.py +0 -0
  108. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_tracking.py +0 -0
  109. {celldetective-1.3.1 → celldetective-1.3.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: celldetective
3
- Version: 1.3.1
3
+ Version: 1.3.2
4
4
  Summary: description
5
5
  Home-page: http://github.com/remyeltorro/celldetective
6
6
  Author: Rémy Torro
@@ -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.set_xlim(min_x, max_x)
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.set_ylim(min_y, max_y)
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
- ymin,ymax = self.ax_props.get_ylim()
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
- exp_subhbox.addWidget(QLabel(name), 90, alignment=Qt.AlignLeft)
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'],['class'], ['t0'], []]
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=[0,1], return_matrix=True, forced_max_duration=max_time)
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=[0,1], return_matrix=True, forced_max_duration=max_time)
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
- # self.visu_btn = QPushButton()
1211
- # self.visu_btn.setIcon(icon(MDI6.eye_check_outline,color="black"))
1212
- # self.visu_btn.setIconSize(QSize(20, 20))
1213
- # self.visu_btn.clicked.connect(self.check_measurements2)
1214
- # self.visu_btn.setToolTip("Open measurement annotator for two populations.")
1215
- # self.visu_btn.setStyleSheet(self.button_select_all)
1216
- # self.grid_contents.addWidget(self.visu_btn, 1,1,1,1,alignment=Qt.AlignRight)
1217
- # rel_layout.addWidget(self.visu_btn, 6)
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 SIGNAL ANALYSIS")
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...')