diff --git a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py index 89d0aa16dc..43e5cdf149 100644 --- a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py +++ b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py @@ -315,6 +315,16 @@ def uncert_cube(self): def spectral_display_unit(self): return astropy.units.Unit(self.app._get_display_unit(self.slice_display_unit_name)) + @property + def mask_non_science(self): + # Aperture masks begin by finding removing from consideration any pixel + # set to NaN, which corresponds to a pixel on the "non-science" portions + # of the detector. For JWST spectral cubes, these pixels are marked in + # the DQ array with flag `513`. + return np.logical_not( + np.isnan(self.dataset.selected_obj.flux.value) + ).astype(float) + @property def aperture_weight_mask(self): # Exact slice mask of cone or cylindrical aperture through the cube. `weight_mask` is @@ -322,21 +332,31 @@ def aperture_weight_mask(self): # wavelength, on the range [0, 1]. if self.aperture.selected == self.aperture.default_text: # Entire Cube - return np.ones_like(self.dataset.selected_obj.flux.value) - return self.aperture.get_mask(self.dataset.selected_obj, - self.aperture_method_selected, - self.spectral_display_unit, - self.reference_spectral_value if self.wavelength_dependent else None) # noqa + return self.mask_non_science + + return ( + self.mask_non_science * + self.aperture.get_mask( + self.dataset.selected_obj, + self.aperture_method_selected, + self.spectral_display_unit, + self.reference_spectral_value if self.wavelength_dependent else None) + ) @property def bg_weight_mask(self): if self.background.selected == self.background.default_text: # NO background return np.zeros_like(self.dataset.selected_obj.flux.value) - return self.background.get_mask(self.dataset.selected_obj, - self.aperture_method_selected, - self.spectral_display_unit, - self.reference_spectral_value if self.bg_wavelength_dependent else None) # noqa + + return ( + self.mask_non_science * + self.background.get_mask( + self.dataset.selected_obj, + self.aperture_method_selected, + self.spectral_display_unit, + self.reference_spectral_value if self.bg_wavelength_dependent else None) + ) @property def aperture_area_along_spectral(self): diff --git a/jdaviz/configs/cubeviz/plugins/spectral_extraction/tests/test_spectral_extraction.py b/jdaviz/configs/cubeviz/plugins/spectral_extraction/tests/test_spectral_extraction.py index 56bdc9902d..9e8e643ffa 100644 --- a/jdaviz/configs/cubeviz/plugins/spectral_extraction/tests/test_spectral_extraction.py +++ b/jdaviz/configs/cubeviz/plugins/spectral_extraction/tests/test_spectral_extraction.py @@ -5,6 +5,7 @@ import numpy as np from astropy import units as u from astropy.nddata import NDDataArray, StdDevUncertainty +from astropy.tests.helper import assert_quantity_allclose from astropy.utils.exceptions import AstropyUserWarning from glue.core.roi import CircularROI, RectangularROI from glue.core.edit_subset_mode import ReplaceMode, AndNotMode, NewMode @@ -518,3 +519,26 @@ def test_spectral_extraction_with_correct_sum_units(cubeviz_helper, ) assert collapsed.flux.unit == u.Jy assert collapsed.uncertainty.unit == u.Jy + + +def test_default_spectral_extraction(cubeviz_helper, spectrum1d_cube_fluxunit_jy_per_steradian): + # spacetelescope/jdaviz#3086 reported that the default cube + # spectral extraction in cubeviz did not match the spectral extraction + # for a spatial subset that captures all spaxels. this regression tests + # make sure that doesn't happen anymore by accounting for non-science pixels + # in the sums: + cubeviz_helper.load_data(spectrum1d_cube_fluxunit_jy_per_steradian) + flux_viewer = cubeviz_helper.app.get_viewer('flux-viewer') + + # create a spatial subset that spans all spaxels: + flux_viewer.apply_roi(CircularROI(1.5, 2, 5)) + + # the first and second spectra correspond to the default extraction + # and the subset extraction. the fluxes in these extractions should agree: + extracted_spectra = list( + cubeviz_helper.specviz.get_spectra(apply_slider_redshift=False).values() + ) + + assert_quantity_allclose( + extracted_spectra[0].flux, extracted_spectra[1].flux + )