celldetective 1.3.5__tar.gz → 1.3.6.post2__tar.gz
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-1.3.5 → celldetective-1.3.6.post2}/PKG-INFO +2 -1
- celldetective-1.3.6.post2/celldetective/_version.py +1 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/filters.py +22 -2
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/btrack_options.py +151 -1
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/classifier_widget.py +26 -22
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/configure_new_exp.py +13 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/control_panel.py +1 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/gui_utils.py +138 -8
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/measurement_options.py +84 -24
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/neighborhood_options.py +1 -1
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/signal_annotator.py +6 -1
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/signal_annotator2.py +22 -19
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/survival_ui.py +0 -2
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/thresholds_gui.py +9 -52
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/viewers.py +58 -21
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/io.py +31 -8
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/measure.py +132 -157
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/scripts/measure_cells.py +28 -13
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/scripts/segment_cells.py +24 -20
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/scripts/segment_cells_thresholds.py +21 -21
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/scripts/track_cells.py +55 -17
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/tracking.py +78 -53
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/utils.py +5 -2
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective.egg-info/PKG-INFO +2 -1
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective.egg-info/requires.txt +1 -0
- celldetective-1.3.5/celldetective/_version.py +0 -1
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/LICENSE +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/README.md +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/__init__.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/__main__.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/datasets/segmentation_annotations/blank +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/datasets/signal_annotations/blank +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/events.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/extra_properties.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/InitWindow.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/__init__.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/about.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/analyze_block.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/generic_signal_plot.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/cell-populations.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/exp-structure.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/feature-btrack.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/neighborhood.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/preprocessing.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/propagate-classification.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/track-postprocessing.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/help/tracking.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/json_readers.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/layouts.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/plot_measurements.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/plot_signals_ui.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/process_block.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/retrain_segmentation_model_options.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/retrain_signal_model_options.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/seg_model_loader.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/signal_annotator_options.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/styles.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/gui/tableUI.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/icons/logo-large.png +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/icons/logo.png +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/icons/signals_icon.png +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/icons/splash-test.png +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/icons/splash.png +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/icons/splash0.png +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/icons/survival2.png +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/icons/vignette_signals2.png +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/icons/vignette_signals2.svg +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/links/zenodo.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/pair_signal_detection/blank +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/segmentation_effectors/blank +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/segmentation_generic/blank +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/segmentation_targets/blank +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/signal_detection/blank +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/tracking_configs/biased_motion.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/tracking_configs/mcf7.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/tracking_configs/ricm.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/models/tracking_configs/ricm2.json +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/neighborhood.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/preprocessing.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/relative_measurements.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/scripts/analyze_signals.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/scripts/measure_relative.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/scripts/train_segmentation_model.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/scripts/train_signal_model.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/segmentation.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective/signals.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective.egg-info/SOURCES.txt +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective.egg-info/dependency_links.txt +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective.egg-info/entry_points.txt +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective.egg-info/not-zip-safe +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/celldetective.egg-info/top_level.txt +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/setup.cfg +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/setup.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/__init__.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_events.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_filters.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_io.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_measure.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_neighborhood.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_preprocessing.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_qt.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_segmentation.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_signals.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_tracking.py +0 -0
- {celldetective-1.3.5 → celldetective-1.3.6.post2}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: celldetective
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.6.post2
|
|
4
4
|
Summary: description
|
|
5
5
|
Home-page: http://github.com/remyeltorro/celldetective
|
|
6
6
|
Author: Rémy Torro
|
|
@@ -42,6 +42,7 @@ Requires-Dist: pytest-qt
|
|
|
42
42
|
Requires-Dist: h5py
|
|
43
43
|
Requires-Dist: cliffs_delta
|
|
44
44
|
Requires-Dist: requests
|
|
45
|
+
Requires-Dist: trackpy
|
|
45
46
|
|
|
46
47
|
# Celldetective
|
|
47
48
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.6.post2"
|
|
@@ -88,9 +88,13 @@ def laplace_filter(img, output=float, interpolate=True, *kwargs):
|
|
|
88
88
|
img = interpolate_nan(img.astype(float))
|
|
89
89
|
return snd.laplace(img.astype(float), *kwargs)
|
|
90
90
|
|
|
91
|
-
def dog_filter(img, sigma_low, sigma_high, interpolate=True, *kwargs):
|
|
91
|
+
def dog_filter(img, blob_size=None, sigma_low=1, sigma_high=2, interpolate=True, *kwargs):
|
|
92
|
+
|
|
92
93
|
if interpolate:
|
|
93
94
|
img = interpolate_nan(img.astype(float))
|
|
95
|
+
if blob_size is not None:
|
|
96
|
+
sigma_low = 1.0 / (1.0 + np.sqrt(2)) * blob_size
|
|
97
|
+
sigma_high = np.sqrt(2)*sigma_low
|
|
94
98
|
return difference_of_gaussians(img.astype(float), sigma_low, sigma_high, *kwargs)
|
|
95
99
|
|
|
96
100
|
def otsu_filter(img, *kwargs):
|
|
@@ -115,15 +119,31 @@ def sauvola_filter(img, *kwargs):
|
|
|
115
119
|
binary = img >= thresh
|
|
116
120
|
return binary.astype(float)
|
|
117
121
|
|
|
118
|
-
def log_filter(img, sigma, *kwargs):
|
|
122
|
+
def log_filter(img, blob_size=None, sigma=1, interpolate=True, *kwargs):
|
|
119
123
|
|
|
120
124
|
if interpolate:
|
|
121
125
|
img = interpolate_nan(img.astype(float))
|
|
126
|
+
if blob_size is not None:
|
|
127
|
+
sigma_low = 1.0 / (1.0 + np.sqrt(2)) * blob_size
|
|
128
|
+
sigma_high = np.sqrt(2)*sigma_low
|
|
129
|
+
|
|
122
130
|
return snd.gaussian_laplace(img.astype(float), sigma, *kwargs)
|
|
123
131
|
|
|
124
132
|
def tophat_filter(img, size, connectivity=4, interpolate=True, *kwargs):
|
|
133
|
+
|
|
125
134
|
if interpolate:
|
|
126
135
|
img = interpolate_nan(img.astype(float))
|
|
127
136
|
structure = snd.generate_binary_structure(rank=2, connectivity=connectivity)
|
|
128
137
|
img = snd.white_tophat(img.astype(float), structure=structure, size=size, *kwargs)
|
|
129
138
|
return img
|
|
139
|
+
|
|
140
|
+
def invert_filter(img, value=65535, *kwargs):
|
|
141
|
+
|
|
142
|
+
img = img.astype(float)
|
|
143
|
+
|
|
144
|
+
image_fill = np.zeros_like(img)
|
|
145
|
+
image_fill[:,:] = value
|
|
146
|
+
|
|
147
|
+
inverted = np.subtract(image_fill, img, where=img==img)
|
|
148
|
+
return inverted
|
|
149
|
+
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QTextEdit, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
|
|
1
|
+
from PyQt5.QtWidgets import QRadioButton, QButtonGroup, QMainWindow, QApplication, QMessageBox, QScrollArea, QComboBox, QFrame, QCheckBox, QFileDialog, QGridLayout, QTextEdit, QLineEdit, QVBoxLayout, QWidget, QLabel, QHBoxLayout, QPushButton
|
|
2
2
|
from PyQt5.QtCore import Qt, QSize
|
|
3
|
+
from PyQt5.QtGui import QDoubleValidator
|
|
4
|
+
|
|
3
5
|
from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, help_generic
|
|
4
6
|
from superqt import QLabeledDoubleSlider,QLabeledSlider
|
|
5
7
|
from superqt.fonticon import icon
|
|
@@ -30,6 +32,8 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
30
32
|
self.setWindowTitle("Configure tracking")
|
|
31
33
|
self.mode = self.parent_window.mode
|
|
32
34
|
self.exp_dir = self.parent_window.exp_dir
|
|
35
|
+
self.floatValidator = QDoubleValidator()
|
|
36
|
+
|
|
33
37
|
if self.mode=="targets":
|
|
34
38
|
self.config_name = os.sep.join(["configs", "btrack_config_targets.json"])
|
|
35
39
|
self.track_instructions_write_path = self.parent_window.exp_dir + os.sep.join(["configs","tracking_instructions_targets.json"])
|
|
@@ -68,9 +72,25 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
68
72
|
main_layout.setContentsMargins(30,30,30,30)
|
|
69
73
|
|
|
70
74
|
# First collapsable Frame CONFIG
|
|
75
|
+
|
|
76
|
+
self.btrack_option = QRadioButton('bTrack')
|
|
77
|
+
self.btrack_option.setChecked(True)
|
|
78
|
+
|
|
79
|
+
self.trackpy_option = QRadioButton('trackpy')
|
|
80
|
+
self.tracker_option_group = QButtonGroup()
|
|
81
|
+
self.tracker_option_group.addButton(self.btrack_option)
|
|
82
|
+
self.tracker_option_group.addButton(self.trackpy_option)
|
|
83
|
+
|
|
71
84
|
self.config_frame = QFrame()
|
|
72
85
|
self.config_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
73
86
|
self.populate_config_frame()
|
|
87
|
+
|
|
88
|
+
tracker_hbox = QHBoxLayout()
|
|
89
|
+
tracker_hbox.setContentsMargins(15,15,15,15)
|
|
90
|
+
tracker_hbox.addWidget(self.btrack_option, 50, alignment=Qt.AlignCenter)
|
|
91
|
+
tracker_hbox.addWidget(self.trackpy_option, 50, alignment=Qt.AlignCenter)
|
|
92
|
+
main_layout.addLayout(tracker_hbox)
|
|
93
|
+
|
|
74
94
|
main_layout.addWidget(self.config_frame)
|
|
75
95
|
|
|
76
96
|
# Second collapsable frame FEATURES
|
|
@@ -79,6 +99,12 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
79
99
|
self.populate_features_frame()
|
|
80
100
|
main_layout.addWidget(self.features_frame)
|
|
81
101
|
|
|
102
|
+
self.config_trackpy_frame = QFrame()
|
|
103
|
+
self.config_trackpy_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
104
|
+
self.populate_config_trackpy_frame()
|
|
105
|
+
main_layout.addWidget(self.config_trackpy_frame)
|
|
106
|
+
self.config_trackpy_frame.hide()
|
|
107
|
+
|
|
82
108
|
# Third collapsable frame POST-PROCESSING
|
|
83
109
|
self.post_proc_frame = QFrame()
|
|
84
110
|
self.post_proc_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
|
|
@@ -102,9 +128,27 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
102
128
|
self.setCentralWidget(self.scroll_area)
|
|
103
129
|
self.show()
|
|
104
130
|
|
|
131
|
+
self.btrack_option.toggled.connect(self.show_tracking_options)
|
|
132
|
+
self.trackpy_option.toggled.connect(self.show_tracking_options)
|
|
133
|
+
|
|
105
134
|
QApplication.processEvents()
|
|
106
135
|
self.adjustScrollArea()
|
|
107
136
|
|
|
137
|
+
def show_tracking_options(self):
|
|
138
|
+
|
|
139
|
+
if self.btrack_option.isChecked():
|
|
140
|
+
self.config_frame.show()
|
|
141
|
+
self.features_frame.show()
|
|
142
|
+
self.config_trackpy_frame.hide()
|
|
143
|
+
#self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
|
|
144
|
+
#self.adjustSize()
|
|
145
|
+
else:
|
|
146
|
+
self.config_frame.hide()
|
|
147
|
+
self.features_frame.hide()
|
|
148
|
+
self.config_trackpy_frame.show()
|
|
149
|
+
#self.scroll_area.setMinimumHeight(self.minimum_height)
|
|
150
|
+
#self.adjustSize()
|
|
151
|
+
|
|
108
152
|
|
|
109
153
|
def populate_post_proc_frame(self):
|
|
110
154
|
|
|
@@ -539,6 +583,29 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
539
583
|
self.collapse_config_btn.clicked.connect(self.collapse_config_advanced)
|
|
540
584
|
#self.ContentsConfig.hide()
|
|
541
585
|
|
|
586
|
+
def populate_config_trackpy_frame(self):
|
|
587
|
+
|
|
588
|
+
grid = QGridLayout(self.config_trackpy_frame)
|
|
589
|
+
panel_title = QLabel(f"CONFIGURATION")
|
|
590
|
+
panel_title.setStyleSheet("""
|
|
591
|
+
font-weight: bold;
|
|
592
|
+
padding: 0px;
|
|
593
|
+
""")
|
|
594
|
+
|
|
595
|
+
grid.addWidget(panel_title, 0, 0, 1, 4, alignment=Qt.AlignCenter)
|
|
596
|
+
|
|
597
|
+
self.collapse_config_trackpy_btn = QPushButton()
|
|
598
|
+
self.collapse_config_trackpy_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
599
|
+
self.collapse_config_trackpy_btn.setIconSize(QSize(20, 20))
|
|
600
|
+
self.collapse_config_trackpy_btn.setStyleSheet(self.button_select_all)
|
|
601
|
+
grid.addWidget(self.collapse_config_trackpy_btn, 0, 0, 1, 4, alignment=Qt.AlignRight)
|
|
602
|
+
self.generate_config_trackpy_panel_contents()
|
|
603
|
+
grid.addWidget(self.ContentsConfigTrackpy, 1, 0, 1, 4, alignment=Qt.AlignTop)
|
|
604
|
+
self.collapse_config_trackpy_btn.clicked.connect(lambda: self.ContentsConfigTrackpy.setHidden(not self.ContentsConfigTrackpy.isHidden()))
|
|
605
|
+
self.collapse_config_trackpy_btn.clicked.connect(self.collapse_config_trackpy_advanced)
|
|
606
|
+
#self.ContentsConfig.hide()
|
|
607
|
+
|
|
608
|
+
|
|
542
609
|
def collapse_config_advanced(self):
|
|
543
610
|
|
|
544
611
|
"""
|
|
@@ -561,6 +628,56 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
561
628
|
self.collapse_config_btn.setIconSize(QSize(20, 20))
|
|
562
629
|
self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
|
|
563
630
|
|
|
631
|
+
def collapse_config_trackpy_advanced(self):
|
|
632
|
+
|
|
633
|
+
"""
|
|
634
|
+
Switch the chevron icon and adjust the size for the CONFIG frame.
|
|
635
|
+
"""
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
post_open = not self.ContentsPostProc.isHidden()
|
|
639
|
+
is_open = np.array([post_open])
|
|
640
|
+
|
|
641
|
+
if self.ContentsConfigTrackpy.isHidden():
|
|
642
|
+
self.collapse_config_trackpy_btn.setIcon(icon(MDI6.chevron_down,color="black"))
|
|
643
|
+
self.collapse_config_trackpy_btn.setIconSize(QSize(20, 20))
|
|
644
|
+
if len(is_open[is_open])==0:
|
|
645
|
+
self.scroll_area.setMinimumHeight(int(self.minimum_height))
|
|
646
|
+
self.adjustSize()
|
|
647
|
+
else:
|
|
648
|
+
self.collapse_config_trackpy_btn.setIcon(icon(MDI6.chevron_up,color="black"))
|
|
649
|
+
self.collapse_config_trackpy_btn.setIconSize(QSize(20, 20))
|
|
650
|
+
self.scroll_area.setMinimumHeight(min(int(930), int(0.9*self.screen_height)))
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
def generate_config_trackpy_panel_contents(self):
|
|
654
|
+
|
|
655
|
+
self.ContentsConfigTrackpy = QFrame()
|
|
656
|
+
layout = QVBoxLayout(self.ContentsConfigTrackpy)
|
|
657
|
+
layout.setContentsMargins(0,0,0,0)
|
|
658
|
+
|
|
659
|
+
sr_layout = QHBoxLayout()
|
|
660
|
+
self.search_range_lbl = QLabel("search range [px]: ")
|
|
661
|
+
self.search_range_le = QLineEdit('30')
|
|
662
|
+
self.search_range_le.setPlaceholderText('search distance in pixels')
|
|
663
|
+
self.search_range_le.setValidator(self.floatValidator)
|
|
664
|
+
sr_layout.addWidget(self.search_range_lbl, 30)
|
|
665
|
+
sr_layout.addWidget(self.search_range_le, 70)
|
|
666
|
+
layout.addLayout(sr_layout)
|
|
667
|
+
|
|
668
|
+
memory_layout = QHBoxLayout()
|
|
669
|
+
self.memory_lbl = QLabel("memory [# frames]: ")
|
|
670
|
+
self.memory_slider = QLabeledSlider()
|
|
671
|
+
self.memory_slider.setSingleStep(1)
|
|
672
|
+
self.memory_slider.setTickInterval(1)
|
|
673
|
+
self.memory_slider.setSingleStep(1)
|
|
674
|
+
self.memory_slider.setOrientation(1)
|
|
675
|
+
self.memory_slider.setRange(0,self.parent_window.parent_window.len_movie)
|
|
676
|
+
self.memory_slider.setValue(0)
|
|
677
|
+
memory_layout.addWidget(self.memory_lbl, 30)
|
|
678
|
+
memory_layout.addWidget(self.memory_slider, 70)
|
|
679
|
+
layout.addLayout(memory_layout)
|
|
680
|
+
|
|
564
681
|
|
|
565
682
|
def generate_config_panel_contents(self):
|
|
566
683
|
|
|
@@ -741,7 +858,23 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
741
858
|
"""
|
|
742
859
|
|
|
743
860
|
print('Writing instructions...')
|
|
861
|
+
|
|
862
|
+
if self.btrack_option.isChecked():
|
|
863
|
+
btrack_option = True
|
|
864
|
+
else:
|
|
865
|
+
btrack_option = False
|
|
866
|
+
|
|
867
|
+
# Fetch trackpky params
|
|
868
|
+
if not btrack_option:
|
|
869
|
+
search_range = int(self.search_range_le.text().replace(',','.'))
|
|
870
|
+
memory = self.memory_slider.value()
|
|
871
|
+
else:
|
|
872
|
+
search_range = None
|
|
873
|
+
memory = None
|
|
874
|
+
|
|
744
875
|
tracking_options = {'btrack_config_path': self.config_path}
|
|
876
|
+
tracking_options.update({'btrack_option': btrack_option, 'search_range': search_range, 'memory': memory})
|
|
877
|
+
|
|
745
878
|
if not self.features_ticked:
|
|
746
879
|
features = None
|
|
747
880
|
masked_channels = None
|
|
@@ -850,6 +983,23 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
850
983
|
self.ContentsFeatures.hide()
|
|
851
984
|
self.uncheck_features()
|
|
852
985
|
|
|
986
|
+
btrack_option = True
|
|
987
|
+
if 'btrack_option' in tracking_instructions:
|
|
988
|
+
btrack_option = tracking_instructions['btrack_option']
|
|
989
|
+
if btrack_option:
|
|
990
|
+
self.btrack_option.click()
|
|
991
|
+
else:
|
|
992
|
+
self.trackpy_option.click()
|
|
993
|
+
|
|
994
|
+
if 'search_range' in tracking_instructions:
|
|
995
|
+
search_range = tracking_instructions['search_range']
|
|
996
|
+
if search_range is not None:
|
|
997
|
+
self.search_range_le.setText(str(search_range).replace('.',','))
|
|
998
|
+
if 'memory' in tracking_instructions:
|
|
999
|
+
memory = tracking_instructions['memory']
|
|
1000
|
+
if memory is not None:
|
|
1001
|
+
self.memory_slider.setValue(memory)
|
|
1002
|
+
|
|
853
1003
|
# Uncheck channels that are masked
|
|
854
1004
|
mask_channels = tracking_instructions['mask_channels']
|
|
855
1005
|
if (mask_channels is not None) and len(mask_channels)>0:
|
|
@@ -95,7 +95,6 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
95
95
|
layout.addLayout(slider_alpha_hbox)
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
|
|
99
98
|
self.features_cb = [QSearchableComboBox() for i in range(2)]
|
|
100
99
|
self.log_btns = [QPushButton() for i in range(2)]
|
|
101
100
|
|
|
@@ -129,7 +128,6 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
129
128
|
layout.addLayout(hbox_classify)
|
|
130
129
|
|
|
131
130
|
self.time_corr = QCheckBox('Time correlated')
|
|
132
|
-
self.time_corr.toggled.connect(self.activate_time_corr_options)
|
|
133
131
|
if "TRACK_ID" in self.df.columns:
|
|
134
132
|
self.time_corr.setEnabled(True)
|
|
135
133
|
else:
|
|
@@ -150,17 +148,14 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
150
148
|
|
|
151
149
|
self.irreversible_event_btn = QRadioButton('irreversible event')
|
|
152
150
|
self.unique_state_btn = QRadioButton('unique state')
|
|
151
|
+
self.transient_event_btn = QRadioButton('transient event')
|
|
153
152
|
time_corr_btn_group = QButtonGroup()
|
|
154
153
|
self.unique_state_btn.click()
|
|
155
|
-
self.time_corr_options = [self.irreversible_event_btn, self.unique_state_btn]
|
|
156
|
-
|
|
157
|
-
for btn in self.time_corr_options:
|
|
158
|
-
time_corr_btn_group.addButton(btn)
|
|
159
|
-
btn.setEnabled(False)
|
|
160
154
|
|
|
161
155
|
time_corr_layout = QHBoxLayout()
|
|
162
|
-
time_corr_layout.addWidget(self.unique_state_btn,
|
|
163
|
-
time_corr_layout.addWidget(self.irreversible_event_btn,
|
|
156
|
+
time_corr_layout.addWidget(self.unique_state_btn, 33, alignment=Qt.AlignCenter)
|
|
157
|
+
time_corr_layout.addWidget(self.irreversible_event_btn, 33,alignment=Qt.AlignCenter)
|
|
158
|
+
time_corr_layout.addWidget(self.transient_event_btn, 33,alignment=Qt.AlignCenter)
|
|
164
159
|
layout.addLayout(time_corr_layout)
|
|
165
160
|
|
|
166
161
|
self.prereq_event_check = QCheckBox('prerequisite event:')
|
|
@@ -171,12 +166,6 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
171
166
|
self.prereq_event_check.setEnabled(False)
|
|
172
167
|
self.prereq_event_cb.setEnabled(False)
|
|
173
168
|
|
|
174
|
-
prereq_layout = QHBoxLayout()
|
|
175
|
-
prereq_layout.addWidget(QLabel(''), 50)
|
|
176
|
-
prereq_layout.addWidget(self.prereq_event_check, 15)
|
|
177
|
-
prereq_layout.addWidget(self.prereq_event_cb, 35)
|
|
178
|
-
layout.addLayout(prereq_layout)
|
|
179
|
-
|
|
180
169
|
self.r2_slider = QLabeledDoubleSlider()
|
|
181
170
|
self.r2_slider.setValue(0.75)
|
|
182
171
|
self.r2_slider.setRange(0,1)
|
|
@@ -186,17 +175,32 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
186
175
|
self.r2_label.setToolTip('Minimum R2 between the fit sigmoid and the binary response to the filters to accept the event.')
|
|
187
176
|
|
|
188
177
|
r2_threshold_layout = QHBoxLayout()
|
|
189
|
-
r2_threshold_layout.addWidget(QLabel(''),
|
|
190
|
-
r2_threshold_layout.addWidget(self.r2_label,
|
|
191
|
-
r2_threshold_layout.addWidget(self.r2_slider,
|
|
192
|
-
|
|
178
|
+
r2_threshold_layout.addWidget(QLabel(''), 33)
|
|
179
|
+
r2_threshold_layout.addWidget(self.r2_label, 13)
|
|
180
|
+
r2_threshold_layout.addWidget(self.r2_slider, 20)
|
|
181
|
+
r2_threshold_layout.addWidget(QLabel(''), 33)
|
|
182
|
+
|
|
183
|
+
layout.addLayout(r2_threshold_layout)
|
|
193
184
|
|
|
185
|
+
self.time_corr_options = [self.irreversible_event_btn, self.unique_state_btn, self.prereq_event_check, self.prereq_event_cb, self.transient_event_btn]
|
|
186
|
+
for btn in [self.irreversible_event_btn, self.unique_state_btn, self.transient_event_btn]:
|
|
187
|
+
time_corr_btn_group.addButton(btn)
|
|
188
|
+
btn.setEnabled(False)
|
|
189
|
+
self.time_corr.toggled.connect(self.activate_time_corr_options)
|
|
190
|
+
|
|
194
191
|
self.irreversible_event_btn.clicked.connect(self.activate_r2)
|
|
195
192
|
self.unique_state_btn.clicked.connect(self.activate_r2)
|
|
193
|
+
self.transient_event_btn.clicked.connect(self.activate_r2)
|
|
196
194
|
|
|
197
195
|
for wg in [self.r2_slider, self.r2_label]:
|
|
198
196
|
wg.setEnabled(False)
|
|
199
197
|
|
|
198
|
+
prereq_layout = QHBoxLayout()
|
|
199
|
+
prereq_layout.setContentsMargins(30,0,0,0)
|
|
200
|
+
prereq_layout.addWidget(self.prereq_event_check, 20)
|
|
201
|
+
prereq_layout.addWidget(self.prereq_event_cb, 80)
|
|
202
|
+
layout.addLayout(prereq_layout)
|
|
203
|
+
|
|
200
204
|
layout.addWidget(QLabel())
|
|
201
205
|
|
|
202
206
|
self.submit_btn = QPushButton('apply')
|
|
@@ -225,10 +229,10 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
225
229
|
|
|
226
230
|
def activate_r2(self):
|
|
227
231
|
if self.irreversible_event_btn.isChecked() and self.time_corr.isChecked():
|
|
228
|
-
for wg in [self.r2_slider, self.r2_label
|
|
232
|
+
for wg in [self.r2_slider, self.r2_label]:
|
|
229
233
|
wg.setEnabled(True)
|
|
230
234
|
else:
|
|
231
|
-
for wg in [self.r2_slider, self.r2_label
|
|
235
|
+
for wg in [self.r2_slider, self.r2_label]:
|
|
232
236
|
wg.setEnabled(False)
|
|
233
237
|
|
|
234
238
|
def activate_time_corr_options(self):
|
|
@@ -441,7 +445,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
441
445
|
if self.prereq_event_check.isChecked() and "t_"+self.prereq_event_cb.currentText() in self.cols:
|
|
442
446
|
pre_event = self.prereq_event_cb.currentText()
|
|
443
447
|
|
|
444
|
-
self.df = interpret_track_classification(self.df, self.class_name_user, irreversible_event=self.irreversible_event_btn.isChecked(), unique_state=self.unique_state_btn.isChecked(), r2_threshold=self.r2_slider.value(), pre_event=pre_event)
|
|
448
|
+
self.df = interpret_track_classification(self.df, self.class_name_user, irreversible_event=self.irreversible_event_btn.isChecked(), unique_state=self.unique_state_btn.isChecked(), transient_event=self.transient_event_btn.isChecked(),r2_threshold=self.r2_slider.value(), pre_event=pre_event)
|
|
445
449
|
|
|
446
450
|
else:
|
|
447
451
|
self.group_name_user = 'group_' + self.name_le.text()
|
|
@@ -453,6 +453,9 @@ class ConfigNewExperiment(QMainWindow, Styles):
|
|
|
453
453
|
config.set('Labels', 'concentrations', self.concentrations)
|
|
454
454
|
config.set('Labels', 'pharmaceutical_agents', self.pharmaceutical_agents)
|
|
455
455
|
|
|
456
|
+
config.add_section('Metadata')
|
|
457
|
+
config.set('Metadata', 'concentration_units', self.concentration_units)
|
|
458
|
+
|
|
456
459
|
# save to a file
|
|
457
460
|
with open('config.ini', 'w') as configfile:
|
|
458
461
|
config.write(configfile)
|
|
@@ -480,6 +483,8 @@ class SetupConditionLabels(QWidget, Styles):
|
|
|
480
483
|
self.antibodies_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
481
484
|
self.concentrations_cbs = [QLineEdit() for i in range(self.n_wells)]
|
|
482
485
|
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')
|
|
483
488
|
|
|
484
489
|
for i in range(self.n_wells):
|
|
485
490
|
hbox = QHBoxLayout()
|
|
@@ -504,6 +509,12 @@ class SetupConditionLabels(QWidget, Styles):
|
|
|
504
509
|
|
|
505
510
|
self.layout.addLayout(hbox)
|
|
506
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
|
+
|
|
507
518
|
btn_hbox = QHBoxLayout()
|
|
508
519
|
btn_hbox.setContentsMargins(0,20,0,0)
|
|
509
520
|
self.skip_btn = QPushButton('Skip')
|
|
@@ -556,6 +567,8 @@ class SetupConditionLabels(QWidget, Styles):
|
|
|
556
567
|
pharamaceutical_text = [c.text() for c in self.pharmaceutical_agents_cbs]
|
|
557
568
|
self.parent_window.pharmaceutical_agents = ','.join(pharamaceutical_text)
|
|
558
569
|
|
|
570
|
+
self.parent_window.concentration_units = self.concentration_units_le.text()
|
|
571
|
+
|
|
559
572
|
|
|
560
573
|
|
|
561
574
|
|
|
@@ -338,6 +338,7 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
338
338
|
self.antibodies = get_experiment_antibodies(self.exp_dir)
|
|
339
339
|
self.pharmaceutical_agents = get_experiment_pharmaceutical_agents(self.exp_dir)
|
|
340
340
|
|
|
341
|
+
self.metadata = ConfigSectionMap(self.exp_config,"Metadata")
|
|
341
342
|
print('Experiment configuration successfully read...')
|
|
342
343
|
|
|
343
344
|
def closeEvent(self, event):
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
-
from PyQt5.QtWidgets import QApplication, QMessageBox, QFrame, QSizePolicy, QWidget, QLineEdit, QListWidget, QVBoxLayout, QComboBox, \
|
|
2
|
+
from PyQt5.QtWidgets import QGridLayout, QApplication, QMessageBox, QFrame, QSizePolicy, QWidget, QLineEdit, QListWidget, QVBoxLayout, QComboBox, \
|
|
3
3
|
QPushButton, QLabel, QHBoxLayout, QCheckBox, QFileDialog, QToolButton, QMenu, QStylePainter, QStyleOptionComboBox, QStyle
|
|
4
4
|
from PyQt5.QtCore import Qt, QSize, QAbstractTableModel, QEvent, pyqtSignal
|
|
5
5
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QStandardItemModel, QPalette
|
|
@@ -15,6 +15,125 @@ import celldetective.extra_properties as extra_properties
|
|
|
15
15
|
from inspect import getmembers, isfunction
|
|
16
16
|
from celldetective.filters import *
|
|
17
17
|
from os import sep
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class PreprocessingLayout(QVBoxLayout, Styles):
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
A widget that allows user to choose preprocessing filters for an image
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, parent_window=None, apply_btn_option=True, *args, **kwargs):
|
|
28
|
+
super().__init__(*args, **kwargs)
|
|
29
|
+
|
|
30
|
+
self.parent_window = parent_window
|
|
31
|
+
self.apply_btn_option = apply_btn_option
|
|
32
|
+
self.generate_components()
|
|
33
|
+
self.add_to_layout()
|
|
34
|
+
|
|
35
|
+
def add_to_layout(self):
|
|
36
|
+
|
|
37
|
+
self.setContentsMargins(20, 20, 20, 20)
|
|
38
|
+
|
|
39
|
+
button_layout = QHBoxLayout()
|
|
40
|
+
button_layout.addWidget(self.preprocess_lbl, 85, alignment=Qt.AlignLeft)
|
|
41
|
+
button_layout.addWidget(self.delete_filter_btn, 5)
|
|
42
|
+
button_layout.addWidget(self.add_filter_btn, 5)
|
|
43
|
+
button_layout.addWidget(self.help_prefilter_btn, 5)
|
|
44
|
+
self.addLayout(button_layout, 25)
|
|
45
|
+
|
|
46
|
+
self.addWidget(self.list, 70)
|
|
47
|
+
if self.apply_btn_option:
|
|
48
|
+
self.addWidget(self.apply_btn, 5)
|
|
49
|
+
|
|
50
|
+
def generate_components(self):
|
|
51
|
+
|
|
52
|
+
self.list = ListWidget(FilterChoice, [])
|
|
53
|
+
|
|
54
|
+
self.preprocess_lbl = QLabel('Preprocessing')
|
|
55
|
+
self.preprocess_lbl.setStyleSheet("font-weight: bold;")
|
|
56
|
+
|
|
57
|
+
self.delete_filter_btn = QPushButton()
|
|
58
|
+
self.delete_filter_btn.setStyleSheet(self.button_select_all)
|
|
59
|
+
self.delete_filter_btn.setIcon(icon(MDI6.trash_can, color="black"))
|
|
60
|
+
self.delete_filter_btn.setToolTip("Remove filter")
|
|
61
|
+
self.delete_filter_btn.setIconSize(QSize(20, 20))
|
|
62
|
+
self.delete_filter_btn.clicked.connect(self.list.removeSel)
|
|
63
|
+
|
|
64
|
+
self.add_filter_btn = QPushButton()
|
|
65
|
+
self.add_filter_btn.setStyleSheet(self.button_select_all)
|
|
66
|
+
self.add_filter_btn.setIcon(icon(MDI6.filter_plus, color="black"))
|
|
67
|
+
self.add_filter_btn.setToolTip("Add filter")
|
|
68
|
+
self.add_filter_btn.setIconSize(QSize(20, 20))
|
|
69
|
+
self.add_filter_btn.clicked.connect(self.list.addItem)
|
|
70
|
+
|
|
71
|
+
self.help_prefilter_btn = QPushButton()
|
|
72
|
+
self.help_prefilter_btn.setIcon(icon(MDI6.help_circle,color=self.help_color))
|
|
73
|
+
self.help_prefilter_btn.setIconSize(QSize(20, 20))
|
|
74
|
+
self.help_prefilter_btn.clicked.connect(self.help_prefilter)
|
|
75
|
+
self.help_prefilter_btn.setStyleSheet(self.button_select_all)
|
|
76
|
+
self.help_prefilter_btn.setToolTip("Help.")
|
|
77
|
+
|
|
78
|
+
if self.apply_btn_option:
|
|
79
|
+
self.apply_btn = QPushButton("Apply")
|
|
80
|
+
self.apply_btn.setIcon(icon(MDI6.filter_cog_outline, color="white"))
|
|
81
|
+
self.apply_btn.setIconSize(QSize(20, 20))
|
|
82
|
+
self.apply_btn.setStyleSheet(self.button_style_sheet)
|
|
83
|
+
self.apply_btn.clicked.connect(self.parent_window.preprocess_image)
|
|
84
|
+
|
|
85
|
+
def help_prefilter(self):
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
Helper for prefiltering strategy
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
dict_path = os.sep.join([get_software_location(),'celldetective','gui','help','prefilter-for-segmentation.json'])
|
|
92
|
+
|
|
93
|
+
with open(dict_path) as f:
|
|
94
|
+
d = json.load(f)
|
|
95
|
+
|
|
96
|
+
suggestion = help_generic(d)
|
|
97
|
+
if isinstance(suggestion, str):
|
|
98
|
+
print(f"{suggestion=}")
|
|
99
|
+
msgBox = QMessageBox()
|
|
100
|
+
msgBox.setIcon(QMessageBox.Information)
|
|
101
|
+
msgBox.setTextFormat(Qt.RichText)
|
|
102
|
+
msgBox.setText(f"The suggested technique is to {suggestion}.\nSee a tutorial <a href='https://celldetective.readthedocs.io/en/latest/segment.html'>here</a>.")
|
|
103
|
+
msgBox.setWindowTitle("Info")
|
|
104
|
+
msgBox.setStandardButtons(QMessageBox.Ok)
|
|
105
|
+
returnValue = msgBox.exec()
|
|
106
|
+
if returnValue == QMessageBox.Ok:
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class PreprocessingLayout2(PreprocessingLayout):
|
|
111
|
+
|
|
112
|
+
def __init__(self, fraction=75, *args, **kwargs):
|
|
113
|
+
|
|
114
|
+
self.fraction = fraction
|
|
115
|
+
super().__init__(apply_btn_option=False, *args, **kwargs)
|
|
116
|
+
self.preprocess_lbl.setText('Preprocessing: ')
|
|
117
|
+
self.preprocess_lbl.setStyleSheet("")
|
|
118
|
+
self.setContentsMargins(0,0,0,0)
|
|
119
|
+
|
|
120
|
+
def add_to_layout(self):
|
|
121
|
+
|
|
122
|
+
main_layout = QHBoxLayout()
|
|
123
|
+
main_layout.setContentsMargins(0,0,0,0)
|
|
124
|
+
main_layout.setSpacing(5)
|
|
125
|
+
main_layout.addWidget(self.preprocess_lbl, self.fraction, alignment=Qt.AlignTop)
|
|
126
|
+
|
|
127
|
+
list_grid = QGridLayout()
|
|
128
|
+
list_grid.addWidget(self.list, 0, 0, 2, 2)
|
|
129
|
+
list_grid.addWidget(self.add_filter_btn, 0, 2, 1, 1)
|
|
130
|
+
list_grid.addWidget(self.delete_filter_btn, 1, 2, 1, 1)
|
|
131
|
+
main_layout.addLayout(list_grid, 100-self.fraction)
|
|
132
|
+
self.add_filter_btn.setFixedWidth(35) # Ensure the button width is fixed
|
|
133
|
+
self.delete_filter_btn.setFixedWidth(35)
|
|
134
|
+
list_grid.setColumnStretch(2, 0)
|
|
135
|
+
|
|
136
|
+
self.addLayout(main_layout)
|
|
18
137
|
|
|
19
138
|
|
|
20
139
|
class QCheckableComboBox(QComboBox):
|
|
@@ -427,7 +546,7 @@ class QHSeperationLine(QFrame):
|
|
|
427
546
|
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
|
|
428
547
|
|
|
429
548
|
|
|
430
|
-
class FeatureChoice(QWidget):
|
|
549
|
+
class FeatureChoice(QWidget, Styles):
|
|
431
550
|
|
|
432
551
|
def __init__(self, parent_window):
|
|
433
552
|
super().__init__()
|
|
@@ -435,7 +554,6 @@ class FeatureChoice(QWidget):
|
|
|
435
554
|
self.setWindowTitle("Add feature")
|
|
436
555
|
# Create the QComboBox and add some items
|
|
437
556
|
self.combo_box = QComboBox(self)
|
|
438
|
-
center_window(self)
|
|
439
557
|
|
|
440
558
|
standard_measurements = ["area",
|
|
441
559
|
"area_bbox",
|
|
@@ -465,12 +583,15 @@ class FeatureChoice(QWidget):
|
|
|
465
583
|
self.combo_box.addItems(standard_measurements)
|
|
466
584
|
|
|
467
585
|
self.add_btn = QPushButton("Add")
|
|
586
|
+
self.add_btn.setStyleSheet(self.button_style_sheet)
|
|
468
587
|
self.add_btn.clicked.connect(self.add_current_feature)
|
|
469
588
|
|
|
470
589
|
# Create the layout
|
|
471
590
|
layout = QVBoxLayout(self)
|
|
472
591
|
layout.addWidget(self.combo_box)
|
|
473
592
|
layout.addWidget(self.add_btn)
|
|
593
|
+
center_window(self)
|
|
594
|
+
|
|
474
595
|
|
|
475
596
|
def add_current_feature(self):
|
|
476
597
|
filtername = self.combo_box.currentText()
|
|
@@ -478,7 +599,7 @@ class FeatureChoice(QWidget):
|
|
|
478
599
|
self.close()
|
|
479
600
|
|
|
480
601
|
|
|
481
|
-
class FilterChoice(QWidget):
|
|
602
|
+
class FilterChoice(QWidget, Styles):
|
|
482
603
|
|
|
483
604
|
def __init__(self, parent_window):
|
|
484
605
|
|
|
@@ -499,9 +620,10 @@ class FilterChoice(QWidget):
|
|
|
499
620
|
'laplace_filter': None,
|
|
500
621
|
'abs_filter': None,
|
|
501
622
|
'ln_filter': None,
|
|
623
|
+
'invert_filter': {'value': 65535},
|
|
502
624
|
'subtract_filter': {'value': 1},
|
|
503
|
-
'dog_filter': {'
|
|
504
|
-
'log_filter': {'
|
|
625
|
+
'dog_filter': {'blob_size': 30},
|
|
626
|
+
'log_filter': {'blob_size': 30},
|
|
505
627
|
'tophat_filter': {'size': 4, 'connectivity': 4},
|
|
506
628
|
'otsu_filter': None,
|
|
507
629
|
'local_filter': {'block_size': 73, 'method': 'mean', 'offset': 0},
|
|
@@ -523,16 +645,18 @@ class FilterChoice(QWidget):
|
|
|
523
645
|
self.arguments_labels = [QLabel('') for i in range(3)]
|
|
524
646
|
for i in range(2):
|
|
525
647
|
hbox = QHBoxLayout()
|
|
526
|
-
hbox.addWidget(self.arguments_labels[i],
|
|
527
|
-
hbox.addWidget(self.arguments_le[i],
|
|
648
|
+
hbox.addWidget(self.arguments_labels[i], 40)
|
|
649
|
+
hbox.addWidget(self.arguments_le[i], 60)
|
|
528
650
|
layout.addLayout(hbox)
|
|
529
651
|
|
|
530
652
|
self.add_btn = QPushButton("Add")
|
|
653
|
+
self.add_btn.setStyleSheet(self.button_style_sheet)
|
|
531
654
|
self.add_btn.clicked.connect(self.add_current_feature)
|
|
532
655
|
layout.addWidget(self.add_btn)
|
|
533
656
|
|
|
534
657
|
self.combo_box.setCurrentIndex(0)
|
|
535
658
|
self.update_arguments()
|
|
659
|
+
center_window(self)
|
|
536
660
|
|
|
537
661
|
def add_current_feature(self):
|
|
538
662
|
|
|
@@ -787,6 +911,9 @@ class ListWidget(QWidget):
|
|
|
787
911
|
self.addItemWindow = self.choiceWidget(self)
|
|
788
912
|
self.addItemWindow.show()
|
|
789
913
|
|
|
914
|
+
def addItemToList(self, item):
|
|
915
|
+
self.list_widget.addItems([item])
|
|
916
|
+
|
|
790
917
|
def getItems(self):
|
|
791
918
|
|
|
792
919
|
"""
|
|
@@ -814,6 +941,9 @@ class ListWidget(QWidget):
|
|
|
814
941
|
items.append(self.dtype(self.list_widget.item(x).text()))
|
|
815
942
|
return items
|
|
816
943
|
|
|
944
|
+
def clear(self):
|
|
945
|
+
self.items = []
|
|
946
|
+
self.list_widget.clear()
|
|
817
947
|
|
|
818
948
|
def removeSel(self):
|
|
819
949
|
|