celldetective 1.3.9.post5__py3-none-any.whl → 1.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- celldetective/__init__.py +0 -3
- celldetective/_version.py +1 -1
- celldetective/events.py +2 -4
- celldetective/exceptions.py +11 -0
- celldetective/extra_properties.py +132 -0
- celldetective/filters.py +7 -1
- celldetective/gui/InitWindow.py +37 -46
- celldetective/gui/__init__.py +3 -9
- celldetective/gui/about.py +19 -15
- celldetective/gui/analyze_block.py +34 -19
- celldetective/gui/base_annotator.py +786 -0
- celldetective/gui/base_components.py +23 -0
- celldetective/gui/classifier_widget.py +86 -94
- celldetective/gui/configure_new_exp.py +163 -46
- celldetective/gui/control_panel.py +76 -146
- celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
- celldetective/gui/generic_signal_plot.py +11 -13
- celldetective/gui/gui_utils.py +54 -23
- celldetective/gui/help/neighborhood.json +2 -2
- celldetective/gui/json_readers.py +5 -4
- celldetective/gui/layouts.py +265 -31
- celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
- celldetective/gui/plot_measurements.py +21 -17
- celldetective/gui/plot_signals_ui.py +125 -72
- celldetective/gui/process_block.py +283 -188
- celldetective/gui/processes/compute_neighborhood.py +594 -0
- celldetective/gui/processes/downloader.py +37 -34
- celldetective/gui/processes/measure_cells.py +19 -8
- celldetective/gui/processes/segment_cells.py +47 -11
- celldetective/gui/processes/track_cells.py +18 -13
- celldetective/gui/seg_model_loader.py +21 -62
- celldetective/gui/settings/__init__.py +7 -0
- celldetective/gui/settings/_settings_base.py +70 -0
- celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
- celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
- celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
- celldetective/gui/settings/_settings_segmentation.py +49 -0
- celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
- celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
- celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
- celldetective/gui/styles.py +2 -1
- celldetective/gui/survival_ui.py +49 -95
- celldetective/gui/tableUI.py +53 -25
- celldetective/gui/table_ops/__init__.py +0 -0
- celldetective/gui/table_ops/merge_groups.py +118 -0
- celldetective/gui/thresholds_gui.py +617 -1221
- celldetective/gui/viewers.py +107 -42
- celldetective/gui/workers.py +8 -4
- celldetective/io.py +137 -57
- celldetective/links/zenodo.json +145 -144
- celldetective/measure.py +94 -53
- celldetective/neighborhood.py +342 -268
- celldetective/preprocessing.py +56 -35
- celldetective/regionprops/_regionprops.py +16 -5
- celldetective/relative_measurements.py +50 -29
- celldetective/scripts/analyze_signals.py +4 -1
- celldetective/scripts/measure_cells.py +5 -5
- celldetective/scripts/measure_relative.py +20 -12
- celldetective/scripts/segment_cells.py +4 -10
- celldetective/scripts/segment_cells_thresholds.py +3 -3
- celldetective/scripts/track_cells.py +10 -8
- celldetective/scripts/train_segmentation_model.py +18 -6
- celldetective/signals.py +29 -14
- celldetective/tracking.py +14 -3
- celldetective/utils.py +91 -62
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
- celldetective-1.4.1.dist-info/RECORD +123 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
- tests/gui/__init__.py +0 -0
- tests/gui/test_new_project.py +228 -0
- tests/gui/test_project.py +99 -0
- tests/test_preprocessing.py +2 -2
- celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
- celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
- celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
- celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
- celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
- celldetective/models/signal_detection/NucCond/config_input.json +0 -1
- celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
- celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
- celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
- celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
- celldetective/models/signal_detection/NucCond/scores.npy +0 -0
- celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
- celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
- celldetective-1.3.9.post5.dist-info/RECORD +0 -129
- tests/test_qt.py +0 -103
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
- {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import
|
|
1
|
+
from PyQt5.QtWidgets import QApplication,QWidget, 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
|
|
15
|
+
from celldetective.gui import CelldetectiveMainWindow, CelldetectiveWidget
|
|
17
16
|
|
|
18
|
-
|
|
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 =
|
|
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,
|
|
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(
|
|
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(
|
|
144
|
+
self.SliderPos.setMaximum(512)
|
|
143
145
|
|
|
144
146
|
self.ms_grid.addWidget(self.SliderPos, 4, 0, 1, 3)
|
|
145
147
|
|
|
@@ -167,8 +169,8 @@ class ConfigNewExperiment(QMainWindow, Styles):
|
|
|
167
169
|
self.movie_length.setToolTip('Optional: depending on how the movies are encoded, the automatic extraction of the number of frames can be difficult.\nThe software will then rely on this value.')
|
|
168
170
|
self.ms_grid.addWidget(self.movie_length,9, 0, 1, 3)
|
|
169
171
|
self.MovieLengthSlider = QLabeledSlider(Qt.Horizontal, self)
|
|
170
|
-
self.MovieLengthSlider.setMinimum(
|
|
171
|
-
self.MovieLengthSlider.setMaximum(128)
|
|
172
|
+
self.MovieLengthSlider.setMinimum(1)
|
|
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("
|
|
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("
|
|
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 =
|
|
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,36 +560,75 @@ 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(
|
|
563
|
+
class SetupConditionLabels(CelldetectiveWidget):
|
|
468
564
|
def __init__(self, parent_window, n_wells):
|
|
469
565
|
super().__init__()
|
|
470
566
|
self.parent_window = parent_window
|
|
471
567
|
self.n_wells = n_wells
|
|
472
568
|
self.setWindowTitle("Well conditions")
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
self.
|
|
569
|
+
|
|
570
|
+
# --- Outer layout ---
|
|
571
|
+
self.outer_layout = QVBoxLayout(self)
|
|
572
|
+
self.outer_layout.setContentsMargins(10, 10, 10, 10)
|
|
573
|
+
|
|
574
|
+
# --- Scroll area ---
|
|
575
|
+
self.scroll = QScrollArea(self)
|
|
576
|
+
self.scroll.setWidgetResizable(True)
|
|
577
|
+
self.outer_layout.addWidget(self.scroll, stretch=1) # takes most space
|
|
578
|
+
|
|
579
|
+
# Container inside scroll
|
|
580
|
+
self.container = QWidget()
|
|
581
|
+
self.scroll.setWidget(self.container)
|
|
582
|
+
|
|
583
|
+
# Content layout (scrollable part)
|
|
584
|
+
self.layout = QVBoxLayout(self.container)
|
|
585
|
+
self.layout.setContentsMargins(30, 30, 30, 30)
|
|
586
|
+
|
|
476
587
|
self.onlyFloat = QDoubleValidator()
|
|
477
588
|
self.populate()
|
|
589
|
+
|
|
590
|
+
self.concentration_units_le = QLineEdit('pM')
|
|
591
|
+
self.concentration_units_le.setPlaceholderText('concentration units')
|
|
592
|
+
|
|
593
|
+
concentration_units_layout = QHBoxLayout()
|
|
594
|
+
concentration_units_layout.addWidget(QLabel('concentration\nunits: '), 5, alignment=Qt.AlignLeft)
|
|
595
|
+
concentration_units_layout.addWidget(self.concentration_units_le, 10)
|
|
596
|
+
concentration_units_layout.addWidget(QLabel(''), 85)
|
|
597
|
+
self.outer_layout.addLayout(concentration_units_layout)
|
|
598
|
+
|
|
599
|
+
# --- Fixed button row (not scrollable) ---
|
|
600
|
+
btn_hbox = QHBoxLayout()
|
|
601
|
+
btn_hbox.setContentsMargins(0, 15, 0, 0)
|
|
602
|
+
|
|
603
|
+
self.skip_btn = QPushButton('Skip')
|
|
604
|
+
self.skip_btn.setStyleSheet(self.button_style_sheet_2)
|
|
605
|
+
self.skip_btn.clicked.connect(self.set_default_values)
|
|
606
|
+
btn_hbox.addWidget(self.skip_btn)
|
|
607
|
+
|
|
608
|
+
self.submit_btn = QPushButton('Submit')
|
|
609
|
+
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
610
|
+
self.submit_btn.clicked.connect(self.set_user_values)
|
|
611
|
+
btn_hbox.addWidget(self.submit_btn)
|
|
612
|
+
|
|
613
|
+
self.outer_layout.addLayout(btn_hbox) # outside scroll
|
|
614
|
+
self.setMinimumWidth(int(0.6 * self.parent_window.parent_window.screen_width))
|
|
615
|
+
|
|
478
616
|
center_window(self)
|
|
479
617
|
|
|
480
618
|
def populate(self):
|
|
481
|
-
|
|
482
619
|
self.cell_type_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
483
620
|
self.antibodies_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
484
621
|
self.concentrations_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
485
622
|
self.pharmaceutical_agents_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
486
|
-
self.concentration_units_le = QLineEdit('pM')
|
|
487
|
-
self.concentration_units_le.setPlaceholderText('concentration units')
|
|
488
623
|
|
|
489
624
|
for i in range(self.n_wells):
|
|
490
625
|
hbox = QHBoxLayout()
|
|
491
|
-
hbox.setContentsMargins(15,5,15,5)
|
|
626
|
+
hbox.setContentsMargins(15, 5, 15, 5)
|
|
492
627
|
hbox.addWidget(QLabel(f'well {i+1}'), 5, alignment=Qt.AlignLeft)
|
|
493
628
|
hbox.addWidget(QLabel('cell type: '), 5)
|
|
494
629
|
hbox.addWidget(self.cell_type_cbs[i], 10)
|
|
495
630
|
self.cell_type_cbs[i].setPlaceholderText('e.g. T-cell, NK')
|
|
496
|
-
|
|
631
|
+
|
|
497
632
|
hbox.addWidget(QLabel('antibody: '), 5)
|
|
498
633
|
hbox.addWidget(self.antibodies_cbs[i], 10)
|
|
499
634
|
self.antibodies_cbs[i].setPlaceholderText('e.g. anti-CD4')
|
|
@@ -506,27 +641,9 @@ class SetupConditionLabels(QWidget, Styles):
|
|
|
506
641
|
hbox.addWidget(QLabel('pharmaceutical agents: '), 5)
|
|
507
642
|
hbox.addWidget(self.pharmaceutical_agents_cbs[i], 10)
|
|
508
643
|
self.pharmaceutical_agents_cbs[i].setPlaceholderText('e.g. dextran')
|
|
509
|
-
|
|
644
|
+
|
|
510
645
|
self.layout.addLayout(hbox)
|
|
511
|
-
|
|
512
|
-
concentration_units_layout = QHBoxLayout()
|
|
513
|
-
concentration_units_layout.addWidget(QLabel('concentration\nunits: '),5,alignment=Qt.AlignLeft)
|
|
514
|
-
concentration_units_layout.addWidget(self.concentration_units_le,10)
|
|
515
|
-
concentration_units_layout.addWidget(QLabel(''), 85)
|
|
516
|
-
self.layout.addLayout(concentration_units_layout)
|
|
517
|
-
|
|
518
|
-
btn_hbox = QHBoxLayout()
|
|
519
|
-
btn_hbox.setContentsMargins(0,20,0,0)
|
|
520
|
-
self.skip_btn = QPushButton('Skip')
|
|
521
|
-
self.skip_btn.setStyleSheet(self.button_style_sheet_2)
|
|
522
|
-
self.skip_btn.clicked.connect(self.set_default_values)
|
|
523
|
-
btn_hbox.addWidget(self.skip_btn)
|
|
524
|
-
|
|
525
|
-
self.submit_btn = QPushButton('Submit')
|
|
526
|
-
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
527
|
-
self.submit_btn.clicked.connect(self.set_user_values)
|
|
528
|
-
btn_hbox.addWidget(self.submit_btn)
|
|
529
|
-
self.layout.addLayout(btn_hbox)
|
|
646
|
+
|
|
530
647
|
|
|
531
648
|
def set_default_values(self):
|
|
532
649
|
|