1+ import os
2+ import warnings
13from datetime import datetime
24
35import bqplot
46import numpy as np
57from astropy import units as u
8+ from astropy .modeling .fitting import LevMarLSQFitter
9+ from astropy .modeling .models import Gaussian1D
610from astropy .table import QTable
711from astropy .time import Time
812from ipywidgets import widget_serialization
@@ -41,6 +45,7 @@ class SimpleAperturePhotometry(TemplateMixin, DatasetSelectMixin):
4145 current_plot_type = Unicode ().tag (sync = True )
4246 plot_available = Bool (False ).tag (sync = True )
4347 radial_plot = Any ('' ).tag (sync = True , ** widget_serialization )
48+ fit_radial_profile = Bool (False ).tag (sync = True )
4449
4550 def __init__ (self , * args , ** kwargs ):
4651 super ().__init__ (* args , ** kwargs )
@@ -329,6 +334,7 @@ def vue_do_aper_phot(self, *args, **kwargs):
329334 bqplot_line = bqplot .Lines (x = x_arr , y = sum_arr , marker = 'circle' ,
330335 scales = {'x' : line_x_sc , 'y' : line_y_sc },
331336 marker_size = 32 , colors = 'gray' )
337+ bqplot_marks = [bqplot_line ]
332338
333339 else : # Radial profile
334340 self ._fig .axes = [bqplot .Axis (scale = line_x_sc , label = 'pix' ),
@@ -344,13 +350,37 @@ def vue_do_aper_phot(self, *args, **kwargs):
344350 marker_size = 32 , colors = 'gray' )
345351 else : # Radial Profile (Raw)
346352 self ._fig .title = 'Raw radial profile from Subset center'
347- radial_r , radial_img = _radial_profile (
353+ x_data , y_data = _radial_profile (
348354 phot_aperstats .data_cutout , phot_aperstats .bbox , aperture , raw = True )
349- bqplot_line = bqplot .Scatter (x = radial_r , y = radial_img , marker = 'circle' ,
355+ bqplot_line = bqplot .Scatter (x = x_data , y = y_data , marker = 'circle' ,
350356 scales = {'x' : line_x_sc , 'y' : line_y_sc },
351357 default_size = 1 , colors = 'gray' )
352358
353- self ._fig .marks = [bqplot_line ]
359+ # Fit Gaussian1D to radial profile data.
360+ if self .fit_radial_profile :
361+ fitter = LevMarLSQFitter ()
362+ y_max = y_data .max ()
363+ x_mean = x_data [np .where (y_data == y_max )].mean ()
364+ std = 0.5 * (phot_table ['semimajor_sigma' ][0 ] + phot_table ['semiminor_sigma' ][0 ])
365+ if isinstance (std , u .Quantity ):
366+ std = std .value
367+ gs = Gaussian1D (amplitude = y_max , mean = x_mean , stddev = std )
368+ with warnings .catch_warnings (record = True ) as warns :
369+ fit_model = fitter (gs , x_data , y_data )
370+ if len (warns ) > 0 :
371+ msg = os .linesep .join ([str (w .message ) for w in warns ])
372+ self .hub .broadcast (SnackbarMessage (
373+ f"Radial profile fitting: { msg } " , color = 'warning' , sender = self ))
374+ y_fit = fit_model (x_data )
375+ self .app .fitted_models ['phot_radial_profile' ] = fit_model
376+ bqplot_fit = bqplot .Lines (x = x_data , y = y_fit , marker = None ,
377+ scales = {'x' : line_x_sc , 'y' : line_y_sc },
378+ colors = 'magenta' , line_style = 'dashed' )
379+ bqplot_marks = [bqplot_line , bqplot_fit ]
380+ else :
381+ bqplot_marks = [bqplot_line ]
382+
383+ self ._fig .marks = bqplot_marks
354384
355385 except Exception as e : # pragma: no cover
356386 self .reset_results ()
0 commit comments