55from .depth_estimation import calculate_brain_center_depths
66from .plane_alignment_functions import plane_alignment
77
8+
89def trim_mean (arr : np .array , percent : int ) -> float :
9- """"
10+ """ "
1011 Calculates the trimmed mean of an array, sourced from:
1112 https://gist.github.com/StuffbyYuki/6f25f9f2f302cb5c1e82e4481016ccde
1213
@@ -23,8 +24,11 @@ def trim_mean(arr: np.array, percent: int) -> float:
2324
2425
2526def 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" ,
2832) -> float :
2933 """
3034 Calculates the average section thickness for a series of predictions
@@ -44,23 +48,21 @@ def calculate_average_section_thickness(
4448 # inter section depth differences
4549 depth_spacing = section_depth [:- 1 ] - section_depth [1 :]
4650 # 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+ )
4854 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 :])
5056 return average_thickness
5157
5258
53-
54-
55-
56-
5759def ideal_spacing (
5860 section_numbers : List [Union [int , float ]],
5961 section_depth : List [Union [int , float ]],
6062 average_thickness : Union [int , float ],
6163 bad_sections : List [bool ] = None ,
62- method = "weighted" ,
63- species = "mouse"
64+ method = "weighted" ,
65+ species = "mouse" ,
6466) -> float :
6567 """
6668 Calculates the ideal spacing for a series of predictions
@@ -77,9 +79,13 @@ def ideal_spacing(
7779 # unaligned voxel position of section numbers (evenly spaced depths)
7880 index_spaced_depth = section_numbers * average_thickness
7981 # 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+ )
8389 # adjust the evenly spaced depths to minimise their distance to the predicted depths
8490 ideal_index_spaced_depth = index_spaced_depth + distance_to_ideal
8591 return ideal_index_spaced_depth
@@ -111,7 +117,9 @@ def enforce_section_ordering(predictions):
111117 :return: the input dataframe ordered by section number
112118 :rtype: pandas.DataFrame
113119 """
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+ )
115123 if len (predictions ) == 1 :
116124 raise ValueError ("Only one section found, cannot space according to index" )
117125 if "nr" not in predictions :
@@ -124,7 +132,7 @@ def enforce_section_ordering(predictions):
124132 depths = np .array (depths )
125133 direction = determine_direction_of_indexing (depths )
126134 predictions ["depths" ] = depths
127-
135+
128136 temp = predictions .copy ()
129137 if direction == "caudal-rostro" :
130138 ascending = False
@@ -133,21 +141,30 @@ def enforce_section_ordering(predictions):
133141 if "bad_section" in temp :
134142 temp_good = temp [temp ["bad_section" ] == False ].copy ().reset_index (drop = True )
135143 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 )
139147 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
142152 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+ )
144156
145-
146157 predictions ["oy" ] = temp ["oy" ].values
147158 return predictions
148159
149160
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+ ):
151168 """
152169 Space evenly according to the section indexes, if these indexes do not represent the precise order in which the sections were
153170 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 =
161178 if voxel_size == None :
162179 raise ValueError ("voxel_size must be specified" )
163180 if section_thickness is not None :
164- section_thickness /= voxel_size
181+ section_thickness /= voxel_size
165182 predictions ["oy" ] = predictions ["oy" ].astype (float )
166183 if len (predictions ) == 1 :
167184 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 =
170187 "No section indexes found, cannot space according to a missing index. You likely did not run predict() with section_numbers=True"
171188 )
172189 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
175192 else :
176193 bad_sections = None
177194 predictions = enforce_section_ordering (predictions )
178195 depths = calculate_brain_center_depths (predictions )
179196 depths = np .array (depths )
180197 if not section_thickness :
181198 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 ,
183203 )
184204 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" )
186206 else :
187207 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" )
189209
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+ )
191213 distance_to_ideal = calculated_spacing - depths
192214 predictions ["oy" ] = predictions ["oy" ] + distance_to_ideal
193215 return predictions
@@ -223,10 +245,12 @@ def number_sections(filenames: List[str], legacy=False) -> List[int]:
223245 return section_numbers
224246
225247
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 :
227251 """
228252 Sets the damaged sections and sections which deepslice may not perform well on for a series of predictions
229-
253+
230254 :param bad_sections: List of bad sections
231255 :param df: dataframe of predictions
232256 :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
240264 bad_section_indexes = [
241265 df .Filenames .str .contains (bad_section ) for bad_section in bad_sections
242266 ]
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+ )
245271 bad_section_indexes = [np .where (x )[0 ] for x in bad_section_indexes ]
246272 bad_section_indexes = np .concatenate (bad_section_indexes )
247273 df .loc [~ df .index .isin (bad_section_indexes ), "bad_section" ] = False
248274 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+
257283 df .loc [bad_section_indexes , "bad_section" ] = True
258284 # make the other sections are False
259-
285+
260286 bad_sections_found = np .sum (bad_section_indexes )
261287 # Tell the user which sections were identified as bad
262288 if bad_sections_found > 0 :
@@ -267,10 +293,16 @@ def set_bad_sections_util(df: pd.DataFrame, bad_sections: List[str], auto = Fals
267293 return df
268294
269295
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 ]:
271303 """
272304 Calculates the weighted accuracy of a list of section numbers for a given species
273-
305+
274306 :param section_numbers: List of section numbers
275307 :param species: Species to calculate accuracy for
276308 :param bad_sections: List of bad sections
@@ -296,8 +328,10 @@ def calculate_weighted_accuracy(section_numbers: List[int], depths: List[float],
296328 weighted_accuracy = [1 for y in section_numbers ]
297329 if len (section_numbers ) <= 2 :
298330 weighted_accuracy = [0.5 , 0.5 ]
299-
331+
300332 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