celldetective 1.3.1__tar.gz → 1.3.3.post1__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.1 → celldetective-1.3.3.post1}/PKG-INFO +6 -6
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/README.md +5 -5
- celldetective-1.3.3.post1/celldetective/_version.py +1 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/events.py +2 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/classifier_widget.py +51 -3
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/control_panel.py +9 -3
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/generic_signal_plot.py +161 -2
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/gui_utils.py +90 -1
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/measurement_options.py +35 -32
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/plot_signals_ui.py +8 -3
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/process_block.py +36 -114
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/retrain_segmentation_model_options.py +3 -1
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/signal_annotator.py +53 -26
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/signal_annotator2.py +17 -30
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/survival_ui.py +7 -3
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/tableUI.py +300 -183
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/thresholds_gui.py +195 -199
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/viewers.py +267 -13
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/io.py +110 -10
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/measure.py +128 -88
- celldetective-1.3.3.post1/celldetective/models/segmentation_effectors/ricm_bf_all_last/config_input.json +79 -0
- celldetective-1.3.3.post1/celldetective/models/segmentation_effectors/ricm_bf_all_last/ricm_bf_all_last +0 -0
- celldetective-1.3.3.post1/celldetective/models/segmentation_effectors/ricm_bf_all_last/training_instructions.json +37 -0
- celldetective-1.3.3.post1/celldetective/models/segmentation_effectors/test-transfer/config_input.json +39 -0
- celldetective-1.3.3.post1/celldetective/models/segmentation_effectors/test-transfer/test-transfer +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/neighborhood.py +154 -69
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/relative_measurements.py +128 -4
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/scripts/measure_cells.py +3 -3
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/signals.py +207 -213
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/utils.py +16 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective.egg-info/PKG-INFO +6 -6
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective.egg-info/SOURCES.txt +5 -0
- celldetective-1.3.1/celldetective/_version.py +0 -1
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/LICENSE +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/__init__.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/__main__.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/datasets/segmentation_annotations/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/datasets/signal_annotations/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/extra_properties.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/filters.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/InitWindow.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/__init__.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/about.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/analyze_block.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/btrack_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/configure_new_exp.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/DL-segmentation-strategy.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/Threshold-vs-DL.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/cell-populations.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/exp-structure.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/feature-btrack.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/neighborhood.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/prefilter-for-segmentation.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/preprocessing.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/propagate-classification.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/track-postprocessing.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/help/tracking.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/json_readers.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/layouts.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/neighborhood_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/plot_measurements.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/retrain_signal_model_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/seg_model_loader.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/signal_annotator_options.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/gui/styles.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/icons/logo-large.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/icons/logo.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/icons/signals_icon.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/icons/splash-test.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/icons/splash.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/icons/splash0.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/icons/survival2.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/icons/vignette_signals2.png +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/icons/vignette_signals2.svg +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/links/zenodo.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/pair_signal_detection/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/segmentation_effectors/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/segmentation_generic/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/segmentation_targets/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/signal_detection/blank +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/tracking_configs/biased_motion.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/tracking_configs/mcf7.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/tracking_configs/no_z_motion.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/tracking_configs/ricm.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/models/tracking_configs/ricm2.json +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/preprocessing.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/scripts/analyze_signals.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/scripts/measure_relative.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/scripts/segment_cells.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/scripts/segment_cells_thresholds.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/scripts/track_cells.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/scripts/train_segmentation_model.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/scripts/train_signal_model.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/segmentation.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective/tracking.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective.egg-info/dependency_links.txt +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective.egg-info/entry_points.txt +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective.egg-info/not-zip-safe +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective.egg-info/requires.txt +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/celldetective.egg-info/top_level.txt +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/setup.cfg +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/setup.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/__init__.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_events.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_filters.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_io.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_measure.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_neighborhood.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_preprocessing.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_qt.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_segmentation.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_signals.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/tests/test_tracking.py +0 -0
- {celldetective-1.3.1 → celldetective-1.3.3.post1}/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.3.post1
|
|
4
4
|
Summary: description
|
|
5
5
|
Home-page: http://github.com/remyeltorro/celldetective
|
|
6
6
|
Author: Rémy Torro
|
|
@@ -172,20 +172,20 @@ For more information about how to get started, please check the [documentation](
|
|
|
172
172
|
# How to cite?
|
|
173
173
|
|
|
174
174
|
If you use this software in your research, please cite the
|
|
175
|
-
[Celldetective](https://www.biorxiv.org/content/10.1101/2024.03.15.
|
|
175
|
+
[Celldetective](https://www.biorxiv.org/content/10.1101/2024.03.15.585250v3)
|
|
176
176
|
paper (currently preprint):
|
|
177
177
|
|
|
178
178
|
``` raw
|
|
179
179
|
@article {Torro2024.03.15.585250,
|
|
180
|
-
author = {R{\'e}my
|
|
180
|
+
author = {Torro, R{\'e}my and D{\'\i}az-Bello, Beatriz and Arawi, Dalia El and Dervanova, Ksenija and Ammer, Lorna and Dupuy, Florian and Chames, Patrick and Sengupta, Kheya and Limozin, Laurent},
|
|
181
181
|
title = {Celldetective: an AI-enhanced image analysis tool for unraveling dynamic cell interactions},
|
|
182
182
|
elocation-id = {2024.03.15.585250},
|
|
183
183
|
year = {2024},
|
|
184
184
|
doi = {10.1101/2024.03.15.585250},
|
|
185
185
|
publisher = {Cold Spring Harbor Laboratory},
|
|
186
|
-
abstract = {A current
|
|
187
|
-
URL = {https://www.biorxiv.org/content/early/2024/
|
|
188
|
-
eprint = {https://www.biorxiv.org/content/early/2024/
|
|
186
|
+
abstract = {A current challenge in bioimaging for immunology and immunotherapy research lies in analyzing multimodal and multidimensional data that capture dynamic interactions between diverse cell populations. Here, we introduce Celldetective, an open-source Python-based software designed for high-performance, end-to-end analysis of image-based in vitro immune and immunotherapy assays. Purpose-built for multicondition, 2D multichannel time-lapse microscopy of mixed cell populations, Celldetective is optimized for the needs of immunology assays. The software seamlessly integrates AI-based segmentation, Bayesian tracking, and automated single-cell event detection, all within an intuitive graphical interface that supports interactive visualization, annotation, and training capabilities. We demonstrate its utility with original data on immune effector cell interactions with an activating surface, mediated by bispecific antibodies, and further showcase its potential for analyzing extensive sets of pairwise interactions in antibody-dependent cell cytotoxicity events.Competing Interest StatementThe authors have declared no competing interest.},
|
|
187
|
+
URL = {https://www.biorxiv.org/content/early/2024/11/13/2024.03.15.585250},
|
|
188
|
+
eprint = {https://www.biorxiv.org/content/early/2024/11/13/2024.03.15.585250.full.pdf},
|
|
189
189
|
journal = {bioRxiv}
|
|
190
190
|
}
|
|
191
191
|
```
|
|
@@ -128,20 +128,20 @@ For more information about how to get started, please check the [documentation](
|
|
|
128
128
|
# How to cite?
|
|
129
129
|
|
|
130
130
|
If you use this software in your research, please cite the
|
|
131
|
-
[Celldetective](https://www.biorxiv.org/content/10.1101/2024.03.15.
|
|
131
|
+
[Celldetective](https://www.biorxiv.org/content/10.1101/2024.03.15.585250v3)
|
|
132
132
|
paper (currently preprint):
|
|
133
133
|
|
|
134
134
|
``` raw
|
|
135
135
|
@article {Torro2024.03.15.585250,
|
|
136
|
-
author = {R{\'e}my
|
|
136
|
+
author = {Torro, R{\'e}my and D{\'\i}az-Bello, Beatriz and Arawi, Dalia El and Dervanova, Ksenija and Ammer, Lorna and Dupuy, Florian and Chames, Patrick and Sengupta, Kheya and Limozin, Laurent},
|
|
137
137
|
title = {Celldetective: an AI-enhanced image analysis tool for unraveling dynamic cell interactions},
|
|
138
138
|
elocation-id = {2024.03.15.585250},
|
|
139
139
|
year = {2024},
|
|
140
140
|
doi = {10.1101/2024.03.15.585250},
|
|
141
141
|
publisher = {Cold Spring Harbor Laboratory},
|
|
142
|
-
abstract = {A current
|
|
143
|
-
URL = {https://www.biorxiv.org/content/early/2024/
|
|
144
|
-
eprint = {https://www.biorxiv.org/content/early/2024/
|
|
142
|
+
abstract = {A current challenge in bioimaging for immunology and immunotherapy research lies in analyzing multimodal and multidimensional data that capture dynamic interactions between diverse cell populations. Here, we introduce Celldetective, an open-source Python-based software designed for high-performance, end-to-end analysis of image-based in vitro immune and immunotherapy assays. Purpose-built for multicondition, 2D multichannel time-lapse microscopy of mixed cell populations, Celldetective is optimized for the needs of immunology assays. The software seamlessly integrates AI-based segmentation, Bayesian tracking, and automated single-cell event detection, all within an intuitive graphical interface that supports interactive visualization, annotation, and training capabilities. We demonstrate its utility with original data on immune effector cell interactions with an activating surface, mediated by bispecific antibodies, and further showcase its potential for analyzing extensive sets of pairwise interactions in antibody-dependent cell cytotoxicity events.Competing Interest StatementThe authors have declared no competing interest.},
|
|
143
|
+
URL = {https://www.biorxiv.org/content/early/2024/11/13/2024.03.15.585250},
|
|
144
|
+
eprint = {https://www.biorxiv.org/content/early/2024/11/13/2024.03.15.585250.full.pdf},
|
|
145
145
|
journal = {bioRxiv}
|
|
146
146
|
}
|
|
147
147
|
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.3.post1"
|
|
@@ -104,6 +104,8 @@ def switch_to_events(classes, event_times, max_times, origin_times=None, left_ce
|
|
|
104
104
|
pass
|
|
105
105
|
elif c==1:
|
|
106
106
|
delta_t = mt - ot
|
|
107
|
+
if cut_observation_time is not None:
|
|
108
|
+
delta_t = cut_observation_time - ot
|
|
107
109
|
if delta_t>0:
|
|
108
110
|
events.append(0)
|
|
109
111
|
survival_times.append(delta_t)
|
|
@@ -253,6 +253,24 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
253
253
|
|
|
254
254
|
def update_props_scatter(self, feature_changed=True):
|
|
255
255
|
|
|
256
|
+
try:
|
|
257
|
+
if np.any(self.df[self.features_cb[0].currentText()].to_numpy() <= 0.):
|
|
258
|
+
if self.ax_props.get_yscale()=='log':
|
|
259
|
+
self.log_btns[0].click()
|
|
260
|
+
self.log_btns[0].setEnabled(False)
|
|
261
|
+
else:
|
|
262
|
+
self.log_btns[0].setEnabled(True)
|
|
263
|
+
|
|
264
|
+
if np.any(self.df[self.features_cb[1].currentText()].to_numpy() <= 0.):
|
|
265
|
+
if self.ax_props.get_xscale()=='log':
|
|
266
|
+
self.log_btns[1].click()
|
|
267
|
+
self.log_btns[1].setEnabled(False)
|
|
268
|
+
else:
|
|
269
|
+
self.log_btns[1].setEnabled(True)
|
|
270
|
+
except Exception as e:
|
|
271
|
+
#print(e)
|
|
272
|
+
pass
|
|
273
|
+
|
|
256
274
|
class_name = self.class_name
|
|
257
275
|
|
|
258
276
|
try:
|
|
@@ -279,11 +297,24 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
279
297
|
max_x = self.df.dropna(subset=feat_x)[feat_x].max()
|
|
280
298
|
min_y = self.df.dropna(subset=feat_y)[feat_y].min()
|
|
281
299
|
max_y = self.df.dropna(subset=feat_y)[feat_y].max()
|
|
300
|
+
|
|
301
|
+
x_padding = (max_x - min_x) * 0.05
|
|
302
|
+
y_padding = (max_y - min_y) * 0.05
|
|
303
|
+
if x_padding==0:
|
|
304
|
+
x_padding = 0.05
|
|
305
|
+
if y_padding==0:
|
|
306
|
+
y_padding = 0.05
|
|
282
307
|
|
|
283
308
|
if min_x==min_x and max_x==max_x:
|
|
284
|
-
self.ax_props.
|
|
309
|
+
if self.ax_props.get_xscale()=='linear':
|
|
310
|
+
self.ax_props.set_xlim(min_x - x_padding, max_x + x_padding)
|
|
311
|
+
else:
|
|
312
|
+
self.ax_props.set_xlim(min_x, max_x)
|
|
285
313
|
if min_y==min_y and max_y==max_y:
|
|
286
|
-
self.ax_props.
|
|
314
|
+
if self.ax_props.get_yscale()=='linear':
|
|
315
|
+
self.ax_props.set_ylim(min_y - y_padding, max_y + y_padding)
|
|
316
|
+
else:
|
|
317
|
+
self.ax_props.set_ylim(min_y, max_y)
|
|
287
318
|
|
|
288
319
|
self.propscanvas.canvas.toolbar.update()
|
|
289
320
|
|
|
@@ -452,22 +483,39 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
452
483
|
|
|
453
484
|
if i==1:
|
|
454
485
|
try:
|
|
486
|
+
feat_x = self.features_cb[1].currentText()
|
|
487
|
+
min_x = self.df.dropna(subset=feat_x)[feat_x].min()
|
|
488
|
+
max_x = self.df.dropna(subset=feat_x)[feat_x].max()
|
|
489
|
+
x_padding = (max_x - min_x) * 0.05
|
|
490
|
+
if x_padding==0:
|
|
491
|
+
x_padding = 0.05
|
|
492
|
+
|
|
455
493
|
if self.ax_props.get_xscale()=='linear':
|
|
494
|
+
self.ax_props.set_xlim(min_x, max_x)
|
|
456
495
|
self.ax_props.set_xscale('log')
|
|
457
496
|
self.log_btns[i].setIcon(icon(MDI6.math_log,color="#1565c0"))
|
|
458
497
|
else:
|
|
459
498
|
self.ax_props.set_xscale('linear')
|
|
499
|
+
self.ax_props.set_xlim(min_x - x_padding, max_x + x_padding)
|
|
460
500
|
self.log_btns[i].setIcon(icon(MDI6.math_log,color="black"))
|
|
461
501
|
except Exception as e:
|
|
462
502
|
print(e)
|
|
463
503
|
elif i==0:
|
|
464
504
|
try:
|
|
505
|
+
feat_y = self.features_cb[0].currentText()
|
|
506
|
+
min_y = self.df.dropna(subset=feat_y)[feat_y].min()
|
|
507
|
+
max_y = self.df.dropna(subset=feat_y)[feat_y].max()
|
|
508
|
+
y_padding = (max_y - min_y) * 0.05
|
|
509
|
+
if y_padding==0:
|
|
510
|
+
y_padding = 0.05
|
|
511
|
+
|
|
465
512
|
if self.ax_props.get_yscale()=='linear':
|
|
466
|
-
|
|
513
|
+
self.ax_props.set_ylim(min_y, max_y)
|
|
467
514
|
self.ax_props.set_yscale('log')
|
|
468
515
|
self.log_btns[i].setIcon(icon(MDI6.math_log,color="#1565c0"))
|
|
469
516
|
else:
|
|
470
517
|
self.ax_props.set_yscale('linear')
|
|
518
|
+
self.ax_props.set_ylim(min_y - y_padding, max_y + y_padding)
|
|
471
519
|
self.log_btns[i].setIcon(icon(MDI6.math_log,color="black"))
|
|
472
520
|
except Exception as e:
|
|
473
521
|
print(e)
|
|
@@ -181,7 +181,13 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
181
181
|
exp_hbox = QHBoxLayout()
|
|
182
182
|
exp_hbox.addWidget(experiment_label, 25, alignment=Qt.AlignRight)
|
|
183
183
|
exp_subhbox = QHBoxLayout()
|
|
184
|
-
|
|
184
|
+
if len(name)>thresh:
|
|
185
|
+
name_cut = name[:thresh - 3]+'...'
|
|
186
|
+
else:
|
|
187
|
+
name_cut = name
|
|
188
|
+
exp_name_lbl = QLabel(name_cut)
|
|
189
|
+
exp_name_lbl.setToolTip(name)
|
|
190
|
+
exp_subhbox.addWidget(exp_name_lbl, 90, alignment=Qt.AlignLeft)
|
|
185
191
|
exp_subhbox.addWidget(self.folder_exp_btn, 5, alignment=Qt.AlignRight)
|
|
186
192
|
exp_subhbox.addWidget(self.edit_config_button, 5, alignment=Qt.AlignRight)
|
|
187
193
|
exp_hbox.addLayout(exp_subhbox, 75)
|
|
@@ -444,8 +450,8 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
444
450
|
self.view_stack_btn.setEnabled(False)
|
|
445
451
|
self.ProcessEffectors.signal_analysis_action.setEnabled(True)
|
|
446
452
|
self.ProcessTargets.signal_analysis_action.setEnabled(True)
|
|
447
|
-
|
|
448
|
-
|
|
453
|
+
if hasattr(self,'delete_tracks_btn'):
|
|
454
|
+
self.delete_tracks_btn.hide()
|
|
449
455
|
self.ProcessTargets.delete_tracks_btn.hide()
|
|
450
456
|
self.ProcessEffectors.delete_tracks_btn.hide()
|
|
451
457
|
else:
|
|
@@ -5,7 +5,11 @@ from PyQt5.QtCore import Qt, QSize
|
|
|
5
5
|
from PyQt5.QtGui import QDoubleValidator
|
|
6
6
|
|
|
7
7
|
from celldetective.gui.gui_utils import center_window, FigureCanvas, ExportPlotBtn
|
|
8
|
+
from celldetective.gui.tableUI import TableUI
|
|
9
|
+
from celldetective.io import collect_experiment_metadata
|
|
10
|
+
|
|
8
11
|
from superqt.fonticon import icon
|
|
12
|
+
from superqt import QLabeledSlider
|
|
9
13
|
from fonticon_mdi6 import MDI6
|
|
10
14
|
import numpy as np
|
|
11
15
|
import json
|
|
@@ -16,7 +20,9 @@ from glob import glob
|
|
|
16
20
|
from matplotlib.cm import tab10
|
|
17
21
|
from celldetective.gui import Styles
|
|
18
22
|
import matplotlib.cm as mcm
|
|
23
|
+
import pandas as pd
|
|
19
24
|
|
|
25
|
+
from lifelines.utils import qth_survival_times
|
|
20
26
|
|
|
21
27
|
class GenericSignalPlotWidget(QWidget, Styles):
|
|
22
28
|
|
|
@@ -136,6 +142,14 @@ class GenericSignalPlotWidget(QWidget, Styles):
|
|
|
136
142
|
plot_buttons_hbox.addWidget(self.export_btn, 5, alignment=Qt.AlignRight)
|
|
137
143
|
self.layout.addLayout(plot_buttons_hbox)
|
|
138
144
|
|
|
145
|
+
self.export_tabular_btn = QPushButton('')
|
|
146
|
+
self.export_tabular_btn.setIcon(icon(MDI6.table,color="black"))
|
|
147
|
+
self.export_tabular_btn.setStyleSheet(self.button_select_all)
|
|
148
|
+
self.export_tabular_btn.setToolTip('Tabulate survival values.')
|
|
149
|
+
self.export_tabular_btn.setIconSize(QSize(20, 20))
|
|
150
|
+
plot_buttons_hbox.addWidget(self.export_tabular_btn, 5, alignment=Qt.AlignRight)
|
|
151
|
+
self.export_tabular_btn.hide()
|
|
152
|
+
|
|
139
153
|
self.ax.set_prop_cycle('color',[self.cmap(i) for i in np.linspace(0, 1, len(self.parent_window.well_indices))])
|
|
140
154
|
|
|
141
155
|
self.fig.set_facecolor('none') # or 'None'
|
|
@@ -671,7 +685,9 @@ class SurvivalPlotWidget(GenericSignalPlotWidget):
|
|
|
671
685
|
self.class_selection_widget.hide()
|
|
672
686
|
self.rescale_widget.hide()
|
|
673
687
|
self.cell_lines_alpha_wdg.hide()
|
|
674
|
-
|
|
688
|
+
self.export_tabular_btn.show()
|
|
689
|
+
self.export_tabular_btn.clicked.connect(self.set_table_options)
|
|
690
|
+
|
|
675
691
|
def switch_to_log(self):
|
|
676
692
|
|
|
677
693
|
"""
|
|
@@ -790,4 +806,147 @@ class SurvivalPlotWidget(GenericSignalPlotWidget):
|
|
|
790
806
|
|
|
791
807
|
# Plot a signal
|
|
792
808
|
if line==line:
|
|
793
|
-
line.plot_survival_function(ci_show=ci_option, ax=self.ax, legend=legend, color=color, label=label, xlabel='timeline [min]')
|
|
809
|
+
line.plot_survival_function(ci_show=ci_option, ax=self.ax, legend=legend, color=color, label=label, xlabel='timeline [min]')
|
|
810
|
+
|
|
811
|
+
def set_table_options(self):
|
|
812
|
+
|
|
813
|
+
self.config_table_wg = QWidget()
|
|
814
|
+
self.config_table_wg.setMinimumWidth(480)
|
|
815
|
+
self.config_table_wg.setWindowTitle('Survival data')
|
|
816
|
+
|
|
817
|
+
layout = QVBoxLayout()
|
|
818
|
+
self.config_table_wg.setLayout(layout)
|
|
819
|
+
|
|
820
|
+
self.all_values_rb = QRadioButton('tabulate all values')
|
|
821
|
+
self.single_timepoint_rb = QRadioButton('survival at single timepoint [min]: ')
|
|
822
|
+
self.ec_rb = QRadioButton(r'EC N% survival: ')
|
|
823
|
+
self.all_values_rb.toggled.connect(self.activate_sliders)
|
|
824
|
+
self.single_timepoint_rb.toggled.connect(self.activate_sliders)
|
|
825
|
+
|
|
826
|
+
self.single_timepoint_slider = QLabeledSlider()
|
|
827
|
+
self.single_timepoint_slider.setRange(0, int(self.df['FRAME'].max()*self.parent_window.FrameToMin))
|
|
828
|
+
self.single_timepoint_slider.setValue(int(self.df['FRAME'].max()*self.parent_window.FrameToMin))
|
|
829
|
+
|
|
830
|
+
self.ec_slider = QLabeledSlider()
|
|
831
|
+
self.ec_slider.setRange(0, 100)
|
|
832
|
+
self.ec_slider.setValue(50)
|
|
833
|
+
|
|
834
|
+
self.ec_rb.toggled.connect(self.activate_sliders)
|
|
835
|
+
self.all_values_rb.click()
|
|
836
|
+
|
|
837
|
+
self.set_btn = QPushButton('Set')
|
|
838
|
+
self.set_btn.setStyleSheet(self.button_style_sheet)
|
|
839
|
+
self.set_btn.clicked.connect(self.assemble_survival_data)
|
|
840
|
+
|
|
841
|
+
layout.addWidget(self.all_values_rb)
|
|
842
|
+
|
|
843
|
+
single_tp_layout = QHBoxLayout()
|
|
844
|
+
single_tp_layout.addWidget(self.single_timepoint_rb, 33)
|
|
845
|
+
single_tp_layout.addWidget(self.single_timepoint_slider, 66)
|
|
846
|
+
layout.addLayout(single_tp_layout)
|
|
847
|
+
|
|
848
|
+
ec_layout = QHBoxLayout()
|
|
849
|
+
ec_layout.addWidget(self.ec_rb, 33)
|
|
850
|
+
ec_layout.addWidget(self.ec_slider, 66)
|
|
851
|
+
layout.addLayout(ec_layout)
|
|
852
|
+
|
|
853
|
+
layout.addWidget(self.set_btn)
|
|
854
|
+
center_window(self.config_table_wg)
|
|
855
|
+
self.config_table_wg.show()
|
|
856
|
+
|
|
857
|
+
def activate_sliders(self):
|
|
858
|
+
if self.all_values_rb.isChecked():
|
|
859
|
+
self.single_timepoint_slider.setEnabled(False)
|
|
860
|
+
self.ec_slider.setEnabled(False)
|
|
861
|
+
elif self.single_timepoint_rb.isChecked():
|
|
862
|
+
self.single_timepoint_slider.setEnabled(True)
|
|
863
|
+
self.ec_slider.setEnabled(False)
|
|
864
|
+
elif self.ec_rb.isChecked():
|
|
865
|
+
self.ec_slider.setEnabled(True)
|
|
866
|
+
self.single_timepoint_slider.setEnabled(False)
|
|
867
|
+
|
|
868
|
+
def assemble_survival_data(self):
|
|
869
|
+
|
|
870
|
+
if self.plot_options[0].isChecked():
|
|
871
|
+
data = self.df_well_info
|
|
872
|
+
groupby = ['well_path']
|
|
873
|
+
if self.plot_options[1].isChecked():
|
|
874
|
+
data = self.df_pos_info
|
|
875
|
+
groupby = ['pos_path']
|
|
876
|
+
if self.plot_options[2].isChecked():
|
|
877
|
+
print('Not implemented yet... Please select "well" or "position" as grouping...')
|
|
878
|
+
return None
|
|
879
|
+
|
|
880
|
+
if self.all_values_rb.isChecked():
|
|
881
|
+
|
|
882
|
+
survival_table = []
|
|
883
|
+
tid=0
|
|
884
|
+
for name,group in data.groupby(groupby):
|
|
885
|
+
print(name)
|
|
886
|
+
if groupby[0]=="pos_path":
|
|
887
|
+
metadata = collect_experiment_metadata(pos_path=name[0])
|
|
888
|
+
elif groupby[0]=="well_path":
|
|
889
|
+
metadata = collect_experiment_metadata(well_path=name[0])
|
|
890
|
+
ks_estimator = group['survival_fit'].values[0]
|
|
891
|
+
if ks_estimator!=ks_estimator:
|
|
892
|
+
continue
|
|
893
|
+
timeline = list(ks_estimator.survival_function_.index)
|
|
894
|
+
survival = ks_estimator.survival_function_['KM_estimate'].values
|
|
895
|
+
lower_error = ks_estimator.confidence_interval_['KM_estimate_lower_0.95'].values
|
|
896
|
+
upper_error = ks_estimator.confidence_interval_['KM_estimate_upper_0.95'].values
|
|
897
|
+
for k in range(len(timeline)):
|
|
898
|
+
dico = metadata.copy()
|
|
899
|
+
dico.update({'TRACK_ID': tid,'FRAME': int(timeline[k] / self.parent_window.FrameToMin),'timeline': timeline[k], 'survival': survival[k], "event_fraction": 1-survival[k], 'KM_estimate_lower_0.95': lower_error[k], 'KM_estimate_upper_0.95': upper_error[k]})
|
|
900
|
+
survival_table.append(dico)
|
|
901
|
+
tid+=1
|
|
902
|
+
|
|
903
|
+
survival_table = pd.DataFrame(survival_table)
|
|
904
|
+
self.table = TableUI(survival_table, f"Survival data", plot_mode="plot_track_signals")
|
|
905
|
+
self.table.show()
|
|
906
|
+
|
|
907
|
+
elif self.single_timepoint_rb.isChecked():
|
|
908
|
+
|
|
909
|
+
survival_table = []
|
|
910
|
+
tid=0
|
|
911
|
+
for name,group in data.groupby(groupby):
|
|
912
|
+
print(name)
|
|
913
|
+
if groupby[0]=="pos_path":
|
|
914
|
+
metadata = collect_experiment_metadata(pos_path=name[0])
|
|
915
|
+
elif groupby[0]=="well_path":
|
|
916
|
+
metadata = collect_experiment_metadata(well_path=name[0])
|
|
917
|
+
ks_estimator = group['survival_fit'].values[0]
|
|
918
|
+
if ks_estimator!=ks_estimator:
|
|
919
|
+
continue
|
|
920
|
+
survival = ks_estimator.survival_function_at_times(self.single_timepoint_slider.value()).values[0]
|
|
921
|
+
dico = metadata.copy()
|
|
922
|
+
dico.update({'timepoint': self.single_timepoint_slider.value(), 'survival': survival, 'event_fraction': 1 - survival})
|
|
923
|
+
survival_table.append(dico)
|
|
924
|
+
tid+=1
|
|
925
|
+
|
|
926
|
+
survival_table = pd.DataFrame(survival_table)
|
|
927
|
+
self.table = TableUI(survival_table, f"Survival data", plot_mode="static")
|
|
928
|
+
self.table.show()
|
|
929
|
+
|
|
930
|
+
elif self.ec_rb.isChecked():
|
|
931
|
+
|
|
932
|
+
survival_table = []
|
|
933
|
+
tid=0
|
|
934
|
+
for name,group in data.groupby(groupby):
|
|
935
|
+
print(name)
|
|
936
|
+
if groupby[0]=="pos_path":
|
|
937
|
+
metadata = collect_experiment_metadata(pos_path=name[0])
|
|
938
|
+
elif groupby[0]=="well_path":
|
|
939
|
+
metadata = collect_experiment_metadata(well_path=name[0])
|
|
940
|
+
ks_estimator = group['survival_fit'].values[0]
|
|
941
|
+
if ks_estimator!=ks_estimator:
|
|
942
|
+
continue
|
|
943
|
+
survival = ks_estimator.survival_function_
|
|
944
|
+
ecN = qth_survival_times(float(self.ec_slider.value())/100.0, survival)
|
|
945
|
+
dico = metadata.copy()
|
|
946
|
+
dico.update({"qth": int(self.ec_slider.value()), f'EC{int(self.ec_slider.value())}% [min]': ecN})
|
|
947
|
+
survival_table.append(dico)
|
|
948
|
+
tid+=1
|
|
949
|
+
|
|
950
|
+
survival_table = pd.DataFrame(survival_table)
|
|
951
|
+
self.table = TableUI(survival_table, f"Survival data", plot_mode="static")
|
|
952
|
+
self.table.show()
|
|
@@ -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
|
|
4
|
-
from PyQt5.QtCore import Qt, QSize
|
|
4
|
+
from PyQt5.QtCore import Qt, QSize, QAbstractTableModel
|
|
5
5
|
from PyQt5.QtGui import QDoubleValidator, QIntValidator
|
|
6
6
|
|
|
7
7
|
from celldetective.gui import Styles
|
|
@@ -16,6 +16,95 @@ from inspect import getmembers, isfunction
|
|
|
16
16
|
from celldetective.filters import *
|
|
17
17
|
from os import sep
|
|
18
18
|
|
|
19
|
+
class PandasModel(QAbstractTableModel):
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
from https://stackoverflow.com/questions/31475965/fastest-way-to-populate-qtableview-from-pandas-data-frame
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, data):
|
|
26
|
+
QAbstractTableModel.__init__(self)
|
|
27
|
+
self._data = data
|
|
28
|
+
self.colors = dict()
|
|
29
|
+
|
|
30
|
+
def rowCount(self, parent=None):
|
|
31
|
+
return self._data.shape[0]
|
|
32
|
+
|
|
33
|
+
def columnCount(self, parent=None):
|
|
34
|
+
return self._data.shape[1]
|
|
35
|
+
|
|
36
|
+
def data(self, index, role=Qt.DisplayRole):
|
|
37
|
+
if index.isValid():
|
|
38
|
+
if role == Qt.DisplayRole:
|
|
39
|
+
return str(self._data.iloc[index.row(), index.column()])
|
|
40
|
+
if role == Qt.BackgroundRole:
|
|
41
|
+
color = self.colors.get((index.row(), index.column()))
|
|
42
|
+
if color is not None:
|
|
43
|
+
return color
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
def headerData(self, rowcol, orientation, role):
|
|
47
|
+
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
|
|
48
|
+
return self._data.columns[rowcol]
|
|
49
|
+
if orientation == Qt.Vertical and role == Qt.DisplayRole:
|
|
50
|
+
return self._data.index[rowcol]
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
def change_color(self, row, column, color):
|
|
54
|
+
ix = self.index(row, column)
|
|
55
|
+
self.colors[(row, column)] = color
|
|
56
|
+
self.dataChanged.emit(ix, ix, (Qt.BackgroundRole,))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class GenericOpColWidget(QWidget, Styles):
|
|
60
|
+
|
|
61
|
+
def __init__(self, parent_window, column=None, title=''):
|
|
62
|
+
|
|
63
|
+
super().__init__()
|
|
64
|
+
|
|
65
|
+
self.parent_window = parent_window
|
|
66
|
+
self.column = column
|
|
67
|
+
self.title = title
|
|
68
|
+
|
|
69
|
+
self.setWindowTitle(self.title)
|
|
70
|
+
# Create the QComboBox and add some items
|
|
71
|
+
|
|
72
|
+
self.layout = QVBoxLayout(self)
|
|
73
|
+
self.layout.setContentsMargins(30,30,30,30)
|
|
74
|
+
|
|
75
|
+
self.sublayout = QVBoxLayout()
|
|
76
|
+
|
|
77
|
+
self.measurements_cb = QComboBox()
|
|
78
|
+
self.measurements_cb.addItems(list(self.parent_window.data.columns))
|
|
79
|
+
if self.column is not None:
|
|
80
|
+
idx = self.measurements_cb.findText(self.column)
|
|
81
|
+
self.measurements_cb.setCurrentIndex(idx)
|
|
82
|
+
|
|
83
|
+
measurement_layout = QHBoxLayout()
|
|
84
|
+
measurement_layout.addWidget(QLabel('measurements: '), 25)
|
|
85
|
+
measurement_layout.addWidget(self.measurements_cb, 75)
|
|
86
|
+
self.sublayout.addLayout(measurement_layout)
|
|
87
|
+
|
|
88
|
+
self.layout.addLayout(self.sublayout)
|
|
89
|
+
|
|
90
|
+
self.submit_btn = QPushButton('Compute')
|
|
91
|
+
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
92
|
+
self.submit_btn.clicked.connect(self.launch_operation)
|
|
93
|
+
self.layout.addWidget(self.submit_btn, 30)
|
|
94
|
+
|
|
95
|
+
self.setAttribute(Qt.WA_DeleteOnClose)
|
|
96
|
+
center_window(self)
|
|
97
|
+
|
|
98
|
+
def launch_operation(self):
|
|
99
|
+
|
|
100
|
+
self.compute()
|
|
101
|
+
self.parent_window.model = PandasModel(self.parent_window.data)
|
|
102
|
+
self.parent_window.table_view.setModel(self.parent_window.model)
|
|
103
|
+
self.close()
|
|
104
|
+
|
|
105
|
+
def compute(self):
|
|
106
|
+
pass
|
|
107
|
+
|
|
19
108
|
|
|
20
109
|
class QuickSliderLayout(QHBoxLayout):
|
|
21
110
|
|
|
@@ -10,7 +10,7 @@ from superqt import QLabeledDoubleSlider
|
|
|
10
10
|
from superqt.fonticon import icon
|
|
11
11
|
from fonticon_mdi6 import MDI6
|
|
12
12
|
|
|
13
|
-
from celldetective.gui.thresholds_gui import ThresholdSpot
|
|
13
|
+
#from celldetective.gui.thresholds_gui import ThresholdSpot
|
|
14
14
|
from celldetective.utils import extract_experiment_channels, get_software_location
|
|
15
15
|
from celldetective.io import load_frames, auto_load_number_of_frames
|
|
16
16
|
from celldetective.measure import compute_haralick_features
|
|
@@ -26,7 +26,7 @@ from tifffile import imread
|
|
|
26
26
|
from pathlib import Path
|
|
27
27
|
import gc
|
|
28
28
|
|
|
29
|
-
from celldetective.gui.viewers import CellEdgeVisualizer
|
|
29
|
+
from celldetective.gui.viewers import CellEdgeVisualizer, SpotDetectionVisualizer
|
|
30
30
|
from celldetective.gui.layouts import ProtocolDesignerLayout, BackgroundFitCorrectionLayout, LocalCorrectionLayout
|
|
31
31
|
from celldetective.gui.gui_utils import ThresholdLineEdit
|
|
32
32
|
from celldetective.gui import Styles
|
|
@@ -951,51 +951,54 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
951
951
|
|
|
952
952
|
layout.addWidget(self.threshold_lbl, 4, 0)
|
|
953
953
|
layout.addWidget(self.threshold_value, 4, 1)
|
|
954
|
-
self.preview_spot = QPushButton('Preview')
|
|
955
|
-
self.preview_spot.clicked.connect(self.spot_preview)
|
|
956
|
-
self.preview_spot.setStyleSheet(self.button_style_sheet_2)
|
|
957
|
-
layout.addWidget(self.preview_spot, 5, 0, 1, 2)
|
|
958
|
-
self.spot_channel.setEnabled(False)
|
|
959
|
-
self.spot_channel_lbl.setEnabled(False)
|
|
960
|
-
self.diameter_value.setEnabled(False)
|
|
961
|
-
self.diameter_lbl.setEnabled(False)
|
|
962
|
-
self.threshold_value.setEnabled(False)
|
|
963
|
-
self.threshold_lbl.setEnabled(False)
|
|
964
|
-
self.preview_spot.setEnabled(False)
|
|
965
954
|
|
|
955
|
+
self.spot_viewer_btn = QPushButton()
|
|
956
|
+
self.spot_viewer_btn.clicked.connect(self.spot_preview)
|
|
957
|
+
self.spot_viewer_btn.setIcon(icon(MDI6.image_check, color="k"))
|
|
958
|
+
self.spot_viewer_btn.setStyleSheet(self.button_select_all)
|
|
959
|
+
self.spot_viewer_btn.setToolTip('Set detection parameters visually.')
|
|
960
|
+
layout.addWidget(self.spot_viewer_btn, 1, 1, 1, 1, alignment=Qt.AlignRight)
|
|
961
|
+
|
|
962
|
+
self.spot_detection_widgets = [self.spot_channel, self.spot_channel_lbl, self.diameter_value, self.diameter_lbl, self.threshold_value, self.threshold_lbl, self.spot_viewer_btn]
|
|
963
|
+
for wg in self.spot_detection_widgets:
|
|
964
|
+
wg.setEnabled(False)
|
|
966
965
|
|
|
967
966
|
def enable_spot_preview(self):
|
|
968
967
|
|
|
969
968
|
diam = self.diameter_value.text().replace(',','').replace('.','')
|
|
970
969
|
thresh = self.threshold_value.text().replace(',','').replace('.','')
|
|
971
970
|
if diam.isnumeric() and thresh.isnumeric():
|
|
972
|
-
self.
|
|
971
|
+
self.spot_viewer_btn.setEnabled(True)
|
|
973
972
|
else:
|
|
974
|
-
self.
|
|
973
|
+
self.spot_viewer_btn.setEnabled(False)
|
|
975
974
|
|
|
976
975
|
def spot_preview(self):
|
|
977
976
|
self.locate_image()
|
|
978
977
|
if self.test_frame is not None:
|
|
979
978
|
self.locate_mask()
|
|
980
979
|
if self.test_mask is not None:
|
|
981
|
-
self.spot_visual =
|
|
982
|
-
|
|
980
|
+
self.spot_visual = SpotDetectionVisualizer(frame_slider=True,
|
|
981
|
+
contrast_slider=True,
|
|
982
|
+
cell_type=self.mode,
|
|
983
|
+
channel_cb=True,
|
|
984
|
+
channel_names = self.channel_names,
|
|
985
|
+
stack_path=self.current_stack,
|
|
986
|
+
n_channels=len(self.channel_names),
|
|
987
|
+
target_channel=self.spot_channel.currentIndex(),
|
|
988
|
+
window_title='Detect spots',
|
|
989
|
+
parent_channel_cb=self.spot_channel,
|
|
990
|
+
parent_diameter_le=self.diameter_value,
|
|
991
|
+
parent_threshold_le=self.threshold_value,
|
|
992
|
+
PxToUm = 1,)
|
|
993
|
+
self.spot_visual.show()
|
|
994
|
+
#self.spot_visual = ThresholdSpot(current_channel=self.spot_channel.currentIndex(), img=self.test_frame,
|
|
995
|
+
# mask=self.test_mask, parent_window=self)
|
|
983
996
|
|
|
984
997
|
def enable_spot_detection(self):
|
|
985
|
-
if self.spot_check.isChecked():
|
|
986
|
-
self.spot_channel.setEnabled(True)
|
|
987
|
-
self.spot_channel_lbl.setEnabled(True)
|
|
988
|
-
self.diameter_value.setEnabled(True)
|
|
989
|
-
self.diameter_lbl.setEnabled(True)
|
|
990
|
-
self.threshold_value.setEnabled(True)
|
|
991
|
-
self.threshold_lbl.setEnabled(True)
|
|
992
|
-
self.preview_spot.setEnabled(True)
|
|
993
998
|
|
|
999
|
+
if self.spot_check.isChecked():
|
|
1000
|
+
for wg in self.spot_detection_widgets:
|
|
1001
|
+
wg.setEnabled(True)
|
|
994
1002
|
else:
|
|
995
|
-
self.
|
|
996
|
-
|
|
997
|
-
self.diameter_value.setEnabled(False)
|
|
998
|
-
self.diameter_lbl.setEnabled(False)
|
|
999
|
-
self.threshold_value.setEnabled(False)
|
|
1000
|
-
self.threshold_lbl.setEnabled(False)
|
|
1001
|
-
self.preview_spot.setEnabled(False)
|
|
1003
|
+
for wg in self.spot_detection_widgets:
|
|
1004
|
+
wg.setEnabled(False)
|
|
@@ -96,7 +96,7 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
96
96
|
main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
|
|
97
97
|
|
|
98
98
|
labels = [QLabel('population: '), QLabel('class: '), QLabel('time of\ninterest: '), QLabel('cmap: ')]
|
|
99
|
-
self.cb_options = [['targets','effectors'],[
|
|
99
|
+
self.cb_options = [['targets','effectors'],[], [], []]
|
|
100
100
|
self.cbs = [QComboBox() for i in range(len(labels))]
|
|
101
101
|
self.cbs[-1] = QColormapComboBox()
|
|
102
102
|
|
|
@@ -183,6 +183,11 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
183
183
|
self.auto_close = True
|
|
184
184
|
return None
|
|
185
185
|
|
|
186
|
+
if 'class' in self.all_columns:
|
|
187
|
+
class_columns.append("class")
|
|
188
|
+
if 't0' in self.all_columns:
|
|
189
|
+
time_columns.append('t0')
|
|
190
|
+
|
|
186
191
|
self.cbs[2].clear()
|
|
187
192
|
self.cbs[2].addItems(np.unique(self.cb_options[2]+time_columns))
|
|
188
193
|
|
|
@@ -339,7 +344,7 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
339
344
|
|
|
340
345
|
for block,movie_group in self.df.groupby(['well','position']):
|
|
341
346
|
|
|
342
|
-
well_signal_mean, well_std_mean, timeline_all, matrix_all = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=
|
|
347
|
+
well_signal_mean, well_std_mean, timeline_all, matrix_all = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=None, return_matrix=True, forced_max_duration=max_time)
|
|
343
348
|
well_signal_event, well_std_event, timeline_event, matrix_event = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=[0], return_matrix=True, forced_max_duration=max_time)
|
|
344
349
|
well_signal_no_event, well_std_no_event, timeline_no_event, matrix_no_event = mean_signal(movie_group, self.feature_selected, class_col, time_col=time_col, class_value=[1], return_matrix=True, forced_max_duration=max_time)
|
|
345
350
|
self.mean_plots_timeline = timeline_all
|
|
@@ -354,7 +359,7 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
354
359
|
# Per well
|
|
355
360
|
for well,well_group in self.df.groupby('well'):
|
|
356
361
|
|
|
357
|
-
well_signal_mean, well_std_mean, timeline_all, matrix_all = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=
|
|
362
|
+
well_signal_mean, well_std_mean, timeline_all, matrix_all = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=None, return_matrix=True, forced_max_duration=max_time)
|
|
358
363
|
well_signal_event, well_std_event, timeline_event, matrix_event = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=[0], return_matrix=True, forced_max_duration=max_time)
|
|
359
364
|
well_signal_no_event, well_std_no_event, timeline_no_event, matrix_no_event = mean_signal(well_group, self.feature_selected, class_col, time_col=time_col, class_value=[1], return_matrix=True, forced_max_duration=max_time)
|
|
360
365
|
|