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.
Files changed (94) hide show
  1. celldetective/__init__.py +0 -3
  2. celldetective/_version.py +1 -1
  3. celldetective/events.py +2 -4
  4. celldetective/exceptions.py +11 -0
  5. celldetective/extra_properties.py +132 -0
  6. celldetective/filters.py +7 -1
  7. celldetective/gui/InitWindow.py +37 -46
  8. celldetective/gui/__init__.py +3 -9
  9. celldetective/gui/about.py +19 -15
  10. celldetective/gui/analyze_block.py +34 -19
  11. celldetective/gui/base_annotator.py +786 -0
  12. celldetective/gui/base_components.py +23 -0
  13. celldetective/gui/classifier_widget.py +86 -94
  14. celldetective/gui/configure_new_exp.py +163 -46
  15. celldetective/gui/control_panel.py +76 -146
  16. celldetective/gui/{signal_annotator.py → event_annotator.py} +533 -1438
  17. celldetective/gui/generic_signal_plot.py +11 -13
  18. celldetective/gui/gui_utils.py +54 -23
  19. celldetective/gui/help/neighborhood.json +2 -2
  20. celldetective/gui/json_readers.py +5 -4
  21. celldetective/gui/layouts.py +265 -31
  22. celldetective/gui/{signal_annotator2.py → pair_event_annotator.py} +433 -635
  23. celldetective/gui/plot_measurements.py +21 -17
  24. celldetective/gui/plot_signals_ui.py +125 -72
  25. celldetective/gui/process_block.py +283 -188
  26. celldetective/gui/processes/compute_neighborhood.py +594 -0
  27. celldetective/gui/processes/downloader.py +37 -34
  28. celldetective/gui/processes/measure_cells.py +19 -8
  29. celldetective/gui/processes/segment_cells.py +47 -11
  30. celldetective/gui/processes/track_cells.py +18 -13
  31. celldetective/gui/seg_model_loader.py +21 -62
  32. celldetective/gui/settings/__init__.py +7 -0
  33. celldetective/gui/settings/_settings_base.py +70 -0
  34. celldetective/gui/{retrain_signal_model_options.py → settings/_settings_event_model_training.py} +54 -109
  35. celldetective/gui/{measurement_options.py → settings/_settings_measurements.py} +54 -92
  36. celldetective/gui/{neighborhood_options.py → settings/_settings_neighborhood.py} +10 -13
  37. celldetective/gui/settings/_settings_segmentation.py +49 -0
  38. celldetective/gui/{retrain_segmentation_model_options.py → settings/_settings_segmentation_model_training.py} +38 -92
  39. celldetective/gui/{signal_annotator_options.py → settings/_settings_signal_annotator.py} +78 -103
  40. celldetective/gui/{btrack_options.py → settings/_settings_tracking.py} +85 -116
  41. celldetective/gui/styles.py +2 -1
  42. celldetective/gui/survival_ui.py +49 -95
  43. celldetective/gui/tableUI.py +53 -25
  44. celldetective/gui/table_ops/__init__.py +0 -0
  45. celldetective/gui/table_ops/merge_groups.py +118 -0
  46. celldetective/gui/thresholds_gui.py +617 -1221
  47. celldetective/gui/viewers.py +107 -42
  48. celldetective/gui/workers.py +8 -4
  49. celldetective/io.py +137 -57
  50. celldetective/links/zenodo.json +145 -144
  51. celldetective/measure.py +94 -53
  52. celldetective/neighborhood.py +342 -268
  53. celldetective/preprocessing.py +56 -35
  54. celldetective/regionprops/_regionprops.py +16 -5
  55. celldetective/relative_measurements.py +50 -29
  56. celldetective/scripts/analyze_signals.py +4 -1
  57. celldetective/scripts/measure_cells.py +5 -5
  58. celldetective/scripts/measure_relative.py +20 -12
  59. celldetective/scripts/segment_cells.py +4 -10
  60. celldetective/scripts/segment_cells_thresholds.py +3 -3
  61. celldetective/scripts/track_cells.py +10 -8
  62. celldetective/scripts/train_segmentation_model.py +18 -6
  63. celldetective/signals.py +29 -14
  64. celldetective/tracking.py +14 -3
  65. celldetective/utils.py +91 -62
  66. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/METADATA +24 -16
  67. celldetective-1.4.1.dist-info/RECORD +123 -0
  68. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/WHEEL +1 -1
  69. tests/gui/__init__.py +0 -0
  70. tests/gui/test_new_project.py +228 -0
  71. tests/gui/test_project.py +99 -0
  72. tests/test_preprocessing.py +2 -2
  73. celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -79
  74. celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
  75. celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -37
  76. celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -39
  77. celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
  78. celldetective/models/signal_detection/NucCond/classification_loss.png +0 -0
  79. celldetective/models/signal_detection/NucCond/classifier.h5 +0 -0
  80. celldetective/models/signal_detection/NucCond/config_input.json +0 -1
  81. celldetective/models/signal_detection/NucCond/log_classifier.csv +0 -126
  82. celldetective/models/signal_detection/NucCond/log_regressor.csv +0 -282
  83. celldetective/models/signal_detection/NucCond/regression_loss.png +0 -0
  84. celldetective/models/signal_detection/NucCond/regressor.h5 +0 -0
  85. celldetective/models/signal_detection/NucCond/scores.npy +0 -0
  86. celldetective/models/signal_detection/NucCond/test_confusion_matrix.png +0 -0
  87. celldetective/models/signal_detection/NucCond/test_regression.png +0 -0
  88. celldetective/models/signal_detection/NucCond/validation_confusion_matrix.png +0 -0
  89. celldetective/models/signal_detection/NucCond/validation_regression.png +0 -0
  90. celldetective-1.3.9.post5.dist-info/RECORD +0 -129
  91. tests/test_qt.py +0 -103
  92. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info}/entry_points.txt +0 -0
  93. {celldetective-1.3.9.post5.dist-info → celldetective-1.4.1.dist-info/licenses}/LICENSE +0 -0
  94. {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 QMainWindow, QApplication, QMessageBox, QHBoxLayout, QFileDialog, QVBoxLayout, QScrollArea, QCheckBox, QGridLayout, QLabel, QLineEdit, QPushButton, QWidget
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 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
 
@@ -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(2)
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("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,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(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
471
567
  self.n_wells = n_wells
472
568
  self.setWindowTitle("Well conditions")
473
- self.layout = QVBoxLayout()
474
- self.layout.setContentsMargins(30,30,30,30)
475
- self.setLayout(self.layout)
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