Skip to content

Commit

Permalink
Remove annulus from aperture photometry plugin (#2276)
Browse files Browse the repository at this point in the history
* Remove annulus from aperture
photometry plugin. Use the draw tool.

[ci skip] [rtd skip]

* Add change log
  • Loading branch information
pllim authored Jul 6, 2023
1 parent 46be84f commit 9402123
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 101 deletions.
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ Cubeviz
Imviz
^^^^^

- Simple Aperture Photometry plugin: Custom annulus background options are removed.
Please draw/load annulus as you would with other region shapes, then select it
in the plugin from Subset dropdown for the background. Using annulus region as
aperture is not supported. [#2276]

Mosviz
^^^^^^

Expand Down
9 changes: 6 additions & 3 deletions docs/imviz/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,18 @@ an interactively selected region. A typical workflow is as follows:
object of interest using its center of mass, if you wish.
Depending on the object, it may take several iterations for re-centering
to converge, or it may never converge at all.

.. note::

You cannot use annulus region as aperture (an exception will be thrown)
but you may use it for background (see below).

5. If you want to subtract background before performing photometry,
you have the following 3 options. Otherwise if your image is already
background subtracted, choose "Manual" and leave the background set at 0:

* Manual: Enter the background value in the :guilabel:`Background value` field.
This value must be in the same unit as display data, if applicable.
* Annulus: Enter its inner radius and width in the :guilabel:`Annulus inner radius`
and :guilabel:`Annulus width`, respectively. Median of the pixels within
the annulus region will be used but the annulus shape will not be shown on display.
* Subset: Define a region for background calculation (median) using Subset draw tool
and select that region using the :guilabel:`Background` dropdown menu. Only regions
created with the :guilabel:`replace` option are acceptable as background regions
Expand Down
39 changes: 2 additions & 37 deletions jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@
from packaging.version import Version
from photutils.aperture import (ApertureStats, CircularAperture, EllipticalAperture,
RectangularAperture)
from regions import (CircleAnnulusPixelRegion, CirclePixelRegion, EllipsePixelRegion,
RectanglePixelRegion)
from traitlets import Any, Bool, Integer, List, Unicode, observe

from jdaviz.core.custom_traitlets import FloatHandleEmpty
from jdaviz.core.events import SnackbarMessage, LinkUpdatedMessage
from jdaviz.core.region_translators import regions2aperture, _get_region_from_spatial_subset
from jdaviz.core.registries import tray_registry
Expand All @@ -38,8 +35,6 @@ class SimpleAperturePhotometry(PluginTemplateMixin, DatasetSelectMixin, TableMix
bg_subset_items = List().tag(sync=True)
bg_subset_selected = Unicode("").tag(sync=True)
background_value = Any(0).tag(sync=True)
bg_annulus_inner_r = FloatHandleEmpty(0).tag(sync=True)
bg_annulus_width = FloatHandleEmpty(10).tag(sync=True)
pixel_area = Any(0).tag(sync=True)
counts_factor = Any(0).tag(sync=True)
flux_scaling = Any(0).tag(sync=True)
Expand All @@ -66,7 +61,7 @@ def __init__(self, *args, **kwargs):
'bg_subset_items',
'bg_subset_selected',
default_text='Manual',
manual_options=['Manual', 'Annulus'],
manual_options=['Manual'],
allowed_type='spatial')

headers = ['xcenter', 'ycenter', 'sky_center',
Expand Down Expand Up @@ -161,7 +156,7 @@ def _on_link_update(self, msg):
if self.dataset_selected == '' or self.subset_selected == '':
return

# Force background auto-calculation (including annulus) to update when linking has changed.
# Force background auto-calculation to update when linking has changed.
self._subset_selected_changed()

@observe('subset_selected')
Expand All @@ -173,18 +168,6 @@ def _subset_selected_changed(self, event={}):
try:
self._selected_subset = _get_region_from_spatial_subset(self, subset_selected)
self._selected_subset.meta['label'] = subset_selected

if isinstance(self._selected_subset, CirclePixelRegion):
self.bg_annulus_inner_r = self._selected_subset.radius
elif isinstance(self._selected_subset, EllipsePixelRegion):
self.bg_annulus_inner_r = max(self._selected_subset.width,
self._selected_subset.height) * 0.5
elif isinstance(self._selected_subset, RectanglePixelRegion):
self.bg_annulus_inner_r = np.sqrt(self._selected_subset.width ** 2 +
self._selected_subset.height ** 2) * 0.5
else: # pragma: no cover
raise TypeError(f'Unsupported region shape: {self._selected_subset.__class__}')

self.subset_area = int(np.ceil(self._selected_subset.area))

except Exception as e:
Expand All @@ -206,30 +189,12 @@ def _calc_bg_subset_median(self, reg):
# photutils/background/_utils.py --> nanmedian()
return np.nanmedian(img_stat) # Naturally in data unit

@observe('bg_annulus_inner_r', 'bg_annulus_width')
def _bg_annulus_updated(self, *args):
if self.bg_subset_selected != 'Annulus':
return

try:
inner_r = float(self.bg_annulus_inner_r)
reg = CircleAnnulusPixelRegion(
self._selected_subset.center, inner_radius=inner_r,
outer_radius=inner_r + float(self.bg_annulus_width))
self.background_value = self._calc_bg_subset_median(reg)

except Exception: # Error snackbar suppressed to prevent excessive queue.
self.background_value = 0

@observe('bg_subset_selected')
def _bg_subset_selected_changed(self, event={}):
bg_subset_selected = event.get('new', self.bg_subset_selected)
if bg_subset_selected == 'Manual':
# we'll later access the user's self.background_value directly
return
if bg_subset_selected == 'Annulus':
self._bg_annulus_updated()
return

try:
reg = _get_region_from_spatial_subset(self, bg_subset_selected)
Expand Down
24 changes: 0 additions & 24 deletions jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,6 @@
</span>
</v-row>

<v-row v-if="bg_subset_selected=='Annulus'">
<v-text-field
label="Annulus inner radius"
v-model.number="bg_annulus_inner_r"
type="number"
:rules="[() => bg_annulus_inner_r>0 || 'Must be positive.']"
hint="Background annulus inner radius in pixels"
persistent-hint
>
</v-text-field>
</v-row>

<v-row v-if="bg_subset_selected=='Annulus'">
<v-text-field
label="Annulus width"
v-model.number="bg_annulus_width"
type="number"
:rules="[() => bg_annulus_width>0 || 'Must be positive.']"
hint="Background annulus width in pixels (inner radius + width = outer radius)"
persistent-hint
>
</v-text-field>
</v-row>

<v-row>
<v-text-field
label="Background value"
Expand Down
66 changes: 29 additions & 37 deletions jdaviz/configs/imviz/tests/test_simple_aper_phot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import numpy as np
from astropy import units as u
from astropy.tests.helper import assert_quantity_allclose
from glue.core.edit_subset_mode import ReplaceMode
from numpy.testing import assert_allclose, assert_array_equal
from photutils.aperture import (ApertureStats, CircularAperture, EllipticalAperture,
RectangularAperture, EllipticalAnnulus)
from regions import CircleAnnulusPixelRegion, PixCoord

from jdaviz.configs.imviz.plugins.aper_phot_simple.aper_phot_simple import (
_curve_of_growth, _radial_profile)
Expand Down Expand Up @@ -52,7 +52,7 @@ def test_plugin_wcs_dithered(self):
phot_plugin.current_plot_type = 'Radial Profile (Raw)'
assert phot_plugin._selected_data is not None
assert phot_plugin._selected_subset is not None
assert phot_plugin.bg_subset.labels == ['Manual', 'Annulus', 'Subset 1']
assert phot_plugin.bg_subset.labels == ['Manual', 'Subset 1']
assert_allclose(phot_plugin.background_value, 0)
assert_allclose(phot_plugin.counts_factor, 0)
assert_allclose(phot_plugin.pixel_area, 0)
Expand Down Expand Up @@ -159,12 +159,6 @@ def test_plugin_wcs_dithered(self):
phot_plugin.dataset_selected = 'twos'
assert_allclose(phot_plugin.background_value, 2) # Recalculate based on new Data

# Check rectangle annulus math
phot_plugin.bg_subset_selected = 'Annulus'
phot_plugin.subset_selected = 'Subset 3'
assert_allclose(phot_plugin.bg_annulus_inner_r, 6.363961030678928) # half-width = 4.5
assert_allclose(phot_plugin.bg_annulus_width, 10)

# Curve of growth
phot_plugin.current_plot_type = 'Curve of Growth'
phot_plugin.vue_do_aper_phot()
Expand Down Expand Up @@ -203,28 +197,37 @@ def test_annulus_background(imviz_helper):
phot_plugin.dataset_selected = 'ones'

# Mark an object of interest
# CirclePixelRegion(center=PixCoord(x=150, y=25), radius=7)
imviz_helper._apply_interactive_region('bqplot:circle', (143, 18), (157, 32))

# Load annulus (this used to be part of the plugin but no longer)
annulus_1 = CircleAnnulusPixelRegion(
PixCoord(x=150, y=25), inner_radius=7, outer_radius=17)
imviz_helper.load_regions([annulus_1])

phot_plugin.subset_selected = 'Subset 1'
phot_plugin.bg_subset_selected = 'Annulus'
phot_plugin.bg_subset_selected = 'Subset 2'

# Check annulus for ones
assert_allclose(phot_plugin.bg_annulus_inner_r, 7) # From circle
assert_allclose(phot_plugin.bg_annulus_width, 10) # Default
assert_allclose(phot_plugin.background_value, 1)

# Switch data
phot_plugin.dataset_selected = 'four_gaussians'
assert_allclose(phot_plugin.bg_annulus_inner_r, 7) # Unchanged
assert_allclose(phot_plugin.bg_annulus_width, 10)
assert_allclose(phot_plugin.background_value, 5.745596129482831) # Changed

# Draw ellipse on another object
# EllipsePixelRegion(center=PixCoord(x=20.5, y=37.5), width=41, height=15)
imviz_helper._apply_interactive_region('bqplot:ellipse', (0, 30), (41, 45))
phot_plugin.subset_selected = 'Subset 2'

# Load annulus (this used to be part of the plugin but no longer)
annulus_2 = CircleAnnulusPixelRegion(
PixCoord(x=20.5, y=37.5), inner_radius=20.5, outer_radius=30.5)
imviz_helper.load_regions([annulus_2])

phot_plugin.subset_selected = 'Subset 3'
phot_plugin.bg_subset_selected = 'Subset 4'

# Check new annulus for four_gaussians
assert_allclose(phot_plugin.bg_annulus_inner_r, 20.5) # From ellipse half-width
assert_allclose(phot_plugin.bg_annulus_width, 10) # Unchanged
assert_allclose(phot_plugin.background_value, 5.13918435824334) # Changed

# Switch to manual, should not change
Expand All @@ -236,29 +239,18 @@ def test_annulus_background(imviz_helper):
assert_allclose(phot_plugin.background_value, 44.72559981461203)

# Switch back to annulus, should be same as before in same mode
phot_plugin.bg_subset_selected = 'Annulus'
assert_allclose(phot_plugin.bg_annulus_inner_r, 20.5)
assert_allclose(phot_plugin.bg_annulus_width, 10)
phot_plugin.bg_subset_selected = 'Subset 4'
assert_allclose(phot_plugin.background_value, 5.13918435824334)

# Manually change inner_r
phot_plugin.bg_annulus_inner_r = 40
assert_allclose(phot_plugin.background_value, 4.783765940615679)

# Manually change width
phot_plugin.bg_annulus_width = 5
assert_allclose(phot_plugin.background_value, 4.894003242594493)

# Move the last created Subset (ellipse) and make sure background updates
imviz_helper.app.session.edit_subset_mode.mode = ReplaceMode
imviz_helper._apply_interactive_region('bqplot:ellipse', (0, 30), (51, 55))
assert_allclose(phot_plugin.bg_annulus_inner_r, 40)
assert_allclose(phot_plugin.bg_annulus_width, 5)
assert_allclose(phot_plugin.background_value, 4.894003)

# Bad annulus should not crash plugin
phot_plugin.bg_annulus_inner_r = -1
assert_allclose(phot_plugin.background_value, 0)
# Edit the annulus and make sure background updates
subset_plugin = imviz_helper.plugins["Subset Tools"]._obj
subset_plugin.subset_selected = "Subset 4"
subset_plugin._set_value_in_subset_definition(0, "X Center", "value", 25.5)
subset_plugin._set_value_in_subset_definition(0, "Y Center", "value", 42.5)
subset_plugin._set_value_in_subset_definition(0, "Inner radius", "value", 40)
subset_plugin._set_value_in_subset_definition(0, "Outer radius", "value", 45)
subset_plugin.vue_update_subset()
assert_allclose(phot_plugin.background_value, 4.89189)


# NOTE: Extracting the cutout for radial profile is aperture
Expand Down

0 comments on commit 9402123

Please sign in to comment.