celldetective 1.1.1.post4__tar.gz → 1.2.0__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.1.1.post4 → celldetective-1.2.0}/PKG-INFO +1 -1
- celldetective-1.2.0/celldetective/__init__.py +3 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/extra_properties.py +62 -34
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/__init__.py +1 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/analyze_block.py +2 -1
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/classifier_widget.py +8 -7
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/control_panel.py +50 -6
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/layouts.py +5 -4
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/neighborhood_options.py +10 -8
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/plot_signals_ui.py +39 -11
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/process_block.py +413 -95
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/retrain_segmentation_model_options.py +17 -4
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/retrain_signal_model_options.py +106 -6
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/signal_annotator.py +25 -5
- celldetective-1.2.0/celldetective/gui/signal_annotator2.py +2708 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/signal_annotator_options.py +3 -1
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/survival_ui.py +15 -6
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/tableUI.py +235 -39
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/io.py +537 -421
- celldetective-1.2.0/celldetective/measure.py +988 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/neighborhood.py +426 -354
- celldetective-1.2.0/celldetective/relative_measurements.py +648 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/scripts/analyze_signals.py +1 -1
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/scripts/measure_cells.py +28 -8
- celldetective-1.2.0/celldetective/scripts/measure_relative.py +103 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/scripts/segment_cells.py +5 -5
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/scripts/track_cells.py +4 -1
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/scripts/train_segmentation_model.py +23 -18
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/scripts/train_signal_model.py +33 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/signals.py +402 -8
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/tracking.py +8 -2
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/utils.py +93 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective.egg-info/PKG-INFO +1 -1
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective.egg-info/SOURCES.txt +4 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/setup.py +1 -1
- celldetective-1.2.0/tests/__init__.py +0 -0
- celldetective-1.1.1.post4/celldetective/__init__.py +0 -2
- celldetective-1.1.1.post4/celldetective/measure.py +0 -1038
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/LICENSE +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/README.md +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/__main__.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/datasets/segmentation_annotations/blank +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/datasets/signal_annotations/blank +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/events.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/filters.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/about.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/btrack_options.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/configure_new_exp.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/gui_utils.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/json_readers.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/measurement_options.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/plot_measurements.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/seg_model_loader.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/styles.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/thresholds_gui.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/gui/viewers.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/icons/logo-large.png +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/icons/logo.png +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/icons/signals_icon.png +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/icons/splash-test.png +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/icons/splash.png +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/icons/splash0.png +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/icons/survival2.png +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/icons/vignette_signals2.png +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/icons/vignette_signals2.svg +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/links/zenodo.json +0 -0
- {celldetective-1.1.1.post4/celldetective/models/segmentation_effectors → celldetective-1.2.0/celldetective/models/pair_signal_detection}/blank +0 -0
- {celldetective-1.1.1.post4/celldetective/models/segmentation_generic → celldetective-1.2.0/celldetective/models/segmentation_effectors}/blank +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/models/segmentation_effectors/primNK_cfse/config_input.json +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/models/segmentation_effectors/primNK_cfse/cp-cfse-transfer +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/models/segmentation_effectors/primNK_cfse/training_instructions.json +0 -0
- {celldetective-1.1.1.post4/celldetective/models/segmentation_targets → celldetective-1.2.0/celldetective/models/segmentation_generic}/blank +0 -0
- {celldetective-1.1.1.post4/celldetective/models/signal_detection → celldetective-1.2.0/celldetective/models/segmentation_targets}/blank +0 -0
- /celldetective-1.1.1.post4/tests/__init__.py → /celldetective-1.2.0/celldetective/models/signal_detection/blank +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/models/tracking_configs/mcf7.json +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/models/tracking_configs/ricm.json +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/models/tracking_configs/ricm2.json +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/preprocessing.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/scripts/segment_cells_thresholds.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective/segmentation.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective.egg-info/dependency_links.txt +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective.egg-info/entry_points.txt +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective.egg-info/not-zip-safe +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective.egg-info/requires.txt +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/celldetective.egg-info/top_level.txt +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/setup.cfg +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_events.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_filters.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_io.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_measure.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_neighborhood.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_preprocessing.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_segmentation.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_signals.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_tracking.py +0 -0
- {celldetective-1.1.1.post4 → celldetective-1.2.0}/tests/test_utils.py +0 -0
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
Copyright © 2022 Laboratoire Adhesion et Inflammation, Authored by Remy Torro,
|
|
3
|
+
Ksenija Dervanova.
|
|
4
|
+
|
|
5
|
+
Add extra properties to measure using regionprops (measure_features).
|
|
6
|
+
The functions must take "regionmask" as the first argument, corresponding
|
|
7
|
+
to the binary mask of each cell of interest generated by regionprops
|
|
8
|
+
and an optional "intensity_image" second argument, i.e. the associated
|
|
9
|
+
multichannel image crop. The measurement will be named after the function
|
|
10
|
+
name. If a function function() has several outputs (e.g. due to a multichannel image),
|
|
11
|
+
they will be labelled with an index as function-0, function-1... A routine
|
|
12
|
+
automatically replacements keywords "intensity-0", "intensity-1" and so on,
|
|
13
|
+
with the actual name of the intensity channel (e.g. "intensity-0" ->
|
|
14
|
+
"brightfield_channel"). Due to this indexing behavior, avoid using digits
|
|
15
|
+
in the function names and prefer text instead: "intensity-99()" -->
|
|
16
|
+
"intensity-ninety-nine()".
|
|
17
|
+
|
|
18
|
+
New functions appear automatically in the ConfigMeasurements widget of the
|
|
19
|
+
GUI.
|
|
5
20
|
|
|
6
21
|
"""
|
|
22
|
+
|
|
7
23
|
import warnings
|
|
8
24
|
|
|
9
25
|
import numpy as np
|
|
10
26
|
from scipy.ndimage import distance_transform_edt, center_of_mass
|
|
11
27
|
from scipy.spatial.distance import euclidean
|
|
12
|
-
|
|
28
|
+
from celldetective.utils import interpolate_nan, contour_of_instance_segmentation
|
|
13
29
|
|
|
14
30
|
# Percentiles
|
|
15
31
|
|
|
@@ -44,6 +60,9 @@ def intensity_nanmean(regionmask, intensity_image):
|
|
|
44
60
|
return np.nanmean(intensity_image[regionmask])
|
|
45
61
|
|
|
46
62
|
def intensity_centre_of_mass_displacement(regionmask, intensity_image):
|
|
63
|
+
|
|
64
|
+
intensity_image = interpolate_nan(intensity_image.copy())
|
|
65
|
+
|
|
47
66
|
y, x = np.mgrid[:regionmask.shape[0], :regionmask.shape[1]]
|
|
48
67
|
xtemp = x.copy()
|
|
49
68
|
ytemp = y.copy()
|
|
@@ -51,60 +70,69 @@ def intensity_centre_of_mass_displacement(regionmask, intensity_image):
|
|
|
51
70
|
centroid_x = intensity_weighted_center[1]
|
|
52
71
|
centroid_y = intensity_weighted_center[0]
|
|
53
72
|
|
|
73
|
+
#centroid_x = np.sum(xtemp * intensity_image) / np.sum(intensity_image)
|
|
54
74
|
geometric_centroid_x = np.sum(xtemp * regionmask) / np.sum(regionmask)
|
|
55
75
|
geometric_centroid_y = np.sum(ytemp * regionmask) / np.sum(regionmask)
|
|
56
|
-
|
|
76
|
+
try:
|
|
77
|
+
distance = euclidean(np.array((geometric_centroid_y, geometric_centroid_x)), np.array((centroid_y, centroid_x)))
|
|
78
|
+
except:
|
|
79
|
+
distance = np.nan
|
|
80
|
+
|
|
57
81
|
delta_x = geometric_centroid_x - centroid_x
|
|
58
82
|
delta_y = geometric_centroid_y - centroid_y
|
|
59
83
|
direction_arctan = np.arctan2(delta_y, delta_x) * 180 / np.pi
|
|
60
84
|
if direction_arctan < 0:
|
|
61
85
|
direction_arctan += 360
|
|
62
|
-
|
|
86
|
+
|
|
87
|
+
return distance, direction_arctan, centroid_x - geometric_centroid_x, centroid_y - geometric_centroid_y
|
|
63
88
|
|
|
64
89
|
def intensity_radial_gradient(regionmask, intensity_image):
|
|
65
|
-
warnings.filterwarnings('ignore', message="Polyfit may be poorly conditioned")
|
|
66
|
-
cell_mask = regionmask.copy()
|
|
67
|
-
intensity = intensity_image.copy()
|
|
68
|
-
y = intensity[cell_mask].flatten()
|
|
69
|
-
x = distance_transform_edt(cell_mask)
|
|
70
|
-
x = x[cell_mask].flatten()
|
|
71
|
-
params = np.polyfit(x, y, 1)
|
|
72
|
-
line = np.poly1d(params)
|
|
73
90
|
|
|
74
|
-
|
|
91
|
+
try:
|
|
92
|
+
warnings.filterwarnings('ignore', message="Polyfit may be poorly conditioned")
|
|
93
|
+
cell_mask = regionmask.copy()
|
|
94
|
+
intensity = intensity_image.copy()
|
|
95
|
+
y = intensity[cell_mask].flatten()
|
|
96
|
+
x = distance_transform_edt(cell_mask)
|
|
97
|
+
x = x[cell_mask].flatten()
|
|
98
|
+
params = np.polyfit(x, y, 1)
|
|
99
|
+
line = np.poly1d(params)
|
|
100
|
+
|
|
101
|
+
return line.coefficients[0], line.coefficients[1]
|
|
102
|
+
except Exception as e:
|
|
103
|
+
print(e)
|
|
104
|
+
return np.nan, np.nan
|
|
75
105
|
|
|
76
106
|
|
|
77
107
|
def intensity_centre_of_mass_displacement_edge(regionmask, intensity_image):
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
thresholded = (edt <= max_distance) * (edt > min_distance)
|
|
82
|
-
edge_mask = np.copy(regionmask)
|
|
83
|
-
edge_mask[np.where(thresholded == 0)] = 0
|
|
84
|
-
y, x = np.mgrid[:edge_mask.shape[0], :edge_mask.shape[1]]
|
|
85
|
-
xtemp = x.copy()
|
|
86
|
-
ytemp = y.copy()
|
|
87
|
-
intensity_edge = intensity_image.copy()
|
|
88
|
-
intensity_edge[np.where(edge_mask == 0)] = 0.
|
|
89
|
-
sum_intensity_edge = np.sum(intensity_edge)
|
|
90
|
-
sum_regionmask = np.sum(regionmask)
|
|
108
|
+
|
|
109
|
+
intensity_image = interpolate_nan(intensity_image.copy())
|
|
110
|
+
edge_mask = contour_of_instance_segmentation(regionmask, 3)
|
|
91
111
|
|
|
92
|
-
if
|
|
93
|
-
|
|
112
|
+
if np.sum(edge_mask)>0:
|
|
113
|
+
|
|
114
|
+
y, x = np.mgrid[:edge_mask.shape[0], :edge_mask.shape[1]]
|
|
94
115
|
xtemp = x.copy()
|
|
95
116
|
ytemp = y.copy()
|
|
96
|
-
intensity_weighted_center = center_of_mass(intensity_image,
|
|
117
|
+
intensity_weighted_center = center_of_mass(intensity_image, edge_mask)
|
|
97
118
|
centroid_x = intensity_weighted_center[1]
|
|
98
119
|
centroid_y = intensity_weighted_center[0]
|
|
99
120
|
|
|
121
|
+
#centroid_x = np.sum(xtemp * intensity_image) / np.sum(intensity_image)
|
|
100
122
|
geometric_centroid_x = np.sum(xtemp * regionmask) / np.sum(regionmask)
|
|
101
123
|
geometric_centroid_y = np.sum(ytemp * regionmask) / np.sum(regionmask)
|
|
102
|
-
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
distance = euclidean(np.array((geometric_centroid_y, geometric_centroid_x)), np.array((centroid_y, centroid_x)))
|
|
127
|
+
except:
|
|
128
|
+
distance = np.nan
|
|
129
|
+
|
|
103
130
|
delta_x = geometric_centroid_x - centroid_x
|
|
104
131
|
delta_y = geometric_centroid_y - centroid_y
|
|
105
132
|
direction_arctan = np.arctan2(delta_y, delta_x) * 180 / np.pi
|
|
106
133
|
if direction_arctan < 0:
|
|
107
134
|
direction_arctan += 360
|
|
108
|
-
|
|
135
|
+
|
|
136
|
+
return distance, direction_arctan, centroid_x - geometric_centroid_x, centroid_y - geometric_centroid_y
|
|
109
137
|
else:
|
|
110
|
-
return np.nan, np.nan
|
|
138
|
+
return np.nan, np.nan, np.nan, np.nan
|
|
@@ -9,6 +9,7 @@ from .survival_ui import ConfigSurvival
|
|
|
9
9
|
from .plot_signals_ui import ConfigSignalPlot
|
|
10
10
|
from .signal_annotator_options import ConfigSignalAnnotator
|
|
11
11
|
from .signal_annotator import SignalAnnotator
|
|
12
|
+
from .signal_annotator2 import SignalAnnotator2
|
|
12
13
|
from .retrain_signal_model_options import ConfigSignalModelTraining
|
|
13
14
|
from .retrain_segmentation_model_options import ConfigSegmentationModelTraining
|
|
14
15
|
from .thresholds_gui import ThresholdConfigWizard
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from PyQt5.QtWidgets import QFrame, QGridLayout, QComboBox,
|
|
1
|
+
from PyQt5.QtWidgets import QFrame, QGridLayout, QComboBox, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QCheckBox, \
|
|
2
|
+
QMessageBox, QSpacerItem, QSizePolicy
|
|
2
3
|
from PyQt5.QtCore import Qt, QSize
|
|
3
4
|
from PyQt5.QtGui import QIcon
|
|
4
5
|
|
|
@@ -375,13 +375,14 @@ class ClassifierWidget(QWidget, Styles):
|
|
|
375
375
|
frames = track['FRAME'].to_numpy()
|
|
376
376
|
t_first = track['t_firstdetection'].to_numpy()[0]
|
|
377
377
|
median_status = np.nanmedian(status_values[frames>=t_first])
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
378
|
+
if median_status==median_status:
|
|
379
|
+
c = ceil(median_status)
|
|
380
|
+
if c==0:
|
|
381
|
+
self.df.loc[indices, self.class_name_user] = 1
|
|
382
|
+
self.df.loc[indices, self.class_name_user.replace('class','t')] = -1
|
|
383
|
+
elif c==1:
|
|
384
|
+
self.df.loc[indices, self.class_name_user] = 2
|
|
385
|
+
self.df.loc[indices, self.class_name_user.replace('class','t')] = -1
|
|
385
386
|
if self.irreversible_event_btn.isChecked():
|
|
386
387
|
self.estimate_time()
|
|
387
388
|
else:
|
|
@@ -3,7 +3,7 @@ from PyQt5.QtWidgets import QMainWindow, QComboBox, QPushButton, QHBoxLayout, QL
|
|
|
3
3
|
from PyQt5.QtCore import Qt, QSize
|
|
4
4
|
from PyQt5.QtGui import QIcon
|
|
5
5
|
from celldetective.gui.gui_utils import center_window, QHSeperationLine
|
|
6
|
-
from celldetective.utils import _extract_labels_from_config, ConfigSectionMap, extract_experiment_channels
|
|
6
|
+
from celldetective.utils import _extract_labels_from_config, ConfigSectionMap, extract_experiment_channels, extract_identity_col
|
|
7
7
|
from celldetective.gui import ConfigEditor, ProcessPanel, PreprocessingPanel, AnalysisPanel, NeighPanel
|
|
8
8
|
from natsort import natsorted
|
|
9
9
|
from glob import glob
|
|
@@ -414,26 +414,46 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
414
414
|
self.pos = self.position_list.currentText()
|
|
415
415
|
panels = [self.ProcessEffectors, self.ProcessTargets]
|
|
416
416
|
if self.position_list.currentText()=="*":
|
|
417
|
+
|
|
417
418
|
for p in panels:
|
|
418
419
|
p.check_seg_btn.setEnabled(False)
|
|
419
420
|
p.check_tracking_result_btn.setEnabled(False)
|
|
421
|
+
|
|
420
422
|
self.ProcessTargets.view_tab_btn.setEnabled(True)
|
|
421
423
|
self.ProcessEffectors.view_tab_btn.setEnabled(True)
|
|
424
|
+
self.NeighPanel.view_tab_btn.setEnabled(True)
|
|
425
|
+
self.ProcessEffectors.signal_analysis_action.setEnabled(True)
|
|
426
|
+
self.ProcessTargets.signal_analysis_action.setEnabled(True)
|
|
427
|
+
|
|
422
428
|
self.ProcessTargets.check_seg_btn.setEnabled(False)
|
|
423
429
|
self.ProcessEffectors.check_seg_btn.setEnabled(False)
|
|
430
|
+
|
|
424
431
|
self.ProcessTargets.check_tracking_result_btn.setEnabled(False)
|
|
425
432
|
self.ProcessEffectors.check_tracking_result_btn.setEnabled(False)
|
|
433
|
+
|
|
426
434
|
self.ProcessEffectors.check_measurements_btn.setEnabled(False)
|
|
427
435
|
self.ProcessTargets.check_measurements_btn.setEnabled(False)
|
|
428
436
|
#self.ProcessTargets.signal_analysis_action.setEnabled(False)
|
|
429
437
|
#self.ProcessEffectors.signal_analysis_action.setEnabled(False)
|
|
438
|
+
|
|
430
439
|
self.ProcessTargets.check_signals_btn.setEnabled(False)
|
|
431
440
|
self.ProcessEffectors.check_signals_btn.setEnabled(False)
|
|
441
|
+
self.NeighPanel.check_signals_btn.setEnabled(False)
|
|
442
|
+
self.ProcessTargets.delete_tracks_btn.hide()
|
|
443
|
+
self.ProcessEffectors.delete_tracks_btn.hide()
|
|
444
|
+
|
|
432
445
|
self.view_stack_btn.setEnabled(False)
|
|
433
446
|
elif self.well_list.currentText()=='*':
|
|
434
447
|
self.ProcessTargets.view_tab_btn.setEnabled(True)
|
|
435
448
|
self.ProcessEffectors.view_tab_btn.setEnabled(True)
|
|
436
|
-
self.
|
|
449
|
+
self.NeighPanel.view_tab_btn.setEnabled(True)
|
|
450
|
+
self.view_stack_btn.setEnabled(False)
|
|
451
|
+
self.ProcessEffectors.signal_analysis_action.setEnabled(True)
|
|
452
|
+
self.ProcessTargets.signal_analysis_action.setEnabled(True)
|
|
453
|
+
|
|
454
|
+
self.delete_tracks_btn.hide()
|
|
455
|
+
self.ProcessTargets.delete_tracks_btn.hide()
|
|
456
|
+
self.ProcessEffectors.delete_tracks_btn.hide()
|
|
437
457
|
else:
|
|
438
458
|
if not self.well_list.currentText()=="*":
|
|
439
459
|
self.locate_selected_position()
|
|
@@ -453,10 +473,16 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
453
473
|
self.ProcessEffectors.check_tracking_result_btn.setEnabled(False)
|
|
454
474
|
|
|
455
475
|
if os.path.exists(os.sep.join([self.pos,'output','tables','trajectories_effectors.csv'])):
|
|
456
|
-
|
|
476
|
+
df = pd.read_csv(os.sep.join([self.pos,'output','tables','trajectories_effectors.csv']), nrows=1)
|
|
477
|
+
id_col = extract_identity_col(df)
|
|
457
478
|
self.ProcessEffectors.check_measurements_btn.setEnabled(True)
|
|
458
|
-
if 'TRACK_ID'
|
|
479
|
+
if id_col=='TRACK_ID':
|
|
459
480
|
self.ProcessEffectors.check_signals_btn.setEnabled(True)
|
|
481
|
+
self.ProcessEffectors.delete_tracks_btn.show()
|
|
482
|
+
self.ProcessEffectors.signal_analysis_action.setEnabled(True)
|
|
483
|
+
else:
|
|
484
|
+
self.ProcessEffectors.signal_analysis_action.setEnabled(False)
|
|
485
|
+
|
|
460
486
|
#self.ProcessEffectors.signal_analysis_action.setEnabled(True)
|
|
461
487
|
self.ProcessEffectors.view_tab_btn.setEnabled(True)
|
|
462
488
|
self.ProcessEffectors.classify_btn.setEnabled(True)
|
|
@@ -466,12 +492,19 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
466
492
|
#self.ProcessEffectors.signal_analysis_action.setEnabled(False)
|
|
467
493
|
self.ProcessEffectors.view_tab_btn.setEnabled(False)
|
|
468
494
|
self.ProcessEffectors.classify_btn.setEnabled(False)
|
|
495
|
+
self.ProcessEffectors.delete_tracks_btn.hide()
|
|
496
|
+
self.ProcessEffectors.signal_analysis_action.setEnabled(False)
|
|
469
497
|
|
|
470
498
|
if os.path.exists(os.sep.join([self.pos,'output','tables','trajectories_targets.csv'])):
|
|
471
|
-
|
|
499
|
+
df = pd.read_csv(os.sep.join([self.pos,'output','tables','trajectories_targets.csv']), nrows=1)
|
|
500
|
+
id_col = extract_identity_col(df)
|
|
472
501
|
self.ProcessTargets.check_measurements_btn.setEnabled(True)
|
|
473
|
-
if 'TRACK_ID'
|
|
502
|
+
if id_col=='TRACK_ID':
|
|
474
503
|
self.ProcessTargets.check_signals_btn.setEnabled(True)
|
|
504
|
+
self.ProcessTargets.signal_analysis_action.setEnabled(True)
|
|
505
|
+
self.ProcessTargets.delete_tracks_btn.show()
|
|
506
|
+
else:
|
|
507
|
+
self.ProcessTargets.signal_analysis_action.setEnabled(False)
|
|
475
508
|
#self.ProcessTargets.signal_analysis_action.setEnabled(True)
|
|
476
509
|
self.ProcessTargets.view_tab_btn.setEnabled(True)
|
|
477
510
|
self.ProcessTargets.classify_btn.setEnabled(True)
|
|
@@ -481,4 +514,15 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
481
514
|
#self.ProcessTargets.signal_analysis_action.setEnabled(False)
|
|
482
515
|
self.ProcessTargets.view_tab_btn.setEnabled(False)
|
|
483
516
|
self.ProcessTargets.classify_btn.setEnabled(False)
|
|
517
|
+
self.ProcessTargets.signal_analysis_action.setEnabled(False)
|
|
518
|
+
self.ProcessTargets.delete_tracks_btn.hide()
|
|
519
|
+
self.ProcessTargets.signal_analysis_action.setEnabled(False)
|
|
520
|
+
|
|
521
|
+
if os.path.exists(os.sep.join([self.pos,'output','tables','trajectories_pairs.csv'])):
|
|
522
|
+
self.NeighPanel.view_tab_btn.setEnabled(True)
|
|
523
|
+
self.NeighPanel.check_signals_btn.setEnabled(True)
|
|
524
|
+
else:
|
|
525
|
+
self.NeighPanel.view_tab_btn.setEnabled(False)
|
|
526
|
+
self.NeighPanel.check_signals_btn.setEnabled(False)
|
|
527
|
+
|
|
484
528
|
|
|
@@ -73,7 +73,7 @@ class ChannelNormGenerator(QVBoxLayout, Styles):
|
|
|
73
73
|
for tab in tables:
|
|
74
74
|
cols = pd.read_csv(tab, nrows=1).columns.tolist()
|
|
75
75
|
all_measurements.extend(cols)
|
|
76
|
-
all_measurements = np.unique(all_measurements)
|
|
76
|
+
all_measurements = np.unique(all_measurements)
|
|
77
77
|
|
|
78
78
|
if self.mode=='signals':
|
|
79
79
|
generic_measurements = ['brightfield_channel', 'live_nuclei_channel', 'dead_nuclei_channel',
|
|
@@ -245,13 +245,14 @@ class ChannelNormGenerator(QVBoxLayout, Styles):
|
|
|
245
245
|
|
|
246
246
|
def check_valid_channels(self):
|
|
247
247
|
|
|
248
|
-
if
|
|
249
|
-
|
|
248
|
+
if hasattr(self.parent_window, "submit_btn"):
|
|
249
|
+
if np.all([cb.currentText()=='--' for cb in self.channel_cbs]):
|
|
250
|
+
self.parent_window.submit_btn.setEnabled(False)
|
|
250
251
|
|
|
251
252
|
if hasattr(self.parent_window, "spatial_calib_le"):
|
|
252
253
|
if self.parent_window.spatial_calib_le.text()!='--':
|
|
253
254
|
self.parent_window.submit_btn.setEnabled(True)
|
|
254
|
-
|
|
255
|
+
elif hasattr(self.parent_window, "submit_btn"):
|
|
255
256
|
self.parent_window.submit_btn.setEnabled(True)
|
|
256
257
|
|
|
257
258
|
|
|
@@ -90,6 +90,8 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
90
90
|
|
|
91
91
|
self.clear_previous_btn = QCheckBox('clear previous neighborhoods')
|
|
92
92
|
self.clear_previous_btn.setToolTip('Clear all previous neighborhood measurements.')
|
|
93
|
+
self.clear_previous_btn.setIcon(icon(MDI6.broom, color='black'))
|
|
94
|
+
|
|
93
95
|
main_layout.addWidget(self.clear_previous_btn, alignment=Qt.AlignRight)
|
|
94
96
|
|
|
95
97
|
main_layout.addWidget(QLabel(''))
|
|
@@ -305,11 +307,13 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
305
307
|
|
|
306
308
|
self.cumulated_presence_btn = QCheckBox('cumulated presence')
|
|
307
309
|
self.cumulated_presence_btn.setToolTip("Compute the cumulated presence time of each neighbor around a reference cell.")
|
|
310
|
+
self.cumulated_presence_btn.setIcon(icon(MDI6.timer_outline, color='black'))
|
|
311
|
+
|
|
308
312
|
layout.addWidget(self.cumulated_presence_btn)
|
|
309
313
|
|
|
310
|
-
self.symmetrize_btn = QCheckBox('symmetrize')
|
|
311
|
-
self.symmetrize_btn.setToolTip("Write the neighborhood of the neighbor cells with respect to the reference cells.")
|
|
312
|
-
layout.addWidget(self.symmetrize_btn)
|
|
314
|
+
# self.symmetrize_btn = QCheckBox('symmetrize')
|
|
315
|
+
# self.symmetrize_btn.setToolTip("Write the neighborhood of the neighbor cells with respect to the reference cells.")
|
|
316
|
+
# layout.addWidget(self.symmetrize_btn)
|
|
313
317
|
|
|
314
318
|
self.fill_cbs_of_neighbor_population()
|
|
315
319
|
self.neighbor_population_cb.currentIndexChanged.connect(self.fill_cbs_of_neighbor_population)
|
|
@@ -424,7 +428,7 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
424
428
|
neighborhood_options.update({'event_time_col': event_time_col})
|
|
425
429
|
|
|
426
430
|
neighborhood_kwargs = {'mode': mode, 'status': status_options, 'not_status_option': [self.not_status_reference, self.not_status_neighbor],
|
|
427
|
-
'compute_cum_sum': self.cumulated_presence_btn.isChecked(), 'attention_weight': True, 'symmetrize':
|
|
431
|
+
'compute_cum_sum': self.cumulated_presence_btn.isChecked(), 'attention_weight': True, 'symmetrize': False,
|
|
428
432
|
'include_dead_weight': True}
|
|
429
433
|
|
|
430
434
|
neighborhood_options.update({'neighborhood_kwargs': neighborhood_kwargs})
|
|
@@ -493,8 +497,6 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
493
497
|
neighborhood_kwargs = neigh_instructions['neighborhood_kwargs']
|
|
494
498
|
if 'compute_cum_sum' in neighborhood_kwargs:
|
|
495
499
|
self.cumulated_presence_btn.setChecked(neighborhood_kwargs['compute_cum_sum'])
|
|
496
|
-
if 'symmetrize' in neighborhood_kwargs:
|
|
497
|
-
self.symmetrize_btn.setChecked(neighborhood_kwargs['symmetrize'])
|
|
498
500
|
if 'status' in neighborhood_kwargs:
|
|
499
501
|
status_options = neighborhood_kwargs['status']
|
|
500
502
|
status_options = ['--' if s is None else s for s in status_options]
|
|
@@ -505,6 +507,6 @@ class ConfigNeighborhoods(QWidget, Styles):
|
|
|
505
507
|
if 'not_status_option' in neighborhood_kwargs:
|
|
506
508
|
not_status_option = neighborhood_kwargs['not_status_option']
|
|
507
509
|
if not_status_option[0]:
|
|
508
|
-
self.
|
|
510
|
+
self.reference_switch_status_btn.click()
|
|
509
511
|
if not_status_option[1]:
|
|
510
|
-
self.
|
|
512
|
+
self.neighbor_switch_status_btn.click()
|
|
@@ -6,7 +6,7 @@ from PyQt5.QtGui import QIcon, QDoubleValidator
|
|
|
6
6
|
from sklearn.preprocessing import MinMaxScaler
|
|
7
7
|
|
|
8
8
|
from celldetective.gui.gui_utils import center_window, FeatureChoice, ListWidget, QHSeperationLine, FigureCanvas, GeometryChoice, OperationChoice
|
|
9
|
-
from superqt import QLabeledSlider
|
|
9
|
+
from superqt import QLabeledSlider, QColormapComboBox
|
|
10
10
|
from superqt.fonticon import icon
|
|
11
11
|
from fonticon_mdi6 import MDI6
|
|
12
12
|
from celldetective.utils import extract_experiment_channels, get_software_location, _extract_labels_from_config
|
|
@@ -33,6 +33,7 @@ from matplotlib.cm import viridis, tab10
|
|
|
33
33
|
import math
|
|
34
34
|
from celldetective.gui import Styles
|
|
35
35
|
from matplotlib import colormaps
|
|
36
|
+
import matplotlib.cm as mcm
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
|
|
@@ -117,9 +118,11 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
117
118
|
""")
|
|
118
119
|
main_layout.addWidget(panel_title, alignment=Qt.AlignCenter)
|
|
119
120
|
|
|
120
|
-
labels = [QLabel('population: '), QLabel('class: '), QLabel('time of\ninterest: ')]
|
|
121
|
-
self.cb_options = [['targets','effectors'],['class'], ['t0']]
|
|
121
|
+
labels = [QLabel('population: '), QLabel('class: '), QLabel('time of\ninterest: '), QLabel('cmap: ')]
|
|
122
|
+
self.cb_options = [['targets','effectors'],['class'], ['t0'], list(plt.colormaps())]
|
|
122
123
|
self.cbs = [QComboBox() for i in range(len(labels))]
|
|
124
|
+
self.cbs[-1] = QColormapComboBox()
|
|
125
|
+
|
|
123
126
|
self.cbs[0].currentIndexChanged.connect(self.set_classes_and_times)
|
|
124
127
|
|
|
125
128
|
choice_layout = QVBoxLayout()
|
|
@@ -128,9 +131,15 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
128
131
|
hbox = QHBoxLayout()
|
|
129
132
|
hbox.addWidget(labels[i], 33)
|
|
130
133
|
hbox.addWidget(self.cbs[i],66)
|
|
131
|
-
|
|
134
|
+
if i < len(labels)-1:
|
|
135
|
+
self.cbs[i].addItems(self.cb_options[i])
|
|
132
136
|
choice_layout.addLayout(hbox)
|
|
133
|
-
|
|
137
|
+
|
|
138
|
+
for cm in list(colormaps):
|
|
139
|
+
try:
|
|
140
|
+
self.cbs[-1].addColormap(cm)
|
|
141
|
+
except:
|
|
142
|
+
pass
|
|
134
143
|
|
|
135
144
|
self.cbs[0].setCurrentIndex(1)
|
|
136
145
|
self.cbs[0].setCurrentIndex(0)
|
|
@@ -150,6 +159,11 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
150
159
|
|
|
151
160
|
self.abs_time_checkbox.stateChanged.connect(self.switch_ref_time_mode)
|
|
152
161
|
|
|
162
|
+
select_layout = QHBoxLayout()
|
|
163
|
+
select_layout.addWidget(QLabel('select cells\nwith query: '), 33)
|
|
164
|
+
self.query_le = QLineEdit()
|
|
165
|
+
select_layout.addWidget(self.query_le, 66)
|
|
166
|
+
main_layout.addLayout(select_layout)
|
|
153
167
|
|
|
154
168
|
time_calib_layout = QHBoxLayout()
|
|
155
169
|
time_calib_layout.setContentsMargins(20,20,20,20)
|
|
@@ -266,9 +280,18 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
266
280
|
self.feature_two_cb.setEnabled(True)
|
|
267
281
|
else:
|
|
268
282
|
self.feature_two_cb.setEnabled(False)
|
|
283
|
+
|
|
269
284
|
def compute_signals(self):
|
|
270
285
|
|
|
271
286
|
if self.df is not None:
|
|
287
|
+
|
|
288
|
+
try:
|
|
289
|
+
query_text = self.query_le.text()
|
|
290
|
+
if query_text != '':
|
|
291
|
+
self.df = self.df.query(query_text)
|
|
292
|
+
except Exception as e:
|
|
293
|
+
print(e, ' The query is misunderstood and will not be applied...')
|
|
294
|
+
|
|
272
295
|
self.feature_selected = self.feature_cb.currentText()
|
|
273
296
|
if self.checkBox_feature.isChecked():
|
|
274
297
|
self.second_feature_selected=self.feature_two_cb.currentText()
|
|
@@ -334,6 +357,10 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
334
357
|
self.initialize_axis()
|
|
335
358
|
plt.tight_layout()
|
|
336
359
|
|
|
360
|
+
cmap_lbl = self.cbs[-1].currentText()
|
|
361
|
+
self.cmap = getattr(mcm, cmap_lbl)
|
|
362
|
+
self.ax.set_prop_cycle('color',[self.cmap(i) for i in np.linspace(0, 1, len(self.well_indices))])
|
|
363
|
+
|
|
337
364
|
|
|
338
365
|
self.fig.set_facecolor('none') # or 'None'
|
|
339
366
|
self.fig.canvas.setStyleSheet("background-color: transparent;")
|
|
@@ -353,7 +380,6 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
353
380
|
radio_hbox.addWidget(self.plot_options[i], 33, alignment=Qt.AlignCenter)
|
|
354
381
|
self.plot_btn_group.buttonClicked[int].connect(self.plot_survivals)
|
|
355
382
|
|
|
356
|
-
print(self.well_indices, self.position_indices)
|
|
357
383
|
if self.position_indices is not None:
|
|
358
384
|
if len(self.well_indices)>1 and len(self.position_indices)==1:
|
|
359
385
|
self.plot_btn_group.buttons()[0].click()
|
|
@@ -725,10 +751,10 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
725
751
|
second_matrix='second_matrix_no_event'
|
|
726
752
|
|
|
727
753
|
|
|
728
|
-
colors = np.array([
|
|
754
|
+
colors = np.array([self.cmap(i / len(self.df_pos_info)) for i in range(len(self.df_pos_info))])
|
|
729
755
|
if self.checkBox_feature.isChecked():
|
|
730
|
-
second_colors =
|
|
731
|
-
well_color = [
|
|
756
|
+
second_colors = self.cmap(np.linspace(0.5, 1.5, len(self.df_pos_info)))
|
|
757
|
+
well_color = [self.cmap(i / len(self.df_well_info)) for i in range(len(self.df_well_info))]
|
|
732
758
|
|
|
733
759
|
if self.plot_mode=='pos':
|
|
734
760
|
self.initialize_axis()
|
|
@@ -801,6 +827,8 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
801
827
|
self.survival_window.canvas.draw()
|
|
802
828
|
|
|
803
829
|
def plot_line(self, line, color, label, mean_signal, ci_option=True, cell_lines_option=False, alpha_ci=0.5, alpha_cell_lines=0.5, std_signal=None, matrix=None):
|
|
830
|
+
|
|
831
|
+
|
|
804
832
|
try:
|
|
805
833
|
if 'second' in str(mean_signal):
|
|
806
834
|
self.ax2.plot(line['timeline'] * self.FrameToMin, line[mean_signal], color=color, label=label)
|
|
@@ -1005,10 +1033,10 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
1005
1033
|
def switch_ref_time_mode(self):
|
|
1006
1034
|
if self.abs_time_checkbox.isChecked():
|
|
1007
1035
|
self.frame_slider.setEnabled(True)
|
|
1008
|
-
self.cbs[-
|
|
1036
|
+
self.cbs[-2].setEnabled(False)
|
|
1009
1037
|
else:
|
|
1010
1038
|
self.frame_slider.setEnabled(False)
|
|
1011
|
-
self.cbs[-
|
|
1039
|
+
self.cbs[-2].setEnabled(True)
|
|
1012
1040
|
|
|
1013
1041
|
def switch_ci(self):
|
|
1014
1042
|
|