celldetective 1.3.4.post1__tar.gz → 1.3.5__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.4.post1 → celldetective-1.3.5}/PKG-INFO +2 -2
- celldetective-1.3.5/celldetective/_version.py +1 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/events.py +10 -5
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/classifier_widget.py +29 -4
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/control_panel.py +3 -2
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/generic_signal_plot.py +2 -6
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/gui_utils.py +34 -6
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/measurement_options.py +1 -30
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/neighborhood_options.py +1 -1
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/plot_signals_ui.py +3 -4
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/process_block.py +8 -6
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/signal_annotator.py +4 -2
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/signal_annotator2.py +141 -191
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/survival_ui.py +122 -33
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/tableUI.py +26 -12
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/io.py +1059 -156
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/measure.py +151 -53
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/preprocessing.py +2 -2
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/relative_measurements.py +6 -9
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/scripts/measure_cells.py +13 -3
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/scripts/segment_cells.py +0 -1
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/signals.py +9 -7
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/tracking.py +52 -28
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/utils.py +23 -5
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective.egg-info/PKG-INFO +2 -2
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective.egg-info/requires.txt +1 -1
- celldetective-1.3.4.post1/celldetective/_version.py +0 -1
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/LICENSE +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/README.md +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/__init__.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/__main__.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/datasets/segmentation_annotations/blank +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/datasets/signal_annotations/blank +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/extra_properties.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/filters.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/InitWindow.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/__init__.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/about.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/analyze_block.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/btrack_options.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/configure_new_exp.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/cell-populations.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/exp-structure.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/feature-btrack.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/neighborhood.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/preprocessing.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/propagate-classification.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/track-postprocessing.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/help/tracking.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/json_readers.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/layouts.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/plot_measurements.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/retrain_segmentation_model_options.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/retrain_signal_model_options.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/seg_model_loader.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/signal_annotator_options.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/styles.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/thresholds_gui.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/gui/viewers.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/icons/logo-large.png +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/icons/logo.png +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/icons/signals_icon.png +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/icons/splash-test.png +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/icons/splash.png +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/icons/splash0.png +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/icons/survival2.png +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/icons/vignette_signals2.png +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/icons/vignette_signals2.svg +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/links/zenodo.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/pair_signal_detection/blank +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/blank +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/test-transfer/config_input.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/segmentation_generic/blank +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/segmentation_targets/blank +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/signal_detection/blank +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/tracking_configs/biased_motion.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/tracking_configs/mcf7.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/tracking_configs/ricm.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/models/tracking_configs/ricm2.json +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/neighborhood.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/scripts/analyze_signals.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/scripts/measure_relative.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/scripts/segment_cells_thresholds.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/scripts/track_cells.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/scripts/train_segmentation_model.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/scripts/train_signal_model.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective/segmentation.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective.egg-info/SOURCES.txt +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective.egg-info/dependency_links.txt +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective.egg-info/entry_points.txt +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective.egg-info/not-zip-safe +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/celldetective.egg-info/top_level.txt +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/setup.cfg +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/setup.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/__init__.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_events.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_filters.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_io.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_measure.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_neighborhood.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_preprocessing.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_qt.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_segmentation.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_signals.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/tests/test_tracking.py +0 -0
- {celldetective-1.3.4.post1 → celldetective-1.3.5}/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.5
|
|
4
4
|
Summary: description
|
|
5
5
|
Home-page: http://github.com/remyeltorro/celldetective
|
|
6
6
|
Author: Rémy Torro
|
|
@@ -20,7 +20,7 @@ Requires-Dist: cellpose<3
|
|
|
20
20
|
Requires-Dist: scikit-learn
|
|
21
21
|
Requires-Dist: btrack
|
|
22
22
|
Requires-Dist: tensorflow~=2.15.0
|
|
23
|
-
Requires-Dist: napari
|
|
23
|
+
Requires-Dist: napari<0.6.0
|
|
24
24
|
Requires-Dist: tqdm
|
|
25
25
|
Requires-Dist: mahotas
|
|
26
26
|
Requires-Dist: fonticon-materialdesignicons6
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.5"
|
|
@@ -143,7 +143,7 @@ def switch_to_events(classes, event_times, max_times, origin_times=None, left_ce
|
|
|
143
143
|
survival_times = [s*FrameToMin for s in survival_times]
|
|
144
144
|
return events, survival_times
|
|
145
145
|
|
|
146
|
-
def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMin=1, cut_observation_time=None):
|
|
146
|
+
def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMin=1, cut_observation_time=None, pairs=False):
|
|
147
147
|
|
|
148
148
|
"""
|
|
149
149
|
Computes survival analysis for a specific class of interest within a dataset, returning a fitted Kaplan-Meier
|
|
@@ -190,9 +190,14 @@ def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMi
|
|
|
190
190
|
assert t_event in cols,"The event time cannot be found in the dataframe..."
|
|
191
191
|
left_censored = False
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
if not pairs:
|
|
194
|
+
groupby_cols = ['position','TRACK_ID']
|
|
195
|
+
else:
|
|
196
|
+
groupby_cols = ['position','REFERENCE_ID','NEIGHBOR_ID']
|
|
197
|
+
|
|
198
|
+
classes = df.groupby(groupby_cols)[class_of_interest].min().values
|
|
199
|
+
event_times = df.groupby(groupby_cols)[t_event].min().values
|
|
200
|
+
max_times = df.groupby(groupby_cols)['FRAME'].max().values
|
|
196
201
|
|
|
197
202
|
if t_reference=="0" or t_reference==0:
|
|
198
203
|
t_reference = None
|
|
@@ -202,7 +207,7 @@ def compute_survival(df, class_of_interest, t_event, t_reference=None, FrameToMi
|
|
|
202
207
|
if t_reference is not None:
|
|
203
208
|
left_censored = True
|
|
204
209
|
assert t_reference in cols,"The reference time cannot be found in the dataframe..."
|
|
205
|
-
first_detections = df.groupby(
|
|
210
|
+
first_detections = df.groupby(groupby_cols)[t_reference].max().values
|
|
206
211
|
|
|
207
212
|
events, survival_times = switch_to_events(classes, event_times, max_times, origin_times=first_detections, left_censored=left_censored, FrameToMin=FrameToMin, cut_observation_time=cut_observation_time)
|
|
208
213
|
ks = KaplanMeierFitter()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from PyQt5.QtWidgets import QWidget, QLineEdit, QMessageBox, QHBoxLayout, QVBoxLayout, QPushButton, QLabel, \
|
|
2
|
-
QCheckBox, QRadioButton, QButtonGroup
|
|
2
|
+
QCheckBox, QRadioButton, QButtonGroup, QComboBox
|
|
3
3
|
from PyQt5.QtCore import Qt, QSize
|
|
4
4
|
from superqt import QLabeledSlider,QLabeledDoubleSlider, QSearchableComboBox
|
|
5
5
|
from superqt.fonticon import icon
|
|
@@ -163,6 +163,20 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
163
163
|
time_corr_layout.addWidget(self.irreversible_event_btn, 50,alignment=Qt.AlignCenter)
|
|
164
164
|
layout.addLayout(time_corr_layout)
|
|
165
165
|
|
|
166
|
+
self.prereq_event_check = QCheckBox('prerequisite event:')
|
|
167
|
+
self.prereq_event_check.toggled.connect(self.activate_prereq_cb)
|
|
168
|
+
self.prereq_event_cb = QComboBox()
|
|
169
|
+
event_cols = ['--'] + [c.replace('t_','') for c in self.cols if c.startswith('t_')]
|
|
170
|
+
self.prereq_event_cb.addItems(event_cols)
|
|
171
|
+
self.prereq_event_check.setEnabled(False)
|
|
172
|
+
self.prereq_event_cb.setEnabled(False)
|
|
173
|
+
|
|
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
|
+
|
|
166
180
|
self.r2_slider = QLabeledDoubleSlider()
|
|
167
181
|
self.r2_slider.setValue(0.75)
|
|
168
182
|
self.r2_slider.setRange(0,1)
|
|
@@ -170,6 +184,7 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
170
184
|
self.r2_slider.setOrientation(1)
|
|
171
185
|
self.r2_label = QLabel('R2 tolerance:')
|
|
172
186
|
self.r2_label.setToolTip('Minimum R2 between the fit sigmoid and the binary response to the filters to accept the event.')
|
|
187
|
+
|
|
173
188
|
r2_threshold_layout = QHBoxLayout()
|
|
174
189
|
r2_threshold_layout.addWidget(QLabel(''), 50)
|
|
175
190
|
r2_threshold_layout.addWidget(self.r2_label, 15)
|
|
@@ -193,6 +208,12 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
193
208
|
self.frame_slider.valueChanged.connect(self.set_frame)
|
|
194
209
|
self.alpha_slider.valueChanged.connect(self.set_transparency)
|
|
195
210
|
|
|
211
|
+
def activate_prereq_cb(self):
|
|
212
|
+
if self.prereq_event_check.isChecked():
|
|
213
|
+
self.prereq_event_cb.setEnabled(True)
|
|
214
|
+
else:
|
|
215
|
+
self.prereq_event_cb.setEnabled(False)
|
|
216
|
+
|
|
196
217
|
def activate_submit_btn(self):
|
|
197
218
|
|
|
198
219
|
if self.property_query_le.text()=='':
|
|
@@ -204,10 +225,10 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
204
225
|
|
|
205
226
|
def activate_r2(self):
|
|
206
227
|
if self.irreversible_event_btn.isChecked() and self.time_corr.isChecked():
|
|
207
|
-
for wg in [self.r2_slider, self.r2_label]:
|
|
228
|
+
for wg in [self.r2_slider, self.r2_label, self.prereq_event_check]:
|
|
208
229
|
wg.setEnabled(True)
|
|
209
230
|
else:
|
|
210
|
-
for wg in [self.r2_slider, self.r2_label]:
|
|
231
|
+
for wg in [self.r2_slider, self.r2_label, self.prereq_event_check]:
|
|
211
232
|
wg.setEnabled(False)
|
|
212
233
|
|
|
213
234
|
def activate_time_corr_options(self):
|
|
@@ -416,7 +437,11 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
416
437
|
self.df = self.df.drop(list(set(name_map.values()) & set(self.df.columns)), axis=1).rename(columns=name_map)
|
|
417
438
|
self.df.reset_index(inplace=True, drop=True)
|
|
418
439
|
|
|
419
|
-
|
|
440
|
+
pre_event = None
|
|
441
|
+
if self.prereq_event_check.isChecked() and "t_"+self.prereq_event_cb.currentText() in self.cols:
|
|
442
|
+
pre_event = self.prereq_event_cb.currentText()
|
|
443
|
+
|
|
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)
|
|
420
445
|
|
|
421
446
|
else:
|
|
422
447
|
self.group_name_user = 'group_' + self.name_le.text()
|
|
@@ -93,6 +93,9 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
93
93
|
self.screen_width = desktop.screenGeometry().width()
|
|
94
94
|
self.scroll.setMinimumWidth(440)
|
|
95
95
|
|
|
96
|
+
self.well_list.setCurrentIndex(0)
|
|
97
|
+
#self.position_list.setCurrentIndex(0)
|
|
98
|
+
|
|
96
99
|
def init_wells_and_positions(self):
|
|
97
100
|
|
|
98
101
|
"""
|
|
@@ -151,10 +154,8 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
151
154
|
#self.locate_selected_position()
|
|
152
155
|
|
|
153
156
|
self.well_list.activated.connect(self.display_positions)
|
|
154
|
-
self.well_list.setCurrentIndex(0)
|
|
155
157
|
|
|
156
158
|
self.position_list.activated.connect(self.update_position_options)
|
|
157
|
-
self.position_list.setCurrentIndex(0)
|
|
158
159
|
|
|
159
160
|
self.view_stack_btn = QPushButton()
|
|
160
161
|
self.view_stack_btn.setStyleSheet(self.button_select_all)
|
|
@@ -62,6 +62,7 @@ class GenericSignalPlotWidget(QWidget, Styles):
|
|
|
62
62
|
self.setLayout(self.layout)
|
|
63
63
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
64
64
|
|
|
65
|
+
|
|
65
66
|
def populate_widget(self):
|
|
66
67
|
|
|
67
68
|
self.plot_options = [QRadioButton() for i in range(3)]
|
|
@@ -221,18 +222,13 @@ class GenericSignalPlotWidget(QWidget, Styles):
|
|
|
221
222
|
self.alpha_slider = QLabeledDoubleSlider()
|
|
222
223
|
alpha_hbox = QuickSliderLayout(label='single-cell\nsignal alpha: ',
|
|
223
224
|
slider=self.alpha_slider,
|
|
224
|
-
slider_initial_value=
|
|
225
|
+
slider_initial_value=self.alpha_setting,
|
|
225
226
|
slider_range=(0,1),
|
|
226
227
|
decimal_option=True,
|
|
227
228
|
precision=1.0E-05,
|
|
228
229
|
)
|
|
229
230
|
self.alpha_slider.valueChanged.connect(self.submit_alpha)
|
|
230
231
|
self.cell_lines_alpha_wdg.setLayout(alpha_hbox)
|
|
231
|
-
|
|
232
|
-
# self.submit_alpha_btn = QPushButton('submit')
|
|
233
|
-
# self.submit_alpha_btn.setStyleSheet(self.button_style_sheet_2)
|
|
234
|
-
# self.submit_alpha_btn.clicked.connect(self.submit_alpha)
|
|
235
|
-
# alpha_hbox.addWidget(self.submit_alpha_btn, 10)
|
|
236
232
|
self.layout.addWidget(self.cell_lines_alpha_wdg)
|
|
237
233
|
|
|
238
234
|
self.select_option = [QRadioButton() for i in range(2)]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
from PyQt5.QtWidgets import QApplication, QMessageBox, QFrame, QSizePolicy, QWidget, QLineEdit, QListWidget, QVBoxLayout, QComboBox, \
|
|
3
3
|
QPushButton, QLabel, QHBoxLayout, QCheckBox, QFileDialog, QToolButton, QMenu, QStylePainter, QStyleOptionComboBox, QStyle
|
|
4
|
-
from PyQt5.QtCore import Qt, QSize, QAbstractTableModel
|
|
4
|
+
from PyQt5.QtCore import Qt, QSize, QAbstractTableModel, QEvent, pyqtSignal
|
|
5
5
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator, QStandardItemModel, QPalette
|
|
6
6
|
|
|
7
7
|
from celldetective.gui import Styles
|
|
@@ -23,12 +23,13 @@ class QCheckableComboBox(QComboBox):
|
|
|
23
23
|
adapted from https://stackoverflow.com/questions/22775095/pyqt-how-to-set-combobox-items-be-checkable
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
|
+
activated = pyqtSignal(str)
|
|
27
|
+
|
|
26
28
|
def __init__(self, obj='', parent_window=None, *args, **kwargs):
|
|
27
29
|
|
|
28
30
|
super().__init__(parent_window, *args, **kwargs)
|
|
29
31
|
|
|
30
32
|
self.setTitle('')
|
|
31
|
-
self.view().pressed.connect(self.handleItemPressed)
|
|
32
33
|
self.setModel(QStandardItemModel(self))
|
|
33
34
|
self.obj = obj
|
|
34
35
|
self.toolButton = QToolButton(parent_window)
|
|
@@ -38,6 +39,9 @@ class QCheckableComboBox(QComboBox):
|
|
|
38
39
|
self.toolButton.setPopupMode(QToolButton.InstantPopup)
|
|
39
40
|
self.anySelected = False
|
|
40
41
|
|
|
42
|
+
self.view().viewport().installEventFilter(self)
|
|
43
|
+
self.view().pressed.connect(self.handleItemPressed)
|
|
44
|
+
|
|
41
45
|
def clear(self):
|
|
42
46
|
|
|
43
47
|
self.unselectAll()
|
|
@@ -70,6 +74,8 @@ class QCheckableComboBox(QComboBox):
|
|
|
70
74
|
elif len(options_checked[options_checked])==0:
|
|
71
75
|
self.setTitle(f"No {self.obj} selected...")
|
|
72
76
|
self.anySelected = False
|
|
77
|
+
|
|
78
|
+
self.activated.emit(self.title())
|
|
73
79
|
|
|
74
80
|
def setCurrentIndex(self, index):
|
|
75
81
|
|
|
@@ -101,6 +107,7 @@ class QCheckableComboBox(QComboBox):
|
|
|
101
107
|
|
|
102
108
|
def setTitle(self, title):
|
|
103
109
|
self._title = title
|
|
110
|
+
self.update()
|
|
104
111
|
self.repaint()
|
|
105
112
|
|
|
106
113
|
def paintEvent(self, event):
|
|
@@ -155,7 +162,12 @@ class QCheckableComboBox(QComboBox):
|
|
|
155
162
|
|
|
156
163
|
def isAnySelected(self):
|
|
157
164
|
return not self.title().startswith('No')
|
|
158
|
-
|
|
165
|
+
|
|
166
|
+
def eventFilter(self, source, event):
|
|
167
|
+
if source is self.view().viewport():
|
|
168
|
+
if event.type() == QEvent.MouseButtonRelease:
|
|
169
|
+
return True # Prevent the popup from closing
|
|
170
|
+
return super().eventFilter(source, event)
|
|
159
171
|
|
|
160
172
|
class PandasModel(QAbstractTableModel):
|
|
161
173
|
|
|
@@ -503,7 +515,11 @@ class FilterChoice(QWidget):
|
|
|
503
515
|
self.combo_box.currentTextChanged.connect(self.update_arguments)
|
|
504
516
|
layout.addWidget(self.combo_box)
|
|
505
517
|
|
|
518
|
+
self.floatValidator = QDoubleValidator()
|
|
506
519
|
self.arguments_le = [QLineEdit() for i in range(3)]
|
|
520
|
+
for i in range(3):
|
|
521
|
+
self.arguments_le[i].setValidator(self.floatValidator)
|
|
522
|
+
|
|
507
523
|
self.arguments_labels = [QLabel('') for i in range(3)]
|
|
508
524
|
for i in range(2):
|
|
509
525
|
hbox = QHBoxLayout()
|
|
@@ -525,8 +541,10 @@ class FilterChoice(QWidget):
|
|
|
525
541
|
|
|
526
542
|
filter_instructions = [filtername.split('_')[0]]
|
|
527
543
|
for a in self.arguments_le:
|
|
528
|
-
|
|
544
|
+
|
|
545
|
+
arg = a.text().replace(',','.')
|
|
529
546
|
arg_num = arg
|
|
547
|
+
|
|
530
548
|
if (arg != '') and arg_num.replace('.', '').replace(',', '').isnumeric():
|
|
531
549
|
num = float(arg)
|
|
532
550
|
if num.is_integer():
|
|
@@ -666,12 +684,14 @@ class DistanceChoice(QWidget):
|
|
|
666
684
|
super().__init__()
|
|
667
685
|
self.parent_window = parent_window
|
|
668
686
|
self.setWindowTitle("Set distances")
|
|
687
|
+
self.floatValidator = QDoubleValidator()
|
|
669
688
|
center_window(self)
|
|
670
689
|
|
|
671
690
|
# Create the QComboBox and add some items
|
|
672
691
|
|
|
673
692
|
self.dist_label = QLabel('Distance [px]: ')
|
|
674
693
|
self.dist_le = QLineEdit('10')
|
|
694
|
+
self.dist_le.setValidator(self.floatValidator)
|
|
675
695
|
|
|
676
696
|
self.add_btn = QPushButton("Add")
|
|
677
697
|
self.add_btn.clicked.connect(self.add_current_feature)
|
|
@@ -686,7 +706,7 @@ class DistanceChoice(QWidget):
|
|
|
686
706
|
layout.addWidget(self.add_btn)
|
|
687
707
|
|
|
688
708
|
def add_current_feature(self):
|
|
689
|
-
value = self.dist_le.text()
|
|
709
|
+
value = self.dist_le.text().replace(',','.')
|
|
690
710
|
values = [value]
|
|
691
711
|
self.parent_window.list_widget.addItems(values)
|
|
692
712
|
self.close()
|
|
@@ -827,13 +847,21 @@ class FigureCanvas(QWidget):
|
|
|
827
847
|
if interactive:
|
|
828
848
|
self.toolbar = NavigationToolbar2QT(self.canvas)
|
|
829
849
|
self.layout = QVBoxLayout(self)
|
|
830
|
-
self.layout.addWidget(self.canvas)
|
|
850
|
+
self.layout.addWidget(self.canvas,90)
|
|
831
851
|
if interactive:
|
|
832
852
|
self.layout.addWidget(self.toolbar)
|
|
833
853
|
|
|
834
854
|
center_window(self)
|
|
835
855
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
836
856
|
|
|
857
|
+
def resizeEvent(self, event):
|
|
858
|
+
|
|
859
|
+
super().resizeEvent(event)
|
|
860
|
+
try:
|
|
861
|
+
self.fig.tight_layout()
|
|
862
|
+
except:
|
|
863
|
+
pass
|
|
864
|
+
|
|
837
865
|
def draw(self):
|
|
838
866
|
self.canvas.draw()
|
|
839
867
|
|
|
@@ -261,7 +261,7 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
261
261
|
self.add_feature_btn.setToolTip("Add feature")
|
|
262
262
|
self.add_feature_btn.setIconSize(QSize(20, 20))
|
|
263
263
|
|
|
264
|
-
self.features_list = ListWidget(FeatureChoice, initial_features=['area', '
|
|
264
|
+
self.features_list = ListWidget(FeatureChoice, initial_features=['area', 'intensity_mean', ])
|
|
265
265
|
|
|
266
266
|
self.del_feature_btn.clicked.connect(self.features_list.removeSel)
|
|
267
267
|
self.add_feature_btn.clicked.connect(self.features_list.addItem)
|
|
@@ -313,25 +313,6 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
313
313
|
|
|
314
314
|
self.feat_sep3 = QHSeperationLine()
|
|
315
315
|
layout.addWidget(self.feat_sep3)
|
|
316
|
-
# self.radial_intensity_btn = QCheckBox('Measure radial intensity distribution')
|
|
317
|
-
# layout.addWidget(self.radial_intensity_btn)
|
|
318
|
-
# self.radial_intensity_btn.clicked.connect(self.enable_step_size)
|
|
319
|
-
# self.channel_chechkboxes=[]
|
|
320
|
-
# for channel in self.channel_names:
|
|
321
|
-
# channel_checkbox=QCheckBox(channel)
|
|
322
|
-
# self.channel_chechkboxes.append(channel_checkbox)
|
|
323
|
-
# layout.addWidget(channel_checkbox)
|
|
324
|
-
# channel_checkbox.setEnabled(False)
|
|
325
|
-
# step_box=QHBoxLayout()
|
|
326
|
-
# self.step_lbl=QLabel("Step size (in px)")
|
|
327
|
-
# self.step_size=QLineEdit()
|
|
328
|
-
# self.step_lbl.setEnabled(False)
|
|
329
|
-
# self.step_size.setEnabled(False)
|
|
330
|
-
# step_box.addWidget(self.step_lbl)
|
|
331
|
-
# step_box.addWidget(self.step_size)
|
|
332
|
-
# layout.addLayout(step_box)
|
|
333
|
-
# self.feat_sep4 = QHSeperationLine()
|
|
334
|
-
# layout.addWidget(self.feat_sep4)
|
|
335
316
|
|
|
336
317
|
# Haralick features parameters
|
|
337
318
|
self.activate_haralick_btn = QCheckBox('Measure Haralick texture features')
|
|
@@ -511,16 +492,6 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
511
492
|
if not border_distances:
|
|
512
493
|
border_distances = None
|
|
513
494
|
measurement_options.update({'border_distances': border_distances})
|
|
514
|
-
# radial_intensity = {}
|
|
515
|
-
# radial_step = int(self.step_size.text())
|
|
516
|
-
# radial_channels = []
|
|
517
|
-
# for checkbox in self.channel_chechkboxes:
|
|
518
|
-
# if checkbox.isChecked():
|
|
519
|
-
# radial_channels.append(checkbox.text())
|
|
520
|
-
# radial_intensity={'radial_step': radial_step, 'radial_channels': radial_channels}
|
|
521
|
-
# if not self.radial_intensity_btn.isChecked():
|
|
522
|
-
# radial_intensity = None
|
|
523
|
-
# measurement_options.update({'radial_intensity' : radial_intensity})
|
|
524
495
|
|
|
525
496
|
self.extract_haralick_options()
|
|
526
497
|
measurement_options.update({'haralick_options': self.haralick_options})
|
|
@@ -174,7 +174,7 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
174
174
|
self.attr_parent.locate_image()
|
|
175
175
|
if self.attr_parent.current_stack is not None:
|
|
176
176
|
self.viewer = CellEdgeVisualizer(
|
|
177
|
-
cell_type=
|
|
177
|
+
cell_type=self.reference_population_cb.currentText(),
|
|
178
178
|
edge_range=(1,30),
|
|
179
179
|
invert=True,
|
|
180
180
|
initial_edge=3,
|
|
@@ -19,6 +19,7 @@ import pandas as pd
|
|
|
19
19
|
import math
|
|
20
20
|
from celldetective.gui import Styles
|
|
21
21
|
from matplotlib import colormaps
|
|
22
|
+
import matplotlib.cm
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class ConfigSignalPlot(QWidget, Styles):
|
|
@@ -110,10 +111,8 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
110
111
|
|
|
111
112
|
all_cms = list(colormaps)
|
|
112
113
|
for cm in all_cms:
|
|
113
|
-
|
|
114
|
-
self.cbs[-1].addColormap(cm)
|
|
115
|
-
except:
|
|
116
|
-
pass
|
|
114
|
+
if hasattr(matplotlib.cm, str(cm).lower()):
|
|
115
|
+
self.cbs[-1].addColormap(cm.lower())
|
|
117
116
|
|
|
118
117
|
self.cbs[0].setCurrentIndex(1)
|
|
119
118
|
self.cbs[0].setCurrentIndex(0)
|
|
@@ -9,7 +9,7 @@ from PyQt5.QtGui import QDoubleValidator, QIntValidator
|
|
|
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
|
-
|
|
12
|
+
control_tracks, load_experiment_tables, get_pair_signal_models_list
|
|
13
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
|
|
@@ -291,7 +291,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
291
291
|
self.track_action.setStyleSheet(self.menu_check_style)
|
|
292
292
|
self.track_action.setIcon(icon(MDI6.chart_timeline_variant,color="black"))
|
|
293
293
|
self.track_action.setIconSize(QSize(20, 20))
|
|
294
|
-
self.track_action.setToolTip("Track the
|
|
294
|
+
self.track_action.setToolTip(f"Track the {self.mode[:-1]} cells.")
|
|
295
295
|
grid_track.addWidget(self.track_action, 75)
|
|
296
296
|
|
|
297
297
|
self.delete_tracks_btn = QPushButton()
|
|
@@ -307,7 +307,7 @@ class ProcessPanel(QFrame, Styles):
|
|
|
307
307
|
self.check_tracking_result_btn = QPushButton()
|
|
308
308
|
self.check_tracking_result_btn.setIcon(icon(MDI6.eye_check_outline,color="black"))
|
|
309
309
|
self.check_tracking_result_btn.setIconSize(QSize(20, 20))
|
|
310
|
-
self.check_tracking_result_btn.setToolTip("View
|
|
310
|
+
self.check_tracking_result_btn.setToolTip("View tracking output in napari.")
|
|
311
311
|
self.check_tracking_result_btn.setStyleSheet(self.button_select_all)
|
|
312
312
|
self.check_tracking_result_btn.clicked.connect(self.open_napari_tracking)
|
|
313
313
|
self.check_tracking_result_btn.setEnabled(False)
|
|
@@ -845,14 +845,16 @@ class ProcessPanel(QFrame, Styles):
|
|
|
845
845
|
|
|
846
846
|
# self.stack = None
|
|
847
847
|
self.parent_window.update_position_options()
|
|
848
|
-
|
|
849
|
-
|
|
848
|
+
|
|
849
|
+
for action in [self.segment_action, self.track_action, self.measure_action, self.signal_analysis_action]:
|
|
850
|
+
if action.isChecked():
|
|
851
|
+
action.setChecked(False)
|
|
850
852
|
|
|
851
853
|
self.cellpose_calibrated = False
|
|
852
854
|
|
|
853
855
|
def open_napari_tracking(self):
|
|
854
856
|
print(f'View the tracks before post-processing for position {self.parent_window.pos} in napari...')
|
|
855
|
-
|
|
857
|
+
control_tracks(self.parent_window.pos, prefix=self.parent_window.movie_prefix, population=self.mode, threads=self.parent_window.parent_window.n_threads)
|
|
856
858
|
|
|
857
859
|
def view_table_ui(self):
|
|
858
860
|
|
|
@@ -457,8 +457,10 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
457
457
|
cols = np.array(self.df_tracks.columns)
|
|
458
458
|
self.class_cols = np.array([c.startswith('class') for c in list(self.df_tracks.columns)])
|
|
459
459
|
self.class_cols = list(cols[self.class_cols])
|
|
460
|
-
self.class_cols
|
|
461
|
-
|
|
460
|
+
if 'class_id' in self.class_cols:
|
|
461
|
+
self.class_cols.remove('class_id')
|
|
462
|
+
if 'class_color' in self.class_cols:
|
|
463
|
+
self.class_cols.remove('class_color')
|
|
462
464
|
self.class_choice_cb.addItems(self.class_cols)
|
|
463
465
|
idx = self.class_choice_cb.findText(self.target_class)
|
|
464
466
|
self.class_choice_cb.setCurrentIndex(idx)
|