celldetective 1.3.0.post1__py3-none-any.whl → 1.3.2__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/events.py +88 -11
- celldetective/extra_properties.py +5 -1
- celldetective/gui/InitWindow.py +35 -9
- celldetective/gui/classifier_widget.py +99 -23
- celldetective/gui/control_panel.py +7 -1
- celldetective/gui/generic_signal_plot.py +161 -2
- celldetective/gui/gui_utils.py +90 -1
- celldetective/gui/layouts.py +128 -7
- celldetective/gui/measurement_options.py +3 -3
- celldetective/gui/plot_signals_ui.py +8 -3
- celldetective/gui/process_block.py +77 -32
- celldetective/gui/retrain_segmentation_model_options.py +24 -10
- celldetective/gui/signal_annotator.py +53 -26
- celldetective/gui/signal_annotator2.py +17 -30
- celldetective/gui/survival_ui.py +24 -3
- celldetective/gui/tableUI.py +300 -183
- celldetective/gui/viewers.py +263 -3
- celldetective/io.py +56 -3
- celldetective/links/zenodo.json +136 -123
- celldetective/measure.py +3 -0
- celldetective/models/tracking_configs/biased_motion.json +68 -0
- celldetective/models/tracking_configs/no_z_motion.json +202 -0
- celldetective/neighborhood.py +154 -69
- celldetective/preprocessing.py +172 -3
- celldetective/relative_measurements.py +128 -4
- celldetective/scripts/measure_cells.py +3 -3
- celldetective/signals.py +212 -215
- celldetective/tracking.py +7 -3
- celldetective/utils.py +22 -6
- {celldetective-1.3.0.post1.dist-info → celldetective-1.3.2.dist-info}/METADATA +3 -3
- {celldetective-1.3.0.post1.dist-info → celldetective-1.3.2.dist-info}/RECORD +36 -34
- {celldetective-1.3.0.post1.dist-info → celldetective-1.3.2.dist-info}/WHEEL +1 -1
- {celldetective-1.3.0.post1.dist-info → celldetective-1.3.2.dist-info}/LICENSE +0 -0
- {celldetective-1.3.0.post1.dist-info → celldetective-1.3.2.dist-info}/entry_points.txt +0 -0
- {celldetective-1.3.0.post1.dist-info → celldetective-1.3.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"TrackerConfig":
|
|
3
|
+
{
|
|
4
|
+
"MotionModel":
|
|
5
|
+
{
|
|
6
|
+
"name": "biased_motion",
|
|
7
|
+
"dt": 1.0,
|
|
8
|
+
"measurements": 3,
|
|
9
|
+
"states": 6,
|
|
10
|
+
"accuracy": 7.5,
|
|
11
|
+
"prob_not_assign": 0.001,
|
|
12
|
+
"max_lost": 5,
|
|
13
|
+
"A": {
|
|
14
|
+
"matrix": [1,0,0,1,0,0,
|
|
15
|
+
0,1,0,0,0,0,
|
|
16
|
+
0,0,1,0,0,1,
|
|
17
|
+
0,0,0,1,0,0,
|
|
18
|
+
0,0,0,0,0,0,
|
|
19
|
+
0,0,0,0,0,1]
|
|
20
|
+
},
|
|
21
|
+
"H": {
|
|
22
|
+
"matrix": [1,0,0,0,0,0,
|
|
23
|
+
0,1,0,0,0,0,
|
|
24
|
+
0,0,1,0,0,0]
|
|
25
|
+
},
|
|
26
|
+
"P": {
|
|
27
|
+
"sigma": 150.0,
|
|
28
|
+
"matrix": [0.1,0,0,0,0,0,
|
|
29
|
+
0,0.1,0,0,0,0,
|
|
30
|
+
0,0,0.1,0,0,0,
|
|
31
|
+
0,0,0,1,0,0,
|
|
32
|
+
0,0,0,0,1,0,
|
|
33
|
+
0,0,0,0,0,1]
|
|
34
|
+
},
|
|
35
|
+
"G": {
|
|
36
|
+
"sigma": 15.0,
|
|
37
|
+
"matrix": [0.5,0.5,0.5,1,1,1]
|
|
38
|
+
|
|
39
|
+
},
|
|
40
|
+
"R": {
|
|
41
|
+
"sigma": 5.0,
|
|
42
|
+
"matrix": [1,0,0,
|
|
43
|
+
0,1,0,
|
|
44
|
+
0,0,1]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"ObjectModel":
|
|
48
|
+
{},
|
|
49
|
+
"HypothesisModel":
|
|
50
|
+
{
|
|
51
|
+
"name": "cell_hypothesis",
|
|
52
|
+
"hypotheses": ["P_FP", "P_init", "P_term", "P_branch","P_link", "P_merge"],
|
|
53
|
+
"lambda_time": 5.0,
|
|
54
|
+
"lambda_dist": 3.0,
|
|
55
|
+
"lambda_link": 10.0,
|
|
56
|
+
"lambda_branch": 1.0,
|
|
57
|
+
"eta": 1e-10,
|
|
58
|
+
"theta_dist": 20.0,
|
|
59
|
+
"theta_time": 5.0,
|
|
60
|
+
"dist_thresh": 35.0,
|
|
61
|
+
"time_thresh": 20.0,
|
|
62
|
+
"apop_thresh": 10,
|
|
63
|
+
"segmentation_miss_rate": 0.05,
|
|
64
|
+
"apoptosis_rate": 0.0005,
|
|
65
|
+
"relax": true
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "no_z_motion",
|
|
3
|
+
"verbose": false,
|
|
4
|
+
"motion_model": {
|
|
5
|
+
"measurements": 3,
|
|
6
|
+
"states": 6,
|
|
7
|
+
"A": [
|
|
8
|
+
1.0,
|
|
9
|
+
0.0,
|
|
10
|
+
0.0,
|
|
11
|
+
1.0,
|
|
12
|
+
0.0,
|
|
13
|
+
0.0,
|
|
14
|
+
0.0,
|
|
15
|
+
1.0,
|
|
16
|
+
0.0,
|
|
17
|
+
0.0,
|
|
18
|
+
1.0,
|
|
19
|
+
0.0,
|
|
20
|
+
0.0,
|
|
21
|
+
0.0,
|
|
22
|
+
0.0,
|
|
23
|
+
0.0,
|
|
24
|
+
0.0,
|
|
25
|
+
0.0,
|
|
26
|
+
0.0,
|
|
27
|
+
0.0,
|
|
28
|
+
0.0,
|
|
29
|
+
1.0,
|
|
30
|
+
0.0,
|
|
31
|
+
0.0,
|
|
32
|
+
0.0,
|
|
33
|
+
0.0,
|
|
34
|
+
0.0,
|
|
35
|
+
0.0,
|
|
36
|
+
1.0,
|
|
37
|
+
0.0,
|
|
38
|
+
0.0,
|
|
39
|
+
0.0,
|
|
40
|
+
0.0,
|
|
41
|
+
0.0,
|
|
42
|
+
0.0,
|
|
43
|
+
0.0
|
|
44
|
+
],
|
|
45
|
+
"H": [
|
|
46
|
+
1.0,
|
|
47
|
+
0.0,
|
|
48
|
+
0.0,
|
|
49
|
+
0.0,
|
|
50
|
+
0.0,
|
|
51
|
+
0.0,
|
|
52
|
+
0.0,
|
|
53
|
+
1.0,
|
|
54
|
+
0.0,
|
|
55
|
+
0.0,
|
|
56
|
+
0.0,
|
|
57
|
+
0.0,
|
|
58
|
+
0.0,
|
|
59
|
+
0.0,
|
|
60
|
+
1.0,
|
|
61
|
+
0.0,
|
|
62
|
+
0.0,
|
|
63
|
+
0.0
|
|
64
|
+
],
|
|
65
|
+
"P": [
|
|
66
|
+
30.0,
|
|
67
|
+
0.0,
|
|
68
|
+
0.0,
|
|
69
|
+
0.0,
|
|
70
|
+
0.0,
|
|
71
|
+
0.0,
|
|
72
|
+
0.0,
|
|
73
|
+
30.0,
|
|
74
|
+
0.0,
|
|
75
|
+
0.0,
|
|
76
|
+
0.0,
|
|
77
|
+
0.0,
|
|
78
|
+
0.0,
|
|
79
|
+
0.0,
|
|
80
|
+
30.0,
|
|
81
|
+
0.0,
|
|
82
|
+
0.0,
|
|
83
|
+
0.0,
|
|
84
|
+
0.0,
|
|
85
|
+
0.0,
|
|
86
|
+
0.0,
|
|
87
|
+
300.0,
|
|
88
|
+
0.0,
|
|
89
|
+
0.0,
|
|
90
|
+
0.0,
|
|
91
|
+
0.0,
|
|
92
|
+
0.0,
|
|
93
|
+
0.0,
|
|
94
|
+
300.0,
|
|
95
|
+
0.0,
|
|
96
|
+
0.0,
|
|
97
|
+
0.0,
|
|
98
|
+
0.0,
|
|
99
|
+
0.0,
|
|
100
|
+
0.0,
|
|
101
|
+
300.0
|
|
102
|
+
],
|
|
103
|
+
"R": [
|
|
104
|
+
10.0,
|
|
105
|
+
0.0,
|
|
106
|
+
0.0,
|
|
107
|
+
0.0,
|
|
108
|
+
10.0,
|
|
109
|
+
0.0,
|
|
110
|
+
0.0,
|
|
111
|
+
0.0,
|
|
112
|
+
10.0
|
|
113
|
+
],
|
|
114
|
+
"G": [
|
|
115
|
+
15.0,
|
|
116
|
+
15.0,
|
|
117
|
+
15.0,
|
|
118
|
+
30.0,
|
|
119
|
+
30.0,
|
|
120
|
+
30.0
|
|
121
|
+
],
|
|
122
|
+
"Q": [
|
|
123
|
+
225.0,
|
|
124
|
+
225.0,
|
|
125
|
+
225.0,
|
|
126
|
+
450.0,
|
|
127
|
+
450.0,
|
|
128
|
+
450.0,
|
|
129
|
+
225.0,
|
|
130
|
+
225.0,
|
|
131
|
+
225.0,
|
|
132
|
+
450.0,
|
|
133
|
+
450.0,
|
|
134
|
+
450.0,
|
|
135
|
+
225.0,
|
|
136
|
+
225.0,
|
|
137
|
+
225.0,
|
|
138
|
+
450.0,
|
|
139
|
+
450.0,
|
|
140
|
+
450.0,
|
|
141
|
+
450.0,
|
|
142
|
+
450.0,
|
|
143
|
+
450.0,
|
|
144
|
+
900.0,
|
|
145
|
+
900.0,
|
|
146
|
+
900.0,
|
|
147
|
+
450.0,
|
|
148
|
+
450.0,
|
|
149
|
+
450.0,
|
|
150
|
+
900.0,
|
|
151
|
+
900.0,
|
|
152
|
+
900.0,
|
|
153
|
+
450.0,
|
|
154
|
+
450.0,
|
|
155
|
+
450.0,
|
|
156
|
+
900.0,
|
|
157
|
+
900.0,
|
|
158
|
+
900.0
|
|
159
|
+
],
|
|
160
|
+
"dt": 1.0,
|
|
161
|
+
"accuracy": 5.0,
|
|
162
|
+
"max_lost": 5,
|
|
163
|
+
"prob_not_assign": 0.1,
|
|
164
|
+
"name": "ricm2"
|
|
165
|
+
},
|
|
166
|
+
"object_model": null,
|
|
167
|
+
"hypothesis_model": {
|
|
168
|
+
"hypotheses": [
|
|
169
|
+
"P_FP",
|
|
170
|
+
"P_init",
|
|
171
|
+
"P_term",
|
|
172
|
+
"P_link"
|
|
173
|
+
],
|
|
174
|
+
"lambda_time": 5.0,
|
|
175
|
+
"lambda_dist": 3.0,
|
|
176
|
+
"lambda_link": 50.0,
|
|
177
|
+
"lambda_branch": 50.0,
|
|
178
|
+
"eta": 1e-10,
|
|
179
|
+
"theta_dist": 20.0,
|
|
180
|
+
"theta_time": 5.0,
|
|
181
|
+
"dist_thresh": 75.0,
|
|
182
|
+
"time_thresh": 5.0,
|
|
183
|
+
"apop_thresh": 5,
|
|
184
|
+
"segmentation_miss_rate": 0.1,
|
|
185
|
+
"apoptosis_rate": 0.001,
|
|
186
|
+
"relax": true,
|
|
187
|
+
"name": "ricm2"
|
|
188
|
+
},
|
|
189
|
+
"max_search_radius": 200.0,
|
|
190
|
+
"return_kalman": false,
|
|
191
|
+
"store_candidate_graph": false,
|
|
192
|
+
"volume": null,
|
|
193
|
+
"update_method": 0,
|
|
194
|
+
"optimizer_options": {
|
|
195
|
+
"tm_lim": 60000
|
|
196
|
+
},
|
|
197
|
+
"features": [],
|
|
198
|
+
"tracking_updates": [
|
|
199
|
+
1
|
|
200
|
+
],
|
|
201
|
+
"enable_optimisation": true
|
|
202
|
+
}
|
celldetective/neighborhood.py
CHANGED
|
@@ -7,6 +7,8 @@ from celldetective.utils import contour_of_instance_segmentation, extract_identi
|
|
|
7
7
|
from scipy.spatial.distance import cdist
|
|
8
8
|
from celldetective.io import locate_labels, get_position_pickle, get_position_table
|
|
9
9
|
|
|
10
|
+
import matplotlib.pyplot as plt
|
|
11
|
+
|
|
10
12
|
abs_path = os.sep.join([os.path.split(os.path.dirname(os.path.realpath(__file__)))[0], 'celldetective'])
|
|
11
13
|
|
|
12
14
|
|
|
@@ -818,10 +820,7 @@ def contact_neighborhood(labelsA, labelsB=None, border=3, connectivity=2):
|
|
|
818
820
|
if labelsB is not None:
|
|
819
821
|
labelsB = labelsB.astype(float)
|
|
820
822
|
|
|
821
|
-
print(f"Border = {border}")
|
|
822
|
-
|
|
823
823
|
if border > 0:
|
|
824
|
-
print(labelsA.shape, border * (-1))
|
|
825
824
|
labelsA_edge = contour_of_instance_segmentation(label=labelsA, distance=border * (-1)).astype(float)
|
|
826
825
|
labelsA[np.where(labelsA_edge > 0)] = labelsA_edge[np.where(labelsA_edge > 0)]
|
|
827
826
|
if labelsB is not None:
|
|
@@ -851,6 +850,7 @@ def contact_neighborhood(labelsA, labelsB=None, border=3, connectivity=2):
|
|
|
851
850
|
return neighs
|
|
852
851
|
|
|
853
852
|
def merge_labels(labelsA, labelsB):
|
|
853
|
+
|
|
854
854
|
labelsA = labelsA.astype(float)
|
|
855
855
|
labelsB = labelsB.astype(float)
|
|
856
856
|
|
|
@@ -861,6 +861,7 @@ def merge_labels(labelsA, labelsB):
|
|
|
861
861
|
|
|
862
862
|
|
|
863
863
|
def find_contact_neighbors(labels, connectivity=2):
|
|
864
|
+
|
|
864
865
|
assert labels.ndim == 2, "Wrong dimension for labels..."
|
|
865
866
|
g, nodes = pixel_graph(labels, mask=labels.astype(bool), connectivity=connectivity)
|
|
866
867
|
g.eliminate_zeros()
|
|
@@ -906,6 +907,15 @@ def mask_contact_neighborhood(setA, setB, labelsA, labelsB, distance, mode='two-
|
|
|
906
907
|
"""
|
|
907
908
|
|
|
908
909
|
# Check live_status option
|
|
910
|
+
# if setA is not None:
|
|
911
|
+
# setA_id = extract_identity_col(setA)
|
|
912
|
+
# if setA_id=="TRACK_ID":
|
|
913
|
+
# setA = setA.loc[~setA['TRACK_ID'].isnull(),:].copy()
|
|
914
|
+
# if setB is not None:
|
|
915
|
+
# setB_id = extract_identity_col(setB)
|
|
916
|
+
# if setB_id=="TRACK_ID":
|
|
917
|
+
# setB = setB.loc[~setB['TRACK_ID'].isnull(),:].copy()
|
|
918
|
+
|
|
909
919
|
if setA is not None and setB is not None:
|
|
910
920
|
setA, setB, status = set_live_status(setA, setB, status, not_status_option)
|
|
911
921
|
else:
|
|
@@ -915,6 +925,25 @@ def mask_contact_neighborhood(setA, setB, labelsA, labelsB, distance, mode='two-
|
|
|
915
925
|
if not isinstance(distance, list):
|
|
916
926
|
distance = [distance]
|
|
917
927
|
|
|
928
|
+
cl = []
|
|
929
|
+
for s in [setA, setB]:
|
|
930
|
+
|
|
931
|
+
# Check whether data can be tracked
|
|
932
|
+
temp_column_labels = column_labels.copy()
|
|
933
|
+
|
|
934
|
+
id_col = extract_identity_col(s)
|
|
935
|
+
temp_column_labels.update({'track': id_col})
|
|
936
|
+
if id_col=='ID':
|
|
937
|
+
compute_cum_sum = False
|
|
938
|
+
|
|
939
|
+
cl.append(temp_column_labels)
|
|
940
|
+
|
|
941
|
+
setA = setA.loc[~setA[cl[0]['track']].isnull(),:].copy()
|
|
942
|
+
setB = setB.loc[~setB[cl[1]['track']].isnull(),:].copy()
|
|
943
|
+
|
|
944
|
+
if labelsB is None:
|
|
945
|
+
labelsB = [None] * len(labelsA)
|
|
946
|
+
|
|
918
947
|
for d in distance:
|
|
919
948
|
# loop over each provided distance
|
|
920
949
|
|
|
@@ -923,22 +952,11 @@ def mask_contact_neighborhood(setA, setB, labelsA, labelsB, distance, mode='two-
|
|
|
923
952
|
elif mode == 'self':
|
|
924
953
|
neigh_col = f'neighborhood_self_contact_{d}_px'
|
|
925
954
|
|
|
926
|
-
|
|
927
|
-
|
|
955
|
+
setA[neigh_col] = np.nan
|
|
956
|
+
setA[neigh_col] = setA[neigh_col].astype(object)
|
|
928
957
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
id_col = extract_identity_col(s)
|
|
933
|
-
temp_column_labels.update({'track': id_col})
|
|
934
|
-
if id_col=='ID':
|
|
935
|
-
compute_cum_sum = False # if no tracking data then cum_sum is not relevant
|
|
936
|
-
cl.append(temp_column_labels)
|
|
937
|
-
|
|
938
|
-
# Remove nan tracks (cells that do not belong to a track)
|
|
939
|
-
s[neigh_col] = np.nan
|
|
940
|
-
s[neigh_col] = s[neigh_col].astype(object)
|
|
941
|
-
s.dropna(subset=[cl[-1]['track']], inplace=True)
|
|
958
|
+
setB[neigh_col] = np.nan
|
|
959
|
+
setB[neigh_col] = setB[neigh_col].astype(object)
|
|
942
960
|
|
|
943
961
|
# Loop over each available timestep
|
|
944
962
|
timeline = np.unique(np.concatenate([setA[cl[0]['time']].to_numpy(), setB[cl[1]['time']].to_numpy()])).astype(
|
|
@@ -946,38 +964,34 @@ def mask_contact_neighborhood(setA, setB, labelsA, labelsB, distance, mode='two-
|
|
|
946
964
|
for t in tqdm(timeline):
|
|
947
965
|
|
|
948
966
|
index_A = list(setA.loc[setA[cl[0]['time']] == t].index)
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
mask_ids_A = setA.loc[setA[cl[0]['time']] == t, cl[0]['mask_id']].to_numpy()
|
|
952
|
-
status_A = setA.loc[setA[cl[0]['time']] == t, status[0]].to_numpy()
|
|
967
|
+
dataA = setA.loc[setA[cl[0]['time']] == t, [cl[0]['x'], cl[0]['y'], cl[0]['track'], cl[0]['mask_id'], status[0]]].to_numpy()
|
|
968
|
+
coordinates_A = dataA[:,[0,1]]; ids_A = dataA[:,2]; mask_ids_A = dataA[:,3]; status_A = dataA[:,4];
|
|
953
969
|
|
|
954
970
|
index_B = list(setB.loc[setB[cl[1]['time']] == t].index)
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
mask_ids_B = setB.loc[setB[cl[1]['time']] == t, cl[1]['mask_id']].to_numpy()
|
|
958
|
-
status_B = setB.loc[setB[cl[1]['time']] == t, status[1]].to_numpy()
|
|
971
|
+
dataB = setB.loc[setB[cl[1]['time']] == t, [cl[1]['x'], cl[1]['y'], cl[1]['track'], cl[1]['mask_id'], status[1]]].to_numpy()
|
|
972
|
+
coordinates_B = dataB[:,[0,1]]; ids_B = dataB[:,2]; mask_ids_B = dataB[:,3]; status_B = dataB[:,4]
|
|
959
973
|
|
|
960
|
-
|
|
961
|
-
print(f"{mask_ids_A=}", f"{mask_ids_B}")
|
|
962
|
-
|
|
963
|
-
if len(ids_A) > 0 and len(ids_B) > 0:
|
|
974
|
+
if len(coordinates_A) > 0 and len(coordinates_B) > 0:
|
|
964
975
|
|
|
965
976
|
# compute distance matrix
|
|
966
977
|
dist_map = cdist(coordinates_A, coordinates_B, metric="euclidean")
|
|
978
|
+
intersection_map = np.zeros_like(dist_map).astype(float)
|
|
967
979
|
|
|
968
980
|
# Do the mask contact computation
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
981
|
+
lblA = labelsA[t]
|
|
982
|
+
lblA = np.where(np.isin(lblA, mask_ids_A), lblA, 0.)
|
|
983
|
+
|
|
984
|
+
lblB = labelsB[t]
|
|
985
|
+
if lblB is not None:
|
|
986
|
+
lblB = np.where(np.isin(lblB, mask_ids_B), lblB, 0.)
|
|
973
987
|
|
|
974
|
-
|
|
975
|
-
contact_pairs = contact_neighborhood(labelsA[t], labelsB=lblB, border=d, connectivity=2)
|
|
988
|
+
contact_pairs = contact_neighborhood(lblA, labelsB=lblB, border=d, connectivity=2)
|
|
976
989
|
|
|
977
|
-
print(t, f"{np.unique(labelsA[t])=}")
|
|
978
|
-
print(f"Frame {t}: found the following contact pairs: {contact_pairs}...")
|
|
979
990
|
# Put infinite distance to all non-contact pairs (something like this)
|
|
980
991
|
plot_map = False
|
|
992
|
+
flatA = lblA.flatten()
|
|
993
|
+
if lblB is not None:
|
|
994
|
+
flatB = lblB.flatten()
|
|
981
995
|
|
|
982
996
|
if len(contact_pairs) > 0:
|
|
983
997
|
mask = np.ones_like(dist_map).astype(bool)
|
|
@@ -985,48 +999,32 @@ def mask_contact_neighborhood(setA, setB, labelsA, labelsB, distance, mode='two-
|
|
|
985
999
|
indices_to_keep = []
|
|
986
1000
|
for cp in contact_pairs:
|
|
987
1001
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
mask_A = cp[0]
|
|
997
|
-
mask_B = cp[1]
|
|
998
|
-
|
|
999
|
-
try:
|
|
1002
|
+
cp = np.abs(cp)
|
|
1003
|
+
mask_A, mask_B = cp
|
|
1004
|
+
idx_A = np.where(mask_ids_A == int(mask_A))[0][0]
|
|
1005
|
+
idx_B = np.where(mask_ids_B == int(mask_B))[0][0]
|
|
1006
|
+
|
|
1007
|
+
intersection = 0
|
|
1008
|
+
if lblB is not None:
|
|
1009
|
+
intersection = len(flatA[(flatA==int(mask_A))&(flatB==int(mask_B))])
|
|
1000
1010
|
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
indices_to_keep.append([idx_A,idx_B])
|
|
1005
|
-
except Exception as e:
|
|
1006
|
-
print(f'{e} {t=} error something happened!!')
|
|
1007
|
-
pass
|
|
1011
|
+
indices_to_keep.append([idx_A,idx_B, intersection])
|
|
1012
|
+
print(f'Ref cell #{ids_A[idx_A]} matched with neigh. cell #{ids_B[idx_B]}...')
|
|
1013
|
+
print(f'Computed intersection: {intersection} px...')
|
|
1008
1014
|
|
|
1009
|
-
print(f'Indices to keep: {indices_to_keep}...')
|
|
1010
1015
|
if len(indices_to_keep) > 0:
|
|
1011
1016
|
indices_to_keep = np.array(indices_to_keep)
|
|
1012
1017
|
mask[indices_to_keep[:, 0], indices_to_keep[:, 1]] = False
|
|
1013
1018
|
if mode == 'self':
|
|
1014
1019
|
mask[indices_to_keep[:, 1], indices_to_keep[:, 0]] = False
|
|
1015
1020
|
dist_map[mask] = 1.0E06
|
|
1021
|
+
intersection_map[indices_to_keep[:,0], indices_to_keep[:,1]] = indices_to_keep[:,2]
|
|
1016
1022
|
plot_map=True
|
|
1017
1023
|
else:
|
|
1018
1024
|
dist_map[:,:] = 1.0E06
|
|
1019
1025
|
else:
|
|
1020
1026
|
dist_map[:, :] = 1.0E06
|
|
1021
1027
|
|
|
1022
|
-
# PROCEED all the same?? --> I guess so
|
|
1023
|
-
# if plot_map:
|
|
1024
|
-
# import matplotlib.pyplot as plt
|
|
1025
|
-
# print(indices_to_keep)
|
|
1026
|
-
# plt.imshow(dist_map)
|
|
1027
|
-
# plt.pause(5)
|
|
1028
|
-
# plt.close()
|
|
1029
|
-
|
|
1030
1028
|
d_filter = 1.0E05
|
|
1031
1029
|
if attention_weight:
|
|
1032
1030
|
weights, closest_A = compute_attention_weight(dist_map, d_filter, status_A, ids_A, axis=1,
|
|
@@ -1036,11 +1034,14 @@ def mask_contact_neighborhood(setA, setB, labelsA, labelsB, distance, mode='two-
|
|
|
1036
1034
|
for k in range(dist_map.shape[0]):
|
|
1037
1035
|
|
|
1038
1036
|
col = dist_map[k, :]
|
|
1037
|
+
col_inter = intersection_map[k, :]
|
|
1039
1038
|
col[col == 0.] = 1.0E06
|
|
1040
1039
|
|
|
1041
1040
|
neighs_B = np.array([ids_B[i] for i in np.where((col <= d_filter))[0]])
|
|
1042
1041
|
status_neigh_B = np.array([status_B[i] for i in np.where((col <= d_filter))[0]])
|
|
1043
1042
|
dist_B = [round(col[i], 2) for i in np.where((col <= d_filter))[0]]
|
|
1043
|
+
intersect_B = [round(col_inter[i], 2) for i in np.where((col <= d_filter))[0]]
|
|
1044
|
+
|
|
1044
1045
|
if len(dist_B) > 0:
|
|
1045
1046
|
closest_B_cell = neighs_B[np.argmin(dist_B)]
|
|
1046
1047
|
|
|
@@ -1080,14 +1081,14 @@ def mask_contact_neighborhood(setA, setB, labelsA, labelsB, distance, mode='two-
|
|
|
1080
1081
|
else:
|
|
1081
1082
|
closest_b = False
|
|
1082
1083
|
if isinstance(sym_neigh, list):
|
|
1083
|
-
sym_neigh.append({'id': ids_A[k], 'distance': dist_B[n], 'status': status_A[k]})
|
|
1084
|
+
sym_neigh.append({'id': ids_A[k], 'distance': dist_B[n], 'status': status_A[k], 'intersection': intersect_B[n]})
|
|
1084
1085
|
else:
|
|
1085
|
-
sym_neigh = [{'id': ids_A[k], 'distance': dist_B[n], 'status': status_A[k]}]
|
|
1086
|
+
sym_neigh = [{'id': ids_A[k], 'distance': dist_B[n], 'status': status_A[k], 'intersection': intersect_B[n]}]
|
|
1086
1087
|
if attention_weight:
|
|
1087
1088
|
sym_neigh[-1].update({'weight': weight_A, 'closest': closest_b})
|
|
1088
1089
|
|
|
1089
1090
|
# Write the minimum info about neighborhing cell B
|
|
1090
|
-
neigh_dico = {'id': neighs_B[n], 'distance': dist_B[n], 'status': status_neigh_B[n]}
|
|
1091
|
+
neigh_dico = {'id': neighs_B[n], 'distance': dist_B[n], 'status': status_neigh_B[n], 'intersection': intersect_B[n]}
|
|
1091
1092
|
if attention_weight:
|
|
1092
1093
|
neigh_dico.update({'weight': weights[n_index], 'closest': closest})
|
|
1093
1094
|
|
|
@@ -1303,6 +1304,90 @@ def compute_contact_neighborhood_at_position(pos, distance, population=['targets
|
|
|
1303
1304
|
return df_A, df_B
|
|
1304
1305
|
|
|
1305
1306
|
|
|
1307
|
+
def extract_neighborhood_in_pair_table(df, distance=None, reference_population="targets", neighbor_population="effectors", mode="circle", neighborhood_key=None, contact_only=True,):
|
|
1308
|
+
|
|
1309
|
+
"""
|
|
1310
|
+
Extracts data from a pair table that matches specific neighborhood criteria based on reference and neighbor
|
|
1311
|
+
populations, distance, and mode of neighborhood computation (e.g., circular or contact-based).
|
|
1312
|
+
|
|
1313
|
+
Parameters
|
|
1314
|
+
----------
|
|
1315
|
+
df : pandas.DataFrame
|
|
1316
|
+
DataFrame containing the pair table, which includes columns for 'reference_population', 'neighbor_population',
|
|
1317
|
+
and a column for neighborhood status.
|
|
1318
|
+
distance : int, optional
|
|
1319
|
+
Radius in pixels for neighborhood calculation, used only if `neighborhood_key` is not provided.
|
|
1320
|
+
reference_population : str, default="targets"
|
|
1321
|
+
The reference population to consider. Must be either "targets" or "effectors".
|
|
1322
|
+
neighbor_population : str, default="effectors"
|
|
1323
|
+
The neighbor population to consider. Must be either "targets" or "effectors", used only if `neighborhood_key` is not provided.
|
|
1324
|
+
mode : str, default="circle"
|
|
1325
|
+
Neighborhood computation mode. Options are "circle" for radius-based or "contact" for contact-based neighborhood, used only if `neighborhood_key` is not provided.
|
|
1326
|
+
neighborhood_key : str, optional
|
|
1327
|
+
A precomputed neighborhood key to identify specific neighborhoods. If provided, this key overrides `distance`,
|
|
1328
|
+
`mode`, and `neighbor_population`.
|
|
1329
|
+
contact_only : bool, default=True
|
|
1330
|
+
If True, only rows indicating contact with the neighbor population (status=1) are kept; if False, both
|
|
1331
|
+
contact (status=1) and no-contact (status=0) rows are included.
|
|
1332
|
+
|
|
1333
|
+
Returns
|
|
1334
|
+
-------
|
|
1335
|
+
pandas.DataFrame
|
|
1336
|
+
Filtered DataFrame containing rows that meet the specified neighborhood criteria.
|
|
1337
|
+
|
|
1338
|
+
Notes
|
|
1339
|
+
-----
|
|
1340
|
+
- When `neighborhood_key` is None, the neighborhood column is generated based on the provided `reference_population`,
|
|
1341
|
+
`neighbor_population`, `distance`, and `mode`.
|
|
1342
|
+
- The function uses `status_<neigh_col>` to filter rows based on `contact_only` criteria.
|
|
1343
|
+
- Ensures that `reference_population` and `neighbor_population` are valid inputs and consistent with the neighborhood
|
|
1344
|
+
mode and key.
|
|
1345
|
+
|
|
1346
|
+
Example
|
|
1347
|
+
-------
|
|
1348
|
+
>>> neighborhood_data = extract_neighborhood_in_pair_table(df, distance=50, reference_population="targets",
|
|
1349
|
+
neighbor_population="effectors", mode="circle")
|
|
1350
|
+
>>> neighborhood_data.head()
|
|
1351
|
+
|
|
1352
|
+
Raises
|
|
1353
|
+
------
|
|
1354
|
+
AssertionError
|
|
1355
|
+
If `reference_population` or `neighbor_population` is not valid, or if the required neighborhood status
|
|
1356
|
+
column does not exist in `df`.
|
|
1357
|
+
"""
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
assert reference_population in ["targets", "effectors"], "Please set a valid reference population ('targets' or 'effectors')"
|
|
1361
|
+
if neighborhood_key is None:
|
|
1362
|
+
assert neighbor_population in ["targets", "effectors"], "Please set a valid neighbor population ('targets' or 'effectors')"
|
|
1363
|
+
assert mode in ["circle", "contact"], "Please set a valid neighborhood computation mode ('circle' or 'contact')"
|
|
1364
|
+
if reference_population==neighbor_population:
|
|
1365
|
+
type = "self"
|
|
1366
|
+
else:
|
|
1367
|
+
type = "2"
|
|
1368
|
+
|
|
1369
|
+
neigh_col = f"neighborhood_{type}_{mode}_{distance}_px"
|
|
1370
|
+
else:
|
|
1371
|
+
neigh_col = neighborhood_key.replace('status_','')
|
|
1372
|
+
if 'self' in neigh_col:
|
|
1373
|
+
neighbor_population = reference_population
|
|
1374
|
+
else:
|
|
1375
|
+
if reference_population=="effectors":
|
|
1376
|
+
neighbor_population=='targets'
|
|
1377
|
+
else:
|
|
1378
|
+
neighbor_population=='effectors'
|
|
1379
|
+
|
|
1380
|
+
assert "status_"+neigh_col in list(df.columns),"The selected neighborhood does not appear in the data..."
|
|
1381
|
+
|
|
1382
|
+
if contact_only:
|
|
1383
|
+
s_keep = [1]
|
|
1384
|
+
else:
|
|
1385
|
+
s_keep = [0,1]
|
|
1386
|
+
|
|
1387
|
+
data = df.loc[(df['reference_population']==reference_population)&(df['neighbor_population']==neighbor_population)&(df["status_"+neigh_col].isin(s_keep))]
|
|
1388
|
+
|
|
1389
|
+
return data
|
|
1390
|
+
|
|
1306
1391
|
|
|
1307
1392
|
# def mask_intersection_neighborhood(setA, labelsA, setB, labelsB, threshold_iou=0.5, viewpoint='B'):
|
|
1308
1393
|
# # do whatever to match objects in A and B
|