celldetective 1.2.1__py3-none-any.whl → 1.2.2__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/__main__.py +12 -5
- celldetective/events.py +28 -2
- celldetective/gui/about.py +0 -1
- celldetective/gui/analyze_block.py +3 -18
- celldetective/gui/btrack_options.py +126 -21
- celldetective/gui/classifier_widget.py +67 -111
- celldetective/gui/configure_new_exp.py +37 -4
- celldetective/gui/control_panel.py +14 -30
- celldetective/gui/generic_signal_plot.py +793 -0
- celldetective/gui/gui_utils.py +401 -226
- celldetective/gui/json_readers.py +0 -2
- celldetective/gui/layouts.py +269 -25
- celldetective/gui/measurement_options.py +14 -23
- celldetective/gui/neighborhood_options.py +3 -15
- celldetective/gui/plot_measurements.py +10 -23
- celldetective/gui/plot_signals_ui.py +53 -687
- celldetective/gui/process_block.py +320 -186
- celldetective/gui/retrain_segmentation_model_options.py +30 -47
- celldetective/gui/retrain_signal_model_options.py +5 -14
- celldetective/gui/seg_model_loader.py +129 -113
- celldetective/gui/signal_annotator.py +89 -99
- celldetective/gui/signal_annotator2.py +5 -9
- celldetective/gui/styles.py +32 -0
- celldetective/gui/survival_ui.py +49 -712
- celldetective/gui/tableUI.py +0 -1
- celldetective/gui/thresholds_gui.py +38 -11
- celldetective/gui/viewers.py +6 -7
- celldetective/io.py +60 -82
- celldetective/measure.py +374 -15
- celldetective/neighborhood.py +1 -7
- celldetective/preprocessing.py +2 -4
- celldetective/relative_measurements.py +0 -3
- celldetective/scripts/analyze_signals.py +0 -1
- celldetective/scripts/measure_cells.py +1 -3
- celldetective/scripts/measure_relative.py +1 -2
- celldetective/scripts/segment_cells.py +16 -12
- celldetective/scripts/segment_cells_thresholds.py +17 -10
- celldetective/scripts/track_cells.py +18 -18
- celldetective/scripts/train_segmentation_model.py +1 -2
- celldetective/scripts/train_signal_model.py +0 -3
- celldetective/segmentation.py +1 -1
- celldetective/signals.py +17 -8
- celldetective/tracking.py +2 -1
- celldetective/utils.py +42 -2
- {celldetective-1.2.1.dist-info → celldetective-1.2.2.dist-info}/METADATA +19 -12
- celldetective-1.2.2.dist-info/RECORD +92 -0
- {celldetective-1.2.1.dist-info → celldetective-1.2.2.dist-info}/WHEEL +1 -1
- celldetective-1.2.1.dist-info/RECORD +0 -91
- {celldetective-1.2.1.dist-info → celldetective-1.2.2.dist-info}/LICENSE +0 -0
- {celldetective-1.2.1.dist-info → celldetective-1.2.2.dist-info}/entry_points.txt +0 -0
- {celldetective-1.2.1.dist-info → celldetective-1.2.2.dist-info}/top_level.txt +0 -0
|
@@ -1,46 +1,41 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QFrame, QGridLayout,
|
|
2
|
-
QMessageBox, QWidget
|
|
1
|
+
from PyQt5.QtWidgets import QFrame, QGridLayout, QComboBox, QListWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QCheckBox, \
|
|
2
|
+
QMessageBox, QWidget
|
|
3
3
|
from PyQt5.QtCore import Qt, QSize
|
|
4
4
|
from superqt.fonticon import icon
|
|
5
5
|
from fonticon_mdi6 import MDI6
|
|
6
6
|
import gc
|
|
7
|
-
from PyQt5.QtGui import
|
|
7
|
+
from PyQt5.QtGui import QDoubleValidator, QIntValidator
|
|
8
8
|
|
|
9
9
|
from celldetective.gui.signal_annotator import MeasureAnnotator
|
|
10
10
|
from celldetective.gui.signal_annotator2 import SignalAnnotator2
|
|
11
11
|
from celldetective.io import get_segmentation_models_list, control_segmentation_napari, get_signal_models_list, \
|
|
12
|
-
control_tracking_btrack, load_experiment_tables, get_pair_signal_models_list
|
|
13
|
-
from celldetective.io import locate_segmentation_model, auto_load_number_of_frames, load_frames, locate_signal_model
|
|
12
|
+
control_tracking_btrack, load_experiment_tables, get_pair_signal_models_list
|
|
13
|
+
from celldetective.io import locate_segmentation_model, fix_missing_labels, auto_load_number_of_frames, load_frames, locate_signal_model
|
|
14
14
|
from celldetective.gui import SegmentationModelLoader, ClassifierWidget, ConfigNeighborhoods, ConfigSegmentationModelTraining, ConfigTracking, SignalAnnotator, ConfigSignalModelTraining, ConfigMeasurements, ConfigSignalAnnotator, TableUI
|
|
15
15
|
from celldetective.gui.gui_utils import QHSeperationLine
|
|
16
16
|
from celldetective.relative_measurements import rel_measure_at_position
|
|
17
17
|
from celldetective.segmentation import segment_at_position, segment_from_threshold_at_position
|
|
18
18
|
from celldetective.tracking import track_at_position
|
|
19
19
|
from celldetective.measure import measure_at_position
|
|
20
|
-
from celldetective.signals import analyze_signals_at_position,
|
|
20
|
+
from celldetective.signals import analyze_signals_at_position, analyze_pair_signals_at_position
|
|
21
21
|
from celldetective.utils import extract_experiment_channels
|
|
22
22
|
import numpy as np
|
|
23
23
|
from glob import glob
|
|
24
24
|
from natsort import natsorted
|
|
25
|
-
from superqt import QLabeledDoubleSlider, QLabeledSlider, QLabeledRangeSlider, QLabeledSlider, QLabeledDoubleRangeSlider
|
|
26
25
|
import os
|
|
27
26
|
import pandas as pd
|
|
28
|
-
from tqdm import tqdm
|
|
29
27
|
from celldetective.gui.gui_utils import center_window
|
|
30
28
|
from tifffile import imwrite
|
|
31
29
|
import json
|
|
32
30
|
import psutil
|
|
33
31
|
from celldetective.neighborhood import compute_neighborhood_at_position, compute_contact_neighborhood_at_position
|
|
34
32
|
from celldetective.gui.gui_utils import FigureCanvas
|
|
35
|
-
|
|
36
|
-
from celldetective.filters import std_filter, median_filter, gauss_filter
|
|
37
|
-
from stardist import fill_label_holes
|
|
38
|
-
from celldetective.preprocessing import correct_background_model_free, estimate_background_per_condition, correct_background_model
|
|
33
|
+
from celldetective.preprocessing import correct_background_model_free, correct_background_model
|
|
39
34
|
from celldetective.utils import _estimate_scale_factor, _extract_channel_indices_from_config, _extract_channel_indices, ConfigSectionMap, _extract_nbr_channels_from_config, _get_img_num_per_channel, normalize_per_channel
|
|
40
|
-
from celldetective.gui.gui_utils import ThresholdLineEdit, QuickSliderLayout
|
|
41
|
-
from celldetective.gui.
|
|
42
|
-
from celldetective.gui.layouts import BackgroundModelFreeCorrectionLayout, ProtocolDesignerLayout, BackgroundFitCorrectionLayout, OperationLayout
|
|
35
|
+
from celldetective.gui.gui_utils import ThresholdLineEdit, QuickSliderLayout, help_generic
|
|
36
|
+
from celldetective.gui.layouts import CellposeParamsWidget, StarDistParamsWidget, BackgroundModelFreeCorrectionLayout, ProtocolDesignerLayout, BackgroundFitCorrectionLayout
|
|
43
37
|
from celldetective.gui import Styles
|
|
38
|
+
from celldetective.utils import get_software_location
|
|
44
39
|
|
|
45
40
|
class ProcessPanel(QFrame, Styles):
|
|
46
41
|
def __init__(self, parent_window, mode):
|
|
@@ -70,29 +65,45 @@ class ProcessPanel(QFrame, Styles):
|
|
|
70
65
|
|
|
71
66
|
"""
|
|
72
67
|
|
|
73
|
-
panel_title = QLabel(f"PROCESS {self.mode.upper()}")
|
|
68
|
+
panel_title = QLabel(f"PROCESS {self.mode.upper()} ")
|
|
74
69
|
panel_title.setStyleSheet("""
|
|
75
70
|
font-weight: bold;
|
|
76
71
|
padding: 0px;
|
|
77
72
|
""")
|
|
78
73
|
|
|
74
|
+
title_hbox = QHBoxLayout()
|
|
79
75
|
self.grid.addWidget(panel_title, 0, 0, 1, 4, alignment=Qt.AlignCenter)
|
|
80
76
|
|
|
77
|
+
self.help_pop_btn = QPushButton()
|
|
78
|
+
self.help_pop_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
|
|
79
|
+
self.help_pop_btn.setIconSize(QSize(20, 20))
|
|
80
|
+
self.help_pop_btn.clicked.connect(self.help_population)
|
|
81
|
+
self.help_pop_btn.setStyleSheet(self.button_select_all)
|
|
82
|
+
self.help_pop_btn.setToolTip("Help.")
|
|
83
|
+
#self.grid.addWidget(self.help_pop_btn, 0, 0, 1, 3, alignment=Qt.AlignRight)
|
|
84
|
+
|
|
85
|
+
|
|
81
86
|
self.select_all_btn = QPushButton()
|
|
82
87
|
self.select_all_btn.setIcon(icon(MDI6.checkbox_blank_outline,color="black"))
|
|
83
88
|
self.select_all_btn.setIconSize(QSize(20, 20))
|
|
84
89
|
self.all_ticked = False
|
|
85
90
|
self.select_all_btn.clicked.connect(self.tick_all_actions)
|
|
86
91
|
self.select_all_btn.setStyleSheet(self.button_select_all)
|
|
87
|
-
self.grid.addWidget(self.select_all_btn, 0, 0, 1, 4, alignment=Qt.AlignLeft)
|
|
92
|
+
#self.grid.addWidget(self.select_all_btn, 0, 0, 1, 4, alignment=Qt.AlignLeft)
|
|
88
93
|
#self.to_disable.append(self.all_tc_actions)
|
|
89
94
|
|
|
90
95
|
self.collapse_btn = QPushButton()
|
|
91
96
|
self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
92
97
|
self.collapse_btn.setIconSize(QSize(25, 25))
|
|
93
98
|
self.collapse_btn.setStyleSheet(self.button_select_all)
|
|
94
|
-
self.grid.addWidget(self.collapse_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
|
|
99
|
+
#self.grid.addWidget(self.collapse_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
|
|
100
|
+
|
|
101
|
+
title_hbox.addWidget(self.select_all_btn, 5)
|
|
102
|
+
title_hbox.addWidget(QLabel(), 85, alignment=Qt.AlignCenter)
|
|
103
|
+
title_hbox.addWidget(self.help_pop_btn, 5)
|
|
104
|
+
title_hbox.addWidget(self.collapse_btn, 5)
|
|
95
105
|
|
|
106
|
+
self.grid.addLayout(title_hbox, 0,0,1,4)
|
|
96
107
|
self.populate_contents()
|
|
97
108
|
|
|
98
109
|
self.grid.addWidget(self.ContentsFrame, 1, 0, 1, 4, alignment=Qt.AlignTop)
|
|
@@ -101,22 +112,48 @@ class ProcessPanel(QFrame, Styles):
|
|
|
101
112
|
self.ContentsFrame.hide()
|
|
102
113
|
|
|
103
114
|
def collapse_advanced(self):
|
|
115
|
+
|
|
116
|
+
effector_open = not self.parent_window.ProcessEffectors.ContentsFrame.isHidden()
|
|
117
|
+
targets_open = not self.parent_window.ProcessTargets.ContentsFrame.isHidden()
|
|
118
|
+
interactions_open = not self.parent_window.NeighPanel.ContentsFrame.isHidden()
|
|
119
|
+
preprocessing_open = not self.parent_window.PreprocessingPanel.ContentsFrame.isHidden()
|
|
120
|
+
is_open = np.array([effector_open, targets_open, interactions_open, preprocessing_open])
|
|
121
|
+
|
|
104
122
|
if self.ContentsFrame.isHidden():
|
|
105
123
|
self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
106
124
|
self.collapse_btn.setIconSize(QSize(20, 20))
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
#self.parent.scroll.adjustSize()
|
|
125
|
+
if len(is_open[is_open])==0:
|
|
126
|
+
self.parent_window.scroll.setMinimumHeight(int(550))
|
|
127
|
+
self.parent_window.adjustSize()
|
|
111
128
|
else:
|
|
112
129
|
self.collapse_btn.setIcon(icon(MDI6.chevron_up,color="black"))
|
|
113
130
|
self.collapse_btn.setIconSize(QSize(20, 20))
|
|
114
|
-
#self.parent.w.adjustSize()
|
|
115
|
-
#self.parent.adjustSize()
|
|
116
131
|
self.parent_window.scroll.setMinimumHeight(min(int(930), int(0.9*self.parent_window.screen_height)))
|
|
117
|
-
self.parent_window.scroll.setMinimumWidth(425)
|
|
118
132
|
|
|
119
|
-
|
|
133
|
+
|
|
134
|
+
def help_population(self):
|
|
135
|
+
|
|
136
|
+
"""
|
|
137
|
+
Helper to choose a proper cell population structure.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','cell-populations.json'])
|
|
141
|
+
|
|
142
|
+
with open(dict_path) as f:
|
|
143
|
+
d = json.load(f)
|
|
144
|
+
|
|
145
|
+
suggestion = help_generic(d)
|
|
146
|
+
if isinstance(suggestion, str):
|
|
147
|
+
print(f"{suggestion=}")
|
|
148
|
+
msgBox = QMessageBox()
|
|
149
|
+
msgBox.setIcon(QMessageBox.Information)
|
|
150
|
+
msgBox.setTextFormat(Qt.RichText)
|
|
151
|
+
msgBox.setText(suggestion)
|
|
152
|
+
msgBox.setWindowTitle("Info")
|
|
153
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
154
|
+
returnValue = msgBox.exec()
|
|
155
|
+
if returnValue == QMessageBox.Ok:
|
|
156
|
+
return None
|
|
120
157
|
|
|
121
158
|
def populate_contents(self):
|
|
122
159
|
self.ContentsFrame = QFrame()
|
|
@@ -265,7 +302,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
265
302
|
padding-left: 10px;
|
|
266
303
|
padding-top: 5px;
|
|
267
304
|
""")
|
|
268
|
-
grid_track.addWidget(self.track_action,
|
|
305
|
+
grid_track.addWidget(self.track_action, 75)
|
|
269
306
|
#self.to_disable.append(self.track_action_tc)
|
|
270
307
|
|
|
271
308
|
# self.show_track_table_btn = QPushButton()
|
|
@@ -304,6 +341,14 @@ class ProcessPanel(QFrame, Styles):
|
|
|
304
341
|
self.track_config_btn.clicked.connect(self.open_tracking_configuration_ui)
|
|
305
342
|
grid_track.addWidget(self.track_config_btn, 6) #4,2,1,1, alignment=Qt.AlignRight
|
|
306
343
|
|
|
344
|
+
self.help_track_btn = QPushButton()
|
|
345
|
+
self.help_track_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
|
|
346
|
+
self.help_track_btn.setIconSize(QSize(20, 20))
|
|
347
|
+
self.help_track_btn.clicked.connect(self.help_tracking)
|
|
348
|
+
self.help_track_btn.setStyleSheet(self.button_select_all)
|
|
349
|
+
self.help_track_btn.setToolTip("Help.")
|
|
350
|
+
grid_track.addWidget(self.help_track_btn, 6) #4,2,1,1, alignment=Qt.AlignRight
|
|
351
|
+
|
|
307
352
|
self.grid_contents.addLayout(grid_track, 4, 0, 1,4)
|
|
308
353
|
|
|
309
354
|
def delete_tracks(self):
|
|
@@ -352,9 +397,15 @@ class ProcessPanel(QFrame, Styles):
|
|
|
352
397
|
self.check_seg_btn.clicked.connect(self.check_segmentation)
|
|
353
398
|
self.check_seg_btn.setStyleSheet(self.button_select_all)
|
|
354
399
|
self.check_seg_btn.setToolTip("View segmentation output in napari.")
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
400
|
+
grid_segment.addWidget(self.check_seg_btn, 5)
|
|
401
|
+
|
|
402
|
+
self.help_seg_btn = QPushButton()
|
|
403
|
+
self.help_seg_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
|
|
404
|
+
self.help_seg_btn.setIconSize(QSize(20, 20))
|
|
405
|
+
self.help_seg_btn.clicked.connect(self.help_segmentation)
|
|
406
|
+
self.help_seg_btn.setStyleSheet(self.button_select_all)
|
|
407
|
+
self.help_seg_btn.setToolTip("Help.")
|
|
408
|
+
grid_segment.addWidget(self.help_seg_btn, 5)
|
|
358
409
|
self.grid_contents.addLayout(grid_segment, 0,0,1,4)
|
|
359
410
|
|
|
360
411
|
seg_option_vbox = QVBoxLayout()
|
|
@@ -391,6 +442,107 @@ class ProcessPanel(QFrame, Styles):
|
|
|
391
442
|
self.seg_model_list.setEnabled(False)
|
|
392
443
|
self.grid_contents.addLayout(seg_option_vbox, 2, 0, 1, 4)
|
|
393
444
|
|
|
445
|
+
def help_segmentation(self):
|
|
446
|
+
|
|
447
|
+
"""
|
|
448
|
+
Widget with different decision helper decision trees.
|
|
449
|
+
"""
|
|
450
|
+
|
|
451
|
+
self.help_w = QWidget()
|
|
452
|
+
self.help_w.setWindowTitle('Helper')
|
|
453
|
+
layout = QVBoxLayout()
|
|
454
|
+
seg_strategy_btn = QPushButton('A guide to choose a segmentation strategy.')
|
|
455
|
+
seg_strategy_btn.setIcon(icon(MDI6.help_circle,color=self.celldetective_blue))
|
|
456
|
+
seg_strategy_btn.setIconSize(QSize(40, 40))
|
|
457
|
+
seg_strategy_btn.setStyleSheet(self.button_style_sheet_5)
|
|
458
|
+
seg_strategy_btn.clicked.connect(self.help_seg_strategy)
|
|
459
|
+
|
|
460
|
+
dl_strategy_btn = QPushButton('A guide to choose your Deep learning segmentation strategy.')
|
|
461
|
+
dl_strategy_btn.setIcon(icon(MDI6.help_circle,color=self.celldetective_blue))
|
|
462
|
+
dl_strategy_btn.setIconSize(QSize(40, 40))
|
|
463
|
+
dl_strategy_btn.setStyleSheet(self.button_style_sheet_5)
|
|
464
|
+
dl_strategy_btn.clicked.connect(self.help_seg_dl_strategy)
|
|
465
|
+
|
|
466
|
+
layout.addWidget(seg_strategy_btn)
|
|
467
|
+
layout.addWidget(dl_strategy_btn)
|
|
468
|
+
|
|
469
|
+
self.help_w.setLayout(layout)
|
|
470
|
+
center_window(self.help_w)
|
|
471
|
+
self.help_w.show()
|
|
472
|
+
|
|
473
|
+
return None
|
|
474
|
+
|
|
475
|
+
def help_seg_strategy(self):
|
|
476
|
+
|
|
477
|
+
"""
|
|
478
|
+
Helper for segmentation strategy between threshold-based and Deep learning.
|
|
479
|
+
"""
|
|
480
|
+
|
|
481
|
+
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','Threshold-vs-DL.json'])
|
|
482
|
+
|
|
483
|
+
with open(dict_path) as f:
|
|
484
|
+
d = json.load(f)
|
|
485
|
+
|
|
486
|
+
suggestion = help_generic(d)
|
|
487
|
+
if isinstance(suggestion, str):
|
|
488
|
+
print(f"{suggestion=}")
|
|
489
|
+
msgBox = QMessageBox()
|
|
490
|
+
msgBox.setIcon(QMessageBox.Information)
|
|
491
|
+
msgBox.setTextFormat(Qt.RichText)
|
|
492
|
+
msgBox.setText(f"The suggested technique is {suggestion}.\nSee a tutorial <a href='https://celldetective.readthedocs.io/en/latest/segment.html'>here</a>.")
|
|
493
|
+
msgBox.setWindowTitle("Info")
|
|
494
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
495
|
+
returnValue = msgBox.exec()
|
|
496
|
+
if returnValue == QMessageBox.Ok:
|
|
497
|
+
return None
|
|
498
|
+
|
|
499
|
+
def help_seg_dl_strategy(self):
|
|
500
|
+
|
|
501
|
+
"""
|
|
502
|
+
Helper for DL segmentation strategy, between pretrained models and custom models.
|
|
503
|
+
"""
|
|
504
|
+
|
|
505
|
+
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','DL-segmentation-strategy.json'])
|
|
506
|
+
|
|
507
|
+
with open(dict_path) as f:
|
|
508
|
+
d = json.load(f)
|
|
509
|
+
|
|
510
|
+
suggestion = help_generic(d)
|
|
511
|
+
if isinstance(suggestion, str):
|
|
512
|
+
print(f"{suggestion=}")
|
|
513
|
+
msgBox = QMessageBox()
|
|
514
|
+
msgBox.setIcon(QMessageBox.Information)
|
|
515
|
+
msgBox.setText(f"The suggested technique is {suggestion}.")
|
|
516
|
+
msgBox.setWindowTitle("Info")
|
|
517
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
518
|
+
returnValue = msgBox.exec()
|
|
519
|
+
if returnValue == QMessageBox.Ok:
|
|
520
|
+
return None
|
|
521
|
+
|
|
522
|
+
def help_tracking(self):
|
|
523
|
+
|
|
524
|
+
"""
|
|
525
|
+
Helper for segmentation strategy between threshold-based and Deep learning.
|
|
526
|
+
"""
|
|
527
|
+
|
|
528
|
+
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','tracking.json'])
|
|
529
|
+
|
|
530
|
+
with open(dict_path) as f:
|
|
531
|
+
d = json.load(f)
|
|
532
|
+
|
|
533
|
+
suggestion = help_generic(d)
|
|
534
|
+
if isinstance(suggestion, str):
|
|
535
|
+
print(f"{suggestion=}")
|
|
536
|
+
msgBox = QMessageBox()
|
|
537
|
+
msgBox.setIcon(QMessageBox.Information)
|
|
538
|
+
msgBox.setTextFormat(Qt.RichText)
|
|
539
|
+
msgBox.setText(f"{suggestion}")
|
|
540
|
+
msgBox.setWindowTitle("Info")
|
|
541
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
542
|
+
returnValue = msgBox.exec()
|
|
543
|
+
if returnValue == QMessageBox.Ok:
|
|
544
|
+
return None
|
|
545
|
+
|
|
394
546
|
def check_segmentation(self):
|
|
395
547
|
|
|
396
548
|
if not os.path.exists(os.sep.join([self.parent_window.pos,f'labels_{self.mode}', os.sep])):
|
|
@@ -422,6 +574,24 @@ class ProcessPanel(QFrame, Styles):
|
|
|
422
574
|
msgBox.setWindowTitle("Warning")
|
|
423
575
|
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
424
576
|
returnValue = msgBox.exec()
|
|
577
|
+
|
|
578
|
+
msgBox = QMessageBox()
|
|
579
|
+
msgBox.setIcon(QMessageBox.Question)
|
|
580
|
+
msgBox.setText("Would you like to pass empty frames to fix the asymmetry?")
|
|
581
|
+
msgBox.setWindowTitle("Question")
|
|
582
|
+
msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
|
|
583
|
+
returnValue = msgBox.exec()
|
|
584
|
+
if returnValue == QMessageBox.Yes:
|
|
585
|
+
print('Fixing the missing labels...')
|
|
586
|
+
fix_missing_labels(self.parent_window.pos, prefix=self.parent_window.movie_prefix,population=self.mode)
|
|
587
|
+
try:
|
|
588
|
+
control_segmentation_napari(self.parent_window.pos, prefix=self.parent_window.movie_prefix, population=self.mode,flush_memory=True)
|
|
589
|
+
except Exception as e:
|
|
590
|
+
print(f'Error {e}')
|
|
591
|
+
return None
|
|
592
|
+
else:
|
|
593
|
+
return None
|
|
594
|
+
|
|
425
595
|
gc.collect()
|
|
426
596
|
|
|
427
597
|
def check_signals(self):
|
|
@@ -507,27 +677,27 @@ class ProcessPanel(QFrame, Styles):
|
|
|
507
677
|
self.all_ticked = True
|
|
508
678
|
|
|
509
679
|
def upload_segmentation_model(self):
|
|
510
|
-
|
|
680
|
+
print('Load a segmentation model or pipeline...')
|
|
511
681
|
self.SegModelLoader = SegmentationModelLoader(self)
|
|
512
682
|
self.SegModelLoader.show()
|
|
513
683
|
|
|
514
684
|
def open_tracking_configuration_ui(self):
|
|
515
|
-
|
|
685
|
+
print('Set the tracking parameters...')
|
|
516
686
|
self.ConfigTracking = ConfigTracking(self)
|
|
517
687
|
self.ConfigTracking.show()
|
|
518
688
|
|
|
519
689
|
def open_signal_model_config_ui(self):
|
|
520
|
-
|
|
690
|
+
print('Set the training parameters for new signal models...')
|
|
521
691
|
self.ConfigSignalTrain = ConfigSignalModelTraining(self)
|
|
522
692
|
self.ConfigSignalTrain.show()
|
|
523
693
|
|
|
524
694
|
def open_segmentation_model_config_ui(self):
|
|
525
|
-
|
|
695
|
+
print('Set the training parameters for a new segmentation model...')
|
|
526
696
|
self.ConfigSegmentationTrain = ConfigSegmentationModelTraining(self)
|
|
527
697
|
self.ConfigSegmentationTrain.show()
|
|
528
698
|
|
|
529
699
|
def open_measurement_configuration_ui(self):
|
|
530
|
-
|
|
700
|
+
print('Set the measurements to be performed...')
|
|
531
701
|
self.ConfigMeasurements = ConfigMeasurements(self)
|
|
532
702
|
self.ConfigMeasurements.show()
|
|
533
703
|
|
|
@@ -611,120 +781,14 @@ class ProcessPanel(QFrame, Styles):
|
|
|
611
781
|
|
|
612
782
|
if self.model_name.startswith('CP') and self.model_name in self.seg_models_generic and not self.cellpose_calibrated:
|
|
613
783
|
|
|
614
|
-
self.diamWidget =
|
|
615
|
-
self.diamWidget.setWindowTitle('Estimate diameter')
|
|
616
|
-
|
|
617
|
-
layout = QVBoxLayout()
|
|
618
|
-
self.diamWidget.setLayout(layout)
|
|
619
|
-
|
|
620
|
-
self.view_diameter_btn = QPushButton()
|
|
621
|
-
self.view_diameter_btn.setStyleSheet(self.button_select_all)
|
|
622
|
-
self.view_diameter_btn.setIcon(icon(MDI6.image_check, color="black"))
|
|
623
|
-
self.view_diameter_btn.setToolTip("View stack.")
|
|
624
|
-
self.view_diameter_btn.setIconSize(QSize(20, 20))
|
|
625
|
-
self.view_diameter_btn.clicked.connect(self.view_current_stack_with_scale_bar)
|
|
626
|
-
|
|
627
|
-
self.diameter_le = ThresholdLineEdit(init_value=40, connected_buttons=[self.view_diameter_btn],placeholder='cell diameter in pixels', value_type='float')
|
|
628
|
-
|
|
629
|
-
self.cellpose_channel_cb = [QComboBox() for i in range(2)]
|
|
630
|
-
self.cellpose_channel_template = ['brightfield_channel', 'live_nuclei_channel']
|
|
631
|
-
if self.model_name=="CP_nuclei":
|
|
632
|
-
self.cellpose_channel_template = ['live_nuclei_channel', 'None']
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
for k in range(2):
|
|
636
|
-
hbox_channel = QHBoxLayout()
|
|
637
|
-
hbox_channel.addWidget(QLabel(f'channel {k+1}: '))
|
|
638
|
-
hbox_channel.addWidget(self.cellpose_channel_cb[k])
|
|
639
|
-
if k==1:
|
|
640
|
-
self.cellpose_channel_cb[k].addItems(list(self.exp_channels)+['None'])
|
|
641
|
-
else:
|
|
642
|
-
self.cellpose_channel_cb[k].addItems(list(self.exp_channels))
|
|
643
|
-
idx = self.cellpose_channel_cb[k].findText(self.cellpose_channel_template[k])
|
|
644
|
-
if idx>0:
|
|
645
|
-
self.cellpose_channel_cb[k].setCurrentIndex(idx)
|
|
646
|
-
else:
|
|
647
|
-
self.cellpose_channel_cb[k].setCurrentIndex(0)
|
|
648
|
-
|
|
649
|
-
if k==1:
|
|
650
|
-
idx = self.cellpose_channel_cb[k].findText('None')
|
|
651
|
-
self.cellpose_channel_cb[k].setCurrentIndex(idx)
|
|
652
|
-
|
|
653
|
-
layout.addLayout(hbox_channel)
|
|
654
|
-
|
|
655
|
-
hbox = QHBoxLayout()
|
|
656
|
-
hbox.addWidget(QLabel('diameter [px]: '), 33)
|
|
657
|
-
hbox.addWidget(self.diameter_le, 61)
|
|
658
|
-
hbox.addWidget(self.view_diameter_btn)
|
|
659
|
-
layout.addLayout(hbox)
|
|
660
|
-
|
|
661
|
-
self.flow_slider = QLabeledDoubleSlider()
|
|
662
|
-
self.flow_slider.setOrientation(1)
|
|
663
|
-
self.flow_slider.setRange(-6,6)
|
|
664
|
-
self.flow_slider.setValue(0.4)
|
|
665
|
-
|
|
666
|
-
hbox = QHBoxLayout()
|
|
667
|
-
hbox.addWidget(QLabel('flow threshold: '), 33)
|
|
668
|
-
hbox.addWidget(self.flow_slider, 66)
|
|
669
|
-
layout.addLayout(hbox)
|
|
670
|
-
|
|
671
|
-
self.cellprob_slider = QLabeledDoubleSlider()
|
|
672
|
-
self.cellprob_slider.setOrientation(1)
|
|
673
|
-
self.cellprob_slider.setRange(-6,6)
|
|
674
|
-
self.cellprob_slider.setValue(0.)
|
|
675
|
-
|
|
676
|
-
hbox = QHBoxLayout()
|
|
677
|
-
hbox.addWidget(QLabel('cellprob threshold: '), 33)
|
|
678
|
-
hbox.addWidget(self.cellprob_slider, 66)
|
|
679
|
-
layout.addLayout(hbox)
|
|
680
|
-
|
|
681
|
-
self.set_cellpose_scale_btn = QPushButton('set')
|
|
682
|
-
self.set_cellpose_scale_btn.clicked.connect(self.set_cellpose_scale)
|
|
683
|
-
layout.addWidget(self.set_cellpose_scale_btn)
|
|
684
|
-
|
|
784
|
+
self.diamWidget = CellposeParamsWidget(self, model_name=self.model_name)
|
|
685
785
|
self.diamWidget.show()
|
|
686
|
-
center_window(self.diamWidget)
|
|
687
786
|
return None
|
|
688
787
|
|
|
689
|
-
|
|
690
788
|
if self.model_name.startswith('SD') and self.model_name in self.seg_models_generic and not self.stardist_calibrated:
|
|
691
789
|
|
|
692
|
-
self.diamWidget =
|
|
693
|
-
self.diamWidget.setWindowTitle('Channels')
|
|
694
|
-
|
|
695
|
-
layout = QVBoxLayout()
|
|
696
|
-
self.diamWidget.setLayout(layout)
|
|
697
|
-
|
|
698
|
-
self.stardist_channel_cb = [QComboBox() for i in range(1)]
|
|
699
|
-
self.stardist_channel_template = ['live_nuclei_channel']
|
|
700
|
-
max_i = 1
|
|
701
|
-
if self.model_name=="SD_versatile_he":
|
|
702
|
-
self.stardist_channel_template = ["H&E_1","H&E_2","H&E_3"]
|
|
703
|
-
self.stardist_channel_cb = [QComboBox() for i in range(3)]
|
|
704
|
-
max_i = 3
|
|
705
|
-
|
|
706
|
-
for k in range(max_i):
|
|
707
|
-
hbox_channel = QHBoxLayout()
|
|
708
|
-
hbox_channel.addWidget(QLabel(f'channel {k+1}: '))
|
|
709
|
-
hbox_channel.addWidget(self.stardist_channel_cb[k])
|
|
710
|
-
if k==1:
|
|
711
|
-
self.stardist_channel_cb[k].addItems(list(self.exp_channels)+['None'])
|
|
712
|
-
else:
|
|
713
|
-
self.stardist_channel_cb[k].addItems(list(self.exp_channels))
|
|
714
|
-
idx = self.stardist_channel_cb[k].findText(self.stardist_channel_template[k])
|
|
715
|
-
if idx>0:
|
|
716
|
-
self.stardist_channel_cb[k].setCurrentIndex(idx)
|
|
717
|
-
else:
|
|
718
|
-
self.stardist_channel_cb[k].setCurrentIndex(0)
|
|
719
|
-
|
|
720
|
-
layout.addLayout(hbox_channel)
|
|
721
|
-
|
|
722
|
-
self.set_stardist_scale_btn = QPushButton('set')
|
|
723
|
-
self.set_stardist_scale_btn.clicked.connect(self.set_stardist_scale)
|
|
724
|
-
layout.addWidget(self.set_stardist_scale_btn)
|
|
725
|
-
|
|
790
|
+
self.diamWidget = StarDistParamsWidget(self, model_name = self.model_name)
|
|
726
791
|
self.diamWidget.show()
|
|
727
|
-
center_window(self.diamWidget)
|
|
728
792
|
return None
|
|
729
793
|
|
|
730
794
|
|
|
@@ -823,27 +887,28 @@ class ProcessPanel(QFrame, Styles):
|
|
|
823
887
|
# QApplication.restoreOverrideCursor()
|
|
824
888
|
# self.unfreeze()
|
|
825
889
|
|
|
826
|
-
def view_current_stack_with_scale_bar(self):
|
|
890
|
+
# def view_current_stack_with_scale_bar(self):
|
|
827
891
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
892
|
+
# self.parent_window.locate_image()
|
|
893
|
+
# if self.parent_window.current_stack is not None:
|
|
894
|
+
# self.viewer = CellSizeViewer(
|
|
895
|
+
# initial_diameter = float(self.diameter_le.text().replace(',', '.')),
|
|
896
|
+
# parent_le = self.diameter_le,
|
|
897
|
+
# stack_path=self.parent_window.current_stack,
|
|
898
|
+
# window_title=f'Position {self.parent_window.position_list.currentText()}',
|
|
899
|
+
# frame_slider = True,
|
|
900
|
+
# contrast_slider = True,
|
|
901
|
+
# channel_cb = True,
|
|
902
|
+
# channel_names = self.parent_window.exp_channels,
|
|
903
|
+
# n_channels = self.parent_window.nbr_channels,
|
|
904
|
+
# PxToUm = 1,
|
|
905
|
+
# )
|
|
906
|
+
# self.viewer.show()
|
|
843
907
|
|
|
844
908
|
|
|
845
909
|
|
|
846
910
|
def open_napari_tracking(self):
|
|
911
|
+
print(f'View the tracks before post-processing for position {self.parent_window.pos} in napari...')
|
|
847
912
|
control_tracking_btrack(self.parent_window.pos, prefix=self.parent_window.movie_prefix, population=self.mode, threads=self.parent_window.parent_window.n_threads)
|
|
848
913
|
|
|
849
914
|
def view_table_ui(self):
|
|
@@ -910,14 +975,14 @@ class ProcessPanel(QFrame, Styles):
|
|
|
910
975
|
|
|
911
976
|
def set_cellpose_scale(self):
|
|
912
977
|
|
|
913
|
-
scale = self.parent_window.PxToUm * float(self.diameter_le.get_threshold()) / 30.0
|
|
978
|
+
scale = self.parent_window.PxToUm * float(self.diamWidget.diameter_le.get_threshold()) / 30.0
|
|
914
979
|
if self.model_name=="CP_nuclei":
|
|
915
|
-
scale = self.parent_window.PxToUm * float(self.diameter_le.get_threshold()) / 17.0
|
|
916
|
-
flow_thresh = self.flow_slider.value()
|
|
917
|
-
cellprob_thresh = self.cellprob_slider.value()
|
|
980
|
+
scale = self.parent_window.PxToUm * float(self.diamWidget.diameter_le.get_threshold()) / 17.0
|
|
981
|
+
flow_thresh = self.diamWidget.flow_slider.value()
|
|
982
|
+
cellprob_thresh = self.diamWidget.cellprob_slider.value()
|
|
918
983
|
model_complete_path = locate_segmentation_model(self.model_name)
|
|
919
984
|
input_config_path = model_complete_path+"config_input.json"
|
|
920
|
-
new_channels = [self.cellpose_channel_cb[i].currentText() for i in range(2)]
|
|
985
|
+
new_channels = [self.diamWidget.cellpose_channel_cb[i].currentText() for i in range(2)]
|
|
921
986
|
print(new_channels)
|
|
922
987
|
with open(input_config_path) as config_file:
|
|
923
988
|
input_config = json.load(config_file)
|
|
@@ -936,21 +1001,13 @@ class ProcessPanel(QFrame, Styles):
|
|
|
936
1001
|
|
|
937
1002
|
def set_stardist_scale(self):
|
|
938
1003
|
|
|
939
|
-
# scale = self.parent.PxToUm * float(self.diameter_le.text()) / 30.0
|
|
940
|
-
# if self.model_name=="CP_nuclei":
|
|
941
|
-
# scale = self.parent.PxToUm * float(self.diameter_le.text()) / 17.0
|
|
942
|
-
# flow_thresh = self.flow_slider.value()
|
|
943
|
-
# cellprob_thresh = self.cellprob_slider.value()
|
|
944
1004
|
model_complete_path = locate_segmentation_model(self.model_name)
|
|
945
1005
|
input_config_path = model_complete_path+"config_input.json"
|
|
946
|
-
new_channels = [self.stardist_channel_cb[i].currentText() for i in range(len(self.stardist_channel_cb))]
|
|
1006
|
+
new_channels = [self.diamWidget.stardist_channel_cb[i].currentText() for i in range(len(self.diamWidget.stardist_channel_cb))]
|
|
947
1007
|
with open(input_config_path) as config_file:
|
|
948
1008
|
input_config = json.load(config_file)
|
|
949
1009
|
|
|
950
|
-
# input_config['spatial_calibration'] = scale
|
|
951
1010
|
input_config['channels'] = new_channels
|
|
952
|
-
# input_config['flow_threshold'] = flow_thresh
|
|
953
|
-
# input_config['cellprob_threshold'] = cellprob_thresh
|
|
954
1011
|
with open(input_config_path, 'w') as f:
|
|
955
1012
|
json.dump(input_config, f, indent=4)
|
|
956
1013
|
|
|
@@ -1008,19 +1065,22 @@ class NeighPanel(QFrame, Styles):
|
|
|
1008
1065
|
|
|
1009
1066
|
def collapse_advanced(self):
|
|
1010
1067
|
|
|
1068
|
+
effector_open = not self.parent_window.ProcessEffectors.ContentsFrame.isHidden()
|
|
1069
|
+
targets_open = not self.parent_window.ProcessTargets.ContentsFrame.isHidden()
|
|
1070
|
+
interactions_open = not self.parent_window.NeighPanel.ContentsFrame.isHidden()
|
|
1071
|
+
preprocessing_open = not self.parent_window.PreprocessingPanel.ContentsFrame.isHidden()
|
|
1072
|
+
is_open = np.array([effector_open, targets_open, interactions_open, preprocessing_open])
|
|
1073
|
+
|
|
1011
1074
|
if self.ContentsFrame.isHidden():
|
|
1012
1075
|
self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
1013
1076
|
self.collapse_btn.setIconSize(QSize(20, 20))
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1077
|
+
if len(is_open[is_open])==0:
|
|
1078
|
+
self.parent_window.scroll.setMinimumHeight(int(550))
|
|
1079
|
+
self.parent_window.adjustSize()
|
|
1017
1080
|
else:
|
|
1018
1081
|
self.collapse_btn.setIcon(icon(MDI6.chevron_up,color="black"))
|
|
1019
1082
|
self.collapse_btn.setIconSize(QSize(20, 20))
|
|
1020
|
-
#self.parent.w.adjustSize()
|
|
1021
|
-
#self.parent.adjustSize()
|
|
1022
1083
|
self.parent_window.scroll.setMinimumHeight(min(int(1000), int(0.9*self.parent_window.screen_height)))
|
|
1023
|
-
self.parent_window.scroll.setMinimumWidth(425)
|
|
1024
1084
|
|
|
1025
1085
|
|
|
1026
1086
|
def populate_contents(self):
|
|
@@ -1042,9 +1102,21 @@ class NeighPanel(QFrame, Styles):
|
|
|
1042
1102
|
#self.neigh_action.setIconSize(QSize(20, 20))
|
|
1043
1103
|
self.neigh_action.setToolTip(
|
|
1044
1104
|
"Compute neighborhoods in list below.")
|
|
1105
|
+
|
|
1045
1106
|
neigh_option_hbox.addWidget(self.neigh_action,90)
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
self.help_neigh_btn = QPushButton()
|
|
1110
|
+
self.help_neigh_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
|
|
1111
|
+
self.help_neigh_btn.setIconSize(QSize(20, 20))
|
|
1112
|
+
self.help_neigh_btn.clicked.connect(self.help_neighborhood)
|
|
1113
|
+
self.help_neigh_btn.setStyleSheet(self.button_select_all)
|
|
1114
|
+
self.help_neigh_btn.setToolTip("Help.")
|
|
1115
|
+
neigh_option_hbox.addWidget(self.help_neigh_btn,5,alignment=Qt.AlignRight)
|
|
1116
|
+
|
|
1046
1117
|
self.grid_contents.addLayout(neigh_option_hbox, 1,0,1,4)
|
|
1047
1118
|
|
|
1119
|
+
|
|
1048
1120
|
neigh_options_layout = QVBoxLayout()
|
|
1049
1121
|
|
|
1050
1122
|
neigh_options_vbox = QVBoxLayout()
|
|
@@ -1233,6 +1305,31 @@ class NeighPanel(QFrame, Styles):
|
|
|
1233
1305
|
self.neigh_action.setChecked(False)
|
|
1234
1306
|
|
|
1235
1307
|
|
|
1308
|
+
def help_neighborhood(self):
|
|
1309
|
+
|
|
1310
|
+
"""
|
|
1311
|
+
Helper for neighborhood strategy.
|
|
1312
|
+
"""
|
|
1313
|
+
|
|
1314
|
+
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','neighborhood.json'])
|
|
1315
|
+
|
|
1316
|
+
with open(dict_path) as f:
|
|
1317
|
+
d = json.load(f)
|
|
1318
|
+
|
|
1319
|
+
suggestion = help_generic(d)
|
|
1320
|
+
if isinstance(suggestion, str):
|
|
1321
|
+
print(f"{suggestion=}")
|
|
1322
|
+
msgBox = QMessageBox()
|
|
1323
|
+
msgBox.setIcon(QMessageBox.Information)
|
|
1324
|
+
msgBox.setTextFormat(Qt.RichText)
|
|
1325
|
+
msgBox.setText(f"{suggestion}\nSee a tutorial <a href='https://celldetective.readthedocs.io/en/latest/interactions.html#neighborhood'>here</a>.")
|
|
1326
|
+
msgBox.setWindowTitle("Info")
|
|
1327
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
1328
|
+
returnValue = msgBox.exec()
|
|
1329
|
+
if returnValue == QMessageBox.Ok:
|
|
1330
|
+
return None
|
|
1331
|
+
|
|
1332
|
+
|
|
1236
1333
|
def load_available_tables(self):
|
|
1237
1334
|
|
|
1238
1335
|
"""
|
|
@@ -1520,19 +1617,22 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1520
1617
|
|
|
1521
1618
|
def collapse_advanced(self):
|
|
1522
1619
|
|
|
1620
|
+
effector_open = not self.parent_window.ProcessEffectors.ContentsFrame.isHidden()
|
|
1621
|
+
targets_open = not self.parent_window.ProcessTargets.ContentsFrame.isHidden()
|
|
1622
|
+
interactions_open = not self.parent_window.NeighPanel.ContentsFrame.isHidden()
|
|
1623
|
+
preprocessing_open = not self.parent_window.PreprocessingPanel.ContentsFrame.isHidden()
|
|
1624
|
+
is_open = np.array([effector_open, targets_open, interactions_open, preprocessing_open])
|
|
1625
|
+
|
|
1523
1626
|
if self.ContentsFrame.isHidden():
|
|
1524
1627
|
self.collapse_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
1525
1628
|
self.collapse_btn.setIconSize(QSize(20, 20))
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1629
|
+
if len(is_open[is_open])==0:
|
|
1630
|
+
self.parent_window.scroll.setMinimumHeight(int(550))
|
|
1631
|
+
self.parent_window.adjustSize()
|
|
1529
1632
|
else:
|
|
1530
1633
|
self.collapse_btn.setIcon(icon(MDI6.chevron_up,color="black"))
|
|
1531
1634
|
self.collapse_btn.setIconSize(QSize(20, 20))
|
|
1532
|
-
#self.parent.w.adjustSize()
|
|
1533
|
-
#self.parent.adjustSize()
|
|
1534
1635
|
self.parent_window.scroll.setMinimumHeight(min(int(930), int(0.9*self.parent_window.screen_height)))
|
|
1535
|
-
self.parent_window.scroll.setMinimumWidth(425)
|
|
1536
1636
|
|
|
1537
1637
|
def populate_contents(self):
|
|
1538
1638
|
|
|
@@ -1547,6 +1647,16 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1547
1647
|
tab_names=['Fit', 'Model-free'],
|
|
1548
1648
|
title='BACKGROUND CORRECTION',
|
|
1549
1649
|
list_title='Corrections to apply:')
|
|
1650
|
+
|
|
1651
|
+
self.help_background_btn = QPushButton()
|
|
1652
|
+
self.help_background_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
|
|
1653
|
+
self.help_background_btn.setIconSize(QSize(20, 20))
|
|
1654
|
+
self.help_background_btn.clicked.connect(self.help_background)
|
|
1655
|
+
self.help_background_btn.setStyleSheet(self.button_select_all)
|
|
1656
|
+
self.help_background_btn.setToolTip("Help.")
|
|
1657
|
+
|
|
1658
|
+
self.protocol_layout.title_layout.addWidget(self.help_background_btn, 5, alignment=Qt.AlignRight)
|
|
1659
|
+
|
|
1550
1660
|
self.grid_contents.addLayout(self.protocol_layout,0,0,1,4)
|
|
1551
1661
|
self.submit_preprocessing_btn = QPushButton("Submit")
|
|
1552
1662
|
self.submit_preprocessing_btn.setStyleSheet(self.button_style_sheet_2)
|
|
@@ -1650,4 +1760,28 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1650
1760
|
self.current_stack = None
|
|
1651
1761
|
return None
|
|
1652
1762
|
else:
|
|
1653
|
-
self.current_stack = movies[0]
|
|
1763
|
+
self.current_stack = movies[0]
|
|
1764
|
+
|
|
1765
|
+
def help_background(self):
|
|
1766
|
+
|
|
1767
|
+
"""
|
|
1768
|
+
Helper to choose a proper cell population structure.
|
|
1769
|
+
"""
|
|
1770
|
+
|
|
1771
|
+
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','preprocessing.json'])
|
|
1772
|
+
|
|
1773
|
+
with open(dict_path) as f:
|
|
1774
|
+
d = json.load(f)
|
|
1775
|
+
|
|
1776
|
+
suggestion = help_generic(d)
|
|
1777
|
+
if isinstance(suggestion, str):
|
|
1778
|
+
print(f"{suggestion=}")
|
|
1779
|
+
msgBox = QMessageBox()
|
|
1780
|
+
msgBox.setIcon(QMessageBox.Information)
|
|
1781
|
+
msgBox.setTextFormat(Qt.RichText)
|
|
1782
|
+
msgBox.setText(suggestion)
|
|
1783
|
+
msgBox.setWindowTitle("Info")
|
|
1784
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
1785
|
+
returnValue = msgBox.exec()
|
|
1786
|
+
if returnValue == QMessageBox.Ok:
|
|
1787
|
+
return None
|