diff --git a/CHANGES.rst b/CHANGES.rst index eedf081154..6e1b515f7c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -37,6 +37,9 @@ API Changes Cubeviz ^^^^^^^ +- Custom Spectrum1D writer format ``jdaviz-cube`` is removed. Use ``wcs1d-fits`` from + ``specutils`` instead. [#2094] + Imviz ^^^^^ diff --git a/docs/cubeviz/export_data.rst b/docs/cubeviz/export_data.rst index 70ebac4c9d..daa3e5c86c 100644 --- a/docs/cubeviz/export_data.rst +++ b/docs/cubeviz/export_data.rst @@ -83,7 +83,7 @@ where the mask (if available) is as defined in .. code-block:: python - mydata.write("mydata.fits", format="jdaviz-cube") + mydata.write("mydata.fits", format="wcs1d-fits") Data can also be accessed directly from ``data_collection`` using the following code: diff --git a/jdaviz/configs/cubeviz/helper.py b/jdaviz/configs/cubeviz/helper.py index dc102af7e0..eb43393e8a 100644 --- a/jdaviz/configs/cubeviz/helper.py +++ b/jdaviz/configs/cubeviz/helper.py @@ -1,9 +1,5 @@ import numpy as np -from astropy.io import fits -from astropy.io import registry as io_registry from glue.core import BaseData -from specutils import Spectrum1D -from specutils.io.registers import _astropy_has_priorities from jdaviz.core.helpers import ImageConfigHelper from jdaviz.configs.default.plugins.line_lists.line_list_mixin import LineListMixin @@ -156,63 +152,3 @@ def get_data(self, data_label=None, cls=None, subset_to_apply=None, function=Non def layer_is_cube_image_data(layer): return isinstance(layer, BaseData) and layer.ndim in (2, 3) - - -# TODO: We can remove this when specutils supports it, i.e., -# https://github.com/astropy/specutils/issues/592 and -# https://github.com/astropy/specutils/pull/1009 -# NOTE: Cannot use custom_write decorator from specutils because -# that involves asking user to manually put something in -# their ~/.specutils directory. - -def jdaviz_cube_fitswriter(spectrum, file_name, **kwargs): - """This is a custom writer for Spectrum1D data cube. - This writer is specifically targetting data cube - generated from Cubeviz plugins (e.g., cube fitting) - with FITS WCS. It writes out data in the following format - (with MASK only exist when applicable):: - - No. Name Ver Type - 0 PRIMARY 1 PrimaryHDU - 1 SCI 1 ImageHDU (float32) - 2 MASK 1 ImageHDU (uint16) - - The FITS file generated by this writer does not need a - custom reader to be read back into Spectrum1D. - - Examples - -------- - To write out a Spectrum1D cube using this writer: - - >>> spec.write("my_output.fits", format="jdaviz-cube", overwrite=True) # doctest: +SKIP - - """ - pri_hdu = fits.PrimaryHDU() - - flux = spectrum.flux - sci_hdu = fits.ImageHDU(flux.value.astype(np.float32)) - sci_hdu.name = "SCI" - sci_hdu.header.update(spectrum.meta) - sci_hdu.header.update(spectrum.wcs.to_header()) - sci_hdu.header['BUNIT'] = flux.unit.to_string(format='fits') - - hlist = [pri_hdu, sci_hdu] - - # https://specutils.readthedocs.io/en/latest/spectrum1d.html#including-masks - # Good: False or 0 - # Bad: True or non-zero - if spectrum.mask is not None: - mask_hdu = fits.ImageHDU(spectrum.mask.astype(np.uint16)) - mask_hdu.name = "MASK" - hlist.append(mask_hdu) - - hdulist = fits.HDUList(hlist) - hdulist.writeto(file_name, **kwargs) - - -if _astropy_has_priorities(): - kwargs = {"priority": 0} -else: # pragma: no cover - kwargs = {} -io_registry.register_writer( - "jdaviz-cube", Spectrum1D, jdaviz_cube_fitswriter, force=False, **kwargs) diff --git a/jdaviz/configs/default/plugins/model_fitting/tests/test_fitting.py b/jdaviz/configs/default/plugins/model_fitting/tests/test_fitting.py index 583c409a71..0981596a92 100644 --- a/jdaviz/configs/default/plugins/model_fitting/tests/test_fitting.py +++ b/jdaviz/configs/default/plugins/model_fitting/tests/test_fitting.py @@ -4,7 +4,6 @@ import pytest from astropy import units as u from astropy.io import fits -from astropy.io.registry.base import IORegistryError from astropy.modeling import models, parameters as params from astropy.nddata import StdDevUncertainty from astropy.wcs import WCS @@ -227,7 +226,7 @@ def test_cube_fitting_backend(cubeviz_helper, unc, tmp_path): # Check I/O roundtrip. out_fn = tmp_path / "fitted_cube.fits" - fitted_spectrum.write(out_fn, format="jdaviz-cube", overwrite=True) + fitted_spectrum.write(out_fn, format="wcs1d-fits", overwrite=True) flux_unit_str = fitted_spectrum.flux.unit.to_string(format="fits") coo_expected = fitted_spectrum.wcs.pixel_to_world(1, 0, 2) with fits.open(out_fn) as pf: @@ -244,12 +243,7 @@ def test_cube_fitting_backend(cubeviz_helper, unc, tmp_path): assert_allclose([coo[1].ra.deg, coo[1].dec.deg], [coo_expected[1].ra.deg, coo_expected[1].dec.deg]) - # Our custom format is not registered to readers, just writers. - # You can read it back in without custom read. See "Cubeviz roundtrip" below. - with pytest.raises(IORegistryError, match="No reader defined"): - Spectrum1D.read(out_fn, format="jdaviz-cube") - - # Check Cubeviz roundtrip. + # Check Cubeviz roundtrip. This should automatically go through wcs1d-fits reader. cubeviz_helper.load_data(out_fn) assert len(cubeviz_helper.app.data_collection) == 2 data_sci = cubeviz_helper.app.data_collection["fitted_cube.fits[SCI]"]