celldetective 1.3.9.post5__py3-none-any.whl → 1.4.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 (57) hide show
  1. celldetective/__init__.py +0 -3
  2. celldetective/_version.py +1 -1
  3. celldetective/events.py +2 -4
  4. celldetective/extra_properties.py +132 -0
  5. celldetective/gui/InitWindow.py +33 -45
  6. celldetective/gui/__init__.py +1 -0
  7. celldetective/gui/about.py +19 -15
  8. celldetective/gui/analyze_block.py +34 -19
  9. celldetective/gui/base_components.py +23 -0
  10. celldetective/gui/btrack_options.py +26 -34
  11. celldetective/gui/classifier_widget.py +68 -81
  12. celldetective/gui/configure_new_exp.py +113 -17
  13. celldetective/gui/control_panel.py +68 -141
  14. celldetective/gui/generic_signal_plot.py +9 -12
  15. celldetective/gui/gui_utils.py +49 -21
  16. celldetective/gui/json_readers.py +5 -4
  17. celldetective/gui/layouts.py +246 -22
  18. celldetective/gui/measurement_options.py +32 -17
  19. celldetective/gui/neighborhood_options.py +10 -13
  20. celldetective/gui/plot_measurements.py +21 -17
  21. celldetective/gui/plot_signals_ui.py +125 -72
  22. celldetective/gui/process_block.py +180 -123
  23. celldetective/gui/processes/compute_neighborhood.py +594 -0
  24. celldetective/gui/processes/measure_cells.py +5 -0
  25. celldetective/gui/processes/segment_cells.py +27 -6
  26. celldetective/gui/processes/track_cells.py +6 -0
  27. celldetective/gui/retrain_segmentation_model_options.py +12 -20
  28. celldetective/gui/retrain_signal_model_options.py +57 -56
  29. celldetective/gui/seg_model_loader.py +21 -62
  30. celldetective/gui/signal_annotator.py +129 -70
  31. celldetective/gui/signal_annotator2.py +431 -635
  32. celldetective/gui/signal_annotator_options.py +8 -11
  33. celldetective/gui/survival_ui.py +49 -95
  34. celldetective/gui/tableUI.py +28 -25
  35. celldetective/gui/thresholds_gui.py +617 -1221
  36. celldetective/gui/viewers.py +106 -39
  37. celldetective/gui/workers.py +9 -3
  38. celldetective/io.py +57 -20
  39. celldetective/measure.py +63 -27
  40. celldetective/neighborhood.py +342 -268
  41. celldetective/preprocessing.py +25 -17
  42. celldetective/relative_measurements.py +50 -29
  43. celldetective/scripts/analyze_signals.py +4 -1
  44. celldetective/scripts/measure_relative.py +4 -1
  45. celldetective/scripts/segment_cells.py +0 -6
  46. celldetective/scripts/track_cells.py +3 -1
  47. celldetective/scripts/train_segmentation_model.py +7 -4
  48. celldetective/signals.py +29 -14
  49. celldetective/tracking.py +7 -2
  50. celldetective/utils.py +36 -8
  51. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/METADATA +24 -16
  52. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/RECORD +57 -55
  53. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/WHEEL +1 -1
  54. tests/test_qt.py +21 -21
  55. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/entry_points.txt +0 -0
  56. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info/licenses}/LICENSE +0 -0
  57. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.0.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,6 @@
1
- from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QHBoxLayout, QFileDialog, QVBoxLayout, QScrollArea, QCheckBox, QGridLayout, QLabel, QLineEdit, QPushButton, QWidget
1
+ from PyQt5.QtWidgets import QApplication, QMessageBox, QHBoxLayout, QFileDialog, QVBoxLayout, QScrollArea, QCheckBox, QGridLayout, QLabel, QLineEdit, QPushButton
2
2
  from PyQt5.QtGui import QIntValidator, QDoubleValidator
3
3
  from celldetective.gui.gui_utils import center_window, help_generic
4
- from celldetective.gui.styles import Styles
5
4
  from celldetective.utils import get_software_location
6
5
  import json
7
6
 
@@ -13,9 +12,10 @@ from configparser import ConfigParser
13
12
  import os
14
13
  from functools import partial
15
14
  import numpy as np
16
- from celldetective.gui import Styles
15
+ from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
17
16
 
18
- class ConfigNewExperiment(QMainWindow, Styles):
17
+
18
+ class ConfigNewExperiment(CelldetectiveMainWindow):
19
19
 
20
20
  def __init__(self, parent_window=None):
21
21
 
@@ -34,11 +34,11 @@ class ConfigNewExperiment(QMainWindow, Styles):
34
34
 
35
35
  # Create button widget and layout
36
36
  self.scroll_area = QScrollArea(self)
37
- button_widget = QWidget()
37
+ button_widget = CelldetectiveWidget()
38
38
  self.grid = QGridLayout()
39
39
  button_widget.setLayout(self.grid)
40
40
 
41
- self.grid.setContentsMargins(30,30,30,30)
41
+ self.grid.setContentsMargins(30, 30, 30, 30)
42
42
  self.grid.addWidget(QLabel("Folder:"), 0, 0, 1, 3)
43
43
  self.supFolder = QLineEdit()
44
44
  self.supFolder.setAlignment(Qt.AlignLeft)
@@ -64,17 +64,20 @@ class ConfigNewExperiment(QMainWindow, Styles):
64
64
  self.grid.addWidget(self.expName, 3, 0, 1, 3)
65
65
 
66
66
  self.generate_movie_settings()
67
- self.grid.addLayout(self.ms_grid,29,0,1,3)
67
+ self.grid.addLayout(self.ms_grid, 29, 0, 1, 3)
68
68
 
69
69
  self.generate_channel_params_box()
70
- self.grid.addLayout(self.channel_grid,30,0,1,3)
70
+ self.grid.addLayout(self.channel_grid, 30, 0, 1, 3)
71
+
72
+ self.generate_population_params_box()
73
+ self.grid.addLayout(self.population_grid, 31, 0, 1, 3)
71
74
 
72
75
  self.validate_button = QPushButton("Submit")
73
76
  self.validate_button.clicked.connect(self.create_config)
74
77
  self.validate_button.setStyleSheet(self.button_style_sheet)
75
78
  #self.validate_button.setIcon(QIcon_from_svg(abs_path+f"/icons/process.svg", color='white'))
76
79
 
77
- self.grid.addWidget(self.validate_button, 31, 0, 1, 3, alignment = Qt.AlignBottom)
80
+ self.grid.addWidget(self.validate_button, 32, 0, 1, 3, alignment = Qt.AlignBottom)
78
81
  button_widget.adjustSize()
79
82
 
80
83
  self.scroll_area.setAlignment(Qt.AlignCenter)
@@ -128,10 +131,9 @@ class ConfigNewExperiment(QMainWindow, Styles):
128
131
  self.help_btn.setToolTip("Help.")
129
132
  self.ms_grid.addWidget(self.help_btn, 1, 0, 1, 3, alignment=Qt.AlignRight)
130
133
 
131
-
132
134
  self.SliderWells = QLabeledSlider(Qt.Horizontal, self)
133
135
  self.SliderWells.setMinimum(1)
134
- self.SliderWells.setMaximum(32)
136
+ self.SliderWells.setMaximum(512)
135
137
  self.ms_grid.addWidget(self.SliderWells, 2, 0, 1, 3, alignment=Qt.AlignTop)
136
138
 
137
139
  self.number_of_positions = QLabel("Number of positions per well:")
@@ -139,7 +141,7 @@ class ConfigNewExperiment(QMainWindow, Styles):
139
141
 
140
142
  self.SliderPos = QLabeledSlider(Qt.Horizontal, self)
141
143
  self.SliderPos.setMinimum(1)
142
- self.SliderPos.setMaximum(50)
144
+ self.SliderPos.setMaximum(512)
143
145
 
144
146
  self.ms_grid.addWidget(self.SliderPos, 4, 0, 1, 3)
145
147
 
@@ -168,7 +170,7 @@ class ConfigNewExperiment(QMainWindow, Styles):
168
170
  self.ms_grid.addWidget(self.movie_length,9, 0, 1, 3)
169
171
  self.MovieLengthSlider = QLabeledSlider(Qt.Horizontal, self)
170
172
  self.MovieLengthSlider.setMinimum(2)
171
- self.MovieLengthSlider.setMaximum(128)
173
+ #self.MovieLengthSlider.setMaximum(128)
172
174
  self.ms_grid.addWidget(self.MovieLengthSlider, 10, 0, 1, 3)
173
175
 
174
176
  self.prefix_lbl = QLabel("Prefix for the movies:")
@@ -181,7 +183,7 @@ class ConfigNewExperiment(QMainWindow, Styles):
181
183
  self.movie_prefix_field.setText("")
182
184
  self.ms_grid.addWidget(self.movie_prefix_field, 12, 0, 1, 3)
183
185
 
184
- self.ms_grid.addWidget(QLabel("X shape in pixels:"), 13, 0, 1, 3)
186
+ self.ms_grid.addWidget(QLabel("Image width:"), 13, 0, 1, 3)
185
187
  self.shape_x_field = QLineEdit()
186
188
  self.shape_x_field.setValidator(onlyInt)
187
189
  self.shape_x_field.setAlignment(Qt.AlignLeft)
@@ -190,7 +192,7 @@ class ConfigNewExperiment(QMainWindow, Styles):
190
192
  self.shape_x_field.setText("2048")
191
193
  self.ms_grid.addWidget(self.shape_x_field, 14, 0, 1, 3)
192
194
 
193
- self.ms_grid.addWidget(QLabel("Y shape in pixels:"), 15, 0, 1, 3)
195
+ self.ms_grid.addWidget(QLabel("Image height:"), 15, 0, 1, 3)
194
196
  self.shape_y_field = QLineEdit()
195
197
  self.shape_y_field.setValidator(onlyInt)
196
198
  self.shape_y_field.setAlignment(Qt.AlignLeft)
@@ -271,7 +273,7 @@ class ConfigNewExperiment(QMainWindow, Styles):
271
273
 
272
274
  def add_custom_channel(self):
273
275
 
274
- self.CustomChannelWidget = QWidget()
276
+ self.CustomChannelWidget = CelldetectiveWidget()
275
277
  self.CustomChannelWidget.setWindowTitle("Custom channel")
276
278
  layout = QVBoxLayout()
277
279
  self.CustomChannelWidget.setLayout(layout)
@@ -323,6 +325,83 @@ class ConfigNewExperiment(QMainWindow, Styles):
323
325
  else:
324
326
  self.sliders[index].setEnabled(False)
325
327
 
328
+ def generate_population_params_box(self):
329
+
330
+ """
331
+ Parameters related to the movie channels
332
+ Rewrite all of it
333
+
334
+ """
335
+
336
+ self.population_grid = QGridLayout()
337
+ self.population_grid.setContentsMargins(21,30,20,30)
338
+
339
+ pop_lbl = QLabel("CELL POPULATIONS")
340
+ pop_lbl.setStyleSheet("""
341
+ font-weight: bold;
342
+ """)
343
+ self.population_grid.addWidget(pop_lbl, 0,0,1,3, alignment=Qt.AlignCenter)
344
+
345
+
346
+ self.populations = ['effectors','targets']
347
+ self.population_checkboxes = [QCheckBox() for i in range(len(self.populations))]
348
+
349
+ for i in range(len(self.populations)):
350
+
351
+ self.population_checkboxes[i].setText(self.populations[i])
352
+ self.population_checkboxes[i].setChecked(True)
353
+ self.population_grid.addWidget(self.population_checkboxes[i], i+1, 0, 1, 1)
354
+
355
+ # Add channel button
356
+ self.addPopBtn = QPushButton('Add a cell population')
357
+ self.addPopBtn.setIcon(icon(MDI6.plus,color="white"))
358
+ self.addPopBtn.setIconSize(QSize(25, 25))
359
+ self.addPopBtn.setStyleSheet(self.button_style_sheet)
360
+ self.addPopBtn.clicked.connect(self.add_custom_population)
361
+ self.population_grid.addWidget(self.addPopBtn, 1000, 0, 1, 1)
362
+
363
+
364
+ def add_custom_population(self):
365
+ self.CustomPopWidget = CelldetectiveWidget()
366
+ self.CustomPopWidget.setWindowTitle("Define custom population")
367
+ layout = QVBoxLayout()
368
+ self.CustomPopWidget.setLayout(layout)
369
+
370
+ self.name_le = QLineEdit()
371
+ self.name_le.setPlaceholderText('name')
372
+ self.name_le.textChanged.connect(self.check_population_name)
373
+ hbox = QHBoxLayout()
374
+ hbox.addWidget(QLabel('population name: '), 33)
375
+ hbox.addWidget(self.name_le, 66)
376
+ layout.addLayout(hbox)
377
+
378
+ self.addPopBtn = QPushButton('add')
379
+ self.addPopBtn.setStyleSheet(self.button_style_sheet)
380
+ self.addPopBtn.setEnabled(False)
381
+ self.addPopBtn.clicked.connect(self.write_custom_population)
382
+ layout.addWidget(self.addPopBtn)
383
+ center_window(self.CustomPopWidget)
384
+ self.CustomPopWidget.show()
385
+
386
+ def check_population_name(self, text):
387
+ # define all conditions for valid population name (like no space)
388
+ if len(text)>0 and ' ' not in text:
389
+ self.addPopBtn.setEnabled(True)
390
+ else:
391
+ self.addPopBtn.setEnabled(False)
392
+
393
+ def write_custom_population(self):
394
+
395
+ self.new_population_name = self.name_le.text()
396
+ name_map = self.new_population_name
397
+
398
+ self.populations.append(self.new_population_name)
399
+ self.population_checkboxes.append(QCheckBox())
400
+ self.CustomPopWidget.close()
401
+
402
+ self.population_checkboxes[-1].setText(self.populations[-1])
403
+ self.population_grid.addWidget(self.population_checkboxes[-1], len(self.populations)+1, 0, 1, 1)
404
+
326
405
  def browse_experiment_folder(self):
327
406
 
328
407
  """
@@ -362,6 +441,17 @@ class ConfigNewExperiment(QMainWindow, Styles):
362
441
  if returnValue == QMessageBox.Ok:
363
442
  return None
364
443
 
444
+ populations_checked = [self.population_checkboxes[i].isChecked() for i in range(len(self.population_checkboxes))]
445
+ if not np.any(populations_checked):
446
+ msgBox = QMessageBox()
447
+ msgBox.setIcon(QMessageBox.Warning)
448
+ msgBox.setText("Please set at least one cell population before proceeding...")
449
+ msgBox.setWindowTitle("Warning")
450
+ msgBox.setStandardButtons(QMessageBox.Ok)
451
+ returnValue = msgBox.exec()
452
+ if returnValue == QMessageBox.Ok:
453
+ return None
454
+
365
455
  sorted_list = set(channel_indices)
366
456
  expected_list = set(np.arange(max(sorted_list)+1))
367
457
  print(sorted_list, expected_list, sorted_list==expected_list)
@@ -429,8 +519,13 @@ class ConfigNewExperiment(QMainWindow, Styles):
429
519
  Write all user input parameters to a configuration file associated to an experiment.
430
520
  """
431
521
 
522
+
432
523
  config = ConfigParser(interpolation=None)
433
524
 
525
+ config.add_section('Populations')
526
+ pops = ','.join([self.populations[i].lower() for i in range(len(self.population_checkboxes)) if self.population_checkboxes[i].isChecked()])
527
+ config.set('Populations','populations', pops)
528
+
434
529
  # add a new section and some values
435
530
  config.add_section('MovieSettings')
436
531
  config.set('MovieSettings', 'PxToUm', self.PxToUm_field.text().replace(',','.'))
@@ -456,6 +551,7 @@ class ConfigNewExperiment(QMainWindow, Styles):
456
551
  config.add_section('Metadata')
457
552
  config.set('Metadata', 'concentration_units', self.concentration_units)
458
553
 
554
+
459
555
  # save to a file
460
556
  with open('config.ini', 'w') as configfile:
461
557
  config.write(configfile)
@@ -464,7 +560,7 @@ class ConfigNewExperiment(QMainWindow, Styles):
464
560
  print(f'New experiment successfully configured in folder {self.directory}...')
465
561
  self.close()
466
562
 
467
- class SetupConditionLabels(QWidget, Styles):
563
+ class SetupConditionLabels(CelldetectiveWidget):
468
564
  def __init__(self, parent_window, n_wells):
469
565
  super().__init__()
470
566
  self.parent_window = parent_window
@@ -1,10 +1,12 @@
1
- from PyQt5.QtWidgets import QMainWindow, QPushButton, QHBoxLayout, QLabel, QWidget, QGridLayout, QFrame, \
2
- QTabWidget, QVBoxLayout, QMessageBox, QScrollArea, QDesktopWidget
1
+ from PyQt5.QtWidgets import QPushButton, QHBoxLayout, QLabel, QGridLayout, QFrame, \
2
+ QTabWidget, QVBoxLayout, QScrollArea, QDesktopWidget
3
+ from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
4
+
3
5
  from PyQt5.QtCore import Qt, QSize
4
- from celldetective.gui.gui_utils import center_window, QHSeperationLine, QCheckableComboBox
5
- from celldetective.utils import _extract_labels_from_config, ConfigSectionMap, extract_experiment_channels, extract_identity_col
6
+ from celldetective.gui.gui_utils import center_window, QHSeperationLine, QCheckableComboBox, generic_message
7
+ from celldetective.utils import _extract_labels_from_config, ConfigSectionMap, extract_identity_col
6
8
  from celldetective.gui import ConfigEditor, ProcessPanel, PreprocessingPanel, AnalysisPanel, NeighPanel
7
- from celldetective.io import get_experiment_wells, get_config, get_spatial_calibration, get_temporal_calibration, get_experiment_concentrations, get_experiment_cell_types, get_experiment_antibodies, get_experiment_pharmaceutical_agents
9
+ from celldetective.io import extract_position_name, get_experiment_wells, get_config, get_spatial_calibration, get_temporal_calibration, get_experiment_concentrations, get_experiment_cell_types, get_experiment_antibodies, get_experiment_pharmaceutical_agents, get_experiment_populations, extract_well_name_and_number
8
10
  from natsort import natsorted
9
11
  from glob import glob
10
12
  import os
@@ -15,11 +17,10 @@ import gc
15
17
  import subprocess
16
18
  from celldetective.gui.viewers import StackVisualizer
17
19
  from celldetective.utils import extract_experiment_channels
18
- from celldetective.gui import Styles
19
20
  import pandas as pd
20
21
 
21
22
 
22
- class ControlPanel(QMainWindow, Styles):
23
+ class ControlPanel(CelldetectiveMainWindow):
23
24
 
24
25
  def __init__(self, parent_window=None, exp_dir=""):
25
26
 
@@ -29,21 +30,20 @@ class ControlPanel(QMainWindow, Styles):
29
30
  if not self.exp_dir.endswith(os.sep):
30
31
  self.exp_dir = self.exp_dir+os.sep
31
32
  self.setWindowTitle("celldetective")
32
- self.setWindowIcon(self.celldetective_icon)
33
33
  self.parent_window = parent_window
34
34
 
35
35
  self.init_wells_and_positions()
36
36
  self.load_configuration()
37
37
 
38
- self.w = QWidget()
38
+ self.w = CelldetectiveWidget()
39
39
  self.grid = QGridLayout(self.w)
40
40
  self.grid.setSpacing(5)
41
- self.grid.setContentsMargins(10,10,10,10) #left top right bottom
41
+ self.grid.setContentsMargins(10, 10, 10, 10) # left top right bottom
42
42
 
43
43
  self.to_disable = []
44
44
  self.generate_header()
45
- self.ProcessEffectors = ProcessPanel(self,'effectors')
46
- self.ProcessTargets = ProcessPanel(self,'targets')
45
+ self.ProcessPopulations = [ProcessPanel(self, pop) for pop in self.populations]
46
+
47
47
  self.NeighPanel = NeighPanel(self)
48
48
  self.PreprocessingPanel = PreprocessingPanel(self)
49
49
 
@@ -57,9 +57,10 @@ class ControlPanel(QMainWindow, Styles):
57
57
  self.SurvivalBlock = AnalysisPanel(self,title='Survival')
58
58
 
59
59
  grid_process.addWidget(self.PreprocessingPanel)
60
- grid_process.addWidget(self.ProcessEffectors)
61
- grid_process.addWidget(self.ProcessTargets)
60
+ for panel in self.ProcessPopulations:
61
+ grid_process.addWidget(panel)
62
62
  grid_process.addWidget(self.NeighPanel)
63
+
63
64
  grid_analyze.addWidget(self.SurvivalBlock)
64
65
 
65
66
  self.scroll=QScrollArea()
@@ -92,7 +93,6 @@ class ControlPanel(QMainWindow, Styles):
92
93
  self.screen_width = desktop.screenGeometry().width()
93
94
  self.scroll.setMinimumWidth(440)
94
95
 
95
- self.setAttribute(Qt.WA_DeleteOnClose)
96
96
  center_window(self)
97
97
 
98
98
 
@@ -108,11 +108,9 @@ class ControlPanel(QMainWindow, Styles):
108
108
  self.wells = get_experiment_wells(self.exp_dir) #natsorted(glob(self.exp_dir + "W*" + os.sep))
109
109
  self.positions = []
110
110
  for w in self.wells:
111
- w = os.path.split(w[:-1])
112
- root = w[0]
113
- w = w[1]
114
- positions_path = natsorted(glob(os.sep.join([root, w, f"{w[1:]}*{os.sep}"])))
115
- self.positions.append([os.path.split(pos[:-1])[1] for pos in positions_path])
111
+ well_name, well_nbr = extract_well_name_and_number(w)
112
+ positions_path = natsorted(glob(os.sep.join([w,f"{well_nbr}*", os.sep])))
113
+ self.positions.append([extract_position_name(pos) for pos in positions_path])
116
114
 
117
115
  def generate_header(self):
118
116
 
@@ -274,15 +272,9 @@ class ControlPanel(QMainWindow, Styles):
274
272
  movies = glob(self.pos + os.sep.join(['movie', f"{self.movie_prefix}*.tif"]))
275
273
 
276
274
  if len(movies) == 0:
277
- msgBox = QMessageBox()
278
- msgBox.setIcon(QMessageBox.Warning)
279
- msgBox.setText("Please select a position containing a movie...")
280
- msgBox.setWindowTitle("Warning")
281
- msgBox.setStandardButtons(QMessageBox.Ok)
282
- returnValue = msgBox.exec()
283
- if returnValue == QMessageBox.Ok:
284
- self.current_stack = None
285
- return None
275
+ generic_message("Please select a position containing a movie...")
276
+ self.current_stack = None
277
+ return None
286
278
  else:
287
279
  self.current_stack = movies[0]
288
280
 
@@ -321,9 +313,11 @@ class ControlPanel(QMainWindow, Styles):
321
313
  print('Reading experiment configuration...')
322
314
  self.exp_config = get_config(self.exp_dir)
323
315
 
316
+ self.populations = get_experiment_populations(self.exp_dir)
324
317
  self.PxToUm = get_spatial_calibration(self.exp_dir)
325
318
  self.FrameToMin = get_temporal_calibration(self.exp_dir)
326
319
 
320
+
327
321
  self.len_movie = int(ConfigSectionMap(self.exp_config,"MovieSettings")["len_movie"])
328
322
  self.shape_x = int(ConfigSectionMap(self.exp_config,"MovieSettings")["shape_x"])
329
323
  self.shape_y = int(ConfigSectionMap(self.exp_config,"MovieSettings")["shape_y"])
@@ -350,7 +344,7 @@ class ControlPanel(QMainWindow, Styles):
350
344
  Close child windows if closed.
351
345
  """
352
346
 
353
- for process_block in [self.ProcessTargets, self.ProcessEffectors]:
347
+ for process_block in self.ProcessPopulations:
354
348
  try:
355
349
  if process_block.SegModelLoader:
356
350
  process_block.SegModelLoader.close()
@@ -436,14 +430,8 @@ class ControlPanel(QMainWindow, Styles):
436
430
  """
437
431
 
438
432
  if self.well_list.isMultipleSelection():
439
- msgBox = QMessageBox()
440
- msgBox.setIcon(QMessageBox.Critical)
441
- msgBox.setText("Please select a single well...")
442
- msgBox.setWindowTitle("Error")
443
- msgBox.setStandardButtons(QMessageBox.Ok)
444
- returnValue = msgBox.exec()
445
- if returnValue == QMessageBox.Ok:
446
- return False
433
+ generic_message("Please select a single well...")
434
+ return False
447
435
  else:
448
436
  self.well_index = self.well_list.getSelectedIndices() #[self.well_list.currentIndex()]
449
437
 
@@ -451,14 +439,8 @@ class ControlPanel(QMainWindow, Styles):
451
439
 
452
440
  pos = self.positions[w_idx]
453
441
  if not self.position_list.isSingleSelection():
454
- msgBox = QMessageBox()
455
- msgBox.setIcon(QMessageBox.Critical)
456
- msgBox.setText("Please select a single position...")
457
- msgBox.setWindowTitle("Error")
458
- msgBox.setStandardButtons(QMessageBox.Ok)
459
- returnValue = msgBox.exec()
460
- if returnValue == QMessageBox.Ok:
461
- return False
442
+ generic_message("Please select a single position...")
443
+ return False
462
444
  else:
463
445
  pos_indices = self.position_list.getSelectedIndices()
464
446
 
@@ -483,127 +465,72 @@ class ControlPanel(QMainWindow, Styles):
483
465
  def update_position_options(self):
484
466
 
485
467
  self.pos = self.position_list.currentText()
486
- panels = [self.ProcessEffectors, self.ProcessTargets]
487
468
 
488
469
  if self.position_list.isMultipleSelection() or not self.position_list.isAnySelected():
489
470
 
490
- for p in panels:
471
+ for p in self.ProcessPopulations:
491
472
  p.check_seg_btn.setEnabled(False)
492
473
  p.check_tracking_result_btn.setEnabled(False)
474
+ p.view_tab_btn.setEnabled(True)
475
+ p.signal_analysis_action.setEnabled(True)
476
+ p.check_seg_btn.setEnabled(False)
477
+ p.check_tracking_result_btn.setEnabled(False)
478
+ p.check_measurements_btn.setEnabled(False)
479
+ p.check_signals_btn.setEnabled(False)
480
+ p.delete_tracks_btn.hide()
493
481
 
494
- self.ProcessTargets.view_tab_btn.setEnabled(True)
495
- self.ProcessEffectors.view_tab_btn.setEnabled(True)
496
- self.NeighPanel.view_tab_btn.setEnabled(True)
497
- self.ProcessEffectors.signal_analysis_action.setEnabled(True)
498
- self.ProcessTargets.signal_analysis_action.setEnabled(True)
499
-
500
- self.ProcessTargets.check_seg_btn.setEnabled(False)
501
- self.ProcessEffectors.check_seg_btn.setEnabled(False)
502
-
503
- self.ProcessTargets.check_tracking_result_btn.setEnabled(False)
504
- self.ProcessEffectors.check_tracking_result_btn.setEnabled(False)
505
-
506
- self.ProcessEffectors.check_measurements_btn.setEnabled(False)
507
- self.ProcessTargets.check_measurements_btn.setEnabled(False)
508
- #self.ProcessTargets.signal_analysis_action.setEnabled(False)
509
- #self.ProcessEffectors.signal_analysis_action.setEnabled(False)
510
482
 
511
- self.ProcessTargets.check_signals_btn.setEnabled(False)
512
- self.ProcessEffectors.check_signals_btn.setEnabled(False)
483
+ self.NeighPanel.view_tab_btn.setEnabled(True)
513
484
  self.NeighPanel.check_signals_btn.setEnabled(False)
514
- self.ProcessTargets.delete_tracks_btn.hide()
515
- self.ProcessEffectors.delete_tracks_btn.hide()
516
-
517
485
  self.view_stack_btn.setEnabled(False)
518
486
 
519
487
  elif self.well_list.isMultipleSelection():
520
488
 
521
- self.ProcessTargets.view_tab_btn.setEnabled(True)
522
- self.ProcessEffectors.view_tab_btn.setEnabled(True)
489
+ for p in self.ProcessPopulations:
490
+ p.view_tab_btn.setEnabled(True)
491
+ p.signal_analysis_action.setEnabled(True)
492
+ p.delete_tracks_btn.hide()
493
+
494
+
523
495
  self.NeighPanel.view_tab_btn.setEnabled(True)
524
496
  self.view_stack_btn.setEnabled(False)
525
- self.ProcessEffectors.signal_analysis_action.setEnabled(True)
526
- self.ProcessTargets.signal_analysis_action.setEnabled(True)
527
497
  if hasattr(self,'delete_tracks_btn'):
528
498
  self.delete_tracks_btn.hide()
529
- self.ProcessTargets.delete_tracks_btn.hide()
530
- self.ProcessEffectors.delete_tracks_btn.hide()
531
499
  else:
532
500
 
533
501
  if self.well_list.isAnySelected() and self.position_list.isAnySelected():
534
502
 
535
503
  self.locate_selected_position()
536
504
  self.view_stack_btn.setEnabled(True)
537
- # if os.path.exists(os.sep.join([self.pos,'labels_effectors', os.sep])):
538
- self.ProcessEffectors.check_seg_btn.setEnabled(True)
539
- # if os.path.exists(os.sep.join([self.pos,'labels_targets', os.sep])):
540
- self.ProcessTargets.check_seg_btn.setEnabled(True)
541
-
542
- # if os.path.exists(os.sep.join([self.pos,'output','tables','napari_target_trajectories.npy'])):
543
- # self.ProcessTargets.check_tracking_result_btn.setEnabled(True)
544
- # else:
545
- # self.ProcessTargets.check_tracking_result_btn.setEnabled(False)
546
- # if os.path.exists(os.sep.join([self.pos,'output','tables','napari_effector_trajectories.npy'])):
547
- # self.ProcessEffectors.check_tracking_result_btn.setEnabled(True)
548
- # else:
549
- # self.ProcessEffectors.check_tracking_result_btn.setEnabled(False)
550
-
551
- if os.path.exists(os.sep.join([self.pos,'output','tables','trajectories_effectors.csv'])):
552
- df = pd.read_csv(os.sep.join([self.pos,'output','tables','trajectories_effectors.csv']), nrows=1)
553
- id_col = extract_identity_col(df)
554
- self.ProcessEffectors.check_measurements_btn.setEnabled(True)
555
- if id_col=='TRACK_ID':
556
- self.ProcessEffectors.check_signals_btn.setEnabled(True)
557
- self.ProcessEffectors.delete_tracks_btn.show()
558
- self.ProcessEffectors.signal_analysis_action.setEnabled(True)
559
- self.ProcessEffectors.check_tracking_result_btn.setEnabled(True)
505
+ for i,p in enumerate(self.ProcessPopulations):
506
+ p.check_seg_btn.setEnabled(True)
507
+ if os.path.exists(os.sep.join([self.pos,'output','tables',f'trajectories_{self.populations[i]}.csv'])):
508
+ df = pd.read_csv(os.sep.join([self.pos,'output','tables',f'trajectories_{self.populations[i]}.csv']), nrows=1)
509
+ id_col = extract_identity_col(df)
510
+ p.check_measurements_btn.setEnabled(True)
511
+
512
+ if id_col=='TRACK_ID':
513
+ p.check_signals_btn.setEnabled(True)
514
+ p.delete_tracks_btn.show()
515
+ p.signal_analysis_action.setEnabled(True)
516
+ p.check_tracking_result_btn.setEnabled(True)
517
+ else:
518
+ p.signal_analysis_action.setEnabled(False)
519
+ p.check_tracking_result_btn.setEnabled(False)
520
+
521
+ p.view_tab_btn.setEnabled(True)
522
+ p.classify_btn.setEnabled(True)
560
523
  else:
561
- self.ProcessEffectors.signal_analysis_action.setEnabled(False)
562
- self.ProcessEffectors.check_tracking_result_btn.setEnabled(False)
563
-
564
- #self.ProcessEffectors.signal_analysis_action.setEnabled(True)
565
- self.ProcessEffectors.view_tab_btn.setEnabled(True)
566
- self.ProcessEffectors.classify_btn.setEnabled(True)
567
- else:
568
- self.ProcessEffectors.check_measurements_btn.setEnabled(False)
569
- self.ProcessEffectors.check_signals_btn.setEnabled(False)
570
- #self.ProcessEffectors.signal_analysis_action.setEnabled(False)
571
- self.ProcessEffectors.view_tab_btn.setEnabled(False)
572
- self.ProcessEffectors.classify_btn.setEnabled(False)
573
- self.ProcessEffectors.delete_tracks_btn.hide()
574
- self.ProcessEffectors.signal_analysis_action.setEnabled(False)
575
-
576
- if os.path.exists(os.sep.join([self.pos,'output','tables','trajectories_targets.csv'])):
577
- df = pd.read_csv(os.sep.join([self.pos,'output','tables','trajectories_targets.csv']), nrows=1)
578
- id_col = extract_identity_col(df)
579
- self.ProcessTargets.check_measurements_btn.setEnabled(True)
580
- if id_col=='TRACK_ID':
581
- self.ProcessTargets.check_signals_btn.setEnabled(True)
582
- self.ProcessTargets.signal_analysis_action.setEnabled(True)
583
- self.ProcessTargets.check_tracking_result_btn.setEnabled(True)
584
- self.ProcessTargets.delete_tracks_btn.show()
585
- else:
586
- self.ProcessTargets.signal_analysis_action.setEnabled(False)
587
- self.ProcessTargets.check_tracking_result_btn.setEnabled(False)
588
-
589
- #self.ProcessTargets.signal_analysis_action.setEnabled(True)
590
- self.ProcessTargets.view_tab_btn.setEnabled(True)
591
- self.ProcessTargets.classify_btn.setEnabled(True)
592
- else:
593
- self.ProcessTargets.check_measurements_btn.setEnabled(False)
594
- self.ProcessTargets.check_signals_btn.setEnabled(False)
595
- #self.ProcessTargets.signal_analysis_action.setEnabled(False)
596
- self.ProcessTargets.view_tab_btn.setEnabled(False)
597
- self.ProcessTargets.classify_btn.setEnabled(False)
598
- self.ProcessTargets.signal_analysis_action.setEnabled(False)
599
- self.ProcessTargets.delete_tracks_btn.hide()
600
- self.ProcessTargets.signal_analysis_action.setEnabled(False)
524
+ p.check_measurements_btn.setEnabled(False)
525
+ p.check_signals_btn.setEnabled(False)
526
+ p.view_tab_btn.setEnabled(False)
527
+ p.classify_btn.setEnabled(False)
528
+ p.delete_tracks_btn.hide()
529
+ p.signal_analysis_action.setEnabled(False)
601
530
 
602
531
  if os.path.exists(os.sep.join([self.pos,'output','tables','trajectories_pairs.csv'])):
603
532
  self.NeighPanel.view_tab_btn.setEnabled(True)
604
533
  self.NeighPanel.check_signals_btn.setEnabled(True)
605
534
  else:
606
535
  self.NeighPanel.view_tab_btn.setEnabled(False)
607
- self.NeighPanel.check_signals_btn.setEnabled(False)
608
-
609
-
536
+ self.NeighPanel.check_signals_btn.setEnabled(False)
@@ -1,5 +1,5 @@
1
1
  from PyQt5.QtWidgets import QMessageBox,QGridLayout, QButtonGroup, \
2
- QCheckBox, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton, \
2
+ QCheckBox, QLineEdit, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, \
3
3
  QRadioButton
4
4
  from PyQt5.QtCore import Qt, QSize
5
5
  from PyQt5.QtGui import QDoubleValidator
@@ -18,13 +18,13 @@ import matplotlib.pyplot as plt
18
18
  plt.rcParams['svg.fonttype'] = 'none'
19
19
  from glob import glob
20
20
  from matplotlib.cm import tab10
21
- from celldetective.gui import Styles
21
+ from celldetective.gui import CelldetectiveWidget
22
22
  import matplotlib.cm as mcm
23
23
  import pandas as pd
24
24
 
25
25
  from lifelines.utils import qth_survival_times
26
26
 
27
- class GenericSignalPlotWidget(QWidget, Styles):
27
+ class GenericSignalPlotWidget(CelldetectiveWidget):
28
28
 
29
29
  def __init__(self, df = None, df_pos_info = None, df_well_info = None, feature_selected = None, parent_window=None, title='plot', *args, **kwargs):
30
30
 
@@ -33,7 +33,6 @@ class GenericSignalPlotWidget(QWidget, Styles):
33
33
 
34
34
  self.parent_window = parent_window
35
35
  self.setWindowTitle(title)
36
- self.setWindowIcon(self.celldetective_icon)
37
36
 
38
37
  self.show_ci = False
39
38
  self.legend_visible = True
@@ -60,8 +59,6 @@ class GenericSignalPlotWidget(QWidget, Styles):
60
59
 
61
60
  self.fig.tight_layout()
62
61
  self.setLayout(self.layout)
63
- self.setAttribute(Qt.WA_DeleteOnClose)
64
-
65
62
 
66
63
  def populate_widget(self):
67
64
 
@@ -170,7 +167,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
170
167
  self.ci_btn.clicked.connect(self.switch_ci)
171
168
  self.cell_lines_btn.clicked.connect(self.switch_cell_lines)
172
169
 
173
- self.class_selection_widget = QWidget()
170
+ self.class_selection_widget = CelldetectiveWidget()
174
171
 
175
172
  self.class_selection_lbl = QLabel('class of interest:')
176
173
  class_hbox = QHBoxLayout()
@@ -197,7 +194,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
197
194
  self.layout.addWidget(self.class_selection_widget) #Layout(class_hbox)
198
195
 
199
196
  # Rescale
200
- self.rescale_widget = QWidget()
197
+ self.rescale_widget = CelldetectiveWidget()
201
198
 
202
199
  scale_hbox = QHBoxLayout()
203
200
  self.rescale_widget.setLayout(scale_hbox)
@@ -216,7 +213,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
216
213
 
217
214
 
218
215
  # Rescale
219
- self.cell_lines_alpha_wdg = QWidget()
216
+ self.cell_lines_alpha_wdg = CelldetectiveWidget()
220
217
  alpha_hbox = QHBoxLayout()
221
218
 
222
219
  self.alpha_slider = QLabeledDoubleSlider()
@@ -225,7 +222,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
225
222
  slider_initial_value=self.alpha_setting,
226
223
  slider_range=(0,1),
227
224
  decimal_option=True,
228
- precision=1.0E-05,
225
+ precision=5,
229
226
  )
230
227
  self.alpha_slider.valueChanged.connect(self.submit_alpha)
231
228
  self.cell_lines_alpha_wdg.setLayout(alpha_hbox)
@@ -343,7 +340,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
343
340
  thresh = 20
344
341
  self.well_name_truncated = [w[:thresh - 3]+'...' if len(w)>thresh else w for w in self.usable_well_labels]
345
342
 
346
- self.line_choice_widget = QWidget()
343
+ self.line_choice_widget = CelldetectiveWidget()
347
344
  self.line_check_vbox = QGridLayout()
348
345
  self.line_choice_widget.setLayout(self.line_check_vbox)
349
346
 
@@ -828,7 +825,7 @@ class SurvivalPlotWidget(GenericSignalPlotWidget):
828
825
 
829
826
  def set_table_options(self):
830
827
 
831
- self.config_table_wg = QWidget()
828
+ self.config_table_wg = CelldetectiveWidget()
832
829
  self.config_table_wg.setMinimumWidth(480)
833
830
  self.config_table_wg.setWindowTitle('Survival data')
834
831