celldetective 1.0.2.post1__py3-none-any.whl → 1.1.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.
Files changed (56) hide show
  1. celldetective/__main__.py +2 -2
  2. celldetective/events.py +2 -44
  3. celldetective/filters.py +4 -5
  4. celldetective/gui/__init__.py +1 -1
  5. celldetective/gui/analyze_block.py +37 -10
  6. celldetective/gui/btrack_options.py +24 -23
  7. celldetective/gui/classifier_widget.py +62 -19
  8. celldetective/gui/configure_new_exp.py +32 -35
  9. celldetective/gui/control_panel.py +115 -81
  10. celldetective/gui/gui_utils.py +674 -396
  11. celldetective/gui/json_readers.py +7 -6
  12. celldetective/gui/layouts.py +755 -0
  13. celldetective/gui/measurement_options.py +168 -487
  14. celldetective/gui/neighborhood_options.py +322 -270
  15. celldetective/gui/plot_measurements.py +1114 -0
  16. celldetective/gui/plot_signals_ui.py +20 -20
  17. celldetective/gui/process_block.py +449 -169
  18. celldetective/gui/retrain_segmentation_model_options.py +27 -26
  19. celldetective/gui/retrain_signal_model_options.py +25 -24
  20. celldetective/gui/seg_model_loader.py +31 -27
  21. celldetective/gui/signal_annotator.py +2326 -2295
  22. celldetective/gui/signal_annotator_options.py +18 -16
  23. celldetective/gui/styles.py +16 -1
  24. celldetective/gui/survival_ui.py +61 -39
  25. celldetective/gui/tableUI.py +60 -23
  26. celldetective/gui/thresholds_gui.py +68 -66
  27. celldetective/gui/viewers.py +596 -0
  28. celldetective/io.py +234 -23
  29. celldetective/measure.py +37 -32
  30. celldetective/neighborhood.py +495 -27
  31. celldetective/preprocessing.py +683 -0
  32. celldetective/scripts/analyze_signals.py +7 -0
  33. celldetective/scripts/measure_cells.py +12 -0
  34. celldetective/scripts/segment_cells.py +5 -0
  35. celldetective/scripts/track_cells.py +11 -0
  36. celldetective/signals.py +221 -98
  37. celldetective/tracking.py +0 -1
  38. celldetective/utils.py +178 -36
  39. celldetective-1.1.0.dist-info/METADATA +305 -0
  40. celldetective-1.1.0.dist-info/RECORD +80 -0
  41. {celldetective-1.0.2.post1.dist-info → celldetective-1.1.0.dist-info}/top_level.txt +1 -0
  42. tests/__init__.py +0 -0
  43. tests/test_events.py +28 -0
  44. tests/test_filters.py +24 -0
  45. tests/test_io.py +70 -0
  46. tests/test_measure.py +141 -0
  47. tests/test_neighborhood.py +70 -0
  48. tests/test_segmentation.py +93 -0
  49. tests/test_signals.py +135 -0
  50. tests/test_tracking.py +164 -0
  51. tests/test_utils.py +71 -0
  52. celldetective-1.0.2.post1.dist-info/METADATA +0 -221
  53. celldetective-1.0.2.post1.dist-info/RECORD +0 -66
  54. {celldetective-1.0.2.post1.dist-info → celldetective-1.1.0.dist-info}/LICENSE +0 -0
  55. {celldetective-1.0.2.post1.dist-info → celldetective-1.1.0.dist-info}/WHEEL +0 -0
  56. {celldetective-1.0.2.post1.dist-info → celldetective-1.1.0.dist-info}/entry_points.txt +0 -0
@@ -12,27 +12,28 @@ import numpy as np
12
12
  from superqt.fonticon import icon
13
13
  from fonticon_mdi6 import MDI6
14
14
  import os
15
+ from celldetective.gui import Styles
15
16
 
16
- class ConfigSignalAnnotator(QMainWindow):
17
+ class ConfigSignalAnnotator(QMainWindow, Styles):
17
18
 
18
19
  """
19
20
  UI to set normalization and animation parameters for the annotator tool.
20
21
 
21
22
  """
22
23
 
23
- def __init__(self, parent=None):
24
+ def __init__(self, parent_window=None):
24
25
 
25
26
  super().__init__()
26
- self.parent = parent
27
+ self.parent_window = parent_window
27
28
  self.setWindowTitle("Configure signal annotator")
28
- self.mode = self.parent.mode
29
- self.exp_dir = self.parent.exp_dir
29
+ self.mode = self.parent_window.mode
30
+ self.exp_dir = self.parent_window.exp_dir
30
31
  self.soft_path = get_software_location()
31
32
 
32
33
  if self.mode=="targets":
33
- self.instructions_path = self.parent.exp_dir + "configs/signal_annotator_config_targets.json"
34
+ self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_targets.json"
34
35
  elif self.mode=="effectors":
35
- self.instructions_path = self.parent.exp_dir + "configs/signal_annotator_config_effectors.json"
36
+ self.instructions_path = self.parent_window.exp_dir + "configs/signal_annotator_config_effectors.json"
36
37
 
37
38
  exp_config = self.exp_dir +"config.ini"
38
39
  #self.config_path = self.exp_dir + self.config_name
@@ -41,7 +42,7 @@ class ConfigSignalAnnotator(QMainWindow):
41
42
  self.channels = np.array(self.channels)
42
43
  self.log_option = False
43
44
 
44
- self.screen_height = self.parent.parent.parent.screen_height
45
+ self.screen_height = self.parent_window.parent_window.parent_window.screen_height
45
46
  center_window(self)
46
47
 
47
48
  self.setMinimumHeight(int(0.4*self.screen_height))
@@ -49,6 +50,7 @@ class ConfigSignalAnnotator(QMainWindow):
49
50
  self.populate_widget()
50
51
  #self.load_previous_measurement_instructions()
51
52
 
53
+
52
54
  def populate_widget(self):
53
55
 
54
56
  """
@@ -59,13 +61,13 @@ class ConfigSignalAnnotator(QMainWindow):
59
61
  self.scroll_area = QScrollArea(self)
60
62
  self.button_widget = QWidget()
61
63
 
62
- main_layout = QVBoxLayout()
63
- main_layout.setContentsMargins(30,30,30,30)
64
+ self.main_layout = QVBoxLayout()
65
+ self.main_layout.setContentsMargins(30,30,30,30)
64
66
 
65
67
  sub_layout = QVBoxLayout()
66
68
  sub_layout.setContentsMargins(10,10,10,20)
67
69
 
68
- self.button_widget.setLayout(main_layout)
70
+ self.button_widget.setLayout(self.main_layout)
69
71
  sub_layout.setContentsMargins(30,30,30,30)
70
72
 
71
73
  sub_layout.addWidget(QLabel('Modality: '))
@@ -85,13 +87,13 @@ class ConfigSignalAnnotator(QMainWindow):
85
87
  self.percentile_btn = QPushButton()
86
88
  self.percentile_btn.setIcon(icon(MDI6.percent_circle_outline,color="black"))
87
89
  self.percentile_btn.setIconSize(QSize(20, 20))
88
- self.percentile_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
90
+ self.percentile_btn.setStyleSheet(self.button_select_all)
89
91
  self.percentile_btn.setToolTip("Switch to percentile normalization values.")
90
92
  self.percentile_btn.clicked.connect(self.switch_to_absolute_normalization_mode)
91
93
 
92
94
  self.log_btn = QPushButton()
93
95
  self.log_btn.setIcon(icon(MDI6.math_log,color="black"))
94
- self.log_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
96
+ self.log_btn.setStyleSheet(self.button_select_all)
95
97
  self.log_btn.clicked.connect(self.switch_to_log)
96
98
  self.log_btn.setToolTip("Log-transform the intensities.")
97
99
  self.log_btn.setIconSize(QSize(20, 20))
@@ -168,12 +170,12 @@ class ConfigSignalAnnotator(QMainWindow):
168
170
  hbox_interval.addWidget(self.interval_slider, 80)
169
171
  sub_layout.addLayout(hbox_interval)
170
172
 
171
- main_layout.addLayout(sub_layout)
173
+ self.main_layout.addLayout(sub_layout)
172
174
 
173
175
  self.submit_btn = QPushButton('Save')
174
- self.submit_btn.setStyleSheet(self.parent.parent.parent.button_style_sheet)
176
+ self.submit_btn.setStyleSheet(self.button_style_sheet)
175
177
  self.submit_btn.clicked.connect(self.write_instructions)
176
- main_layout.addWidget(self.submit_btn)
178
+ self.main_layout.addWidget(self.submit_btn)
177
179
 
178
180
 
179
181
  self.button_widget.adjustSize()
@@ -4,6 +4,14 @@ class Styles(object):
4
4
 
5
5
  self.init_button_styles()
6
6
  self.init_tab_styles()
7
+ self.init_label_styles()
8
+
9
+ self.celldetective_blue = "#1565c0"
10
+
11
+ self.action_lbl_style_sheet = """
12
+ font-size: 10px;
13
+ padding-left: 10px;
14
+ """
7
15
 
8
16
  def init_button_styles(self):
9
17
 
@@ -214,4 +222,11 @@ class Styles(object):
214
222
  QTabBar::tab:left:only-one, QTabBar::tab:right:only-one {
215
223
  margin-bottom: 0;
216
224
  }
217
- """
225
+ """
226
+
227
+ def init_label_styles(self):
228
+
229
+ self.block_title = '''
230
+ font-weight: bold;
231
+ padding: 0px;
232
+ '''
@@ -2,7 +2,7 @@ from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QScrollArea,
2
2
  from PyQt5.QtCore import Qt, QSize
3
3
  from PyQt5.QtGui import QIcon, QDoubleValidator
4
4
  from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, GeometryChoice, OperationChoice
5
- from superqt import QLabeledDoubleRangeSlider, QLabeledDoubleSlider,QLabeledSlider
5
+ from superqt import QLabeledDoubleRangeSlider, QLabeledDoubleSlider,QLabeledSlider, QColormapComboBox
6
6
  from superqt.fonticon import icon
7
7
  from fonticon_mdi6 import MDI6
8
8
  from celldetective.utils import extract_experiment_channels, get_software_location, _extract_labels_from_config
@@ -26,40 +26,38 @@ from tqdm import tqdm
26
26
  from lifelines import KaplanMeierFitter
27
27
  import matplotlib.cm as mcm
28
28
  import math
29
- from celldetective.events import switch_to_events_v2
29
+ from celldetective.events import switch_to_events
30
+ from celldetective.gui import Styles
30
31
 
31
- class ConfigSurvival(QWidget):
32
+ class ConfigSurvival(QWidget, Styles):
32
33
 
33
34
  """
34
35
  UI to set survival instructions.
35
36
 
36
37
  """
37
38
 
38
- def __init__(self, parent=None):
39
+ def __init__(self, parent_window=None):
39
40
 
40
41
  super().__init__()
41
- self.parent = parent
42
+ self.parent_window = parent_window
42
43
  self.setWindowTitle("Configure survival")
43
- self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','mexican-hat.png'])))
44
+ self.setWindowIcon(QIcon(os.sep.join(['celldetective','icons','logo.png'])))
44
45
 
45
- self.exp_dir = self.parent.exp_dir
46
+ self.exp_dir = self.parent_window.exp_dir
46
47
  self.soft_path = get_software_location()
47
48
  self.exp_config = self.exp_dir +"config.ini"
48
- self.wells = np.array(self.parent.parent.wells,dtype=str)
49
+ self.wells = np.array(self.parent_window.parent_window.wells,dtype=str)
49
50
  self.well_labels = _extract_labels_from_config(self.exp_config,len(self.wells))
50
- self.FrameToMin = self.parent.parent.FrameToMin
51
+ self.FrameToMin = self.parent_window.parent_window.FrameToMin
51
52
  self.float_validator = QDoubleValidator()
52
53
  self.auto_close = False
53
54
 
54
- print('Parent wells: ', self.wells)
55
-
56
-
57
- self.well_option = self.parent.parent.well_list.currentIndex()
58
- self.position_option = self.parent.parent.position_list.currentIndex()
55
+ self.well_option = self.parent_window.parent_window.well_list.currentIndex()
56
+ self.position_option = self.parent_window.parent_window.position_list.currentIndex()
59
57
  self.interpret_pos_location()
60
58
  #self.config_path = self.exp_dir + self.config_name
61
59
 
62
- self.screen_height = self.parent.parent.parent.screen_height
60
+ self.screen_height = self.parent_window.parent_window.parent_window.screen_height
63
61
  center_window(self)
64
62
 
65
63
  self.setMinimumWidth(350)
@@ -69,6 +67,7 @@ class ConfigSurvival(QWidget):
69
67
  #self.load_previous_measurement_instructions()
70
68
  if self.auto_close:
71
69
  self.close()
70
+ self.setAttribute(Qt.WA_DeleteOnClose)
72
71
 
73
72
  def interpret_pos_location(self):
74
73
 
@@ -109,9 +108,10 @@ class ConfigSurvival(QWidget):
109
108
  main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
110
109
 
111
110
 
112
- labels = [QLabel('population: '), QLabel('time of\ninterest: '), QLabel('time of\nreference: '), QLabel('cmap: ')] #QLabel('class: '),
113
- self.cb_options = [['targets','effectors'],['t0','first detection'], ['0','first detection', 't0'], list(plt.colormaps())] #['class'],
111
+ labels = [QLabel('population: '), QLabel('time of\nreference: '), QLabel('time of\ninterest: '), QLabel('exclude\nclass: '), QLabel('cmap: ')] #QLabel('class: '),
112
+ self.cb_options = [['targets','effectors'], ['0','t_firstdetection'], ['t0'], ['--'], list(plt.colormaps())] #['class'],
114
113
  self.cbs = [QComboBox() for i in range(len(labels))]
114
+ self.cbs[-1] = QColormapComboBox()
115
115
  self.cbs[0].currentIndexChanged.connect(self.set_classes_and_times)
116
116
 
117
117
  choice_layout = QVBoxLayout()
@@ -120,12 +120,15 @@ class ConfigSurvival(QWidget):
120
120
  hbox = QHBoxLayout()
121
121
  hbox.addWidget(labels[i], 33)
122
122
  hbox.addWidget(self.cbs[i],66)
123
- self.cbs[i].addItems(self.cb_options[i])
123
+ if i < len(labels)-1:
124
+ self.cbs[i].addItems(self.cb_options[i])
124
125
  choice_layout.addLayout(hbox)
126
+
127
+ self.cbs[-1].addColormaps(self.cb_options[-1])
125
128
  main_layout.addLayout(choice_layout)
126
129
 
127
- self.cbs[0].setCurrentIndex(1)
128
130
  self.cbs[0].setCurrentIndex(0)
131
+ self.cbs[1].setCurrentText('t_firstdetection')
129
132
 
130
133
  time_calib_layout = QHBoxLayout()
131
134
  time_calib_layout.setContentsMargins(20,20,20,20)
@@ -137,7 +140,7 @@ class ConfigSurvival(QWidget):
137
140
  main_layout.addLayout(time_calib_layout)
138
141
 
139
142
  self.submit_btn = QPushButton('Submit')
140
- self.submit_btn.setStyleSheet(self.parent.parent.parent.button_style_sheet)
143
+ self.submit_btn.setStyleSheet(self.button_style_sheet)
141
144
  self.submit_btn.clicked.connect(self.process_survival)
142
145
  main_layout.addWidget(self.submit_btn)
143
146
 
@@ -150,7 +153,7 @@ class ConfigSurvival(QWidget):
150
153
  def set_classes_and_times(self):
151
154
 
152
155
  # Look for all classes and times
153
- tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_*']))
156
+ tables = glob(self.exp_dir+os.sep.join(['W*','*','output','tables',f'trajectories_*.csv']))
154
157
  self.all_columns = []
155
158
  for tab in tables:
156
159
  cols = pd.read_csv(tab, nrows=1,encoding_errors='ignore').columns.tolist()
@@ -158,6 +161,8 @@ class ConfigSurvival(QWidget):
158
161
  self.all_columns = np.unique(self.all_columns)
159
162
  #class_idx = np.array([s.startswith('class_') for s in self.all_columns])
160
163
  time_idx = np.array([s.startswith('t_') for s in self.all_columns])
164
+ class_idx = np.array([s.startswith('class') for s in self.all_columns])
165
+
161
166
  # class_columns = list(self.all_columns[class_idx])
162
167
  # for c in ['class_id', 'class_color']:
163
168
  # if c in class_columns:
@@ -170,12 +175,22 @@ class ConfigSurvival(QWidget):
170
175
  self.auto_close = True
171
176
  return None
172
177
 
173
- self.cbs[1].clear()
174
- self.cbs[1].addItems(np.unique(self.cb_options[1]+time_columns))
178
+ try:
179
+ class_columns = list(self.all_columns[class_idx])
180
+ self.cbs[3].clear()
181
+ self.cbs[3].addItems(np.unique(self.cb_options[3]+class_columns))
182
+ except:
183
+ print('no column starts with class')
184
+ self.auto_close = True
185
+ return None
175
186
 
176
187
  self.cbs[2].clear()
177
188
  self.cbs[2].addItems(np.unique(self.cb_options[2]+time_columns))
178
189
 
190
+ self.cbs[1].clear()
191
+ self.cbs[1].addItems(np.unique(self.cb_options[1]+time_columns))
192
+ self.cbs[1].setCurrentText('t_firstdetection')
193
+
179
194
  # self.cbs[3].clear()
180
195
  # self.cbs[3].addItems(np.unique(self.cb_options[3]+class_columns))
181
196
 
@@ -186,7 +201,7 @@ class ConfigSurvival(QWidget):
186
201
  self.FrameToMin = float(self.time_calibration_le.text().replace(',','.'))
187
202
  print(self.FrameToMin, 'set')
188
203
 
189
- self.time_of_interest = self.cbs[1].currentText()
204
+ self.time_of_interest = self.cbs[2].currentText()
190
205
  if self.time_of_interest=="t0":
191
206
  self.class_of_interest = "class"
192
207
  else:
@@ -194,7 +209,14 @@ class ConfigSurvival(QWidget):
194
209
 
195
210
  # read instructions from combobox options
196
211
  self.load_available_tables_local()
212
+
197
213
  if self.df is not None:
214
+
215
+ excluded_class = self.cbs[3].currentText()
216
+ if excluded_class!='--':
217
+ print(f"Excluding {excluded_class}...")
218
+ self.df = self.df.loc[~(self.df[excluded_class].isin([0,2])),:]
219
+
198
220
  self.compute_survival_functions()
199
221
  # prepare survival
200
222
 
@@ -216,7 +238,7 @@ class ConfigSurvival(QWidget):
216
238
 
217
239
  self.legend_btn = QPushButton('')
218
240
  self.legend_btn.setIcon(icon(MDI6.text_box,color="black"))
219
- self.legend_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
241
+ self.legend_btn.setStyleSheet(self.button_select_all)
220
242
  self.legend_btn.setToolTip('Show or hide the legend')
221
243
  self.legend_visible = True
222
244
  self.legend_btn.clicked.connect(self.show_hide_legend)
@@ -225,7 +247,7 @@ class ConfigSurvival(QWidget):
225
247
 
226
248
  self.log_btn = QPushButton('')
227
249
  self.log_btn.setIcon(icon(MDI6.math_log,color="black"))
228
- self.log_btn.setStyleSheet(self.parent.parent.parent.button_select_all)
250
+ self.log_btn.setStyleSheet(self.button_select_all)
229
251
  self.log_btn.clicked.connect(self.switch_to_log)
230
252
  self.log_btn.setToolTip('Enable or disable log scale')
231
253
  plot_buttons_hbox.addWidget(self.log_btn, 5, alignment=Qt.AlignRight)
@@ -369,12 +391,12 @@ class ConfigSurvival(QWidget):
369
391
 
370
392
  """
371
393
 
372
- self.well_option = self.parent.parent.well_list.currentIndex()
394
+ self.well_option = self.parent_window.parent_window.well_list.currentIndex()
373
395
  if self.well_option==len(self.wells):
374
396
  wo = '*'
375
397
  else:
376
398
  wo = self.well_option
377
- self.position_option = self.parent.parent.position_list.currentIndex()
399
+ self.position_option = self.parent_window.parent_window.position_list.currentIndex()
378
400
  if self.position_option==0:
379
401
  po = '*'
380
402
  else:
@@ -403,14 +425,14 @@ class ConfigSurvival(QWidget):
403
425
  for block,movie_group in self.df.groupby(['well','position']):
404
426
  try:
405
427
  classes = movie_group.groupby('TRACK_ID')[self.class_of_interest].min().values
406
- times = movie_group.groupby('TRACK_ID')[self.cbs[1].currentText()].min().values
428
+ times = movie_group.groupby('TRACK_ID')[self.cbs[2].currentText()].min().values
407
429
  except Exception as e:
408
430
  print(e)
409
431
  continue
410
432
  max_times = movie_group.groupby('TRACK_ID')['FRAME'].max().values
411
433
  first_detections = None
412
434
 
413
- if self.cbs[2].currentText()=='first detection':
435
+ if self.cbs[1].currentText()=='first detection':
414
436
  left_censored = True
415
437
 
416
438
  first_detections = []
@@ -427,17 +449,17 @@ class ConfigSurvival(QWidget):
427
449
  else:
428
450
  continue
429
451
 
430
- elif self.cbs[2].currentText().startswith('t'):
452
+ elif self.cbs[1].currentText().startswith('t'):
431
453
  left_censored = True
432
- first_detections = movie_group.groupby('TRACK_ID')[self.cbs[2].currentText()].max().values
454
+ first_detections = movie_group.groupby('TRACK_ID')[self.cbs[1].currentText()].max().values
433
455
  print(first_detections)
434
456
 
435
457
 
436
- if self.cbs[2].currentText()=='first detection' or self.cbs[2].currentText().startswith('t'):
458
+ if self.cbs[1].currentText()=='first detection' or self.cbs[1].currentText().startswith('t'):
437
459
  left_censored = True
438
460
  else:
439
461
  left_censored = False
440
- events, survival_times = switch_to_events_v2(classes, times, max_times, first_detections, left_censored=left_censored, FrameToMin=self.FrameToMin)
462
+ events, survival_times = switch_to_events(classes, times, max_times, first_detections, left_censored=left_censored, FrameToMin=self.FrameToMin)
441
463
  ks = KaplanMeierFitter()
442
464
  if len(events)>0:
443
465
  ks.fit(survival_times, event_observed=events)
@@ -455,14 +477,14 @@ class ConfigSurvival(QWidget):
455
477
  for block,movie_group in well_group.groupby('position'):
456
478
  try:
457
479
  classes = movie_group.groupby('TRACK_ID')[self.class_of_interest].min().values
458
- times = movie_group.groupby('TRACK_ID')[self.cbs[1].currentText()].min().values
480
+ times = movie_group.groupby('TRACK_ID')[self.cbs[2].currentText()].min().values
459
481
  except Exception as e:
460
482
  print(e)
461
483
  continue
462
484
  max_times = movie_group.groupby('TRACK_ID')['FRAME'].max().values
463
485
  first_detections = None
464
486
 
465
- if self.cbs[2].currentText()=='first detection':
487
+ if self.cbs[1].currentText()=='first detection':
466
488
 
467
489
  left_censored = True
468
490
  first_detections = []
@@ -477,9 +499,9 @@ class ConfigSurvival(QWidget):
477
499
  # think about assymmetry with class and times
478
500
  continue
479
501
 
480
- elif self.cbs[2].currentText().startswith('t'):
502
+ elif self.cbs[1].currentText().startswith('t'):
481
503
  left_censored = True
482
- first_detections = movie_group.groupby('TRACK_ID')[self.cbs[2].currentText()].max().values
504
+ first_detections = movie_group.groupby('TRACK_ID')[self.cbs[1].currentText()].max().values
483
505
 
484
506
  else:
485
507
  pass
@@ -494,7 +516,7 @@ class ConfigSurvival(QWidget):
494
516
  well_first_detections = None
495
517
 
496
518
  print(f"{well_classes=}; {well_times=}")
497
- events, survival_times = switch_to_events_v2(well_classes, well_times, well_max_times, well_first_detections,left_censored=left_censored, FrameToMin=self.FrameToMin)
519
+ events, survival_times = switch_to_events(well_classes, well_times, well_max_times, well_first_detections,left_censored=left_censored, FrameToMin=self.FrameToMin)
498
520
  print(f"{events=}; {survival_times=}")
499
521
  ks = KaplanMeierFitter()
500
522
  if len(survival_times)>0:
@@ -9,6 +9,8 @@ import numpy as np
9
9
  import seaborn as sns
10
10
  import matplotlib.cm as mcm
11
11
  import os
12
+ from celldetective.gui import Styles
13
+ from superqt import QColormapComboBox
12
14
 
13
15
  class PandasModel(QAbstractTableModel):
14
16
 
@@ -36,10 +38,10 @@ class PandasModel(QAbstractTableModel):
36
38
 
37
39
  class QueryWidget(QWidget):
38
40
 
39
- def __init__(self, parent):
41
+ def __init__(self, parent_window):
40
42
 
41
43
  super().__init__()
42
- self.parent = parent
44
+ self.parent_window = parent_window
43
45
  self.setWindowTitle("Filter table")
44
46
  # Create the QComboBox and add some items
45
47
  center_window(self)
@@ -57,7 +59,7 @@ class QueryWidget(QWidget):
57
59
  def filter_table(self):
58
60
  try:
59
61
  query_text = self.query_le.text().replace('class', '`class`')
60
- tab = self.parent.data.query(query_text)
62
+ tab = self.parent_window.data.query(query_text)
61
63
  self.subtable = TableUI(tab, query_text, plot_mode="scatter")
62
64
  self.subtable.show()
63
65
  self.close()
@@ -67,10 +69,10 @@ class QueryWidget(QWidget):
67
69
 
68
70
  class RenameColWidget(QWidget):
69
71
 
70
- def __init__(self, parent, column=None):
72
+ def __init__(self, parent_window, column=None):
71
73
 
72
74
  super().__init__()
73
- self.parent = parent
75
+ self.parent_window = parent_window
74
76
  self.column = column
75
77
  if self.column is None:
76
78
  self.column = ''
@@ -93,15 +95,15 @@ class RenameColWidget(QWidget):
93
95
 
94
96
  old_name = self.column
95
97
  new_name = self.new_col_name.text()
96
- self.parent.data = self.parent.data.rename(columns={old_name: new_name})
98
+ self.parent_window.data = self.parent_window.data.rename(columns={old_name: new_name})
97
99
  print(self.parent.data.columns)
98
100
 
99
- self.parent.model = PandasModel(self.parent.data)
100
- self.parent.table_view.setModel(self.parent.model)
101
+ self.parent_window.model = PandasModel(self.parent_window.data)
102
+ self.parent_window.table_view.setModel(self.parent_window.model)
101
103
  self.close()
102
104
 
103
105
 
104
- class TableUI(QMainWindow):
106
+ class TableUI(QMainWindow, Styles):
105
107
  def __init__(self, data, title, population='targets',plot_mode="plot_track_signals", *args, **kwargs):
106
108
 
107
109
  QMainWindow.__init__(self, *args, **kwargs)
@@ -280,6 +282,7 @@ class TableUI(QMainWindow):
280
282
  layout.addLayout(hbox)
281
283
 
282
284
  self.set_projection_btn = QPushButton('set')
285
+ self.set_projection_btn.setStyleSheet(self.button_style_sheet)
283
286
  self.set_projection_btn.clicked.connect(self.set_proj_mode)
284
287
  layout.addWidget(self.set_projection_btn)
285
288
 
@@ -313,24 +316,33 @@ class TableUI(QMainWindow):
313
316
  layout.addWidget(self.box_check)
314
317
  layout.addWidget(self.boxenplot_check)
315
318
 
319
+ self.x_cb = QComboBox()
320
+ self.x_cb.addItems(['--']+list(self.data.columns))
321
+
316
322
  self.hue_cb = QComboBox()
317
323
  self.hue_cb.addItems(list(self.data.columns))
318
324
  idx = self.hue_cb.findText('well_index')
319
- self.hue_cb.setCurrentIndex(idx)
325
+
326
+ self.x_cb.findText('--')
327
+ hbox = QHBoxLayout()
328
+ hbox.addWidget(QLabel('x: '), 33)
329
+ hbox.addWidget(self.x_cb, 66)
330
+ layout.addLayout(hbox)
331
+
320
332
  hbox = QHBoxLayout()
321
333
  hbox.addWidget(QLabel('hue: '), 33)
322
334
  hbox.addWidget(self.hue_cb, 66)
323
335
  layout.addLayout(hbox)
324
336
 
325
-
326
- self.cmap_cb = QComboBox()
327
- self.cmap_cb.addItems(list(plt.colormaps()))
337
+ self.cmap_cb = QColormapComboBox()
338
+ self.cmap_cb.addColormaps(list(plt.colormaps()))
328
339
  hbox = QHBoxLayout()
329
340
  hbox.addWidget(QLabel('colormap: '), 33)
330
341
  hbox.addWidget(self.cmap_cb, 66)
331
342
  layout.addLayout(hbox)
332
343
 
333
344
  self.plot1d_btn = QPushButton('set')
345
+ self.plot1d_btn.setStyleSheet(self.button_style_sheet)
334
346
  self.plot1d_btn.clicked.connect(self.plot1d)
335
347
  layout.addWidget(self.plot1d_btn)
336
348
 
@@ -340,6 +352,11 @@ class TableUI(QMainWindow):
340
352
 
341
353
  def plot1d(self):
342
354
 
355
+ self.x_option = False
356
+ if self.x_cb.currentText()!='--':
357
+ self.x_option = True
358
+ self.x = self.x_cb.currentText()
359
+
343
360
  x = self.table_view.selectedIndexes()
344
361
  col_idx = np.array([l.column() for l in x])
345
362
  row_idx = np.array([l.row() for l in x])
@@ -371,24 +388,44 @@ class TableUI(QMainWindow):
371
388
  legend = False
372
389
 
373
390
  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
391
+ if self.x_option:
392
+ 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)
393
+ legend = False
394
+ else:
395
+ sns.swarmplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors)
396
+ legend = False
376
397
 
377
398
  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
399
+ if self.x_option:
400
+ 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)
401
+ legend = False
402
+ else:
403
+ sns.violinplot(data=self.data, y=column_names[unique_cols],dodge=True, hue=hue_variable,legend=legend, ax=self.ax, palette=colors, cut=0)
404
+ legend = False
380
405
 
381
406
  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
407
+ if self.x_option:
408
+ 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,)
409
+ legend = False
410
+ else:
411
+ 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,)
412
+ legend = False
384
413
 
385
414
  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
415
+ if self.x_option:
416
+ 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,)
417
+ legend = False
418
+ else:
419
+ 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,)
420
+ legend = False
388
421
 
389
422
  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
423
+ if self.x_option:
424
+ 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)
425
+ legend = False
426
+ else:
427
+ sns.stripplot(data=self.data, y=column_names[unique_cols],dodge=True, ax=self.ax, hue=hue_variable, legend=legend, palette=colors)
428
+ legend = False
392
429
 
393
430
  plt.tight_layout()
394
431
  self.fig.set_facecolor('none') # or 'None'