5
5
from .depth_estimation import calculate_brain_center_depths
6
6
from .plane_alignment_functions import plane_alignment
7
7
8
+
8
9
def trim_mean (arr : np .array , percent : int ) -> float :
9
- """"
10
+ """ "
10
11
Calculates the trimmed mean of an array, sourced from:
11
12
https://gist.github.com/StuffbyYuki/6f25f9f2f302cb5c1e82e4481016ccde
12
13
@@ -23,8 +24,11 @@ def trim_mean(arr: np.array, percent: int) -> float:
23
24
24
25
25
26
def calculate_average_section_thickness (
26
- section_numbers : List [Union [int , float ]], section_depth : List [Union [int , float ]], bad_sections , method = "weighted" ,
27
- species = "mouse"
27
+ section_numbers : List [Union [int , float ]],
28
+ section_depth : List [Union [int , float ]],
29
+ bad_sections ,
30
+ method = "weighted" ,
31
+ species = "mouse" ,
28
32
) -> float :
29
33
"""
30
34
Calculates the average section thickness for a series of predictions
@@ -44,23 +48,21 @@ def calculate_average_section_thickness(
44
48
# inter section depth differences
45
49
depth_spacing = section_depth [:- 1 ] - section_depth [1 :]
46
50
# dividing depth spacing by number spacing allows us to control for missing sections
47
- weighted_accuracy = calculate_weighted_accuracy (section_numbers , section_depth , species , None , method )
51
+ weighted_accuracy = calculate_weighted_accuracy (
52
+ section_numbers , section_depth , species , None , method
53
+ )
48
54
section_thicknesses = depth_spacing / number_spacing
49
- average_thickness = np .average (section_thicknesses , weights = weighted_accuracy [1 :])
55
+ average_thickness = np .average (section_thicknesses , weights = weighted_accuracy [1 :])
50
56
return average_thickness
51
57
52
58
53
-
54
-
55
-
56
-
57
59
def ideal_spacing (
58
60
section_numbers : List [Union [int , float ]],
59
61
section_depth : List [Union [int , float ]],
60
62
average_thickness : Union [int , float ],
61
63
bad_sections : List [bool ] = None ,
62
- method = "weighted" ,
63
- species = "mouse"
64
+ method = "weighted" ,
65
+ species = "mouse" ,
64
66
) -> float :
65
67
"""
66
68
Calculates the ideal spacing for a series of predictions
@@ -77,9 +79,13 @@ def ideal_spacing(
77
79
# unaligned voxel position of section numbers (evenly spaced depths)
78
80
index_spaced_depth = section_numbers * average_thickness
79
81
# average distance between the depths and the evenly spaced depths
80
-
81
- weighted_accuracy = calculate_weighted_accuracy (section_numbers , section_depth , species , bad_sections , method )
82
- distance_to_ideal = np .average (section_depth - index_spaced_depth , weights = weighted_accuracy )
82
+
83
+ weighted_accuracy = calculate_weighted_accuracy (
84
+ section_numbers , section_depth , species , bad_sections , method
85
+ )
86
+ distance_to_ideal = np .average (
87
+ section_depth - index_spaced_depth , weights = weighted_accuracy
88
+ )
83
89
# adjust the evenly spaced depths to minimise their distance to the predicted depths
84
90
ideal_index_spaced_depth = index_spaced_depth + distance_to_ideal
85
91
return ideal_index_spaced_depth
@@ -111,7 +117,9 @@ def enforce_section_ordering(predictions):
111
117
:return: the input dataframe ordered by section number
112
118
:rtype: pandas.DataFrame
113
119
"""
114
- predictions = predictions .sort_values (by = ["nr" ], ascending = True ).reset_index (drop = True )
120
+ predictions = predictions .sort_values (by = ["nr" ], ascending = True ).reset_index (
121
+ drop = True
122
+ )
115
123
if len (predictions ) == 1 :
116
124
raise ValueError ("Only one section found, cannot space according to index" )
117
125
if "nr" not in predictions :
@@ -124,7 +132,7 @@ def enforce_section_ordering(predictions):
124
132
depths = np .array (depths )
125
133
direction = determine_direction_of_indexing (depths )
126
134
predictions ["depths" ] = depths
127
-
135
+
128
136
temp = predictions .copy ()
129
137
if direction == "caudal-rostro" :
130
138
ascending = False
@@ -133,21 +141,30 @@ def enforce_section_ordering(predictions):
133
141
if "bad_section" in temp :
134
142
temp_good = temp [temp ["bad_section" ] == False ].copy ().reset_index (drop = True )
135
143
temp_good_copy = temp_good .copy ()
136
- temp_good_copy = temp_good_copy .sort_values (by = [ "depths" ], ascending = ascending ). reset_index (
137
- drop = True
138
- )
144
+ temp_good_copy = temp_good_copy .sort_values (
145
+ by = [ "depths" ], ascending = ascending
146
+ ). reset_index ( drop = True )
139
147
temp_good ["oy" ] = temp_good_copy ["oy" ]
140
-
141
- predictions .loc [predictions ["bad_section" ] == False , "oy" ] = temp_good ["oy" ].values
148
+
149
+ predictions .loc [predictions ["bad_section" ] == False , "oy" ] = temp_good [
150
+ "oy"
151
+ ].values
142
152
else :
143
- temp = temp .sort_values (by = ["depths" ], ascending = ascending ).reset_index (drop = True )
153
+ temp = temp .sort_values (by = ["depths" ], ascending = ascending ).reset_index (
154
+ drop = True
155
+ )
144
156
145
-
146
157
predictions ["oy" ] = temp ["oy" ].values
147
158
return predictions
148
159
149
160
150
- def space_according_to_index (predictions , section_thickness = None , voxel_size = None , suppress = False , species = "mouse" ):
161
+ def space_according_to_index (
162
+ predictions ,
163
+ section_thickness = None ,
164
+ voxel_size = None ,
165
+ suppress = False ,
166
+ species = "mouse" ,
167
+ ):
151
168
"""
152
169
Space evenly according to the section indexes, if these indexes do not represent the precise order in which the sections were
153
170
cut, this will lead to less accurate predictions. Section indexes must account for missing sections (ie, if section 3 is missing
@@ -161,7 +178,7 @@ def space_according_to_index(predictions, section_thickness = None, voxel_size =
161
178
if voxel_size == None :
162
179
raise ValueError ("voxel_size must be specified" )
163
180
if section_thickness is not None :
164
- section_thickness /= voxel_size
181
+ section_thickness /= voxel_size
165
182
predictions ["oy" ] = predictions ["oy" ].astype (float )
166
183
if len (predictions ) == 1 :
167
184
raise ValueError ("Only one section found, cannot space according to index" )
@@ -170,24 +187,29 @@ def space_according_to_index(predictions, section_thickness = None, voxel_size =
170
187
"No section indexes found, cannot space according to a missing index. You likely did not run predict() with section_numbers=True"
171
188
)
172
189
else :
173
- if ' bad_section' in predictions :
174
- bad_sections = predictions [' bad_section' ].values
190
+ if " bad_section" in predictions :
191
+ bad_sections = predictions [" bad_section" ].values
175
192
else :
176
193
bad_sections = None
177
194
predictions = enforce_section_ordering (predictions )
178
195
depths = calculate_brain_center_depths (predictions )
179
196
depths = np .array (depths )
180
197
if not section_thickness :
181
198
section_thickness = calculate_average_section_thickness (
182
- predictions ["nr" ], section_depth = depths , bad_sections = bad_sections , species = species
199
+ predictions ["nr" ],
200
+ section_depth = depths ,
201
+ bad_sections = bad_sections ,
202
+ species = species ,
183
203
)
184
204
if not suppress :
185
- print (f' predicted thickness is { section_thickness * voxel_size } µm' )
205
+ print (f" predicted thickness is { section_thickness * voxel_size } µm" )
186
206
else :
187
207
if not suppress :
188
- print (f' specified thickness is { section_thickness * voxel_size } µm' )
208
+ print (f" specified thickness is { section_thickness * voxel_size } µm" )
189
209
190
- calculated_spacing = ideal_spacing (predictions ["nr" ], depths , section_thickness , bad_sections , species = species )
210
+ calculated_spacing = ideal_spacing (
211
+ predictions ["nr" ], depths , section_thickness , bad_sections , species = species
212
+ )
191
213
distance_to_ideal = calculated_spacing - depths
192
214
predictions ["oy" ] = predictions ["oy" ] + distance_to_ideal
193
215
return predictions
@@ -223,10 +245,12 @@ def number_sections(filenames: List[str], legacy=False) -> List[int]:
223
245
return section_numbers
224
246
225
247
226
- def set_bad_sections_util (df : pd .DataFrame , bad_sections : List [str ], auto = False ) -> pd .DataFrame :
248
+ def set_bad_sections_util (
249
+ df : pd .DataFrame , bad_sections : List [str ], auto = False
250
+ ) -> pd .DataFrame :
227
251
"""
228
252
Sets the damaged sections and sections which deepslice may not perform well on for a series of predictions
229
-
253
+
230
254
:param bad_sections: List of bad sections
231
255
:param df: dataframe of predictions
232
256
:param auto: automatically set bad sections based on if theyre badly positioned relative to their section index
@@ -240,23 +264,25 @@ def set_bad_sections_util(df: pd.DataFrame, bad_sections: List[str], auto = Fals
240
264
bad_section_indexes = [
241
265
df .Filenames .str .contains (bad_section ) for bad_section in bad_sections
242
266
]
243
- if np .any ([np .sum (x )> 1 for x in bad_section_indexes ]):
244
- raise ValueError ("Multiple sections match the same bad section string, make sure each bad section string is unique" )
267
+ if np .any ([np .sum (x ) > 1 for x in bad_section_indexes ]):
268
+ raise ValueError (
269
+ "Multiple sections match the same bad section string, make sure each bad section string is unique"
270
+ )
245
271
bad_section_indexes = [np .where (x )[0 ] for x in bad_section_indexes ]
246
272
bad_section_indexes = np .concatenate (bad_section_indexes )
247
273
df .loc [~ df .index .isin (bad_section_indexes ), "bad_section" ] = False
248
274
if auto :
249
- df [' depths' ] = calculate_brain_center_depths (df )
250
- x = df ['nr' ].values
251
- y = df [' depths' ].values
252
- m ,b = np .polyfit (x ,y , 1 )
253
- residuals = y - (m * x + b )
254
- outliers = np .abs (residuals ) > 1.5 * np .std (residuals )
255
- df .loc [outliers , ' bad_section' ] = True
256
-
275
+ df [" depths" ] = calculate_brain_center_depths (df )
276
+ x = df ["nr" ].values
277
+ y = df [" depths" ].values
278
+ m , b = np .polyfit (x , y , 1 )
279
+ residuals = y - (m * x + b )
280
+ outliers = np .abs (residuals ) > 1.5 * np .std (residuals )
281
+ df .loc [outliers , " bad_section" ] = True
282
+
257
283
df .loc [bad_section_indexes , "bad_section" ] = True
258
284
# make the other sections are False
259
-
285
+
260
286
bad_sections_found = np .sum (bad_section_indexes )
261
287
# Tell the user which sections were identified as bad
262
288
if bad_sections_found > 0 :
@@ -267,10 +293,16 @@ def set_bad_sections_util(df: pd.DataFrame, bad_sections: List[str], auto = Fals
267
293
return df
268
294
269
295
270
- def calculate_weighted_accuracy (section_numbers : List [int ], depths : List [float ], species : str , bad_sections : List [Optional [bool ]] = None , method : str = "weighted" ) -> List [float ]:
296
+ def calculate_weighted_accuracy (
297
+ section_numbers : List [int ],
298
+ depths : List [float ],
299
+ species : str ,
300
+ bad_sections : List [Optional [bool ]] = None ,
301
+ method : str = "weighted" ,
302
+ ) -> List [float ]:
271
303
"""
272
304
Calculates the weighted accuracy of a list of section numbers for a given species
273
-
305
+
274
306
:param section_numbers: List of section numbers
275
307
:param species: Species to calculate accuracy for
276
308
:param bad_sections: List of bad sections
@@ -296,8 +328,10 @@ def calculate_weighted_accuracy(section_numbers: List[int], depths: List[float],
296
328
weighted_accuracy = [1 for y in section_numbers ]
297
329
if len (section_numbers ) <= 2 :
298
330
weighted_accuracy = [0.5 , 0.5 ]
299
-
331
+
300
332
if bad_sections is not None :
301
- weighted_accuracy = [x if y == False else 0 for x ,y in zip (weighted_accuracy ,bad_sections )]
302
-
303
- return weighted_accuracy
333
+ weighted_accuracy = [
334
+ x if y == False else 0 for x , y in zip (weighted_accuracy , bad_sections )
335
+ ]
336
+
337
+ return weighted_accuracy
0 commit comments