@@ -79,6 +79,13 @@ def __init__(
7979 "Error in EnclosedEnergyImageProcessor(): "
8080 + f"enclosed_shape must be one of { allowed_shapes } , but is '{ enclosed_shape } '" ,
8181 )
82+ if percentages_of_interest is not None :
83+ if not np .all ([poi >= 0 and poi <= 1.0 for poi in percentages_of_interest ]):
84+ lt .error_and_raise (
85+ ValueError ,
86+ "Error in EnclosedEnergyImageProcessor(): "
87+ + f"percentages_of_interest must be between 0 and 1 but { percentages_of_interest = } !" ,
88+ )
8289
8390 # use default values
8491 if enclosed_energy_style is None :
@@ -182,6 +189,9 @@ def calculate_enclosed_energy(self, image: CacheableImage, center_location: tupl
182189
183190 # Sanity checks
184191 assert len (enclosed_energy_sums ) == max_radius + 1
192+ assert np .all (
193+ [enclosed_energy_sums [i ] >= enclosed_energy_sums [i - 1 ] for i in range (1 , len (enclosed_energy_sums ))]
194+ )
185195
186196 if enclosed_energy_sums [- 1 ] != total_energy :
187197 lt .error_and_raise (
@@ -192,7 +202,7 @@ def calculate_enclosed_energy(self, image: CacheableImage, center_location: tupl
192202
193203 return enclosed_energy_sums , example_enclosed_image
194204
195- def build_enclosed_energy_plot (self , enclosed_energy_sums : list [int ]) -> np .ndarray :
205+ def build_enclosed_energy_plot (self , enclosed_energy_sums : list [int ]) -> tuple [ np .ndarray , dict [ float , int ]] :
196206 """
197207 Builds a plot of the enclosed energy around the central_locator of the input image.
198208
@@ -209,29 +219,35 @@ def build_enclosed_energy_plot(self, enclosed_energy_sums: list[int]) -> np.ndar
209219 -------
210220 plot_image: np.ndarray
211221 A np.ndarray containing the enclosed energy plot.
222+ percentages_of_interest_radiuses: dict[float,int]
223+ The radiuses (in pixels) at which the enclosed energy of
224+ interest percentages are first reached.
212225 """
213226 # Determine the axes ranges
214227 if self .plot_x_limit_pixels > 0 :
215228 x_range = self .plot_x_limit_pixels
216229 else :
217230 x_range = len (enclosed_energy_sums )
218231
219- # Build the data as a fraction of the total
232+ # Build the data as a fraction of the total.
220233 pq_vals : list [tuple [int , int ]] = []
221- enclosed_energy_fractions : list [float ] = []
234+ enclosed_energy_fractions : list [tuple [ int , int , float ] ] = []
222235 total_enclosed_energy = enclosed_energy_sums [- 1 ]
223236 for radius in range (len (enclosed_energy_sums )):
224- enclosed_energy_fractions .append (enclosed_energy_sums [radius ] / total_enclosed_energy )
237+ enclosed_energy_fractions .append (
238+ tuple ([radius , enclosed_energy_sums [radius ], enclosed_energy_sums [radius ] / total_enclosed_energy ])
239+ )
225240 pq_vals .append (tuple ([radius , enclosed_energy_fractions [radius - 1 ]]))
226241 assert len (enclosed_energy_fractions ) == len (enclosed_energy_sums )
227242
228243 # Pad the plot for the given plot_x_limit_pixels, if any is given
229244 for radius in range (len (pq_vals ) + 1 , x_range + 1 ):
230- pq_vals .append (tuple (radius , enclosed_energy_fractions [- 1 ]))
245+ pq_vals .append (tuple (radius , enclosed_energy_fractions [- 1 ][ 2 ] ))
231246
232247 # Limit the plot to the x range
248+ print (f"{ len (pq_vals )= } " )
233249 pq_vals = pq_vals [: x_range + 1 ]
234- assert len (pq_vals ) == x_range + 1
250+ assert len (pq_vals ) == x_range , f" { len ( pq_vals ) = } != { x_range = } "
235251
236252 # Create a new figure for the plot
237253 figure_control = rcfg .RenderControlFigure ()
@@ -247,15 +263,19 @@ def build_enclosed_energy_plot(self, enclosed_energy_sums: list[int]) -> np.ndar
247263 )
248264
249265 # Draw the percentages of interest
266+ percentages_of_interest_radii : dict [float , int ] = {}
250267 if self .percentages_of_interest is not None :
251268 for poi in sorted (self .percentages_of_interest ):
252- closest_radius , closest_dist = 0 , np .abs (poi - enclosed_energy_fractions [0 ])
253- for radius , fraction in enumerate ( enclosed_energy_fractions ) :
269+ closest_radius , closest_dist = 0 , np .abs (poi - enclosed_energy_fractions [0 ][ 2 ] )
270+ for radius , enclosed_energy_sum , fraction in enclosed_energy_fractions :
254271 dist = np .abs (fraction - poi )
255272 if dist < closest_dist :
256273 closest_radius = radius
257274 closest_dist = dist
275+
258276 lt .info (f"Percentage of interest { poi } is at radius { closest_radius } " )
277+ percentages_of_interest_radii [poi ] = closest_radius
278+
259279 fig_record .view .draw_pq_list (
260280 [(0 , poi ), (closest_radius , poi )], style = self .percentages_of_interest_style .measured
261281 )
@@ -273,7 +293,7 @@ def build_enclosed_energy_plot(self, enclosed_energy_sums: list[int]) -> np.ndar
273293 # close the figure
274294 fig_record .close ()
275295
276- return plot_image
296+ return plot_image , percentages_of_interest_radii
277297
278298 def _execute (self , operable : SpotAnalysisOperable , is_last : bool ) -> list [SpotAnalysisOperable ]:
279299 # Calculate the enclosed energy around the central_locator of the image
@@ -283,11 +303,11 @@ def _execute(self, operable: SpotAnalysisOperable, is_last: bool) -> list[SpotAn
283303 )
284304
285305 # Generate a visual plot of the enclosed energy
286- enclosed_energy_plot = self .build_enclosed_energy_plot (enclosed_energy_sums )
306+ enclosed_energy_plot , percentages_of_interest_radii = self .build_enclosed_energy_plot (enclosed_energy_sums )
287307
288308 # Build the new operable
289309 notes = copy .copy (operable .image_processor_notes )
290- notes .append (tuple ([self .name , [ str (v ) for v in enclosed_energy_sums ]]))
310+ notes .append (tuple ([self .name , tuple ([ percentages_of_interest_radii , [ str (v ) for v in enclosed_energy_sums ]]) ]))
291311 algorithm_images = copy .copy (operable .algorithm_images )
292312 algorithm_images [self ] = [CacheableImage .from_single_source (example_enclosed_energy_image )]
293313 vis_images = copy .copy (operable .visualization_images )
0 commit comments