From 64ad231f549972da286f39b36a9222efd469ef41 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Tue, 19 Nov 2024 12:57:05 -0500 Subject: [PATCH 1/8] Add spaxel to the list of recognized solid angle units --- jdaviz/core/unit_conversion_utils.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/jdaviz/core/unit_conversion_utils.py b/jdaviz/core/unit_conversion_utils.py index ebad68b367..91c9068fde 100644 --- a/jdaviz/core/unit_conversion_utils.py +++ b/jdaviz/core/unit_conversion_utils.py @@ -115,15 +115,11 @@ def check_if_unit_is_per_solid_angle(unit, return_unit=False): # to check type new_unit_str = ' '.join(i).translate(str.maketrans('', '', '()')) new_unit = u.Unit(new_unit_str) - if new_unit.physical_type == 'solid angle': + if new_unit.physical_type == 'solid angle' or new_unit == PIX2 or new_unit_str == 'spaxel': # noqa + # square pixel and spaxel should be considered square angle units if return_unit: # area units present and requested to be returned return new_unit return True # area units present but not requested to be returned - # square pixel should be considered a square angle unit - if new_unit == PIX2: - if return_unit: - return new_unit - return True # in the case there are no area units, but return units were requested if return_unit: From 78f572473903beb69874bf756943d03f03681f78 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Tue, 19 Nov 2024 14:07:09 -0500 Subject: [PATCH 2/8] Update test to use a newer file that would fail the test on main --- jdaviz/configs/cubeviz/plugins/tests/test_data_retrieval.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/cubeviz/plugins/tests/test_data_retrieval.py b/jdaviz/configs/cubeviz/plugins/tests/test_data_retrieval.py index ee1acdef34..414893190e 100644 --- a/jdaviz/configs/cubeviz/plugins/tests/test_data_retrieval.py +++ b/jdaviz/configs/cubeviz/plugins/tests/test_data_retrieval.py @@ -16,8 +16,9 @@ def test_data_retrieval(cubeviz_helper): return the same spectrum values. """ # This file is originally from - # https://data.sdss.org/sas/dr14/manga/spectro/redux/v2_1_2/7495/stack/manga-7495-12704-LOGCUBE.fits.gz - URL = 'https://stsci.box.com/shared/static/28a88k1qfipo4yxc4p4d40v4axtlal8y.fits' + # https://data.sdss.org/sas/dr17/manga/spectro/redux/v3_1_1/9862/stack/manga-9862-12703-LOGCUBE.fits.gz + # (Updated to a newer file 11/19/2024) + URL = 'https://stsci.box.com/shared/static/gts87zqt5265msuwi4w5u003b6typ6h0.gz' spectrum_viewer_reference_name = "spectrum-viewer" fn = download_file(URL, cache=True) From a7e88a73151d3d617a0065ebfe4d9175912505ab Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Thu, 21 Nov 2024 10:07:09 -0500 Subject: [PATCH 3/8] convert per spaxel to per pixel squared on data load --- jdaviz/configs/cubeviz/plugins/parsers.py | 3 +++ .../configs/specviz/plugins/unit_conversion/unit_conversion.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/jdaviz/configs/cubeviz/plugins/parsers.py b/jdaviz/configs/cubeviz/plugins/parsers.py index 3a989c4fc5..8c8906d92d 100644 --- a/jdaviz/configs/cubeviz/plugins/parsers.py +++ b/jdaviz/configs/cubeviz/plugins/parsers.py @@ -203,6 +203,9 @@ def _return_spectrum_with_correct_units(flux, wcs, metadata, data_type=None, if (apply_pix2 and (data_type != "mask") and (not check_if_unit_is_per_solid_angle(flux.unit))): target_flux_unit = flux.unit / PIX2 + elif check_if_unit_is_per_solid_angle(flux.unit, return_unit=True) == "spaxel": + # We need to convert spaxel to pixel squared, since spaxel isn't fully supported by astropy + target_flux_unit = flux.unit * u.Unit('spaxel') / PIX2 if target_wave_unit is None and hdulist is not None: found_target = False diff --git a/jdaviz/configs/specviz/plugins/unit_conversion/unit_conversion.py b/jdaviz/configs/specviz/plugins/unit_conversion/unit_conversion.py index f54a0655fb..192113978e 100644 --- a/jdaviz/configs/specviz/plugins/unit_conversion/unit_conversion.py +++ b/jdaviz/configs/specviz/plugins/unit_conversion/unit_conversion.py @@ -146,7 +146,7 @@ def __init__(self, *args, **kwargs): items='angle_unit_items', selected='angle_unit_selected') # NOTE: will switch to pix2 only if first data loaded into viewer is in pix2 units - # initialize flux choices to empty list, will be populated when data is loaded + # initialize angle unit choices to empty list, will be populated when data is loaded self.angle_unit.choices = [] self.has_sb = self.has_angle or self.config in ('imviz',) From 30b71a4d43ff4fe444e8ee2eb03d827849d6cc65 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Thu, 21 Nov 2024 16:21:43 -0500 Subject: [PATCH 4/8] Only add spaxel once, on app load. --- jdaviz/app.py | 4 +++- .../cubeviz/plugins/moment_maps/moment_maps.py | 3 --- jdaviz/configs/cubeviz/plugins/parsers.py | 6 +++++- .../plugins/gaussian_smooth/gaussian_smooth.py | 5 ----- jdaviz/core/custom_units_and_equivs.py | 18 ++++++++++++++++-- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/jdaviz/app.py b/jdaviz/app.py index b5885b44b5..556e0279a5 100644 --- a/jdaviz/app.py +++ b/jdaviz/app.py @@ -52,7 +52,7 @@ from jdaviz.utils import (SnackbarQueue, alpha_index, data_has_valid_wcs, layer_is_table_data, MultiMaskSubsetState, _wcs_only_label, flux_conversion, spectral_axis_conversion) -from jdaviz.core.custom_units_and_equivs import SPEC_PHOTON_FLUX_DENSITY_UNITS +from jdaviz.core.custom_units_and_equivs import SPEC_PHOTON_FLUX_DENSITY_UNITS, enable_spaxel_unit from jdaviz.core.unit_conversion_utils import (check_if_unit_is_per_solid_angle, combine_flux_and_angle_units, supported_sq_angle_units) @@ -62,6 +62,8 @@ SplitPanes() GoldenLayout() +enable_spaxel_unit() + CONTAINER_TYPES = dict(row='gl-row', col='gl-col', stack='gl-stack') EXT_TYPES = dict(flux=['flux', 'sci'], uncert=['ivar', 'err', 'var', 'uncert'], diff --git a/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py b/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py index 339f23d660..44c9662a94 100644 --- a/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py +++ b/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py @@ -24,9 +24,6 @@ SPECUTILS_LT_1_15_1 = not minversion(specutils, "1.15.1.dev") -spaxel = u.def_unit('spaxel', 1 * u.Unit("")) -u.add_enabled_units([spaxel]) - moment_unit_options = {0: ["Surface Brightness"], 1: ["Velocity", "Spectral Unit"], 2: ["Velocity", "Velocity^N"]} diff --git a/jdaviz/configs/cubeviz/plugins/parsers.py b/jdaviz/configs/cubeviz/plugins/parsers.py index 8c8906d92d..a3ba374f43 100644 --- a/jdaviz/configs/cubeviz/plugins/parsers.py +++ b/jdaviz/configs/cubeviz/plugins/parsers.py @@ -5,7 +5,7 @@ import numpy as np from astropy import units as u from astropy.io import fits -from astropy.nddata import StdDevUncertainty +from astropy.nddata import StdDevUncertainty, InverseVariance from astropy.time import Time from astropy.wcs import WCS from specutils import Spectrum1D @@ -205,6 +205,7 @@ def _return_spectrum_with_correct_units(flux, wcs, metadata, data_type=None, target_flux_unit = flux.unit / PIX2 elif check_if_unit_is_per_solid_angle(flux.unit, return_unit=True) == "spaxel": # We need to convert spaxel to pixel squared, since spaxel isn't fully supported by astropy + # This is horribly ugly but just multiplying by u.Unit("spaxel") doesn't work target_flux_unit = flux.unit * u.Unit('spaxel') / PIX2 if target_wave_unit is None and hdulist is not None: @@ -451,6 +452,9 @@ def _parse_spectrum1d_3d(app, file_obj, data_label=None, if attr == "mask": flux = val << u.dimensionless_unscaled # DQ flags have no unit elif attr == "uncertainty": + if isinstance(val, InverseVariance): + # We don't want to divide by 0 and get infs + val.array[np.where(val.array == 0)] = np.nan flux = val.represent_as(StdDevUncertainty).quantity else: flux = val diff --git a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py index 28884d8a6a..13c759cb11 100644 --- a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py +++ b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py @@ -16,11 +16,6 @@ __all__ = ['GaussianSmooth'] - -spaxel = u.def_unit('spaxel', 1 * u.Unit("")) -u.add_enabled_units([spaxel]) - - @tray_registry('g-gaussian-smooth', label="Gaussian Smooth", viewer_requirements=['spectrum', 'flux']) class GaussianSmooth(PluginTemplateMixin, DatasetSelectMixin, AddResultsMixin): diff --git a/jdaviz/core/custom_units_and_equivs.py b/jdaviz/core/custom_units_and_equivs.py index 3a5ba5405d..ea6f611637 100644 --- a/jdaviz/core/custom_units_and_equivs.py +++ b/jdaviz/core/custom_units_and_equivs.py @@ -8,6 +8,13 @@ PIX2 = u.pix * u.pix +# Add spaxel to enabled units +def enable_spaxel_unit(): + spaxel = u.Unit('spaxel', represents=u.pixel, parse_strict='silent') + u.add_enabled_units([spaxel]) + return + + def _spectral_and_photon_flux_density_units(freq_only=False, wav_only=False, as_units=False): """ @@ -92,8 +99,15 @@ def _eqv_flux_to_sb_pixel(): u.ct, u.DN, u.DN / u.s] - return [(flux_unit, flux_unit / PIX2, lambda x: x, lambda x: x) - for flux_unit in flux_units] + + equivs = [(flux_unit, flux_unit / PIX2, lambda x: x, lambda x: x) + for flux_unit in flux_units] + + # We also need to convert between spaxel and pixel squared + equivs += [(flux_unit / u.Unit('spaxel'), flux_unit / PIX2, + lambda x: x, lambda x: x) for flux_unit in flux_units] + + return equivs def _eqv_sb_per_pixel_to_per_angle(flux_unit, scale_factor=1): From d64a00f75b22fc9296802ac68059fba4af7e2541 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Thu, 21 Nov 2024 16:22:53 -0500 Subject: [PATCH 5/8] Codestyle --- .../configs/default/plugins/gaussian_smooth/gaussian_smooth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py index 13c759cb11..7fe61ada22 100644 --- a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py +++ b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py @@ -1,6 +1,5 @@ import numpy as np -from astropy import units as u from astropy.convolution import convolve, Gaussian2DKernel from specutils import Spectrum1D from specutils.manipulation import gaussian_smooth @@ -16,6 +15,7 @@ __all__ = ['GaussianSmooth'] + @tray_registry('g-gaussian-smooth', label="Gaussian Smooth", viewer_requirements=['spectrum', 'flux']) class GaussianSmooth(PluginTemplateMixin, DatasetSelectMixin, AddResultsMixin): From 5e439cb18a83ba613d64bcab175c8c8bb83e89e3 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 22 Nov 2024 10:05:48 -0500 Subject: [PATCH 6/8] Set bad uncert values to 0 instead of NaN here --- jdaviz/configs/cubeviz/plugins/parsers.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/cubeviz/plugins/parsers.py b/jdaviz/configs/cubeviz/plugins/parsers.py index a3ba374f43..9b7ea49fa6 100644 --- a/jdaviz/configs/cubeviz/plugins/parsers.py +++ b/jdaviz/configs/cubeviz/plugins/parsers.py @@ -452,10 +452,13 @@ def _parse_spectrum1d_3d(app, file_obj, data_label=None, if attr == "mask": flux = val << u.dimensionless_unscaled # DQ flags have no unit elif attr == "uncertainty": + bad_locs = None if isinstance(val, InverseVariance): - # We don't want to divide by 0 and get infs - val.array[np.where(val.array == 0)] = np.nan + bad_locs = val.array[np.where(val.array == 0)] flux = val.represent_as(StdDevUncertainty).quantity + if bad_locs is not None: + # Prefer 0 over inf for the masked out values here + flux[bad_locs] = 0 else: flux = val From 127952653849e22c1f670a10911e64cc24ea0881 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 22 Nov 2024 10:57:02 -0500 Subject: [PATCH 7/8] Remove inf uncertainty replacement --- jdaviz/configs/cubeviz/plugins/parsers.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/jdaviz/configs/cubeviz/plugins/parsers.py b/jdaviz/configs/cubeviz/plugins/parsers.py index 9b7ea49fa6..10eed517ad 100644 --- a/jdaviz/configs/cubeviz/plugins/parsers.py +++ b/jdaviz/configs/cubeviz/plugins/parsers.py @@ -452,13 +452,7 @@ def _parse_spectrum1d_3d(app, file_obj, data_label=None, if attr == "mask": flux = val << u.dimensionless_unscaled # DQ flags have no unit elif attr == "uncertainty": - bad_locs = None - if isinstance(val, InverseVariance): - bad_locs = val.array[np.where(val.array == 0)] flux = val.represent_as(StdDevUncertainty).quantity - if bad_locs is not None: - # Prefer 0 over inf for the masked out values here - flux[bad_locs] = 0 else: flux = val From 8e50ce76d87fef17da3aa97c3eee361e1c3c5142 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 22 Nov 2024 11:09:04 -0500 Subject: [PATCH 8/8] Remove unused import --- jdaviz/configs/cubeviz/plugins/parsers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdaviz/configs/cubeviz/plugins/parsers.py b/jdaviz/configs/cubeviz/plugins/parsers.py index 10eed517ad..91d6f17a9d 100644 --- a/jdaviz/configs/cubeviz/plugins/parsers.py +++ b/jdaviz/configs/cubeviz/plugins/parsers.py @@ -5,7 +5,7 @@ import numpy as np from astropy import units as u from astropy.io import fits -from astropy.nddata import StdDevUncertainty, InverseVariance +from astropy.nddata import StdDevUncertainty from astropy.time import Time from astropy.wcs import WCS from specutils import Spectrum1D