Skip to content

Commit

Permalink
BUG: Fix specviz2d loader with ext keyword (#2830)
Browse files Browse the repository at this point in the history
* BUG: Let Specviz2d choose ext

* TST: Add a regression test that fails on main
but should pass with this patch

* BUG: 2D spec might not have valid WCS
but that should not crash the mouseover display.
  • Loading branch information
pllim authored Apr 26, 2024
1 parent 1b72aef commit f133145
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ Specviz
Specviz2d
^^^^^^^^^

- Loading a specific extension with ``ext`` keyword no longer crashes. [#2830]

Other Changes and Additions
---------------------------

Expand Down
22 changes: 13 additions & 9 deletions jdaviz/configs/imviz/plugins/coords_info/coords_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,16 +397,20 @@ def _image_viewer_update(self, viewer, x, y):
self._dict['world'] = (sky.ra.value, sky.dec.value)
self._dict['world:unreliable'] = unreliable_world
elif isinstance(viewer, MosvizProfile2DView) and hasattr(getattr(image, 'coords', None),
'pixel_to_world_values'):
'pixel_to_world'):
# use WCS to expose the wavelength for a 2d spectrum shown in pixel space
wave, pixel = image.coords.pixel_to_world(x, y)
self.row2_title = 'Wave'
self.row2_text = f'{wave.value:10.5e} {wave.unit.to_string()}'
self.row2_unreliable = False
try:
wave, pixel = image.coords.pixel_to_world(x, y)
except Exception: # WCS might not be valid # pragma: no cover
coords_status = False
else:
self.row2_title = 'Wave'
self.row2_text = f'{wave.value:10.5e} {wave.unit.to_string()}'
self.row2_unreliable = False

self.row3_title = '\u00A0'
self.row3_text = ""
self.row3_unreliable = False
self.row3_title = '\u00A0'
self.row3_text = ""
self.row3_unreliable = False
else:
self.row2_title = '\u00A0'
self.row2_text = ""
Expand Down Expand Up @@ -484,7 +488,7 @@ def _image_viewer_update(self, viewer, x, y):
self.marks[viewer._reference_id].visible = True

for matched_marker_id in self._matched_markers.get(viewer._reference_id, []):
if hasattr(getattr(image, 'coords', None), 'pixel_to_world_values'):
if coords_status and hasattr(getattr(image, 'coords', None), 'pixel_to_world'):
# should already have wave computed from setting the coords-info
matched_viewer = self.app.get_viewer(matched_marker_id.split(':matched')[0])
wave = wave.to_value(matched_viewer.state.x_display_unit)
Expand Down
2 changes: 1 addition & 1 deletion jdaviz/configs/mosviz/plugins/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def _parse_as_spectrum1d(hdulist, ext, transpose):
data_obj = [data_obj]

# See if this is a multi s2d file
if len(data_obj) == 1 and _check_is_file(data_obj[0]):
if app.config == "mosviz" and len(data_obj) == 1 and _check_is_file(data_obj[0]):
if identify_jwst_s2d_multi_fits("test", data_obj[0]):
data_obj = SpectrumList.read(data_obj[0])

Expand Down
33 changes: 33 additions & 0 deletions jdaviz/configs/specviz2d/tests/test_parsers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pytest
import stdatamodels
from astropy.io import fits
from astropy.utils.data import download_file

from jdaviz.utils import PRIHDR_KEY
from jdaviz.configs.imviz.tests.utils import create_example_gwcs


@pytest.mark.remote_data
Expand Down Expand Up @@ -89,6 +91,37 @@ def test_2d_parser_no_unit(specviz2d_helper, mos_spectrum2d):
assert label_mouseover.icon == 'b'


def test_2d_parser_hdulist_ext(tmp_path, specviz2d_helper, mos_spectrum2d_as_hdulist):
in_filename = tmp_path / "my_2d_spec.fits"

# Create a dummy ASDF extension to trick specutil to use JWST s2d parser.
# The actual values do not matter here; they are currently nonsense.
w = create_example_gwcs(mos_spectrum2d_as_hdulist['SCI'].data.shape)
w.bounding_box = ((-1, 2.9), (6, 7.5))
tree = {
'model': {
'sci': {
'data': mos_spectrum2d_as_hdulist['SCI'].data
}
},
'meta': {'wcs': w}
}
stdatamodels.asdf_in_fits.write(in_filename, tree, mos_spectrum2d_as_hdulist, overwrite=True)

specviz2d_helper.load_data(in_filename, ext=1)
assert len(specviz2d_helper.app.data_collection) == 2

dc_0 = specviz2d_helper.app.data_collection[0]
assert dc_0.label == 'Spectrum 2D'
assert dc_0.get_component('flux').units == 'ct'

dc_1 = specviz2d_helper.app.data_collection[1]
assert dc_1.label == 'Spectrum 1D'
assert dc_1.get_component('flux').units == dc_0.get_component('flux').units

# The rest already checked in test_2d_parser_no_unit above.


def test_1d_parser(specviz2d_helper, spectrum1d):
specviz2d_helper.load_data(spectrum_1d=spectrum1d)
assert len(specviz2d_helper.app.data_collection) == 1
Expand Down
42 changes: 32 additions & 10 deletions jdaviz/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,15 +288,7 @@ def spectrum2d():
return Spectrum1D(flux=data*u.MJy, spectral_axis=data[3]*u.um)


@pytest.fixture
def mos_spectrum2d():
'''
A specially defined 2D (spatial) Spectrum1D whose wavelength range matches the
mos-specific 1D spectrum.
TODO: This should be reformed to match the global Spectrum1D defined above so that we may
deprecate the mos-specific spectrum1d.
'''
def _generate_mos_spectrum2d():
header = {
'WCSAXES': 2,
'CRPIX1': 0.0, 'CRPIX2': 1024.5,
Expand All @@ -305,12 +297,42 @@ def mos_spectrum2d():
'CTYPE1': 'WAVE', 'CTYPE2': 'OFFSET',
'CRVAL1': 0.0, 'CRVAL2': 5.0,
'RADESYS': 'ICRS', 'SPECSYS': 'BARYCENT'}
wcs = WCS(header)
np.random.seed(42)
data = np.random.sample((1024, 15)) * u.one
return data, header


@pytest.fixture
def mos_spectrum2d():
'''
A specially defined 2D (spatial) Spectrum1D whose wavelength range matches the
mos-specific 1D spectrum.
TODO: This should be reformed to match the global Spectrum1D defined above so that we may
deprecate the mos-specific spectrum1d.
'''
data, header = _generate_mos_spectrum2d()
wcs = WCS(header)
return Spectrum1D(data, wcs=wcs, meta=header)


@pytest.fixture
def mos_spectrum2d_as_hdulist():
data, header = _generate_mos_spectrum2d()
hdu = fits.ImageHDU(data.value)
hdu.header.update(header)

# This layout is to trick specutils to think it is JWST s2d
hdulist = fits.HDUList([fits.PrimaryHDU(), hdu, hdu])
hdulist[0].header["TELESCOP"] = "JWST"
hdulist[1].name = "SCI"
hdulist[1].ver = 1
hdulist[2].name = "SCI"
hdulist[2].ver = 2

return hdulist


@pytest.fixture
def mos_image():
header = {
Expand Down

0 comments on commit f133145

Please sign in to comment.