celldetective 1.3.8.post1__py3-none-any.whl → 1.3.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- celldetective/_version.py +1 -1
- celldetective/extra_properties.py +113 -17
- celldetective/filters.py +12 -12
- celldetective/gui/btrack_options.py +1 -1
- celldetective/gui/control_panel.py +1 -1
- celldetective/gui/gui_utils.py +4 -4
- celldetective/gui/measurement_options.py +1 -1
- celldetective/gui/plot_signals_ui.py +23 -6
- celldetective/gui/process_block.py +1 -1
- celldetective/gui/processes/measure_cells.py +4 -4
- celldetective/gui/processes/segment_cells.py +3 -3
- celldetective/gui/processes/track_cells.py +4 -4
- celldetective/gui/signal_annotator.py +26 -6
- celldetective/gui/signal_annotator2.py +1 -1
- celldetective/gui/signal_annotator_options.py +1 -1
- celldetective/gui/survival_ui.py +4 -1
- celldetective/gui/thresholds_gui.py +6 -5
- celldetective/io.py +1 -44
- celldetective/measure.py +22 -16
- celldetective/regionprops/__init__.py +1 -0
- celldetective/regionprops/_regionprops.py +310 -0
- celldetective/regionprops/props.json +63 -0
- celldetective/scripts/measure_relative.py +2 -20
- celldetective/segmentation.py +14 -4
- celldetective/utils.py +182 -171
- {celldetective-1.3.8.post1.dist-info → celldetective-1.3.9.dist-info}/METADATA +1 -1
- {celldetective-1.3.8.post1.dist-info → celldetective-1.3.9.dist-info}/RECORD +31 -28
- {celldetective-1.3.8.post1.dist-info → celldetective-1.3.9.dist-info}/LICENSE +0 -0
- {celldetective-1.3.8.post1.dist-info → celldetective-1.3.9.dist-info}/WHEEL +0 -0
- {celldetective-1.3.8.post1.dist-info → celldetective-1.3.9.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.8.post1.dist-info → celldetective-1.3.9.dist-info}/top_level.txt +0 -0
celldetective/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.3.
|
|
1
|
+
__version__ = "1.3.9"
|
|
@@ -26,29 +26,125 @@ import numpy as np
|
|
|
26
26
|
from scipy.ndimage import distance_transform_edt, center_of_mass
|
|
27
27
|
from scipy.spatial.distance import euclidean
|
|
28
28
|
from celldetective.utils import interpolate_nan, contour_of_instance_segmentation
|
|
29
|
+
import skimage.measure as skm
|
|
30
|
+
from stardist import fill_label_holes
|
|
31
|
+
from celldetective.segmentation import segment_frame_from_thresholds
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# def area_detected_in_ricm(regionmask, intensity_image, target_channel='adhesion_channel'):
|
|
35
|
+
|
|
36
|
+
# instructions = {
|
|
37
|
+
# "thresholds": [
|
|
38
|
+
# 0.02,
|
|
39
|
+
# 1000
|
|
40
|
+
# ],
|
|
41
|
+
# "filters": [
|
|
42
|
+
# [
|
|
43
|
+
# "subtract",
|
|
44
|
+
# 1
|
|
45
|
+
# ],
|
|
46
|
+
# [
|
|
47
|
+
# "abs",
|
|
48
|
+
# 2
|
|
49
|
+
# ],
|
|
50
|
+
# [
|
|
51
|
+
# "gauss",
|
|
52
|
+
# 0.8
|
|
53
|
+
# ]
|
|
54
|
+
# ],
|
|
55
|
+
# #"marker_min_distance": 1,
|
|
56
|
+
# #"marker_footprint_size": 10,
|
|
57
|
+
# "feature_queries": [
|
|
58
|
+
# "eccentricity > 0.99 or area < 60"
|
|
59
|
+
# ],
|
|
60
|
+
# }
|
|
61
|
+
|
|
62
|
+
# lbl = segment_frame_from_thresholds(intensity_image, fill_holes=True, do_watershed=False, equalize_reference=None, edge_exclusion=False, **instructions)
|
|
63
|
+
# lbl[lbl>0] = 1 # instance to binary
|
|
64
|
+
# lbl[~regionmask] = 0 # make sure we don't measure stuff outside cell
|
|
65
|
+
|
|
66
|
+
# return np.sum(lbl)
|
|
67
|
+
|
|
68
|
+
def fraction_of_area_detected_in_ricm(regionmask, intensity_image, target_channel='adhesion_channel'):
|
|
69
|
+
|
|
70
|
+
instructions = {
|
|
71
|
+
"thresholds": [
|
|
72
|
+
0.02,
|
|
73
|
+
1000
|
|
74
|
+
],
|
|
75
|
+
"filters": [
|
|
76
|
+
[
|
|
77
|
+
"subtract",
|
|
78
|
+
1
|
|
79
|
+
],
|
|
80
|
+
[
|
|
81
|
+
"abs",
|
|
82
|
+
2
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
"gauss",
|
|
86
|
+
0.8
|
|
87
|
+
]
|
|
88
|
+
],
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
lbl = segment_frame_from_thresholds(intensity_image, do_watershed=False, fill_holes=True, equalize_reference=None, edge_exclusion=False, **instructions)
|
|
92
|
+
lbl[lbl>0] = 1 # instance to binary
|
|
93
|
+
lbl[~regionmask] = 0 # make sure we don't measure stuff outside cell
|
|
94
|
+
|
|
95
|
+
return float(np.sum(lbl)) / float(np.sum(regionmask))
|
|
96
|
+
|
|
97
|
+
def area_detected_in_ricm(regionmask, intensity_image, target_channel='adhesion_channel'):
|
|
98
|
+
|
|
99
|
+
instructions = {
|
|
100
|
+
"thresholds": [
|
|
101
|
+
0.02,
|
|
102
|
+
1000
|
|
103
|
+
],
|
|
104
|
+
"filters": [
|
|
105
|
+
[
|
|
106
|
+
"subtract",
|
|
107
|
+
1
|
|
108
|
+
],
|
|
109
|
+
[
|
|
110
|
+
"abs",
|
|
111
|
+
2
|
|
112
|
+
],
|
|
113
|
+
[
|
|
114
|
+
"gauss",
|
|
115
|
+
0.8
|
|
116
|
+
]
|
|
117
|
+
],
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
lbl = segment_frame_from_thresholds(intensity_image, do_watershed=False, fill_holes=True, equalize_reference=None, edge_exclusion=False, **instructions)
|
|
121
|
+
lbl[lbl>0] = 1 # instance to binary
|
|
122
|
+
lbl[~regionmask] = 0 # make sure we don't measure stuff outside cell
|
|
123
|
+
|
|
124
|
+
return float(np.sum(lbl))
|
|
29
125
|
|
|
30
|
-
# Percentiles
|
|
31
|
-
|
|
32
|
-
def custom_area(regionmask):
|
|
33
|
-
return np.sum(regionmask)
|
|
34
126
|
|
|
35
|
-
def
|
|
127
|
+
def area_dark(regionmask, intensity_image, target_channel='adhesion_channel', fill_holes=True): #, target_channel='adhesion_channel'
|
|
36
128
|
|
|
37
|
-
subregion =
|
|
38
|
-
if
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
129
|
+
subregion = (intensity_image < 0.95)*regionmask # under one, under 0.8, under 0.6, whatever value!
|
|
130
|
+
if fill_holes:
|
|
131
|
+
subregion = skm.label(subregion, connectivity=2, background=0)
|
|
132
|
+
subregion = fill_label_holes(subregion)
|
|
133
|
+
subregion[subregion>0] = 1
|
|
134
|
+
|
|
135
|
+
return float(np.sum(subregion))
|
|
42
136
|
|
|
43
|
-
def intensity_fraction_of_area_under_one(regionmask, intensity_image):
|
|
44
137
|
|
|
45
|
-
|
|
46
|
-
|
|
138
|
+
def fraction_of_area_dark(regionmask, intensity_image, target_channel='adhesion_channel', fill_holes=True): #, target_channel='adhesion_channel'
|
|
139
|
+
|
|
140
|
+
subregion = (intensity_image < 0.95)*regionmask # under one, under 0.8, under 0.6, whatever value!
|
|
141
|
+
if fill_holes:
|
|
142
|
+
subregion = skm.label(subregion, connectivity=2, background=0)
|
|
143
|
+
subregion = fill_label_holes(subregion)
|
|
144
|
+
subregion[subregion>0] = 1
|
|
145
|
+
|
|
146
|
+
return float(np.sum(subregion)) / float(np.sum(regionmask))
|
|
47
147
|
|
|
48
|
-
if len(subregion) > 0:
|
|
49
|
-
return float(np.sum(subregion)) / float(area)
|
|
50
|
-
else:
|
|
51
|
-
return 0.0
|
|
52
148
|
|
|
53
149
|
def intensity_percentile_ninety_nine(regionmask, intensity_image):
|
|
54
150
|
return np.nanpercentile(intensity_image[regionmask],99)
|
celldetective/filters.py
CHANGED
|
@@ -5,14 +5,14 @@ import numpy as np
|
|
|
5
5
|
|
|
6
6
|
def gauss_filter(img, sigma, interpolate=True, *kwargs):
|
|
7
7
|
|
|
8
|
-
if interpolate:
|
|
8
|
+
if np.any(img!=img) and interpolate:
|
|
9
9
|
img = interpolate_nan(img.astype(float))
|
|
10
10
|
|
|
11
11
|
return snd.gaussian_filter(img.astype(float), sigma, *kwargs)
|
|
12
12
|
|
|
13
13
|
def median_filter(img, size, interpolate=True, *kwargs):
|
|
14
14
|
|
|
15
|
-
if interpolate:
|
|
15
|
+
if np.any(img!=img) and interpolate:
|
|
16
16
|
img = interpolate_nan(img.astype(float))
|
|
17
17
|
|
|
18
18
|
size = int(size)
|
|
@@ -20,19 +20,19 @@ def median_filter(img, size, interpolate=True, *kwargs):
|
|
|
20
20
|
return snd.median_filter(img, size, *kwargs)
|
|
21
21
|
|
|
22
22
|
def maximum_filter(img, size, interpolate=True, *kwargs):
|
|
23
|
-
if interpolate:
|
|
23
|
+
if np.any(img!=img) and interpolate:
|
|
24
24
|
img = interpolate_nan(img.astype(float))
|
|
25
25
|
|
|
26
26
|
return snd.maximum_filter(img.astype(float), size, *kwargs)
|
|
27
27
|
|
|
28
28
|
def minimum_filter(img, size, interpolate=True, *kwargs):
|
|
29
|
-
if interpolate:
|
|
29
|
+
if np.any(img!=img) and interpolate:
|
|
30
30
|
img = interpolate_nan(img.astype(float))
|
|
31
31
|
|
|
32
32
|
return snd.minimum_filter(img.astype(float), size, *kwargs)
|
|
33
33
|
|
|
34
34
|
def percentile_filter(img, percentile, size, interpolate=True, *kwargs):
|
|
35
|
-
if interpolate:
|
|
35
|
+
if np.any(img!=img) and interpolate:
|
|
36
36
|
img = interpolate_nan(img.astype(float))
|
|
37
37
|
|
|
38
38
|
return snd.percentile_filter(img.astype(float), percentile, size, *kwargs)
|
|
@@ -44,7 +44,7 @@ def abs_filter(img, *kwargs):
|
|
|
44
44
|
return np.abs(img)
|
|
45
45
|
|
|
46
46
|
def ln_filter(img, interpolate=True, *kwargs):
|
|
47
|
-
if interpolate:
|
|
47
|
+
if np.any(img!=img) and interpolate:
|
|
48
48
|
img = interpolate_nan(img.astype(float))
|
|
49
49
|
|
|
50
50
|
img[np.where(img>0.)] = np.log(img[np.where(img>0.)])
|
|
@@ -54,7 +54,7 @@ def ln_filter(img, interpolate=True, *kwargs):
|
|
|
54
54
|
|
|
55
55
|
def variance_filter(img, size, interpolate=True):
|
|
56
56
|
|
|
57
|
-
if interpolate:
|
|
57
|
+
if np.any(img!=img) and interpolate:
|
|
58
58
|
img = interpolate_nan(img.astype(float))
|
|
59
59
|
|
|
60
60
|
size = int(size)
|
|
@@ -67,7 +67,7 @@ def variance_filter(img, size, interpolate=True):
|
|
|
67
67
|
|
|
68
68
|
def std_filter(img, size, interpolate=True):
|
|
69
69
|
|
|
70
|
-
if interpolate:
|
|
70
|
+
if np.any(img!=img) and interpolate:
|
|
71
71
|
img = interpolate_nan(img.astype(float))
|
|
72
72
|
|
|
73
73
|
size = int(size)
|
|
@@ -84,13 +84,13 @@ def std_filter(img, size, interpolate=True):
|
|
|
84
84
|
return img
|
|
85
85
|
|
|
86
86
|
def laplace_filter(img, output=float, interpolate=True, *kwargs):
|
|
87
|
-
if interpolate:
|
|
87
|
+
if np.any(img!=img) and interpolate:
|
|
88
88
|
img = interpolate_nan(img.astype(float))
|
|
89
89
|
return snd.laplace(img.astype(float), *kwargs)
|
|
90
90
|
|
|
91
91
|
def dog_filter(img, blob_size=None, sigma_low=1, sigma_high=2, interpolate=True, *kwargs):
|
|
92
92
|
|
|
93
|
-
if interpolate:
|
|
93
|
+
if np.any(img!=img) and interpolate:
|
|
94
94
|
img = interpolate_nan(img.astype(float))
|
|
95
95
|
if blob_size is not None:
|
|
96
96
|
sigma_low = 1.0 / (1.0 + np.sqrt(2)) * blob_size
|
|
@@ -121,7 +121,7 @@ def sauvola_filter(img, *kwargs):
|
|
|
121
121
|
|
|
122
122
|
def log_filter(img, blob_size=None, sigma=1, interpolate=True, *kwargs):
|
|
123
123
|
|
|
124
|
-
if interpolate:
|
|
124
|
+
if np.any(img!=img) and interpolate:
|
|
125
125
|
img = interpolate_nan(img.astype(float))
|
|
126
126
|
if blob_size is not None:
|
|
127
127
|
sigma_low = 1.0 / (1.0 + np.sqrt(2)) * blob_size
|
|
@@ -131,7 +131,7 @@ def log_filter(img, blob_size=None, sigma=1, interpolate=True, *kwargs):
|
|
|
131
131
|
|
|
132
132
|
def tophat_filter(img, size, connectivity=4, interpolate=True, *kwargs):
|
|
133
133
|
|
|
134
|
-
if interpolate:
|
|
134
|
+
if np.any(img!=img) and interpolate:
|
|
135
135
|
img = interpolate_nan(img.astype(float))
|
|
136
136
|
structure = snd.generate_binary_structure(rank=2, connectivity=connectivity)
|
|
137
137
|
img = snd.white_tophat(img.astype(float), structure=structure, size=size, *kwargs)
|
|
@@ -44,7 +44,7 @@ class ConfigTracking(QMainWindow, Styles):
|
|
|
44
44
|
|
|
45
45
|
exp_config = self.exp_dir +"config.ini"
|
|
46
46
|
self.config_path = self.exp_dir + self.config_name
|
|
47
|
-
self.channel_names, self.channels = extract_experiment_channels(
|
|
47
|
+
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
48
48
|
self.channel_names = np.array(self.channel_names)
|
|
49
49
|
self.channels = np.array(self.channels)
|
|
50
50
|
self.screen_height = self.parent_window.parent_window.parent_window.screen_height
|
|
@@ -330,7 +330,7 @@ class ControlPanel(QMainWindow, Styles):
|
|
|
330
330
|
self.movie_prefix = ConfigSectionMap(self.exp_config,"MovieSettings")["movie_prefix"]
|
|
331
331
|
|
|
332
332
|
# Read channels
|
|
333
|
-
self.exp_channels, channel_indices = extract_experiment_channels(self.
|
|
333
|
+
self.exp_channels, channel_indices = extract_experiment_channels(self.exp_dir)
|
|
334
334
|
self.nbr_channels = len(self.exp_channels)
|
|
335
335
|
|
|
336
336
|
number_of_wells = len(self.wells)
|
celldetective/gui/gui_utils.py
CHANGED
|
@@ -575,10 +575,10 @@ class FeatureChoice(QWidget, Styles):
|
|
|
575
575
|
"intensity_min",
|
|
576
576
|
]
|
|
577
577
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
578
|
+
members = getmembers(extra_properties, isfunction)
|
|
579
|
+
for o in members:
|
|
580
|
+
if isfunction(o[1]) and o[1].__module__=="celldetective.extra_properties":
|
|
581
|
+
standard_measurements.append(o[0])
|
|
582
582
|
|
|
583
583
|
self.combo_box.addItems(standard_measurements)
|
|
584
584
|
|
|
@@ -58,7 +58,7 @@ class ConfigMeasurements(QMainWindow, Styles):
|
|
|
58
58
|
|
|
59
59
|
exp_config = self.exp_dir + "config.ini"
|
|
60
60
|
self.config_path = self.exp_dir + self.config_name
|
|
61
|
-
self.channel_names, self.channels = extract_experiment_channels(
|
|
61
|
+
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
62
62
|
self.channel_names = np.array(self.channel_names)
|
|
63
63
|
self.channels = np.array(self.channels)
|
|
64
64
|
|
|
@@ -164,6 +164,18 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
164
164
|
pool_layout.addWidget(self.pool_option_cb, 66)
|
|
165
165
|
main_layout.addLayout(pool_layout)
|
|
166
166
|
|
|
167
|
+
n_cells_layout = QHBoxLayout()
|
|
168
|
+
n_cells_layout.setContentsMargins(20,3,20,3)
|
|
169
|
+
self.n_cells_slider = QLabeledSlider()
|
|
170
|
+
self.n_cells_slider.setSingleStep(1)
|
|
171
|
+
self.n_cells_slider.setOrientation(1)
|
|
172
|
+
self.n_cells_slider.setRange(1,100)
|
|
173
|
+
self.n_cells_slider.setValue(2)
|
|
174
|
+
n_cells_layout.addWidget(QLabel('min # cells\nfor pool:'), 33)
|
|
175
|
+
n_cells_layout.addWidget(self.n_cells_slider, 66)
|
|
176
|
+
main_layout.addLayout(n_cells_layout)
|
|
177
|
+
|
|
178
|
+
|
|
167
179
|
self.submit_btn = QPushButton('Submit')
|
|
168
180
|
self.submit_btn.setStyleSheet(self.button_style_sheet)
|
|
169
181
|
self.submit_btn.clicked.connect(self.process_signal)
|
|
@@ -363,6 +375,11 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
363
375
|
return None
|
|
364
376
|
|
|
365
377
|
# Per position signal
|
|
378
|
+
self.df = self.df.dropna(subset=['FRAME'])
|
|
379
|
+
if len(self.df)==0:
|
|
380
|
+
print('Warning... The dataset is empty. Please check your filters. Abort...')
|
|
381
|
+
return None
|
|
382
|
+
|
|
366
383
|
max_time = int(self.df.FRAME.max()) + 1
|
|
367
384
|
class_col = self.class_columns[self.cbs[1].currentIndex()]
|
|
368
385
|
time_col = self.time_columns[self.cbs[2].currentIndex()]
|
|
@@ -371,9 +388,9 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
371
388
|
|
|
372
389
|
for block,movie_group in self.df.groupby(['well','position']):
|
|
373
390
|
|
|
374
|
-
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, projection=self.pool_option_cb.currentText())
|
|
375
|
-
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, projection=self.pool_option_cb.currentText())
|
|
376
|
-
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, projection=self.pool_option_cb.currentText())
|
|
391
|
+
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, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
|
|
392
|
+
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, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
|
|
393
|
+
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, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
|
|
377
394
|
self.mean_plots_timeline = timeline_all
|
|
378
395
|
|
|
379
396
|
self.df_pos_info.loc[self.df_pos_info['pos_path'] == block[1], 'signal'] = [
|
|
@@ -386,9 +403,9 @@ class ConfigSignalPlot(QWidget, Styles):
|
|
|
386
403
|
# Per well
|
|
387
404
|
for well,well_group in self.df.groupby('well'):
|
|
388
405
|
|
|
389
|
-
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, projection=self.pool_option_cb.currentText())
|
|
390
|
-
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, projection=self.pool_option_cb.currentText())
|
|
391
|
-
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, projection=self.pool_option_cb.currentText())
|
|
406
|
+
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, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
|
|
407
|
+
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, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
|
|
408
|
+
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, projection=self.pool_option_cb.currentText(), min_nbr_values=self.n_cells_slider.value())
|
|
392
409
|
|
|
393
410
|
self.df_well_info.loc[self.df_well_info['well_path']==well,'signal'] = [{'mean_all': well_signal_mean, 'std_all': well_std_mean,'matrix_all': matrix_all,'mean_event': well_signal_event, 'std_event': well_std_event,
|
|
394
411
|
'matrix_event': matrix_event,'mean_no_event': well_signal_no_event, 'std_no_event': well_std_no_event, 'matrix_no_event': matrix_no_event, 'timeline': self.mean_plots_timeline}]
|
|
@@ -1503,7 +1503,7 @@ class PreprocessingPanel(QFrame, Styles):
|
|
|
1503
1503
|
self.exp_dir = self.parent_window.exp_dir
|
|
1504
1504
|
self.wells = np.array(self.parent_window.wells,dtype=str)
|
|
1505
1505
|
exp_config = self.exp_dir + "config.ini"
|
|
1506
|
-
self.channel_names, self.channels = extract_experiment_channels(
|
|
1506
|
+
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
1507
1507
|
self.channel_names = np.array(self.channel_names)
|
|
1508
1508
|
self.background_correction = []
|
|
1509
1509
|
self.onlyFloat = QDoubleValidator()
|
|
@@ -75,7 +75,7 @@ class MeasurementProcess(Process):
|
|
|
75
75
|
def read_measurement_instructions(self):
|
|
76
76
|
|
|
77
77
|
print('Looking for measurement instruction file...')
|
|
78
|
-
instr_path = PurePath(self.
|
|
78
|
+
instr_path = PurePath(self.exp_dir,Path(f"{self.instruction_file}"))
|
|
79
79
|
if os.path.exists(instr_path):
|
|
80
80
|
with open(instr_path, 'r') as f:
|
|
81
81
|
self.instructions = json.load(f)
|
|
@@ -175,14 +175,14 @@ class MeasurementProcess(Process):
|
|
|
175
175
|
self.shape_x = int(ConfigSectionMap(self.config,"MovieSettings")["shape_x"])
|
|
176
176
|
self.shape_y = int(ConfigSectionMap(self.config,"MovieSettings")["shape_y"])
|
|
177
177
|
|
|
178
|
-
self.channel_names, self.channel_indices = extract_experiment_channels(self.
|
|
178
|
+
self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
|
|
179
179
|
self.nbr_channels = len(self.channel_names)
|
|
180
180
|
|
|
181
181
|
def locate_experiment_config(self):
|
|
182
182
|
|
|
183
183
|
parent1 = Path(self.pos).parent
|
|
184
|
-
self.
|
|
185
|
-
self.config = PurePath(self.
|
|
184
|
+
self.exp_dir = parent1.parent
|
|
185
|
+
self.config = PurePath(self.exp_dir,Path("config.ini"))
|
|
186
186
|
|
|
187
187
|
if not os.path.exists(self.config):
|
|
188
188
|
print('The configuration file for the experiment was not found...')
|
|
@@ -66,13 +66,13 @@ class BaseSegmentProcess(Process):
|
|
|
66
66
|
self.len_movie = float(ConfigSectionMap(self.config,"MovieSettings")["len_movie"])
|
|
67
67
|
self.movie_prefix = ConfigSectionMap(self.config,"MovieSettings")["movie_prefix"]
|
|
68
68
|
self.nbr_channels = _extract_nbr_channels_from_config(self.config)
|
|
69
|
-
self.channel_names, self.channel_indices = extract_experiment_channels(self.
|
|
69
|
+
self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
|
|
70
70
|
|
|
71
71
|
def locate_experiment_config(self):
|
|
72
72
|
|
|
73
73
|
parent1 = Path(self.pos).parent
|
|
74
|
-
|
|
75
|
-
self.config = PurePath(
|
|
74
|
+
self.exp_dir = parent1.parent
|
|
75
|
+
self.config = PurePath(self.exp_dir,Path("config.ini"))
|
|
76
76
|
|
|
77
77
|
if not os.path.exists(self.config):
|
|
78
78
|
print('The configuration file for the experiment could not be located. Abort.')
|
|
@@ -60,7 +60,7 @@ class TrackingProcess(Process):
|
|
|
60
60
|
|
|
61
61
|
def read_tracking_instructions(self):
|
|
62
62
|
|
|
63
|
-
instr_path = PurePath(self.
|
|
63
|
+
instr_path = PurePath(self.exp_dir,Path(f"{self.instruction_file}"))
|
|
64
64
|
if os.path.exists(instr_path):
|
|
65
65
|
print(f"Tracking instructions for the {self.mode} population have been successfully loaded...")
|
|
66
66
|
with open(instr_path, 'r') as f:
|
|
@@ -156,14 +156,14 @@ class TrackingProcess(Process):
|
|
|
156
156
|
self.shape_x = int(ConfigSectionMap(self.config,"MovieSettings")["shape_x"])
|
|
157
157
|
self.shape_y = int(ConfigSectionMap(self.config,"MovieSettings")["shape_y"])
|
|
158
158
|
|
|
159
|
-
self.channel_names, self.channel_indices = extract_experiment_channels(self.
|
|
159
|
+
self.channel_names, self.channel_indices = extract_experiment_channels(self.exp_dir)
|
|
160
160
|
self.nbr_channels = len(self.channel_names)
|
|
161
161
|
|
|
162
162
|
def locate_experiment_config(self):
|
|
163
163
|
|
|
164
164
|
parent1 = Path(self.pos).parent
|
|
165
|
-
self.
|
|
166
|
-
self.config = PurePath(self.
|
|
165
|
+
self.exp_dir = parent1.parent
|
|
166
|
+
self.config = PurePath(self.exp_dir,Path("config.ini"))
|
|
167
167
|
|
|
168
168
|
if not os.path.exists(self.config):
|
|
169
169
|
print('The configuration file for the experiment was not found...')
|
|
@@ -7,7 +7,7 @@ from celldetective.gui.gui_utils import center_window, color_from_state
|
|
|
7
7
|
from superqt import QLabeledDoubleSlider, QLabeledDoubleRangeSlider, QSearchableComboBox
|
|
8
8
|
from celldetective.utils import extract_experiment_channels, get_software_location, _get_img_num_per_channel
|
|
9
9
|
from celldetective.io import auto_load_number_of_frames, load_frames, \
|
|
10
|
-
load_napari_data, get_experiment_metadata
|
|
10
|
+
load_napari_data, get_experiment_metadata, get_experiment_labels
|
|
11
11
|
from celldetective.gui.gui_utils import FigureCanvas, color_from_status, color_from_class, ExportPlotBtn
|
|
12
12
|
import json
|
|
13
13
|
import numpy as np
|
|
@@ -687,7 +687,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
687
687
|
if len_movie_auto is not None:
|
|
688
688
|
self.len_movie = len_movie_auto
|
|
689
689
|
exp_config = self.exp_dir + "config.ini"
|
|
690
|
-
self.channel_names, self.channels = extract_experiment_channels(
|
|
690
|
+
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
691
691
|
self.channel_names = np.array(self.channel_names)
|
|
692
692
|
self.channels = np.array(self.channels)
|
|
693
693
|
self.nbr_channels = len(self.channels)
|
|
@@ -780,6 +780,7 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
780
780
|
|
|
781
781
|
self.MinMaxScaler = MinMaxScaler()
|
|
782
782
|
self.columns_to_rescale = list(self.df_tracks.columns)
|
|
783
|
+
#self.columns_to_rescale = self.df_tracks.select_dtypes(exclude=['object']).columns
|
|
783
784
|
|
|
784
785
|
# is_number = np.vectorize(lambda x: np.issubdtype(x, np.number))
|
|
785
786
|
# is_number_test = is_number(self.df_tracks.dtypes)
|
|
@@ -788,17 +789,25 @@ class SignalAnnotator(QMainWindow, Styles):
|
|
|
788
789
|
|
|
789
790
|
cols_to_remove = ['status', 'status_color', 'class_color', 'TRACK_ID', 'FRAME', 'x_anim', 'y_anim', 't',
|
|
790
791
|
'state', 'generation', 'root', 'parent', 'class_id', 'class', 't0', 'POSITION_X',
|
|
791
|
-
'POSITION_Y', 'position', 'well', 'well_index', 'well_name', 'pos_name', 'index',
|
|
792
|
-
|
|
792
|
+
'POSITION_Y', 'position', 'well', 'well_index', 'well_name', 'pos_name', 'index',] + self.class_cols
|
|
793
|
+
|
|
793
794
|
meta = get_experiment_metadata(self.exp_dir)
|
|
794
795
|
if meta is not None:
|
|
795
796
|
keys = list(meta.keys())
|
|
796
797
|
cols_to_remove.extend(keys)
|
|
797
798
|
|
|
799
|
+
labels = get_experiment_labels(self.exp_dir)
|
|
800
|
+
if labels is not None:
|
|
801
|
+
keys = list(labels.keys())
|
|
802
|
+
cols_to_remove.extend(labels)
|
|
803
|
+
|
|
798
804
|
cols = np.array(list(self.df_tracks.columns))
|
|
799
805
|
time_cols = np.array([c.startswith('t_') for c in cols])
|
|
800
806
|
time_cols = list(cols[time_cols])
|
|
801
807
|
cols_to_remove += time_cols
|
|
808
|
+
#cols_to_remove.extend(self.df_tracks.select_dtypes(include=['object']).columns)
|
|
809
|
+
|
|
810
|
+
print(f"{cols_to_remove=}")
|
|
802
811
|
|
|
803
812
|
for tr in cols_to_remove:
|
|
804
813
|
try:
|
|
@@ -2273,12 +2282,23 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2273
2282
|
'state', 'generation', 'root', 'parent', 'class_id', 'class', 't0', 'POSITION_X',
|
|
2274
2283
|
'POSITION_Y', 'position', 'well', 'well_index', 'well_name', 'pos_name', 'index',
|
|
2275
2284
|
'concentration', 'cell_type', 'antibody', 'pharmaceutical_agent', 'ID'] + self.class_cols
|
|
2276
|
-
|
|
2285
|
+
|
|
2286
|
+
meta = get_experiment_metadata(self.exp_dir)
|
|
2287
|
+
if meta is not None:
|
|
2288
|
+
keys = list(meta.keys())
|
|
2289
|
+
cols_to_remove.extend(keys)
|
|
2290
|
+
|
|
2291
|
+
labels = get_experiment_labels(self.exp_dir)
|
|
2292
|
+
if labels is not None:
|
|
2293
|
+
keys = list(labels.keys())
|
|
2294
|
+
cols_to_remove.extend(labels)
|
|
2295
|
+
|
|
2277
2296
|
for tr in cols_to_remove:
|
|
2278
2297
|
try:
|
|
2279
2298
|
self.columns_to_rescale.remove(tr)
|
|
2280
2299
|
except:
|
|
2281
2300
|
pass
|
|
2301
|
+
|
|
2282
2302
|
# print(f'column {tr} could not be found...')
|
|
2283
2303
|
|
|
2284
2304
|
x = self.df_tracks[self.columns_to_rescale].values
|
|
@@ -2496,7 +2516,7 @@ class MeasureAnnotator(SignalAnnotator):
|
|
|
2496
2516
|
if len_movie_auto is not None:
|
|
2497
2517
|
self.len_movie = len_movie_auto
|
|
2498
2518
|
exp_config = self.exp_dir + "config.ini"
|
|
2499
|
-
self.channel_names, self.channels = extract_experiment_channels(
|
|
2519
|
+
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
2500
2520
|
self.channel_names = np.array(self.channel_names)
|
|
2501
2521
|
self.channels = np.array(self.channels)
|
|
2502
2522
|
self.nbr_channels = len(self.channels)
|
|
@@ -1043,7 +1043,7 @@ class SignalAnnotator2(QMainWindow,Styles):
|
|
|
1043
1043
|
if len_movie_auto is not None:
|
|
1044
1044
|
self.len_movie = len_movie_auto
|
|
1045
1045
|
exp_config = self.exp_dir +"config.ini"
|
|
1046
|
-
self.channel_names, self.channels = extract_experiment_channels(
|
|
1046
|
+
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
1047
1047
|
self.channel_names = np.array(self.channel_names)
|
|
1048
1048
|
self.channels = np.array(self.channels)
|
|
1049
1049
|
self.nbr_channels = len(self.channels)
|
|
@@ -39,7 +39,7 @@ class ConfigSignalAnnotator(QMainWindow, Styles):
|
|
|
39
39
|
|
|
40
40
|
exp_config = self.exp_dir +"config.ini"
|
|
41
41
|
#self.config_path = self.exp_dir + self.config_name
|
|
42
|
-
self.channel_names, self.channels = extract_experiment_channels(
|
|
42
|
+
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
43
43
|
self.channel_names = np.array(self.channel_names)
|
|
44
44
|
self.channels = np.array(self.channels)
|
|
45
45
|
self.log_option = False
|
celldetective/gui/survival_ui.py
CHANGED
|
@@ -153,7 +153,10 @@ class ConfigSurvival(QWidget, Styles):
|
|
|
153
153
|
all_cms = list(colormaps)
|
|
154
154
|
for cm in all_cms:
|
|
155
155
|
if hasattr(matplotlib.cm, str(cm).lower()):
|
|
156
|
-
|
|
156
|
+
try:
|
|
157
|
+
self.cbs[-1].addColormap(cm.lower())
|
|
158
|
+
except:
|
|
159
|
+
pass
|
|
157
160
|
#try:
|
|
158
161
|
# self.cbs[-1].addColormap(cm)
|
|
159
162
|
# except:
|
|
@@ -181,7 +181,7 @@ class ThresholdConfigWizard(QMainWindow, Styles):
|
|
|
181
181
|
self.threshold_slider.setSingleStep(0.00001)
|
|
182
182
|
self.threshold_slider.setTickInterval(0.00001)
|
|
183
183
|
self.threshold_slider.setOrientation(1)
|
|
184
|
-
self.threshold_slider.setDecimals(
|
|
184
|
+
self.threshold_slider.setDecimals(5)
|
|
185
185
|
self.threshold_slider.setRange(np.amin(self.img[self.img==self.img]), np.amax(self.img[self.img==self.img]))
|
|
186
186
|
self.threshold_slider.setValue([np.percentile(self.img.flatten(), 90), np.amax(self.img)])
|
|
187
187
|
self.threshold_slider.valueChanged.connect(self.threshold_changed)
|
|
@@ -422,7 +422,7 @@ class ThresholdConfigWizard(QMainWindow, Styles):
|
|
|
422
422
|
if len_movie_auto is not None:
|
|
423
423
|
self.len_movie = len_movie_auto
|
|
424
424
|
exp_config = self.exp_dir + "config.ini"
|
|
425
|
-
self.channel_names, self.channels = extract_experiment_channels(
|
|
425
|
+
self.channel_names, self.channels = extract_experiment_channels(self.exp_dir)
|
|
426
426
|
self.channel_names = np.array(self.channel_names)
|
|
427
427
|
self.channels = np.array(self.channels)
|
|
428
428
|
self.nbr_channels = len(self.channels)
|
|
@@ -861,11 +861,12 @@ class ThresholdConfigWizard(QMainWindow, Styles):
|
|
|
861
861
|
|
|
862
862
|
filters = threshold_instructions['filters']
|
|
863
863
|
items_to_add = [f[0] + '_filter' for f in filters]
|
|
864
|
-
self.
|
|
865
|
-
self.
|
|
864
|
+
self.preprocessing.list.list_widget.clear()
|
|
865
|
+
self.preprocessing.list.list_widget.addItems(items_to_add)
|
|
866
866
|
self.preprocessing.list.items = filters
|
|
867
867
|
|
|
868
|
-
self.
|
|
868
|
+
self.preprocessing.apply_btn.click()
|
|
869
|
+
#self.apply_filters_btn.click()
|
|
869
870
|
|
|
870
871
|
thresholds = threshold_instructions['thresholds']
|
|
871
872
|
self.threshold_slider.setValue(thresholds)
|
celldetective/io.py
CHANGED
|
@@ -25,7 +25,7 @@ from pathlib import Path, PurePath
|
|
|
25
25
|
from shutil import copyfile, rmtree
|
|
26
26
|
|
|
27
27
|
from celldetective.utils import _rearrange_multichannel_frame, _fix_no_contrast, zoom_multiframes,ConfigSectionMap, extract_experiment_channels, _extract_labels_from_config, get_zenodo_files, download_zenodo_file
|
|
28
|
-
from celldetective.utils import interpolate_nan_multichannel, _estimate_scale_factor, _extract_channel_indices_from_config, _extract_channel_indices, _extract_nbr_channels_from_config, _get_img_num_per_channel, normalize_per_channel
|
|
28
|
+
from celldetective.utils import interpolate_nan_multichannel, _estimate_scale_factor, _extract_channel_indices_from_config, _extract_channel_indices, _extract_nbr_channels_from_config, _get_img_num_per_channel, normalize_per_channel, get_config
|
|
29
29
|
|
|
30
30
|
from stardist import fill_label_holes
|
|
31
31
|
from skimage.transform import resize
|
|
@@ -261,49 +261,6 @@ def get_experiment_wells(experiment):
|
|
|
261
261
|
return np.array(wells, dtype=str)
|
|
262
262
|
|
|
263
263
|
|
|
264
|
-
def get_config(experiment):
|
|
265
|
-
|
|
266
|
-
"""
|
|
267
|
-
Retrieves the path to the configuration file for a given experiment.
|
|
268
|
-
|
|
269
|
-
Parameters
|
|
270
|
-
----------
|
|
271
|
-
experiment : str
|
|
272
|
-
The file system path to the experiment directory.
|
|
273
|
-
|
|
274
|
-
Returns
|
|
275
|
-
-------
|
|
276
|
-
str
|
|
277
|
-
The full path to the configuration file (`config.ini`) within the experiment directory.
|
|
278
|
-
|
|
279
|
-
Raises
|
|
280
|
-
------
|
|
281
|
-
AssertionError
|
|
282
|
-
If the `config.ini` file does not exist in the specified experiment directory.
|
|
283
|
-
|
|
284
|
-
Notes
|
|
285
|
-
-----
|
|
286
|
-
- The function ensures that the provided experiment path ends with the appropriate file separator (`os.sep`)
|
|
287
|
-
before appending `config.ini` to locate the configuration file.
|
|
288
|
-
- The configuration file is expected to be named `config.ini` and located at the root of the experiment directory.
|
|
289
|
-
|
|
290
|
-
Example
|
|
291
|
-
-------
|
|
292
|
-
>>> experiment = "/path/to/experiment"
|
|
293
|
-
>>> config_path = get_config(experiment)
|
|
294
|
-
>>> print(config_path)
|
|
295
|
-
'/path/to/experiment/config.ini'
|
|
296
|
-
|
|
297
|
-
"""
|
|
298
|
-
|
|
299
|
-
if not experiment.endswith(os.sep):
|
|
300
|
-
experiment += os.sep
|
|
301
|
-
|
|
302
|
-
config = experiment + 'config.ini'
|
|
303
|
-
config = rf"{config}"
|
|
304
|
-
assert os.path.exists(config), 'The experiment configuration could not be located...'
|
|
305
|
-
return config
|
|
306
|
-
|
|
307
264
|
|
|
308
265
|
def get_spatial_calibration(experiment):
|
|
309
266
|
|