Skip to content

Commit 07ef774

Browse files
committed
Gaussian1D for radial profile
1 parent cf22f84 commit 07ef774

6 files changed

Lines changed: 79 additions & 6 deletions

File tree

CHANGES.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ Cubeviz
2323
Imviz
2424
^^^^^
2525

26+
- Added the ability to fit Gaussian1D model to radial profile in
27+
Simple Aperture Photometry plugin. [#1409]
28+
2629
Mosviz
2730
^^^^^^
2831

docs/imviz/plugins.rst

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,9 @@ an interactively selected region. A typical workflow is as follows:
160160
Caution: having too many data points may cause performance issues with this feature.
161161
The exact limitations depend on your hardware.
162162

163-
10. Once all inputs are populated correctly, click on the :guilabel:`CALCULATE`
163+
10. Toggle :guilabel:`Fit Gaussian` on to fit a `~astropy.modeling.functional_models.Gaussian1D`
164+
model to the radial profile data. This is disabled for curve-of-growth.
165+
11. Once all inputs are populated correctly, click on the :guilabel:`CALCULATE`
164166
button to perform simple aperture photometry.
165167

166168
.. note::
@@ -182,7 +184,7 @@ of the background subtracted data and the photometry results are displayed under
182184

183185
Radial profile (raw).
184186

185-
You can also retrieve the results as `~astropy.table.QTable` as follows,
187+
You can also retrieve the photometry results as `~astropy.table.QTable` as follows,
186188
assuming ``imviz`` is the instance of your Imviz application::
187189

188190
results = imviz.get_aperture_photometry_results()
@@ -258,6 +260,12 @@ The columns are as follow:
258260
Once you have the results in a table, you can further manipulated them as
259261
documented in :ref:`astropy:astropy-table`.
260262

263+
If you opted to fit a `~astropy.modeling.functional_models.Gaussian1D`
264+
to the radial profile, the last fitted model can be obtained by as follows.
265+
See :ref:`astropy:astropy-modeling` on how to manipulate the model::
266+
267+
my_gaussian1d = imviz.app.fitted_models['phot_radial_profile']
268+
261269
.. _imviz-export-plot:
262270

263271
Export Plot

jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import os
2+
import warnings
13
from datetime import datetime
24

35
import bqplot
46
import numpy as np
57
from astropy import units as u
8+
from astropy.modeling.fitting import LevMarLSQFitter
9+
from astropy.modeling.models import Gaussian1D
610
from astropy.table import QTable
711
from astropy.time import Time
812
from 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()

jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@
112112
></v-select>
113113
</v-row>
114114

115+
<v-row v-if="current_plot_type != 'Curve of Growth'">
116+
<v-switch
117+
label="Fit Gaussian"
118+
hint="Fit Gaussian1D to radial profile"
119+
v-model="fit_radial_profile"
120+
persistent-hint>
121+
</v-switch>
122+
</v-row>
123+
115124
<v-row justify="end">
116125
<v-btn color="primary" text @click="do_aper_phot">Calculate</v-btn>
117126
</v-row>

jdaviz/configs/imviz/tests/test_simple_aper_phot.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ def test_plugin_wcs_dithered(self):
1818

1919
phot_plugin = self.imviz.app.get_tray_item_from_name('imviz-aper-phot-simple')
2020

21+
# Model fitting is already tested in astropy.
22+
# Here, we enable it just to make sure it does not crash.
23+
phot_plugin.fit_radial_profile = True
24+
2125
# Make sure invalid Data/Subset selection does not crash plugin.
2226
with pytest.raises(ValueError):
2327
phot_plugin.dataset_selected = 'no_such_data'

notebooks/concepts/imviz_simple_aper_phot.ipynb

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,29 @@
190190
"results"
191191
]
192192
},
193+
{
194+
"cell_type": "markdown",
195+
"id": "b45fcdfe",
196+
"metadata": {},
197+
"source": [
198+
"If you fitted Gaussian to radial profile, you can get it back out like this."
199+
]
200+
},
201+
{
202+
"cell_type": "code",
203+
"execution_count": null,
204+
"id": "bcb594f2",
205+
"metadata": {},
206+
"outputs": [],
207+
"source": [
208+
"my_gaussian = imviz.app.fitted_models['phot_radial_profile']\n",
209+
"my_gaussian"
210+
]
211+
},
193212
{
194213
"cell_type": "code",
195214
"execution_count": null,
196-
"id": "00435609",
215+
"id": "1e546682",
197216
"metadata": {},
198217
"outputs": [],
199218
"source": []

0 commit comments

Comments
 (0)