diff --git a/docs/create_products.rst b/docs/create_products.rst index 3a78bd6991..ebd7c62a9f 100644 --- a/docs/create_products.rst +++ b/docs/create_products.rst @@ -5,14 +5,14 @@ Creating Jdaviz-readable Products Spectroscopic data products (1D, 2D, and 3D) can be loaded in the different ``jdaviz`` configurations using -essentially two methods, i.e., loading :class:`~specutils.Spectrum1D` objects or +essentially two methods, i.e., loading :class:`~specutils.Spectrum` objects or from FITS files. Here, we list a few ways in which data can be packaged to be easily loaded into a ``jdaviz`` configuration. Data in a database ------------------ -If the data are stored in a database, we recommend storing a :class:`~specutils.Spectrum1D` object +If the data are stored in a database, we recommend storing a :class:`~specutils.Spectrum` object per entry. This would allow the user to query the data and visualize it in ``jdaviz`` with few lines of code; also see :ref:`create_product_spectrum1d_obj`. @@ -34,8 +34,8 @@ Available loaders can be listed with the following commands: .. code-block:: python - from specutils import Spectrum1D - Spectrum1D.read.list_formats() + from specutils import Spectrum + Spectrum.read.list_formats() The majority are fairly specific to missions and instruments. Four formats are more generic and adaptable: ``ASCII``, ``ECSV``, ``tabular-fits``, and @@ -55,14 +55,14 @@ is available. We are working on the necessary documentation to prompt .. _create_product_spectrum1d_obj: -Providing scripts to load the data as Spectrum1D objects +Providing scripts to load the data as Spectrum objects ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If none of the above is an acceptable option, the user can create the data products with their custom format and provide scripts or Jupyter Notebooks -that show how to read the products and create :class:`~specutils.Spectrum1D` objects +that show how to read the products and create :class:`~specutils.Spectrum` objects that can be read into ``jdaviz``. More about -how to create :class:`~specutils.Spectrum1D` objects for the 1D, 2D, and 3D cases can be +how to create :class:`~specutils.Spectrum` objects for the 1D, 2D, and 3D cases can be found in the corresponding "Importing data" sections of the various configurations: * :ref:`specviz-import-data` diff --git a/docs/cubeviz/export_data.rst b/docs/cubeviz/export_data.rst index 976e204d4d..87587b3819 100644 --- a/docs/cubeviz/export_data.rst +++ b/docs/cubeviz/export_data.rst @@ -65,12 +65,12 @@ with the name of the data you want to extract): mydata = cubeviz.get_data(data_label="data_name") -The data is returned as a 3D `specutils.Spectrum1D` object. +The data is returned as a 3D `specutils.Spectrum` object. -To write out a `specutils.Spectrum1D` cube from Cubeviz +To write out a `specutils.Spectrum` cube from Cubeviz (e.g., a fitted cube from :ref:`model-fitting`), where the mask (if available) is as defined in -`Spectrum1D masks `_: +`Spectrum masks `_: .. code-block:: python diff --git a/docs/cubeviz/import_data.rst b/docs/cubeviz/import_data.rst index 27ced24856..d9cb50be99 100644 --- a/docs/cubeviz/import_data.rst +++ b/docs/cubeviz/import_data.rst @@ -5,24 +5,24 @@ Importing Data into Cubeviz *************************** By design, Cubeviz only supports data that can be parsed as -:class:`~specutils.Spectrum1D` objects. Despite the name, :class:`~specutils.Spectrum1D` -supports 3D cubes and allows the Python-level interface and parsing tools to +:class:`~specutils.Spectrum` objects. :class:`~specutils.Spectrum` supports 3D cubes +and allows the Python-level interface and parsing tools to be defined in ``specutils`` instead of being duplicated in Jdaviz. -:class:`~specutils.Spectrum1D` objects are very flexible in their capabilities, however, +:class:`~specutils.Spectrum` objects are very flexible in their capabilities, however, and hence should address most astronomical spectrum use cases. If you are creating your own data products, please read the page :ref:`create_products`. Cubeviz will automatically parse the data into the multiple viewers as described in :ref:`cubeviz-display-cubes`. For the best experience, data loaded into Cubeviz should contain valid WCS -keywords. For more information on how :class:`~specutils.Spectrum1D` -uses WCS, please go to the `Spectrum1D defining WCS section `_. +keywords. For more information on how :class:`~specutils.Spectrum` +uses WCS, please go to the `Spectrum defining WCS section `_. To check if your FITS file contains valid WCS keywords, please use `Astropy WCS validate `. For an example on loading a cube with valid WCS keywords, please see the :ref:`cubeviz-import-api` section below. Loading data without WCS is also possible as long as they are compatible -with :class:`~specutils.Spectrum1D`. However, not all plugins will work with this data. +with :class:`~specutils.Spectrum`. However, not all plugins will work with this data. .. _cubeviz-viewers: @@ -60,7 +60,7 @@ Importing data through the GUI Users may load data into the Cubeviz application by clicking the :guilabel:`Import Data` button at the top left of the application's user interface. This opens a dialogue with a prompt to select a file -that can be parsed as a :class:`~specutils.Spectrum1D` object. +that can be parsed as a :class:`~specutils.Spectrum` object. After clicking :guilabel:`Import`, the data file will be parsed and loaded into the application. A notification will appear to confirm whether the data import @@ -75,7 +75,7 @@ Importing data via the API Alternatively, users who work in a coding environment like a Jupyter notebook can access the Cubeviz helper class API. Using this API, users can load data into the application through code with the :py:meth:`~jdaviz.configs.specviz.helper.Specviz.load_data` -method, which takes as input a :class:`~specutils.Spectrum1D` object. +method, which takes as input a :class:`~specutils.Spectrum` object. FITS Files ---------- @@ -89,33 +89,33 @@ The example below loads a FITS file into Cubeviz: cubeviz.load_data("/path/to/data/file.fits") cubeviz.show() -Spectrum1D (from file) +Spectrum (from file) ---------------------- For cases where the built-in parser is unable to understand your file format, -you can try the `~specutils.Spectrum1D` parser directly and then pass the object to the +you can try the `~specutils.Spectrum` parser directly and then pass the object to the :py:meth:`~jdaviz.core.helpers.ConfigHelper.load_data` method: .. code-block:: python - from specutils import Spectrum1D + from specutils import Spectrum from jdaviz import Cubeviz - spec3d = Spectrum1D.read("/path/to/data/file.fits") + spec3d = Spectrum.read("/path/to/data/file.fits") cubeviz = Cubeviz() cubeviz.load_data(spec3d, data_label='My Cube') cubeviz.show() -Spectrum1D (from array) +Spectrum (from array) ----------------------- -You can create your own :class:`~specutils.Spectrum1D` object by hand to load into Cubeviz: +You can create your own :class:`~specutils.Spectrum` object by hand to load into Cubeviz: .. code-block:: python import numpy as np from astropy import units as u from astropy.wcs import WCS - from specutils import Spectrum1D + from specutils import Spectrum from jdaviz import Cubeviz flux = np.arange(16).reshape((2, 2, 4)) * u.Jy @@ -125,7 +125,7 @@ You can create your own :class:`~specutils.Spectrum1D` object by hand to load in "CRPIX1": 0, "CRPIX2": 0, "CRPIX3": 0} w = WCS(wcs_dict) - cube = Spectrum1D(flux=flux, wcs=w) + cube = Spectrum(flux=flux, wcs=w) cubeviz = Cubeviz() cubeviz.load_data(cube, data_label='My Cube') cubeviz.show() @@ -149,7 +149,7 @@ object, you can load it into Cubeviz as follows: mydatamodel = datamodels.open(file) # mydatamodel is a jwst.datamodels object - # Due to current schema in jwst.datamodels, you'll need to create your own WCS object before you create your Spectrum1D object + # Due to current schema in jwst.datamodels, you'll need to create your own WCS object before you create your Spectrum object wcs_dict = {"CTYPE1": mydatamodel.meta.wcsinfo.ctype3, "CTYPE2": mydatamodel.meta.wcsinfo.ctype2, "CTYPE3": mydatamodel.meta.wcsinfo.ctype1, "CRVAL1": mydatamodel.meta.wcsinfo.crval3, "CRVAL2": mydatamodel.meta.wcsinfo.crval2, @@ -166,7 +166,7 @@ object, you can load it into Cubeviz as follows: data = np.swapaxes(data, 1, 2) # Create your spectrum1 - spec3d = Spectrum1D(data, wcs=my_wcs) + spec3d = Spectrum(data, wcs=my_wcs) cubeviz = Cubeviz() cubeviz.load_data(spec3d, data_label='My Cube') cubeviz.show() diff --git a/docs/cubeviz/plugins.rst b/docs/cubeviz/plugins.rst index fb24f0727c..074ea066bf 100644 --- a/docs/cubeviz/plugins.rst +++ b/docs/cubeviz/plugins.rst @@ -12,7 +12,7 @@ icon in the upper right corner of the Cubeviz application. The data analysis plugins are meant to aid quick-look analysis of both 3D and 1D spectroscopic data. In many cases, functions can be applied to -`~specutils.Spectrum1D` objects, which include both 3D and 1D datasets. +`~specutils.Spectrum` objects, which include both 3D and 1D datasets. Plugins that are specific to 1D spectra are described in more detail under :ref:`Specviz: Data Analysis Plugins `. In many cases, these capabilities can be further applied on a per spaxel basis diff --git a/docs/mosviz/plugins.rst b/docs/mosviz/plugins.rst index c49ba83f67..2b99238a41 100644 --- a/docs/mosviz/plugins.rst +++ b/docs/mosviz/plugins.rst @@ -3,7 +3,7 @@ Data Analysis Plugins ********************* The Mosviz data analysis plugins include operations on both -2D images and Spectrum1D one dimensional datasets. +2D images and Spectrum one dimensional datasets. Plugins that are specific to 1D spectra are described in more detail under Specviz:Data Analysis Plugins. All plugins are accessed via the plugin icon in the upper right corner @@ -120,5 +120,5 @@ The :guilabel:`Remove` button can be used to remove a slit once it has been appl In order to plot a slit onto the image viewer, we need WCS information from an image and slit position from a 2D spectrum. The slit position is calculated using the ``S_REGION`` header extension value, located in the -`~specutils.Spectrum1D.meta` attribute of the :class:`~specutils.Spectrum1D` object +`~specutils.Spectrum.meta` attribute of the :class:`~specutils.Spectrum` object that is active in the 2D spectrum viewer. diff --git a/docs/specviz/export_data.rst b/docs/specviz/export_data.rst index 886098751c..59fcd3e2fe 100644 --- a/docs/specviz/export_data.rst +++ b/docs/specviz/export_data.rst @@ -14,8 +14,8 @@ those data currently back into your Jupyter notebook: specviz.get_spectra() -which yields a either a single `specutils.Spectrum1D` object or a dictionary of -`specutils.Spectrum1D` (if there are multiple displayed spectra) that you can +which yields a either a single `specutils.Spectrum` object or a dictionary of +`specutils.Spectrum` (if there are multiple displayed spectra) that you can manipulate however you wish. You can then load the modified spectrum back into the notebook via the API described in :ref:`specviz-import-api`. @@ -35,7 +35,7 @@ To extract a spectrum with a spectral subset applied: specviz.get_data(spectral_subset='Subset 1') -In this case, the returned `specutils.Spectrum1D` object will have a ``mask`` +In this case, the returned `specutils.Spectrum` object will have a ``mask`` attribute, where ``True`` corresponds to the region outside the selected subset (i.e., the region that has been masked out). You could load back in a copy of the spectrum containing only your subset by running: @@ -43,7 +43,7 @@ spectrum containing only your subset by running: .. code-block:: python spec = specviz.get_data(spectral_subset='Subset 1') - subset_spec = Spectrum1D(flux=spec.flux[~spec.mask], + subset_spec = Spectrum(flux=spec.flux[~spec.mask], spectral_axis=spec.spectral_axis[~spec.mask]) specviz.load_data(subset_spec) diff --git a/docs/specviz/import_data.rst b/docs/specviz/import_data.rst index 075c6aefd0..000f310875 100644 --- a/docs/specviz/import_data.rst +++ b/docs/specviz/import_data.rst @@ -4,17 +4,17 @@ Importing Data Into Specviz *************************** -By design, Specviz only supports data that can be parsed as :class:`~specutils.Spectrum1D` objects, +By design, Specviz only supports data that can be parsed as :class:`~specutils.Spectrum` objects, as that allows the Python-level interface and parsing tools to be defined in ``specutils`` instead of being duplicated in Jdaviz. -:class:`~specutils.Spectrum1D` objects are very flexible in their capabilities, however, +:class:`~specutils.Spectrum` objects are very flexible in their capabilities, however, and hence should address most astronomical spectrum use cases. If you are creating your own data products, please read the page :ref:`create_products`. .. seealso:: `Reading from a File `_ - Specutils documentation on loading data as :class:`~specutils.Spectrum1D` objects. + Specutils documentation on loading data as :class:`~specutils.Spectrum` objects. .. _specviz-import-commandline: @@ -36,7 +36,7 @@ Importing data through the GUI You can load your data into the Specviz application by clicking the :guilabel:`Import Data` button at the top left of the application's user interface. This opens a dialogue where the user can select a file -that can be parsed as a :class:`~specutils.Spectrum1D`. +that can be parsed as a :class:`~specutils.Spectrum`. After clicking :guilabel:`Import`, the data file will be parsed and loaded into the application. A notification will appear to let users know if the data import @@ -52,7 +52,7 @@ Alternatively, users who work in a coding environment like a Jupyter notebook can access the Specviz helper class API. Using this API, users can load data into the application through code with the :py:meth:`~jdaviz.configs.specviz.helper.Specviz.load_data` -method, which takes as input a :class:`~specutils.Spectrum1D` object. +method, which takes as input a :class:`~specutils.Spectrum` object. FITS Files ---------- @@ -61,13 +61,13 @@ The example below loads a FITS file into Specviz: .. code-block:: python - from specutils import Spectrum1D - spec1d = Spectrum1D.read("/path/to/data/file") + from specutils import Spectrum + spec1d = Spectrum.read("/path/to/data/file") specviz = Specviz() specviz.load_data(spec1d, data_label="my_spec") specviz.show() -You can also pass the path to a file that `~specutils.Spectrum1D` understands directly to the +You can also pass the path to a file that `~specutils.Spectrum` understands directly to the :py:meth:`~jdaviz.configs.specviz.helper.Specviz.load_data` method: .. code-block:: python @@ -83,12 +83,12 @@ You can create your own array to load into Specviz: import numpy as np import astropy.units as u - from specutils import Spectrum1D + from specutils import Spectrum from jdaviz import Specviz flux = np.random.randn(200) * u.Jy wavelength = np.arange(5100, 5300) * u.AA - spec1d = Spectrum1D(spectral_axis=wavelength, flux=flux) + spec1d = Spectrum(spectral_axis=wavelength, flux=flux) specviz = Specviz() specviz.load_data(spec1d, data_label="my_spec") specviz.show() @@ -101,7 +101,7 @@ object, you can load it into Specviz as follows: .. code-block:: python - from specutils import Spectrum1D + from specutils import Spectrum from jdaviz import Specviz # mydatamodel is a jwst.datamodels.MultiSpecModel object @@ -109,7 +109,7 @@ object, you can load it into Specviz as follows: flux = a.spec_table['FLUX'] wave = a.spec_table['WAVELENGTH'] - spec1d = Spectrum1D(flux=flux, spectral_axis=wave) + spec1d = Spectrum(flux=flux, spectral_axis=wave) specviz = Specviz() specviz.load_data(spec1d, data_label="MultiSpecModel") specviz.show() @@ -124,7 +124,7 @@ Importing a SpectrumList The :py:meth:`~jdaviz.configs.specviz.helper.Specviz.load_data` also accepts a `~specutils.SpectrumList` object, in which case it will both load the -individual `~specutils.Spectrum1D` objects in the list and additionally attempt +individual `~specutils.Spectrum` objects in the list and additionally attempt to stitch together the spectra into a single data object so that they can be manipulated and analyzed in the application as a single entity: diff --git a/docs/specviz/plugins.rst b/docs/specviz/plugins.rst index 8770eb7be8..443b9e58bc 100644 --- a/docs/specviz/plugins.rst +++ b/docs/specviz/plugins.rst @@ -65,12 +65,12 @@ Markers Gaussian Smooth =============== -Gaussian Smooth is performed on a Spectrum1D data object. +Gaussian Smooth is performed on a Spectrum data object. The spectrum is convolved with a Gaussian function. The Gaussian standard deviation in pixels must be entered into the :guilabel:`Standard deviation` field in the plugin. -A new Spectrum1D object is generated and is added to the spectrum +A new Spectrum object is generated and is added to the spectrum viewer. It can be selected and shown in the viewer via the :guilabel:`Data` icon in the viewer toolbar. diff --git a/docs/specviz2d/export_data.rst b/docs/specviz2d/export_data.rst index 4fc2ecd8bc..a91d67b222 100644 --- a/docs/specviz2d/export_data.rst +++ b/docs/specviz2d/export_data.rst @@ -9,7 +9,7 @@ Exporting Data From Specviz2D 2D Spectra ========== -Images in the 2D spectrum viewer can be exported as `specutils.Spectrum1D` objects into +Images in the 2D spectrum viewer can be exported as `specutils.Spectrum` objects into the notebook (replace "2D data" with the label of the desired data): .. code-block:: python diff --git a/docs/specviz2d/import_data.rst b/docs/specviz2d/import_data.rst index 6018ef122f..cb6554c3a5 100644 --- a/docs/specviz2d/import_data.rst +++ b/docs/specviz2d/import_data.rst @@ -4,17 +4,17 @@ Importing Data Into Specviz2D ***************************** -By design, Specviz2D only supports data that can be parsed as :class:`~specutils.Spectrum1D` objects, +By design, Specviz2D only supports data that can be parsed as :class:`~specutils.Spectrum` objects, as that allows the Python-level interface and parsing tools to be defined in ``specutils`` instead of being duplicated in Jdaviz. -:class:`~specutils.Spectrum1D` objects are very flexible in their capabilities, however, +:class:`~specutils.Spectrum` objects are very flexible in their capabilities, however, and hence should address most astronomical spectrum use cases. If you are creating your own data products, please read the page :ref:`create_products`. .. seealso:: `Reading from a File `_ - Specutils documentation on loading data as :class:`~specutils.Spectrum1D` objects. + Specutils documentation on loading data as :class:`~specutils.Spectrum` objects. Specviz2D can either take both a 2D and 1D spectrum as input, or can automatically extract a 1D spectrum if only a 2D spectrum is provided. To view the extraction parameters and override the @@ -42,7 +42,7 @@ Importing data through the GUI You can load your data into the Specviz2D application by clicking the :guilabel:`Import Data` button at the top left of the application's user interface. This opens a dialogue where the user can select a file -that can be parsed as a :class:`~specutils.Spectrum1D`. +that can be parsed as a :class:`~specutils.Spectrum`. After clicking :guilabel:`Import`, the data file will be parsed and loaded into the application. @@ -56,7 +56,7 @@ Alternatively, users who work in a coding environment like a Jupyter notebook can access the Specviz2D helper class API. Using this API, users can load data into the application through code with the :meth:`~jdaviz.configs.specviz2d.helper.Specviz2d.load_data` -method, which takes as input a :class:`~specutils.Spectrum1D` object or filename for the +method, which takes as input a :class:`~specutils.Spectrum` object or filename for the 2D spectrum and (optionally) the 1D spectrum. .. code-block:: python diff --git a/docs/specviz2d/plugins.rst b/docs/specviz2d/plugins.rst index d7639dd97e..7ec9206b9b 100644 --- a/docs/specviz2d/plugins.rst +++ b/docs/specviz2d/plugins.rst @@ -156,7 +156,7 @@ To export and access the specreduce Background object defined in the plugin, cal bg = sp_ext.export_bg() -To access the background image, background spectrum, or background-subtracted image as a :class:`~specutils.Spectrum1D` object, +To access the background image, background spectrum, or background-subtracted image as a :class:`~specutils.Spectrum` object, call :py:meth:`~jdaviz.configs.specviz2d.plugins.spectral_extraction.spectral_extraction.SpectralExtraction.export_bg_img`, :py:meth:`~jdaviz.configs.specviz2d.plugins.spectral_extraction.spectral_extraction.SpectralExtraction.export_bg_spectrum`, or :py:meth:`~jdaviz.configs.specviz2d.plugins.spectral_extraction.spectral_extraction.SpectralExtraction.export_bg_sub`, respectively. @@ -203,7 +203,7 @@ To export and access the specreduce extraction object defined in the plugin, cal ext = sp_ext.export_extract() -To access the extracted spectrum as a :class:`~specutils.Spectrum1D` object, call :py:meth:`~jdaviz.configs.specviz2d.plugins.spectral_extraction.spectral_extraction.SpectralExtraction.export_extract_spectrum`. +To access the extracted spectrum as a :class:`~specutils.Spectrum` object, call :py:meth:`~jdaviz.configs.specviz2d.plugins.spectral_extraction.spectral_extraction.SpectralExtraction.export_extract_spectrum`. To import the parameters from a specreduce extraction object (either a new object, or an exported one modified in the notebook) into the plugin, call :py:meth:`~jdaviz.configs.specviz2d.plugins.spectral_extraction.spectral_extraction.SpectralExtraction.import_extract`: diff --git a/jdaviz/app.py b/jdaviz/app.py index ffbd64a19d..f6d2e61c2c 100644 --- a/jdaviz/app.py +++ b/jdaviz/app.py @@ -35,7 +35,7 @@ from ipyvuetify import VuetifyTemplate from ipywidgets import widget_serialization from traitlets import Dict, Bool, Unicode, Any -from specutils import Spectrum1D, SpectralRegion +from specutils import Spectrum, SpectralRegion from jdaviz import __version__ from jdaviz import style_registry @@ -105,10 +105,10 @@ def to_unit(self, data, cid, values, original_units, target_units): return values elif cid.label == "flux": try: - spec = data.get_object(cls=Spectrum1D) + spec = data.get_object(cls=Spectrum) except RuntimeError: data = data.get_object(cls=NDDataArray) - spec = Spectrum1D(flux=data.data * u.Unit(original_units)) + spec = Spectrum(flux=data.data * u.Unit(original_units)) return flux_conversion(values, original_units, target_units, spec) else: # spectral axis return spectral_axis_conversion(values, original_units, target_units) @@ -755,17 +755,12 @@ def _link_new_data(self, reference_data=None, data_to_be_linked=None): elif self.config == 'cubeviz' and linked_data.ndim == 1: # Don't want to use negative indices in case there are extra components like a mask - ref_wavelength_component = dc[0].components[5] - ref_flux_component = dc[0].components[6] + spectral_axis_index = dc[0].meta['spectral_axis_index'] + ref_wavelength_component = dc[0].components[spectral_axis_index] + # May need to update this for specutils 2 linked_wavelength_component = dc[-1].components[1] - linked_flux_component = dc[-1].components[-1] - links = [ - LinkSameWithUnits(ref_wavelength_component, linked_wavelength_component), - LinkSame(ref_flux_component, linked_flux_component) - ] - - dc.add_link(links) + dc.add_link(LinkSame(ref_wavelength_component, linked_wavelength_component)) return elif (linked_data.meta.get('Plugin', None) == 'Spectral Extraction' or @@ -1082,7 +1077,7 @@ def _get_range_subset_bounds(self, subset_state, if not hasattr(subset_state.att, "parent"): # e.g., Cubeviz viewer = self.get_viewer(self._jdaviz_helper._default_spectrum_viewer_reference_name) data = viewer.data() - if data and len(data) > 0 and isinstance(data[0], Spectrum1D): + if data and len(data) > 0 and isinstance(data[0], Spectrum): units = data[0].spectral_axis.unit else: raise ValueError("Unable to find spectral axis units") @@ -1092,7 +1087,7 @@ def _get_range_subset_bounds(self, subset_state, if ndim == 2: units = u.pix else: - handler, _ = data_translator.get_handler_for(Spectrum1D) + handler, _ = data_translator.get_handler_for(Spectrum) spec = handler.to_object(data) units = spec.spectral_axis.unit @@ -1535,7 +1530,7 @@ def return_data_label(self, loaded_object, ext=None, alt_name=None, check_unique Parameters ---------- loaded_object : str or object - The path to a data file or FITS HDUList or image object or Spectrum1D or + The path to a data file or FITS HDUList or image object or Spectrum or NDData array or numpy.ndarray. ext : str, optional The extension (or other distinguishing feature) of data used to identify it. @@ -1573,8 +1568,8 @@ def return_data_label(self, loaded_object, ext=None, alt_name=None, check_unique data_label = f"{loaded_object.file_name}[HDU object]" else: data_label = "Unknown HDU object" - elif isinstance(loaded_object, Spectrum1D): - data_label = "Spectrum1D" + elif isinstance(loaded_object, Spectrum): + data_label = "Spectrum" elif isinstance(loaded_object, NDData): data_label = "NDData" elif isinstance(loaded_object, np.ndarray): diff --git a/jdaviz/configs/cubeviz/helper.py b/jdaviz/configs/cubeviz/helper.py index 42065f8401..e9006c9676 100644 --- a/jdaviz/configs/cubeviz/helper.py +++ b/jdaviz/configs/cubeviz/helper.py @@ -54,7 +54,7 @@ def load_data(self, data, data_label=None, override_cube_limit=False, **kwargs): Parameters ---------- - data : str, `~astropy.io.fits.HDUList`, `~specutils.Spectrum1D`, or ndarray + data : str, `~astropy.io.fits.HDUList`, `~specutils.Spectrum`, or ndarray A string file path, astropy FITS object pointing to the data cube, a spectrum object, or a Numpy array cube. If plain array is given, axes order must be ``(x, y, z)``. diff --git a/jdaviz/configs/cubeviz/plugins/mixins.py b/jdaviz/configs/cubeviz/plugins/mixins.py index 41ec392cf7..c941e7bd4a 100644 --- a/jdaviz/configs/cubeviz/plugins/mixins.py +++ b/jdaviz/configs/cubeviz/plugins/mixins.py @@ -63,10 +63,19 @@ def _set_slice_indicator_value(self, value): class WithSliceSelection: - @property + @cached_property def slice_index(self): # index in state.slices corresponding to the slice axis - return 2 + for layer in self.layers: + try: + data_obj = layer.layer.data + return data_obj.meta['spectral_axis_index'] + except (AttributeError, KeyError): + raise + else: + break + else: + return 2 @property def slice_component_label(self): diff --git a/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py b/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py index ddc9c70dfc..400a76a347 100644 --- a/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py +++ b/jdaviz/configs/cubeviz/plugins/moment_maps/moment_maps.py @@ -4,7 +4,7 @@ from astropy.nddata import CCDData from astropy.utils import minversion from traitlets import Bool, List, Unicode, observe -from specutils import manipulation, analysis, Spectrum1D +from specutils import manipulation, analysis, Spectrum from jdaviz.core.custom_traitlets import IntHandleEmpty, FloatHandleEmpty from jdaviz.core.events import SnackbarMessage, GlobalDisplayUnitChanged @@ -306,12 +306,12 @@ def calculate_moment(self, add_data=True): ref_wavelength = self.reference_wavelength * u.Unit(self.dataset_spectral_unit) slab_sa = slab.spectral_axis.to("km/s", doppler_convention="relativistic", doppler_rest=ref_wavelength) - slab = Spectrum1D(slab.flux, slab_sa, uncertainty=slab.uncertainty) + slab = Spectrum(slab.flux, slab_sa, uncertainty=slab.uncertainty) # Otherwise convert spectral axis to display units, have to do frequency <-> wavelength # before calculating else: slab_sa = slab.spectral_axis.to(self.app._get_display_unit('spectral')) - slab = Spectrum1D(slab.flux, slab_sa, uncertainty=slab.uncertainty) + slab = Spectrum(slab.flux, slab_sa, uncertainty=slab.uncertainty) # Finally actually calculate the moment self.moment = analysis.moment(slab, order=n_moment).T diff --git a/jdaviz/configs/cubeviz/plugins/moment_maps/tests/test_moment_maps.py b/jdaviz/configs/cubeviz/plugins/moment_maps/tests/test_moment_maps.py index 44389b352d..4ee0f26819 100644 --- a/jdaviz/configs/cubeviz/plugins/moment_maps/tests/test_moment_maps.py +++ b/jdaviz/configs/cubeviz/plugins/moment_maps/tests/test_moment_maps.py @@ -84,6 +84,9 @@ def test_moment_calculation(cubeviz_helper, spectrum1d_cube, flux_viewer = cubeviz_helper.app.get_viewer(cubeviz_helper._default_flux_viewer_reference_name) + print(spectrum1d_cube.shape, spectrum1d_cube.spectral_axis_index) + print(flux_viewer.layers[0].layer.data.meta['spectral_axis_index']) + # Since we are not really displaying, need this to trigger GUI stuff. flux_viewer.shape = (100, 100) flux_viewer.state._set_axes_aspect_ratio(1) @@ -109,7 +112,7 @@ def test_moment_calculation(cubeviz_helper, spectrum1d_cube, assert len(mv_data) == 1 assert mv_data[0].label == 'moment 0' - assert len(dc.links) == 19 + assert len(dc.links) == 17 # label should remain unchanged but raise overwrite warnings assert mm._obj.results_label == 'moment 0' @@ -119,7 +122,7 @@ def test_moment_calculation(cubeviz_helper, spectrum1d_cube, label_mouseover = cubeviz_helper.app.session.application._tools['g-coords-info'] label_mouseover._viewer_mouse_event(flux_viewer, {'event': 'mousemove', 'domain': {'x': 0, 'y': 0}}) - assert flux_viewer.state.slices == (0, 0, 1) + assert flux_viewer.state.slices == (1, 0, 0) # Slice 0 has 8 pixels, this is Slice 1 assert label_mouseover.as_text() == (f"Pixel x=00.0 y=00.0 Value +8.00000e+00 {cube_unit}", "World 13h39m59.9731s +27d00m00.3600s (ICRS)", diff --git a/jdaviz/configs/cubeviz/plugins/parsers.py b/jdaviz/configs/cubeviz/plugins/parsers.py index 017cde1264..647dc2fb11 100644 --- a/jdaviz/configs/cubeviz/plugins/parsers.py +++ b/jdaviz/configs/cubeviz/plugins/parsers.py @@ -6,9 +6,8 @@ from astropy import units as u from astropy.io import fits from astropy.nddata import StdDevUncertainty -from astropy.time import Time from astropy.wcs import WCS -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz.core.custom_units_and_equivs import PIX2, _eqv_flux_to_sb_pixel from jdaviz.core.registries import data_parser_registry @@ -24,7 +23,8 @@ @data_parser_registry("cubeviz-data-parser") def parse_data(app, file_obj, data_type=None, data_label=None, - parent=None, cache=None, local_path=None, timeout=None): + parent=None, cache=None, local_path=None, timeout=None, + specutils_format=None): """ Attempts to parse a data file and auto-populate available viewers in cubeviz. @@ -52,6 +52,11 @@ def parse_data(app, file_obj, data_type=None, data_label=None, remote requests in seconds (passed to `~astropy.utils.data.download_file` or `~astroquery.mast.Conf.timeout`). + specutils_format : str, optional + Optional format string to pass to Spectrum.read(), see + https://specutils.readthedocs.io/en/stable/spectrum1d.html#list-of-loaders + for valid format strings. Useful for processed files that may not include + the original headers with information used to auto-identify. """ flux_viewer_reference_name = app._jdaviz_helper._default_flux_viewer_reference_name @@ -70,7 +75,7 @@ def parse_data(app, file_obj, data_type=None, data_label=None, if isinstance(file_obj, fits.hdu.hdulist.HDUList): try: _parse_spectrum1d_3d( - app, Spectrum1D.read(file_obj), data_label=data_label, + app, Spectrum.read(file_obj), data_label=data_label, flux_viewer_reference_name=flux_viewer_reference_name, uncert_viewer_reference_name=uncert_viewer_reference_name ) @@ -91,6 +96,16 @@ def parse_data(app, file_obj, data_type=None, data_label=None, file_obj, cache=cache, local_path=local_path, timeout=timeout ) + if specutils_format is not None: + sc = Spectrum.read(file_obj, format=specutils_format) + _parse_spectrum1d_3d( + app, sc, data_label=data_label, + flux_viewer_reference_name=flux_viewer_reference_name, + uncert_viewer_reference_name=uncert_viewer_reference_name + ) + app.get_tray_item_from_name("Spectral Extraction").disabled_msg = "" + return + file_name = os.path.basename(file_obj) with fits.open(file_obj) as hdulist: @@ -100,45 +115,20 @@ def parse_data(app, file_obj, data_type=None, data_label=None, # NOTE: Alerted to deprecation of FILETYPE keyword from pipeline on 2022-07-08 # Kept for posterity in for data processed prior to this date. Use EXP_TYPE instead filetype = prihdr.get('FILETYPE', '').lower() - system = prihdr.get('SYSTEM', '').lower() if telescop == 'jwst' and ('ifu' in exptype or 'mrs' in exptype or filetype == '3d ifu cube'): - for ext, viewer_name in (('SCI', flux_viewer_reference_name), - ('ERR', uncert_viewer_reference_name), - ('DQ', None)): - data_label = app.return_data_label(file_name, ext) - - if ext == 'SCI': - sci_ext = data_label - - # TODO: generalize/centralize this for use in other configs too - - if parent is not None: - parent_data_label = parent - elif ext == 'DQ': - parent_data_label = sci_ext - else: - parent_data_label = None - - _parse_jwst_s3d( - app, hdulist, data_label, ext=ext, viewer_name=viewer_name, - flux_viewer_reference_name=flux_viewer_reference_name, - parent=parent_data_label - ) - elif telescop == 'jwst' and filetype == 'r3d' and system == 'esa-pipeline': - for ext, viewer_name in (('DATA', flux_viewer_reference_name), - ('ERR', uncert_viewer_reference_name), - ('QUALITY', None)): - data_label = app.return_data_label(file_name, ext) - _parse_esa_s3d( - app, hdulist, data_label, ext=ext, viewer_name=viewer_name, - flux_viewer_reference_name=flux_viewer_reference_name, - ) + sc = Spectrum.read(file_obj) + data_label = app.return_data_label(file_name) + _parse_spectrum1d_3d( + app, sc, data_label=data_label, + flux_viewer_reference_name=flux_viewer_reference_name, + uncert_viewer_reference_name=uncert_viewer_reference_name + ) else: try: _parse_spectrum1d_3d( - app, Spectrum1D.read(hdulist), data_label=data_label or file_name, + app, Spectrum.read(hdulist), data_label=data_label or file_name, flux_viewer_reference_name=flux_viewer_reference_name, uncert_viewer_reference_name=uncert_viewer_reference_name ) @@ -152,7 +142,7 @@ def parse_data(app, file_obj, data_type=None, data_label=None, # If the data types are custom data objects, use explicit parsers. Note # that this relies on the glue-astronomy machinery to turn the data object # into something glue can understand. - elif isinstance(file_obj, Spectrum1D) and file_obj.flux.ndim in (1, 3): + elif isinstance(file_obj, Spectrum) and file_obj.flux.ndim in (1, 3): if file_obj.flux.ndim == 3: _parse_spectrum1d_3d( app, file_obj, data_label=data_label, @@ -180,7 +170,8 @@ def _get_celestial_wcs(wcs): def _return_spectrum_with_correct_units(flux, wcs, metadata, data_type=None, target_wave_unit=None, hdulist=None, - uncertainty=None, mask=None, apply_pix2=False): + uncertainty=None, mask=None, apply_pix2=False, + spectral_axis=None): """Upstream issue of WCS not using the correct units for data must be fixed here. Issue: https://github.com/astropy/astropy/issues/3658. @@ -196,7 +187,11 @@ def _return_spectrum_with_correct_units(flux, wcs, metadata, data_type=None, warnings.filterwarnings( 'ignore', message='Input WCS indicates that the spectral axis is not last', category=UserWarning) - sc = Spectrum1D(flux=flux, wcs=wcs, meta=metadata, uncertainty=uncertainty, mask=mask) + if spectral_axis is None: + sc = Spectrum(flux=flux, wcs=wcs, uncertainty=uncertainty, mask=mask) + else: + sc = Spectrum(flux=flux, spectral_axis=spectral_axis, + uncertainty=uncertainty, mask=mask) # convert flux and uncertainty to per-pix2 if input is not a surface brightness target_flux_unit = None @@ -224,6 +219,8 @@ def _return_spectrum_with_correct_units(flux, wcs, metadata, data_type=None, target_wave_unit = u.Unit(hdr[cunit_key]) found_target = True break + print(f"Target wave unit: {target_wave_unit}") + print(f"Current unit: {sc.spectral_axis.unit}") if target_wave_unit == sc.spectral_axis.unit: target_wave_unit = None @@ -324,124 +321,10 @@ def _parse_hdulist(app, hdulist, file_name=None, app._jdaviz_helper._loaded_flux_cube = app.data_collection[data_label] -def _parse_jwst_s3d(app, hdulist, data_label, ext='SCI', - viewer_name=None, flux_viewer_reference_name=None, - parent=None): - hdu = hdulist[ext] - data_type = _get_data_type_by_hdu(hdu) - - # Manually inject MJD-OBS until we can support GWCS, see - # https://github.com/spacetelescope/jdaviz/issues/690 and - # https://github.com/glue-viz/glue-astronomy/issues/59 - if ext == 'SCI' and 'MJD-OBS' not in hdu.header: - for key in ('MJD-BEG', 'DATE-OBS'): # Possible alternatives - if key in hdu.header: - if key.startswith('MJD'): - hdu.header['MJD-OBS'] = hdu.header[key] - break - else: - t = Time(hdu.header[key]) - hdu.header['MJD-OBS'] = t.mjd - break - - if ext == 'DQ': # DQ flags have no unit - flux = hdu.data << u.dimensionless_unscaled - else: - unit = u.Unit(hdu.header.get('BUNIT', 'count')) - flux = hdu.data << unit - wcs = WCS(hdulist['SCI'].header, hdulist) # Everything uses SCI WCS - - metadata = standardize_metadata(hdu.header) - - # store original WCS in metadata. this is a hacky workaround for converting subsets - # to sky regions, where the parent data of the subset might have dropped spatial WCS info - metadata['_orig_spatial_wcs'] = _get_celestial_wcs(wcs) - - if hdu.name != 'PRIMARY' and 'PRIMARY' in hdulist: - metadata[PRIHDR_KEY] = standardize_metadata(hdulist['PRIMARY'].header) - - data = _return_spectrum_with_correct_units( - flux, wcs, metadata, data_type=data_type, hdulist=hdulist) - app.add_data(data, data_label, parent=parent) - - # get glue data and update if DQ: - if ext == 'DQ': - # prevent circular import: - from jdaviz.configs.imviz.plugins.parsers import prep_data_layer_as_dq - - data = app.data_collection[-1] - prep_data_layer_as_dq(data) - - if data_type == 'flux': # Forced wave unit conversion made it lose stuff, so re-add - app.data_collection[-1].get_component("flux").units = flux.unit - - if viewer_name is not None: - app.add_data_to_viewer(viewer_name, data_label) - - if ext == 'DQ': - app.add_data_to_viewer(flux_viewer_reference_name, data_label, visible=False) - - if data_type == 'flux': - app._jdaviz_helper._loaded_flux_cube = app.data_collection[data_label] - elif data_type == 'uncert': - app._jdaviz_helper._loaded_uncert_cube = app.data_collection[data_label] - - -def _parse_esa_s3d(app, hdulist, data_label, ext='DATA', flux_viewer_reference_name=None): - hdu = hdulist[ext] - data_type = _get_data_type_by_hdu(hdu) - - if ext == 'QUALITY': # QUALITY flags have no unit - flux = hdu.data << u.dimensionless_unscaled - else: - unit = u.Unit(hdu.header.get('BUNIT', 'count')) - flux = hdu.data << unit - - hdr = hdulist[1].header - - wcs_dict = { - 'CTYPE1': 'WAVE ', 'CUNIT1': 'um', 'CDELT1': hdr['CDELT3'] * 1E6, - 'CRPIX1': hdr['CRPIX3'], - 'CRVAL1': hdr['CRVAL3'] * 1E6, 'NAXIS1': hdr['NAXIS3'], - 'CTYPE2': 'DEC--TAN', 'CUNIT2': 'deg', 'CDELT2': hdr['CDELT1'], 'CRPIX2': hdr['CRPIX1'], - 'CRVAL2': hdr['CRVAL1'], 'NAXIS2': hdr['NAXIS1'], - 'CTYPE3': 'RA---TAN', 'CUNIT3': 'deg', 'CDELT3': hdr['CDELT2'], 'CRPIX3': hdr['CRPIX2'], - 'CRVAL3': hdr['CRVAL2'], 'NAXIS3': hdr['NAXIS2']} - - wcs = WCS(wcs_dict) - flux = np.moveaxis(flux, 0, -1) - flux = np.swapaxes(flux, 0, 1) - - metadata = standardize_metadata(hdu.header) - metadata.update(wcs_dict) # To be internally consistent - if hdu.name != 'PRIMARY' and 'PRIMARY' in hdulist: - metadata[PRIHDR_KEY] = standardize_metadata(hdulist['PRIMARY'].header) - - # store original WCS in metadata. this is a hacky workaround for converting subsets - # to sky regions, where the parent data of the subset might have dropped spatial WCS info - metadata['_orig_spatial_wcs'] = _get_celestial_wcs(wcs) - - data = _return_spectrum_with_correct_units( - flux, wcs, metadata, data_type=data_type, hdulist=hdulist) - - app.add_data(data, data_label) - - if data_type == 'flux': # Forced wave unit conversion made it lose stuff, so re-add - app.data_collection[-1].get_component("flux").units = flux.unit - - app.add_data_to_viewer(flux_viewer_reference_name, data_label) - - if data_type == 'flux': - app._jdaviz_helper._loaded_flux_cube = app.data_collection[data_label] - elif data_type == 'uncert': - app._jdaviz_helper._loaded_uncert_cube = app.data_collection[data_label] - elif data_type == 'mask': - app._jdaviz_helper._loaded_mask_cube = app.data_collection[data_label] - - def _parse_spectrum1d_3d(app, file_obj, data_label=None, flux_viewer_reference_name=None, - uncert_viewer_reference_name=None): + uncert_viewer_reference_name=None, + parent=None): """Load spectrum1d as a cube.""" if data_label is None: @@ -460,6 +343,13 @@ def _parse_spectrum1d_3d(app, file_obj, data_label=None, else: flux = val + if parent is not None: + parent_data_label = parent + elif attr == 'uncertainty': + parent_data_label = app.return_data_label(data_label, "FLUX").split(" ")[0] + else: + parent_data_label = None + with warnings.catch_warnings(): warnings.filterwarnings( 'ignore', message='Input WCS indicates that the spectral axis is not last', @@ -479,7 +369,7 @@ def _parse_spectrum1d_3d(app, file_obj, data_label=None, flux, file_obj.wcs, meta, data_type=attr, apply_pix2=True) cur_data_label = app.return_data_label(data_label, attr.upper()) - app.add_data(s1d, cur_data_label) + app.add_data(s1d, cur_data_label, parent=parent_data_label) if attr == 'flux': app.add_data_to_viewer(flux_viewer_reference_name, cur_data_label) @@ -493,7 +383,7 @@ def _parse_spectrum1d_3d(app, file_obj, data_label=None, def _parse_spectrum1d(app, file_obj, data_label=None, spectrum_viewer_reference_name=None): - # Here 'file_obj' is a Spectrum1D + # Here 'file_obj' is a Spectrum if data_label is None: data_label = app.return_data_label(file_obj) @@ -503,7 +393,7 @@ def _parse_spectrum1d(app, file_obj, data_label=None, spectrum_viewer_reference_ file_obj.meta['_orig_spatial_wcs'] = _get_celestial_wcs(file_obj.wcs) if hasattr(file_obj, 'wcs') else None # noqa: E501 # TODO: glue-astronomy translators only look at the flux property of - # specutils Spectrum1D objects. Fix to support uncertainties and masks. + # specutils Spectrum objects. Fix to support uncertainties and masks. # convert data loaded in flux units to a per-square-pixel surface # brightness unit (e.g Jy to Jy/pix**2) @@ -532,7 +422,7 @@ def _parse_ndarray(app, file_obj, data_label=None, data_type=None, flux = flux << (u.count / PIX2) meta = standardize_metadata({'_orig_spatial_wcs': None}) - s3d = Spectrum1D(flux=flux, meta=meta) + s3d = Spectrum(flux=flux, meta=meta) # convert data loaded in flux units to a per-square-pixel surface # brightness unit (e.g Jy to Jy/pix**2) @@ -565,7 +455,7 @@ def _parse_gif(app, file_obj, data_label=None, flux_viewer_reference_name=None): flux = np.rot90(np.moveaxis(flux, 0, 2), k=-1, axes=(0, 1)) meta = {'filename': file_name, '_orig_spatial_wcs': None} - s3d = Spectrum1D(flux=flux * (u.count / PIX2), meta=standardize_metadata(meta)) + s3d = Spectrum(flux=flux * (u.count / PIX2), meta=standardize_metadata(meta)) app.add_data(s3d, data_label) app.add_data_to_viewer(flux_viewer_reference_name, data_label) diff --git a/jdaviz/configs/cubeviz/plugins/slice/slice.py b/jdaviz/configs/cubeviz/plugins/slice/slice.py index b2c9ae3974..ea95c35bba 100644 --- a/jdaviz/configs/cubeviz/plugins/slice/slice.py +++ b/jdaviz/configs/cubeviz/plugins/slice/slice.py @@ -166,7 +166,7 @@ def slice_display_unit_name(self): @property def valid_slice_att_names(self): if self.app.config == 'cubeviz': - return _spectral_axis_names + ['Pixel Axis 2 [x]', 'World 0'] + return _spectral_axis_names + ['Pixel Axis 2 [x]'] elif self.app.config == 'rampviz': return _temporal_axis_names + ['Pixel Axis 2 [x]'] diff --git a/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py b/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py index 06d647bc68..981c3f2042 100644 --- a/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py +++ b/jdaviz/configs/cubeviz/plugins/slice/tests/test_slice.py @@ -34,8 +34,8 @@ def test_slice(cubeviz_helper, spectrum1d_cube): assert sl.value == slice_values[1] assert cubeviz_helper.app.get_viewer("flux-viewer").slice == 1 - assert cubeviz_helper.app.get_viewer("flux-viewer").state.slices[-1] == 1 - assert cubeviz_helper.app.get_viewer("uncert-viewer").state.slices[-1] == 1 + assert cubeviz_helper.app.get_viewer("flux-viewer").state.slices[0] == 1 + assert cubeviz_helper.app.get_viewer("uncert-viewer").state.slices[0] == 1 cubeviz_helper.select_wavelength(slice_values[0]) assert cubeviz_helper.app.get_viewer("flux-viewer").slice == 0 assert sl.value == slice_values[0] @@ -124,7 +124,7 @@ def test_init_slice(cubeviz_helper, spectrum1d_cube): assert sl.value == slice_values[1] assert fv.slice == 1 - assert fv.state.slices == (0, 0, 1) + assert fv.state.slices == (1, 0, 0) # make sure adding new data doesn't revert slice to 0 mm = cubeviz_helper.plugins['Moment Maps'] @@ -132,4 +132,4 @@ def test_init_slice(cubeviz_helper, spectrum1d_cube): assert sl.value == slice_values[1] assert fv.slice == 1 - assert fv.state.slices == (0, 0, 1) + assert fv.state.slices == (1, 0, 0) diff --git a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py index c1f87223cc..ec3c984dd1 100644 --- a/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py +++ b/jdaviz/configs/cubeviz/plugins/spectral_extraction/spectral_extraction.py @@ -142,6 +142,8 @@ def __init__(self, *args, **kwargs): self.aperture._initialize_choices() self.aperture.select_default() + self.spectral_axis_index = 0 + self.background = ApertureSubsetSelect(self, 'bg_items', 'bg_selected', @@ -495,7 +497,7 @@ def _extract_from_aperture(self, cube, uncert_cube, mask_cube, aperture, # This is the attribute for a PaddedSpectrumWCS in the 3D case wcs = cube.coords.spectral_wcs else: - wcs = None + wcs = cube.coords # Filter out NaNs (False = good) mask = np.logical_or(mask, np.isnan(flux)) @@ -560,12 +562,12 @@ def _extract_from_aperture(self, cube, uncert_cube, mask_cube, aperture, return self._return_extracted(cube, wcs, collapsed_nddata) - def _return_extracted(self, cube, wcs, collapsed_nddata): - # Convert to Spectrum1D, with the spectral axis in correct units: + def _return_extracted(self, cube, wcs, collapsed_nddata, pass_spectral_axis=False): + # Convert to Spectrum, with the spectral axis in correct units: if hasattr(cube.coords, 'spectral_wcs'): - target_wave_unit = cube.coords.spectral_wcs.world_axis_units[0] + target_wave_unit = cube.coords.spectral_wcs.world_axis_units[self.spectral_axis_index] elif hasattr(cube.coords, 'spectral'): - target_wave_unit = cube.coords.spectral.world_axis_units[0] + target_wave_unit = cube.coords.spectral.world_axis_units[self.spectral_axis_index] else: target_wave_unit = None @@ -576,11 +578,20 @@ def _return_extracted(self, cube, wcs, collapsed_nddata): mask = collapsed_nddata.mask uncertainty = collapsed_nddata.uncertainty + if pass_spectral_axis: + wcs_args = [0, 0, 0] + spec_indices = np.arange(cube.shape[self.spectral_axis_index]) + wcs_args[self.spectral_axis_index] = spec_indices + wcs_args.reverse() + spectral_and_spatial = wcs.pixel_to_world(*wcs_args) + spectral_axis = [x for x in spectral_and_spatial if isinstance(x, SpectralCoord)][0] # noqa + collapsed_spec = _return_spectrum_with_correct_units( flux, wcs, collapsed_nddata.meta, data_type='flux', target_wave_unit=target_wave_unit, uncertainty=uncertainty, - mask=mask + mask=mask, + spectral_axis=spectral_axis ) return collapsed_spec 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 9893fd5420..59ff1bf12a 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 @@ -12,7 +12,7 @@ from numpy.testing import assert_allclose, assert_array_equal from regions import (CirclePixelRegion, CircleAnnulusPixelRegion, EllipsePixelRegion, RectanglePixelRegion, PixCoord) -from specutils import Spectrum1D +from specutils import Spectrum from specutils.manipulation import FluxConservingResampler from jdaviz.core.custom_units_and_equivs import PIX2, SPEC_PHOTON_FLUX_DENSITY_UNITS @@ -47,7 +47,7 @@ def test_version_after_nddata_update(cubeviz_helper, spectrum1d_cube_with_uncert assert plg._obj.disabled_msg == '' assert isinstance(spectral_cube, NDDataArray) - assert isinstance(collapsed_cube_s1d, Spectrum1D) + assert isinstance(collapsed_cube_s1d, Spectrum) assert_allclose( collapsed_cube_nddata.data, @@ -393,7 +393,7 @@ def test_cone_and_cylinder_errors(cubeviz_helper, spectrum1d_cube_largest): def test_cone_aperture_with_frequency_units(cubeviz_helper, spectral_cube_wcs): - data = Spectrum1D(flux=np.ones((128, 129, 256)) * u.nJy, wcs=spectral_cube_wcs) + data = Spectrum(flux=np.ones((128, 129, 256)) * u.nJy, wcs=spectral_cube_wcs) cubeviz_helper.load_data(data, data_label="Test Flux") cubeviz_helper.plugins['Subset Tools'].import_region( [CirclePixelRegion(PixCoord(14, 15), radius=2.5)]) @@ -611,7 +611,7 @@ def test_spectral_extraction_scientific_validation( calspec_fitsrec = fits.getdata(calspec_url) column_units = [u.AA] + 2 * [u.Unit('erg s-1 cm-2 AA-1')] spectra_table = QTable(calspec_fitsrec, units=column_units) - model_spectrum = Spectrum1D( + model_spectrum = Spectrum( flux=spectra_table['FLUX'], spectral_axis=spectra_table['WAVELENGTH'] ) diff --git a/jdaviz/configs/cubeviz/plugins/tests/test_parsers.py b/jdaviz/configs/cubeviz/plugins/tests/test_parsers.py index dd3e587628..8e92a47e7a 100644 --- a/jdaviz/configs/cubeviz/plugins/tests/test_parsers.py +++ b/jdaviz/configs/cubeviz/plugins/tests/test_parsers.py @@ -4,7 +4,7 @@ import pytest from astropy import units as u from astropy.wcs import WCS -from specutils import Spectrum1D, SpectralRegion +from specutils import Spectrum, SpectralRegion from glue_astronomy.translators.spectrum1d import PaddedSpectrumWCS from numpy.testing import assert_allclose, assert_array_equal @@ -32,7 +32,7 @@ def test_fits_image_hdu_with_microns(image_cube_hdu_obj_microns, cubeviz_helper) assert len(cubeviz_helper.app.data_collection) == 4 # 3 cubes and extracted spectrum assert cubeviz_helper.app.data_collection[0].label == 'has_microns[FLUX]' - flux_cube = cubeviz_helper.app.data_collection[0].get_object(Spectrum1D, statistic=None) + flux_cube = cubeviz_helper.app.data_collection[0].get_object(Spectrum, statistic=None) assert flux_cube.spectral_axis.unit == u.um # This tests the same data as test_fits_image_hdu_parse above. @@ -125,7 +125,7 @@ def test_fits_image_hdu_parse_from_file(tmpdir, image_cube_hdu_obj, cubeviz_help def test_spectrum3d_parse(image_cube_hdu_obj, cubeviz_helper): flux = image_cube_hdu_obj[1].data << u.Unit(image_cube_hdu_obj[1].header['BUNIT']) wcs = WCS(image_cube_hdu_obj[1].header, image_cube_hdu_obj) - sc = Spectrum1D(flux=flux, wcs=wcs) + sc = Spectrum(flux=flux, wcs=wcs) cubeviz_helper.load_data(sc) data = cubeviz_helper.app.data_collection[0] @@ -152,7 +152,7 @@ def test_spectrum3d_parse(image_cube_hdu_obj, cubeviz_helper): @pytest.mark.parametrize("flux_unit", [u.nJy, u.DN, u.DN / u.s]) def test_spectrum3d_no_wcs_parse(cubeviz_helper, flux_unit): - sc = Spectrum1D(flux=np.ones(24).reshape((2, 3, 4)) * flux_unit) # x, y, z + sc = Spectrum(flux=np.ones(24).reshape((2, 3, 4)) * flux_unit) # x, y, z cubeviz_helper.load_data(sc) assert sc.spectral_axis.unit == u.pix @@ -169,7 +169,7 @@ def test_spectrum1d_parse(spectrum1d, cubeviz_helper): cubeviz_helper.load_data(spectrum1d) assert len(cubeviz_helper.app.data_collection) == 1 - assert cubeviz_helper.app.data_collection[0].label.endswith('Spectrum1D') + assert cubeviz_helper.app.data_collection[0].label.endswith('Spectrum') assert cubeviz_helper.app.data_collection[0].meta['uncertainty_type'] == 'std' # Coordinate display is only for spatial image, which is missing here. @@ -265,7 +265,7 @@ def test_invalid_data_types(cubeviz_helper): cubeviz_helper.load_data(WCS(naxis=3)) with pytest.raises(NotImplementedError, match='Unsupported data format'): - cubeviz_helper.load_data(Spectrum1D(flux=np.ones((2, 2)) * u.nJy)) + cubeviz_helper.load_data(Spectrum(flux=np.ones((2, 2)) * u.nJy)) with pytest.raises(NotImplementedError, match='Unsupported data format'): cubeviz_helper.load_data(np.ones((2, 2))) diff --git a/jdaviz/configs/cubeviz/plugins/tests/test_regions.py b/jdaviz/configs/cubeviz/plugins/tests/test_regions.py index 230f7b9dda..234a4eb1f4 100644 --- a/jdaviz/configs/cubeviz/plugins/tests/test_regions.py +++ b/jdaviz/configs/cubeviz/plugins/tests/test_regions.py @@ -7,7 +7,7 @@ from astropy import units as u from astropy.coordinates import SkyCoord from regions import PixCoord, CirclePixelRegion, CircleSkyRegion, EllipsePixelRegion -from specutils import Spectrum1D, SpectralRegion +from specutils import Spectrum, SpectralRegion from jdaviz.configs.imviz.tests.test_regions import BaseRegionHandler @@ -82,4 +82,4 @@ def test_spatial_spectral_mix(self): 'Spectrum (sum) (Subset 2)', 'Spectrum (Subset 1, sum) (Subset 2)'] for sp in spectral_subsets.values(): - assert isinstance(sp, Spectrum1D) + assert isinstance(sp, Spectrum) diff --git a/jdaviz/configs/cubeviz/plugins/tools.py b/jdaviz/configs/cubeviz/plugins/tools.py index ec77106dda..d18ac0f181 100644 --- a/jdaviz/configs/cubeviz/plugins/tools.py +++ b/jdaviz/configs/cubeviz/plugins/tools.py @@ -5,7 +5,7 @@ from glue_jupyter.bqplot.image import BqplotImageView from glue.viewers.common.tool import CheckableTool import numpy as np -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz.core.events import SliceToolStateMessage, SliceSelectSliceMessage from jdaviz.core.tools import PanZoom, BoxZoom, _MatchedZoomMixin @@ -147,7 +147,7 @@ def _mouse_move_worker(self, x, y): return cube_data = cube_data[0] - if isinstance(cube_data, Spectrum1D): + if isinstance(cube_data, Spectrum): spectrum = cube_data else: spectrum = cube_data.get_object(statistic=None) @@ -155,7 +155,7 @@ def _mouse_move_worker(self, x, y): x_unit = self._profile_viewer.state.x_display_unit if spectrum.spectral_axis.unit != x_unit: new_spectral_axis = spectrum.spectral_axis.to(x_unit) - spectrum = Spectrum1D(spectrum.flux, new_spectral_axis) + spectrum = Spectrum(spectrum.flux, new_spectral_axis) if x >= spectrum.flux.shape[0] or x < 0 or y >= spectrum.flux.shape[1] or y < 0: self._reset_profile_viewer_bounds() diff --git a/jdaviz/configs/cubeviz/plugins/viewers.py b/jdaviz/configs/cubeviz/plugins/viewers.py index 7bba966582..b9ac2bf868 100644 --- a/jdaviz/configs/cubeviz/plugins/viewers.py +++ b/jdaviz/configs/cubeviz/plugins/viewers.py @@ -78,9 +78,6 @@ def _initial_x_axis(self, *args): x_att = att_name self.state.x_att_world = ref_data.id[x_att] break - else: - x_att = "Pixel Axis 0 [z]" - self.state.x_att = ref_data.id[x_att] def set_plot_axes(self): self.figure.axes[1].tick_format = None diff --git a/jdaviz/configs/default/plugins/collapse/tests/test_collapse.py b/jdaviz/configs/default/plugins/collapse/tests/test_collapse.py index eec8067aa1..cd408f6cb9 100644 --- a/jdaviz/configs/default/plugins/collapse/tests/test_collapse.py +++ b/jdaviz/configs/default/plugins/collapse/tests/test_collapse.py @@ -1,12 +1,12 @@ import numpy as np import pytest from astropy import units as u -from specutils import Spectrum1D +from specutils import Spectrum @pytest.mark.filterwarnings('ignore') def test_linking_after_collapse(cubeviz_helper, spectral_cube_wcs): - cubeviz_helper.load_data(Spectrum1D(flux=np.ones((3, 4, 5)) * u.nJy, wcs=spectral_cube_wcs)) + cubeviz_helper.load_data(Spectrum(flux=np.ones((3, 4, 5)) * u.nJy, wcs=spectral_cube_wcs)) dc = cubeviz_helper.app.data_collection # TODO: this now fails when instantiating Collapse after initialization @@ -39,7 +39,7 @@ def test_linking_after_collapse(cubeviz_helper, spectral_cube_wcs): def test_collapsed_to_extract_plugin(cubeviz_helper, spectral_cube_wcs, tmp_path): - cubeviz_helper.load_data(Spectrum1D(flux=np.ones((3, 4, 5)) * u.nJy, wcs=spectral_cube_wcs)) + cubeviz_helper.load_data(Spectrum(flux=np.ones((3, 4, 5)) * u.nJy, wcs=spectral_cube_wcs)) collapse_plugin = cubeviz_helper.plugins['Collapse'] diff --git a/jdaviz/configs/default/plugins/export/export.py b/jdaviz/configs/default/plugins/export/export.py index 9360d075f6..b32615ddf3 100644 --- a/jdaviz/configs/default/plugins/export/export.py +++ b/jdaviz/configs/default/plugins/export/export.py @@ -1,8 +1,13 @@ import os import time from pathlib import Path -from traitlets import Bool, List, Unicode, observe + +from astropy import units as u +from astropy.nddata import CCDData +from glue.core.message import SubsetCreateMessage, SubsetDeleteMessage, SubsetUpdateMessage from glue_jupyter.bqplot.image import BqplotImageView +from specutils import Spectrum +from traitlets import Bool, List, Unicode, observe from jdaviz.core.custom_traitlets import FloatHandleEmpty, IntHandleEmpty from jdaviz.core.marks import ShadowMixin @@ -12,15 +17,9 @@ SubsetSelectMixin, PluginTableSelectMixin, PluginPlotSelectMixin, AutoTextField, MultiselectMixin, with_spinner) -from glue.core.message import SubsetCreateMessage, SubsetDeleteMessage, SubsetUpdateMessage - from jdaviz.core.events import AddDataMessage, SnackbarMessage from jdaviz.core.user_api import PluginUserApi -from specutils import Spectrum1D -from astropy import units as u -from astropy.nddata import CCDData - try: import cv2 except ImportError: @@ -361,7 +360,7 @@ def _set_dataset_not_supported_msg(self, msg=None): # NOTE: should not be a valid choice due to dataset filters, but we'll include # another check here. self.data_invalid_msg = "Data export is only available for plugin generated data." - elif not isinstance(self.dataset.selected_obj, (Spectrum1D, CCDData)): + elif not isinstance(self.dataset.selected_obj, (Spectrum, CCDData)): self.data_invalid_msg = "Export is not yet implemented for this type of data" elif (data_unit := self.dataset.selected_obj.unit) == u.Unit('DN/s'): self.data_invalid_msg = f'Export Disabled: The unit {data_unit} could not be saved in native FITS format.' # noqa: E501 diff --git a/jdaviz/configs/default/plugins/export/tests/test_export.py b/jdaviz/configs/default/plugins/export/tests/test_export.py index 35b61c25cd..aad7982e82 100644 --- a/jdaviz/configs/default/plugins/export/tests/test_export.py +++ b/jdaviz/configs/default/plugins/export/tests/test_export.py @@ -8,7 +8,7 @@ from astropy.nddata import NDData from glue.core.roi import CircularROI from regions import Regions, CircleSkyRegion -from specutils import Spectrum1D, SpectralRegion +from specutils import Spectrum, SpectralRegion from pathlib import Path @@ -75,8 +75,8 @@ def test_not_implemented(self, cubeviz_helper, spectral_cube_wcs): the correct warning message to display in UI). """ - data = Spectrum1D(flux=np.ones((500, 500, 2)) * u.nJy, - wcs=spectral_cube_wcs) + data = Spectrum(flux=np.ones((500, 500, 2)) * u.nJy, + wcs=spectral_cube_wcs) cubeviz_helper.load_data(data) subset_plugin = cubeviz_helper.plugins['Subset Tools'] subset_plugin.import_region(CircularROI(xc=255, yc=255, radius=50)) @@ -119,7 +119,7 @@ def test_export_subsets_wcs(self, imviz_helper, spectral_cube_wcs): def test_basic_export_subsets_cubeviz(self, cubeviz_helper, spectral_cube_wcs): - data = Spectrum1D(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) + data = Spectrum(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) cubeviz_helper.load_data(data) subset_plugin = cubeviz_helper.plugins['Subset Tools'] @@ -256,7 +256,7 @@ def test_disable_export_for_unsupported_units(specviz2d_helper): dn_per_s = u.DN / u.s data = np.zeros((5, 10)) data[3] = np.arange(10) - data = Spectrum1D(flux=data*dn_per_s, spectral_axis=data[3]*u.um) + data = Spectrum(flux=data*dn_per_s, spectral_axis=data[3]*u.um) specviz2d_helper.load_data(data) gs = specviz2d_helper.plugins["Gaussian Smooth"] diff --git a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py index 7fe61ada22..f2b344e2dc 100644 --- a/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py +++ b/jdaviz/configs/default/plugins/gaussian_smooth/gaussian_smooth.py @@ -1,7 +1,7 @@ import numpy as np from astropy.convolution import convolve, Gaussian2DKernel -from specutils import Spectrum1D +from specutils import Spectrum from specutils.manipulation import gaussian_smooth from traitlets import List, Unicode, Bool, observe @@ -151,7 +151,7 @@ def smooth(self, add_data=True): Returns ------- - spec : `~specutils.Spectrum1D` + spec : `~specutils.Spectrum` The smoothed spectrum or data cube """ if self.mode_selected == 'Spatial': @@ -190,18 +190,18 @@ def spectral_smooth(self): Returns ------- - spec : `~specutils.Spectrum1D` + spec : `~specutils.Spectrum` The smoothed spectrum """ # Testing inputs to make sure putting smoothed spectrum into # datacollection works # input_flux = Quantity(np.array([0.2, 0.3, 2.2, 0.3]), u.Jy) # input_spaxis = Quantity(np.array([1, 2, 3, 4]), u.micron) - # spec1 = Spectrum1D(input_flux, spectral_axis=input_spaxis) + # spec1 = Spectrum(input_flux, spectral_axis=input_spaxis) # Takes the user input from the dialog (stddev) and uses it to # define a standard deviation for gaussian smoothing - cube = self.dataset.get_object(cls=Spectrum1D, statistic=None) + cube = self.dataset.get_object(cls=Spectrum, statistic=None) spec_smoothed = gaussian_smooth(cube, stddev=self.stddev) return spec_smoothed @@ -215,7 +215,7 @@ def spatial_smooth(self): Returns ------- - cube : `~specutils.Spectrum1D` + cube : `~specutils.Spectrum` The smoothed cube """ cube = self.dataset.selected_obj @@ -237,6 +237,6 @@ def spatial_smooth(self): # Create a new cube with the old metadata. Note that astropy # convolution generates values for masked (NaN) data. - newcube = Spectrum1D(flux=convolved_data * flux_unit, wcs=w) + newcube = Spectrum(flux=convolved_data * flux_unit, wcs=w) return newcube diff --git a/jdaviz/configs/default/plugins/gaussian_smooth/tests/test_gaussian_smooth.py b/jdaviz/configs/default/plugins/gaussian_smooth/tests/test_gaussian_smooth.py index 32dbffa23a..49cf6da0c0 100644 --- a/jdaviz/configs/default/plugins/gaussian_smooth/tests/test_gaussian_smooth.py +++ b/jdaviz/configs/default/plugins/gaussian_smooth/tests/test_gaussian_smooth.py @@ -1,7 +1,7 @@ import numpy as np import pytest from astropy.utils.exceptions import AstropyUserWarning -from specutils import Spectrum1D +from specutils import Spectrum def test_linking_after_spectral_smooth(cubeviz_helper, spectrum1d_cube): @@ -122,7 +122,7 @@ def test_spatial_convolution(cubeviz_helper, spectrum1d_cube): assert len(dc) == 3 assert dc[-1].label == f'{data_label}[FLUX] spatial-smooth stddev-3.0' assert dc[-1].shape == (4, 2, 2) # specutils moved spectral axis to last - assert (dc[f'{data_label}[FLUX] spatial-smooth stddev-3.0'].get_object(cls=Spectrum1D, + assert (dc[f'{data_label}[FLUX] spatial-smooth stddev-3.0'].get_object(cls=Spectrum, statistic=None).shape == (4, 2, 2)) diff --git a/jdaviz/configs/default/plugins/line_lists/line_lists.py b/jdaviz/configs/default/plugins/line_lists/line_lists.py index 81bad779a1..febff06a54 100644 --- a/jdaviz/configs/default/plugins/line_lists/line_lists.py +++ b/jdaviz/configs/default/plugins/line_lists/line_lists.py @@ -208,7 +208,7 @@ def _on_viewer_data_changed(self, msg=None): self._bounds["min"] = viewer_data.spectral_axis[0] self._bounds["max"] = viewer_data.spectral_axis[-1] - # set redshift slider to redshift stored in Spectrum1D object + # set redshift slider to redshift stored in Spectrum object if viewer_data.meta.get('plugin', None) is not None: self.rs_redshift = (viewer_data.redshift.value if hasattr(viewer_data.redshift, 'value') diff --git a/jdaviz/configs/default/plugins/line_lists/tests/test_line_lists.py b/jdaviz/configs/default/plugins/line_lists/tests/test_line_lists.py index 37062dde72..24499f1f8f 100644 --- a/jdaviz/configs/default/plugins/line_lists/tests/test_line_lists.py +++ b/jdaviz/configs/default/plugins/line_lists/tests/test_line_lists.py @@ -4,15 +4,15 @@ import astropy.units as u from astropy.table import QTable -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz.core.marks import SpectralLine from jdaviz.core.linelists import get_available_linelists def test_line_lists(specviz_helper): - spec = Spectrum1D(flux=np.random.rand(100)*u.Jy, - spectral_axis=np.arange(6000, 7000, 10)*u.AA) + spec = Spectrum(flux=np.random.rand(100)*u.Jy, + spectral_axis=np.arange(6000, 7000, 10)*u.AA) specviz_helper.load_data(spec) lt = QTable() diff --git a/jdaviz/configs/default/plugins/model_fitting/fitting_backend.py b/jdaviz/configs/default/plugins/model_fitting/fitting_backend.py index 9c2bb75a78..4afec6a648 100644 --- a/jdaviz/configs/default/plugins/model_fitting/fitting_backend.py +++ b/jdaviz/configs/default/plugins/model_fitting/fitting_backend.py @@ -7,7 +7,7 @@ import astropy.units as u -from specutils import Spectrum1D +from specutils import Spectrum from specutils.fitting import fit_lines __all__ = ['fit_model_to_spectrum'] @@ -16,7 +16,7 @@ def fit_model_to_spectrum(spectrum, component_list, expression, run_fitter=False, window=None, n_cpu=None): """Fits a `~astropy.modeling.CompoundModel` to a - `~specutils.Spectrum1D` instance. + `~specutils.Spectrum` instance. If the input spectrum represents a spectral cube, then fits the model to every spaxel in the cube, using @@ -25,7 +25,7 @@ def fit_model_to_spectrum(spectrum, component_list, expression, Parameters ---------- - spectrum : `~specutils.Spectrum1D` + spectrum : `~specutils.Spectrum` The spectrum to be fitted. component_list : list @@ -62,7 +62,7 @@ def fit_model_to_spectrum(spectrum, component_list, expression, spaxel, a list with 2D arrays, each one storing fitted parameter values for all spaxels, is returned. - output_spectrum : `~specutils.Spectrum1D` + output_spectrum : `~specutils.Spectrum` The realization of the fitted model as a spectrum. The spectrum will be 1D or 3D depending on the shape of input spectrum. """ @@ -77,13 +77,13 @@ def fit_model_to_spectrum(spectrum, component_list, expression, def _fit_1D(initial_model, spectrum, run_fitter, filter_non_finite=True, window=None): """ - Fits an astropy CompoundModel to a Spectrum1D instance. + Fits an astropy CompoundModel to a Spectrum instance. Parameters ---------- initial_model : :class: `astropy.modeling.CompoundModel` Initial guess for the model to be fitted. - spectrum : :class:`specutils.Spectrum1D` + spectrum : :class:`specutils.Spectrum` The spectrum to be fitted. run_fitter : bool When False (the default), the function composes the compound @@ -95,7 +95,7 @@ def _fit_1D(initial_model, spectrum, run_fitter, filter_non_finite=True, window= ------- output_model : :class: `astropy.modeling.CompoundModel` The model resulting from the fit. - output_spectrum : :class:`specutils.Spectrum1D` + output_spectrum : :class:`specutils.Spectrum` The realization of the fitted model as a spectrum. """ @@ -113,9 +113,9 @@ def _fit_1D(initial_model, spectrum, run_fitter, filter_non_finite=True, window= output_values = initial_model(spectrum.spectral_axis) # Build return spectrum - output_spectrum = Spectrum1D(spectral_axis=spectrum.spectral_axis, - flux=output_values, - mask=spectrum.mask) + output_spectrum = Spectrum(spectral_axis=spectrum.spectral_axis, + flux=output_values, + mask=spectrum.mask) return output_model, output_spectrum @@ -130,7 +130,7 @@ def _fit_3D(initial_model, spectrum, window=None, n_cpu=None): ---------- initial_model : :class: `astropy.modeling.CompoundModel` Initial guess for the model to be fitted. - spectrum : :class:`specutils.Spectrum1D` + spectrum : :class:`specutils.Spectrum` The spectrum that stores the cube in its 'flux' attribute. window : `None` or :class:`specutils.spectra.SpectralRegion` See :func:`specutils.fitting.fitmodels.fit_lines`. @@ -145,7 +145,7 @@ def _fit_3D(initial_model, spectrum, window=None, n_cpu=None): output_model : :list: a list that stores 2D arrays. Each array contains one parameter from `astropy.modeling.CompoundModel` instances fitted to every spaxel in the input cube. - output_spectrum : :class:`specutils.Spectrum1D` + output_spectrum : :class:`specutils.Spectrum` The spectrum that stores the fitted model values in its 'flux' attribute. """ @@ -215,9 +215,9 @@ def collect_result(results): # Build output 3D spectrum funit = spectrum.flux.unit - output_spectrum = Spectrum1D(wcs=spectrum.wcs, - flux=output_flux_cube * funit, - mask=spectrum.mask) + output_spectrum = Spectrum(wcs=spectrum.wcs, + flux=output_flux_cube * funit, + mask=spectrum.mask) return fitted_models, output_spectrum @@ -251,7 +251,7 @@ def __call__(self): x = parameters[0] y = parameters[1] - # Calling the Spectrum1D constructor for every spaxel + # Calling the Spectrum constructor for every spaxel # turned out to be less expensive than expected. Experiments # show that the cost amounts to a couple percent additional # running time in comparison with a version that uses a 3D @@ -266,7 +266,7 @@ def __call__(self): # If no mask is provided: mask = np.zeros_like(flux.value).astype(bool) - sp = Spectrum1D(spectral_axis=self.wave, flux=flux, mask=mask) + sp = Spectrum(spectral_axis=self.wave, flux=flux, mask=mask) if sp.uncertainty and not np.all(sp.uncertainty.array == 0): weights = 'unc' @@ -366,7 +366,7 @@ def _generate_spaxel_list(spectrum): Parameters ---------- - spectrum : :class:`specutils.Spectrum1D` + spectrum : :class:`specutils.Spectrum` The spectrum that stores the cube in its ``'flux'`` attribute. Returns diff --git a/jdaviz/configs/default/plugins/model_fitting/model_fitting.py b/jdaviz/configs/default/plugins/model_fitting/model_fitting.py index f9346e5e2f..bf13586c72 100644 --- a/jdaviz/configs/default/plugins/model_fitting/model_fitting.py +++ b/jdaviz/configs/default/plugins/model_fitting/model_fitting.py @@ -3,7 +3,7 @@ from copy import deepcopy import astropy.units as u -from specutils import Spectrum1D +from specutils import Spectrum from specutils.utils import QuantityModel from traitlets import Bool, List, Unicode, observe @@ -195,6 +195,7 @@ def _param_units(self, param, model_type=None): y_params = ["amplitude", "amplitude_L", "intercept", "scale"] if param == "slope": + print(self._units) return str(u.Unit(self._units["y"]) / u.Unit(self._units["x"])) elif model_type == 'Polynomial1D': # param names are all named cN, where N is the order @@ -358,7 +359,7 @@ def _dataset_selected_changed(self, event=None): if selected_spec is None: return - # Replace NaNs from collapsed Spectrum1D in Cubeviz + # Replace NaNs from collapsed Spectrum in Cubeviz # (won't affect calculations because these locations are masked) selected_spec.flux[np.isnan(selected_spec.flux)] = 0.0 @@ -979,7 +980,7 @@ def _fit_model_to_cube(self, add_data): if "_orig_spec" in data.meta: spec = data.meta["_orig_spec"] else: - spec = data.get_object(cls=Spectrum1D, statistic=None) + spec = data.get_object(cls=Spectrum, statistic=None) sb_unit = self.app._get_display_unit('sb') if spec.flux.unit != sb_unit: @@ -1040,7 +1041,7 @@ def _fit_model_to_cube(self, add_data): temp_label = "{} ({}, {})".format(self.results_label, m["x"], m["y"]) self.app.fitted_models[temp_label] = m["model"] - output_cube = Spectrum1D(flux=fitted_spectrum.flux, wcs=fitted_spectrum.wcs) + output_cube = Spectrum(flux=fitted_spectrum.flux, wcs=fitted_spectrum.wcs) selected_spec = self.dataset.selected_obj if '_pixel_scale_factor' in selected_spec.meta: 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 403167e533..40f62bdd5c 100644 --- a/jdaviz/configs/default/plugins/model_fitting/tests/test_fitting.py +++ b/jdaviz/configs/default/plugins/model_fitting/tests/test_fitting.py @@ -10,7 +10,7 @@ from astropy.wcs import WCS from glue.core.roi import XRangeROI from numpy.testing import assert_allclose, assert_array_equal -from specutils.spectra import Spectrum1D +from specutils.spectra import Spectrum from jdaviz.configs.default.plugins.model_fitting import fitting_backend as fb from jdaviz.configs.default.plugins.model_fitting import initializers @@ -58,7 +58,7 @@ def test_model_params(): def test_model_ids(cubeviz_helper, spectral_cube_wcs): - cubeviz_helper.load_data(Spectrum1D(flux=np.ones((3, 4, 5)) * u.nJy, wcs=spectral_cube_wcs), + cubeviz_helper.load_data(Spectrum(flux=np.ones((3, 4, 5)) * u.nJy, wcs=spectral_cube_wcs), data_label='test') plugin = cubeviz_helper.plugins["Model Fitting"]._obj plugin.dataset_selected = 'Spectrum (sum)' @@ -86,7 +86,7 @@ def test_parameter_retrieval(cubeviz_helper, spectral_cube_wcs): flux = np.ones((3, 4, 5)) flux[2, 2, :] = [1, 2, 3, 4, 5] - cubeviz_helper.load_data(Spectrum1D(flux=flux * flux_unit, wcs=spectral_cube_wcs), + cubeviz_helper.load_data(Spectrum(flux=flux * flux_unit, wcs=spectral_cube_wcs), data_label='test') plugin = cubeviz_helper.plugins["Model Fitting"] @@ -129,7 +129,7 @@ def test_fitting_backend(unc): uncertainties = StdDevUncertainty(np.zeros(y.shape)*u.Jy) elif unc is None: uncertainties = None - spectrum = Spectrum1D(flux=y*u.Jy, spectral_axis=x*u.um, uncertainty=uncertainties) + spectrum = Spectrum(flux=y*u.Jy, spectral_axis=x*u.um, uncertainty=uncertainties) g1f = models.Gaussian1D(0.7*u.Jy, 4.65*u.um, 0.3*u.um, name='g1') g2f = models.Gaussian1D(2.0*u.Jy, 5.55*u.um, 0.3*u.um, name='g2') @@ -166,7 +166,7 @@ def test_cube_fitting_backend(cubeviz_helper, unc, tmp_path): IMAGE_SIZE_X = 15 IMAGE_SIZE_Y = 14 - # Flux cube oriented as in JWST data. To build a Spectrum1D + # Flux cube oriented as in JWST data. To build a Spectrum # instance with this, one need to transpose it so the spectral # axis direction corresponds to the last index. flux_cube = np.zeros((SPECTRUM_SIZE, IMAGE_SIZE_X, IMAGE_SIZE_Y)) @@ -181,7 +181,7 @@ def test_cube_fitting_backend(cubeviz_helper, unc, tmp_path): for spx in spaxels: flux_cube[:, spx[0], spx[1]] = build_spectrum(sigma=SIGMA)[1] - # Transpose so it can be packed in a Spectrum1D instance. + # Transpose so it can be packed in a Spectrum instance. flux_cube = flux_cube.transpose(1, 2, 0) # (15, 14, 200) cube_wcs = WCS({ 'WCSAXES': 3, 'RADESYS': 'ICRS', 'EQUINOX': 2000.0, @@ -201,8 +201,8 @@ def test_cube_fitting_backend(cubeviz_helper, unc, tmp_path): elif unc is None: uncertainties = None - spectrum = Spectrum1D(flux=flux_cube*u.Jy, wcs=cube_wcs, - uncertainty=uncertainties, mask=mask) + spectrum = Spectrum(flux=flux_cube*u.Jy, wcs=cube_wcs, + uncertainty=uncertainties, mask=mask) # Initial model for fit. g1f = models.Gaussian1D(0.7*u.Jy, 4.65*u.um, 0.3*u.um, name='g1') @@ -238,7 +238,7 @@ def test_cube_fitting_backend(cubeviz_helper, unc, tmp_path): assert fitted_model[0].mean.unit == u.um # Check that spectrum result is formatted as expected. - assert isinstance(fitted_spectrum, Spectrum1D) + assert isinstance(fitted_spectrum, Spectrum) assert len(fitted_spectrum.shape) == 3 assert fitted_spectrum.shape == (IMAGE_SIZE_X, IMAGE_SIZE_Y, SPECTRUM_SIZE) @@ -405,7 +405,7 @@ def test_incompatible_units(specviz_helper, spectrum1d): def test_cube_fit_with_nans(cubeviz_helper): flux = np.ones((7, 8, 9)) * u.nJy flux[:, :, 0] = np.nan - spec = Spectrum1D(flux=flux) + spec = Spectrum(flux=flux) cubeviz_helper.load_data(spec, data_label="test") mf = cubeviz_helper.plugins["Model Fitting"] @@ -426,7 +426,7 @@ def test_cube_fit_with_subset_and_nans(cubeviz_helper): # Also test with existing mask flux = np.ones((7, 8, 9)) * u.nJy flux[:, :, 0] = np.nan - spec = Spectrum1D(flux=flux) + spec = Spectrum(flux=flux) spec.flux[5, 5, 7] = 10 * u.nJy cubeviz_helper.load_data(spec, data_label="test") @@ -448,7 +448,7 @@ def test_fit_with_count_units(cubeviz_helper): flux = np.random.random((7, 8, 9)) * u.count spectral_axis = np.linspace(4000, 5000, flux.shape[-1]) * u.AA - spec = Spectrum1D(flux=flux, spectral_axis=spectral_axis) + spec = Spectrum(flux=flux, spectral_axis=spectral_axis) cubeviz_helper.load_data(spec, data_label="test") mf = cubeviz_helper.plugins["Model Fitting"] diff --git a/jdaviz/configs/default/plugins/model_fitting/tests/test_plugin.py b/jdaviz/configs/default/plugins/model_fitting/tests/test_plugin.py index 3069429174..fd73eeb9c3 100644 --- a/jdaviz/configs/default/plugins/model_fitting/tests/test_plugin.py +++ b/jdaviz/configs/default/plugins/model_fitting/tests/test_plugin.py @@ -15,7 +15,7 @@ import astropy.units as u from glue.core.roi import CircularROI -from specutils import Spectrum1D, SpectralRegion +from specutils import Spectrum, SpectralRegion from jdaviz.configs.default.plugins.model_fitting.initializers import MODELS @@ -168,9 +168,9 @@ def test_initialize_gaussian_with_cube(cubeviz_helper, spectrum1d_cube_larger): def test_fit_cube_no_wcs(cubeviz_helper): - # This is like when user does something to a cube outside of Jdaviz - # and then loads it back into a new instance of Cubeviz for further analysis. - sp = Spectrum1D(flux=np.ones((7, 8, 9)) * u.nJy) # nx, ny, nz + # This is like when user do something to a cube outside of Jdaviz + # and then load it back into a new instance of Cubeviz for further analysis. + sp = Spectrum(flux=np.ones((7, 8, 9)) * u.nJy, spectral_axis_index=2) # ny, nx, nz cubeviz_helper.load_data(sp, data_label="test_cube") mf = cubeviz_helper.plugins['Model Fitting'] mf.create_model_component('Linear1D') @@ -189,7 +189,7 @@ def test_fit_cube_no_wcs(cubeviz_helper): def test_toggle_cube_fit_subset(cubeviz_helper): - sp = Spectrum1D(flux=np.ones((7, 8, 9)) * u.nJy) # ny, nx, nz + sp = Spectrum(flux=np.ones((7, 8, 9)) * u.nJy) # ny, nx, nz cubeviz_helper.load_data(sp, data_label="test_cube") mf = cubeviz_helper.plugins['Model Fitting'] @@ -352,7 +352,7 @@ def test_subset_masks(cubeviz_helper, spectrum1d_cube_larger): # Get the data object again (ensures mask == None) data = cubeviz_helper.app.data_collection[-1].get_object() subset = cubeviz_helper.app.data_collection[-1].get_subset_object( - p.spectral_subset_selected, cls=Spectrum1D, statistic=None + p.spectral_subset_selected, cls=Spectrum, statistic=None ) masked_data = p._apply_subset_masks(data, p.spectral_subset) @@ -368,8 +368,8 @@ def test_invalid_subset(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d, data_label="right_spectrum") # 5000-7000 - sp2 = Spectrum1D(spectral_axis=spectrum1d.spectral_axis - 1000*spectrum1d.spectral_axis.unit, - flux=spectrum1d.flux * 1.25) + sp2 = Spectrum(spectral_axis=spectrum1d.spectral_axis - 1000*spectrum1d.spectral_axis.unit, + flux=spectrum1d.flux * 1.25) specviz_helper.load_data(sp2, data_label="left_spectrum") # apply subset that overlaps on left_spectrum, but not right_spectrum @@ -404,7 +404,7 @@ def test_all_nan_uncert(specviz_helper): # being filtered in the fitter, as would normally happen with nans) uncertainty = StdDevUncertainty([np.nan, np.nan, np.nan, np.nan, np.nan, np.nan] * u.Jy) - spec = Spectrum1D(flux=[1, 2, 3, 4, 5, 6]*u.Jy, uncertainty=uncertainty) + spec = Spectrum(flux=[1, 2, 3, 4, 5, 6]*u.Jy, uncertainty=uncertainty) specviz_helper.load_data(spec) plugin = specviz_helper.plugins['Model Fitting'] @@ -431,7 +431,7 @@ def test_all_nan_uncert_subset(specviz_helper): # message uncertainty = StdDevUncertainty([1, 1, np.nan, np.nan, np.nan, np.nan] * u.Jy) - spec = Spectrum1D(flux=[2, 4, 3, 4, 5, 6]*u.Jy, uncertainty=uncertainty) + spec = Spectrum(flux=[2, 4, 3, 4, 5, 6]*u.Jy, uncertainty=uncertainty) specviz_helper.load_data(spec) plugin = specviz_helper.plugins['Model Fitting'] diff --git a/jdaviz/configs/imviz/helper.py b/jdaviz/configs/imviz/helper.py index dbd97f369c..dc868be035 100644 --- a/jdaviz/configs/imviz/helper.py +++ b/jdaviz/configs/imviz/helper.py @@ -335,7 +335,7 @@ def get_data(self, data_label=None, spatial_subset=None, cls=None): Provide a label to retrieve a specific data set from data_collection. spatial_subset : str, optional Spatial subset applied to data. - cls : `~specutils.Spectrum1D`, `~astropy.nddata.CCDData`, optional + cls : `~specutils.Spectrum`, `~astropy.nddata.CCDData`, optional The type that data will be returned as. Returns diff --git a/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py b/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py index 557420b367..a75d42c6ed 100644 --- a/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py +++ b/jdaviz/configs/imviz/plugins/aper_phot_simple/aper_phot_simple.py @@ -491,9 +491,17 @@ def _calc_background_median(self, reg, data=None): data = self.dataset.selected_dc_item comp = data.get_component(data.main_components[0]) + if self.config == "cubeviz" and data.ndim > 2: + if "spectral_axis_index" in getattr(data, "meta", {}): + spectral_axis_index = data.meta["spectral_axis_index"] + else: + spectral_axis_index = 0 if self.config == "cubeviz" and data.ndim > 2: - comp_data = comp.data[:, :, self._cubeviz_slice_ind].T # nx, ny --> ny, nx + if spectral_axis_index == 0: + comp_data = comp.data[self._cubeviz_slice_ind, :, :] + else: + comp_data = comp.data[:, :, self._cubeviz_slice_ind].T # nx, ny --> ny, nx # Similar to coords_info logic. if '_orig_spec' in getattr(data, 'meta', {}): w = data.meta['_orig_spec'].wcs.celestial @@ -592,6 +600,12 @@ def calculate_photometry(self, dataset=None, aperture=None, background=None, # we can use the pre-cached value data = self.dataset.selected_dc_item + if self.config == "cubeviz" and data.ndim > 2: + if "spectral_axis_index" in getattr(data, "meta", {}): + spectral_axis_index = data.meta["spectral_axis_index"] + else: + spectral_axis_index = 0 + if aperture is not None: if aperture not in self.aperture.choices: raise ValueError(f"aperture must be one of {self.aperture.choices}") @@ -675,7 +689,10 @@ def calculate_photometry(self, dataset=None, aperture=None, background=None, raise ValueError('Missing or invalid background value') if self.config == "cubeviz" and data.ndim > 2: - comp_data = comp.data[:, :, self._cubeviz_slice_ind].T # nx, ny --> ny, nx + if spectral_axis_index == 0: + comp_data = comp.data[self._cubeviz_slice_ind, :, :] + else: + comp_data = comp.data[:, :, self._cubeviz_slice_ind].T # nx, ny --> ny, nx # Similar to coords_info logic. if '_orig_spec' in getattr(data, 'meta', {}): w = data.meta['_orig_spec'].wcs @@ -696,8 +713,11 @@ def calculate_photometry(self, dataset=None, aperture=None, background=None, ycenter = reg.center.y if data.coords is not None: if self.config == "cubeviz" and data.ndim > 2: - sky_center = w.pixel_to_world(self._cubeviz_slice_ind, - ycenter, xcenter)[1] + if spectral_axis_index == 0: + sky = w.pixel_to_world(xcenter, ycenter, self._cubeviz_slice_ind) + else: + sky = w.pixel_to_world(self._cubeviz_slice_ind, ycenter, xcenter) + sky_center = [coord for coord in sky if hasattr(coord, "icrs")][0] else: # "imviz" sky_center = w.pixel_to_world(xcenter, ycenter) else: diff --git a/jdaviz/configs/imviz/plugins/coords_info/coords_info.py b/jdaviz/configs/imviz/plugins/coords_info/coords_info.py index bec01c238c..af8ebc709c 100644 --- a/jdaviz/configs/imviz/plugins/coords_info/coords_info.py +++ b/jdaviz/configs/imviz/plugins/coords_info/coords_info.py @@ -63,6 +63,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._marks = {} self._dict = {} # dictionary representation of current mouseover info + self._spectral_axis_index = 2 # Needed for cube data self._x, self._y = None, None # latest known cursor positions self.image_unit = None @@ -252,7 +253,10 @@ def _image_shape_inds(self, image): # return the indices in image.shape for the x and y dimension, respectively if image.ndim == 3: # cubeviz case - return (0, 1) # (ix_shape, iy_shape) + if self._spectral_axis_index == 0: + return (2, 1) + else: + return (0, 1) # (ix_shape, iy_shape) elif image.ndim == 2: return (1, 0) # (ix_shape, iy_shape) else: # pragma: no cover @@ -261,7 +265,10 @@ def _image_shape_inds(self, image): def _get_cube_value(self, image, arr, x, y, viewer): if image.ndim == 3: # cubeviz case: - return arr[int(round(x)), int(round(y)), viewer.state.slices[-1]] + if self._spectral_axis_index == 0: + return arr[viewer.state.slices[-1], int(round(y)), int(round(x))] + else: + return arr[int(round(x)), int(round(y)), viewer.state.slices[-1]] elif image.ndim == 2: if isinstance(viewer, RampvizImageView): x, y = y, x @@ -359,10 +366,17 @@ def _image_viewer_update(self, viewer, x, y): else: data_wcs = None + if "spectral_axis_index" in getattr(coo_data, "meta", {}): + self._spectral_axis_index = coo_data.meta["spectral_axis_index"] + if data_wcs: try: if wcs_ndim == 3: - sky = data_wcs.pixel_to_world(viewer.slice, y, x)[1].icrs + if self._spectral_axis_index == 0: + sky = data_wcs.pixel_to_world(x, y, viewer.slice) + else: + sky = data_wcs.pixel_to_world(viewer.slice, y, x) + sky = [coord for coord in sky if hasattr(coord, "icrs")][0].icrs else: # wcs_ndim == 2 sky = data_wcs.pixel_to_world(x, y).icrs except Exception: diff --git a/jdaviz/configs/mosviz/helper.py b/jdaviz/configs/mosviz/helper.py index bd3cf23e1e..f0f192ad70 100644 --- a/jdaviz/configs/mosviz/helper.py +++ b/jdaviz/configs/mosviz/helper.py @@ -258,7 +258,7 @@ def _get_sp_attribute(table_data, row, attr, fill=None): if sp1_val is not None and sp1_val != sp2_val: # then there was a conflict - msg = f"Warning: value for {attr} in row {row} in disagreement between Spectrum1D and Spectrum2D" # noqa + msg = f"Warning: value for {attr} in row {row} in disagreement between Spectrum and Spectrum2D" # noqa msg = SnackbarMessage(msg, color='warning', sender=self) self.app.hub.broadcast(msg) @@ -283,12 +283,12 @@ def load_data(self, spectra_1d=None, spectra_2d=None, images=None, ---------- spectra_1d : list or str A list of spectra as translatable container objects (e.g. - ``Spectrum1D``) that can be read by glue-jupyter. Alternatively, + ``Spectrum``) that can be read by glue-jupyter. Alternatively, can be a string file path. spectra_2d : list or str A list of spectra as translatable container objects (e.g. - ``Spectrum1D``) that can be read by glue-jupyter. Alternatively, + ``Spectrum``) that can be read by glue-jupyter. Alternatively, can be a string file path. images : list of obj, str, or `None` @@ -460,12 +460,12 @@ def load_spectra(self, spectra_1d, spectra_2d): ---------- spectra_1d : list or str A list of spectra as translatable container objects (e.g. - ``Spectrum1D``) that can be read by glue-jupyter. Alternatively, + ``Spectrum``) that can be read by glue-jupyter. Alternatively, can be a string file path. spectra_2d : list or str A list of spectra as translatable container objects (e.g. - ``Spectrum1D``) that can be read by glue-jupyter. Alternatively, + ``Spectrum``) that can be read by glue-jupyter. Alternatively, can be a string file path. """ @@ -499,7 +499,7 @@ def load_1d_spectra(self, data_obj, data_labels=None, add_redshift_column=False) ---------- data_obj : list or str A list of spectra as translatable container objects (e.g. - ``Spectrum1D``) that can be read by glue-jupyter. Alternatively, + ``Spectrum``) that can be read by glue-jupyter. Alternatively, can be a string file path. data_labels : str or list String representing the label for the data item loaded via @@ -527,7 +527,7 @@ def load_2d_spectra(self, data_obj, data_labels=None, add_redshift_column=False) ---------- data_obj : list or str A list of 2D spectra as translatable container objects (e.g. - ``Spectrum1D``) that can be read by glue-jupyter. Alternatively, + ``Spectrum``) that can be read by glue-jupyter. Alternatively, can be a string file path. data_labels : str or list String representing the label for the data item loaded via @@ -921,7 +921,7 @@ def get_spectrum_1d(self, row=None, apply_slider_redshift="Warn"): Returns ------- - `~specutils.Spectrum1D` + `~specutils.Spectrum` """ return self._get_spectrum('1D Spectra', row, apply_slider_redshift) @@ -941,7 +941,7 @@ def get_spectrum_2d(self, row=None, apply_slider_redshift="Warn"): Returns ------- - `~specutils.Spectrum1D` + `~specutils.Spectrum` """ return self._get_spectrum('2D Spectra', row, apply_slider_redshift) @@ -956,7 +956,7 @@ def get_data(self, data_label=None, spectral_subset=None, cls=None): Provide a label to retrieve a specific data set from data_collection. spectral_subset : str, optional Spectral subset applied to data. - cls : `~specutils.Spectrum1D`, `~astropy.nddata.CCDData`, optional + cls : `~specutils.Spectrum`, `~astropy.nddata.CCDData`, optional The type that data will be returned as. Returns diff --git a/jdaviz/configs/mosviz/plugins/parsers.py b/jdaviz/configs/mosviz/plugins/parsers.py index 31579799ac..196e0b4682 100644 --- a/jdaviz/configs/mosviz/plugins/parsers.py +++ b/jdaviz/configs/mosviz/plugins/parsers.py @@ -10,7 +10,7 @@ from astropy.wcs import WCS from glue.core.data import Data from glue.core.link_helpers import LinkSameWithUnits -from specutils import Spectrum1D, SpectrumList, SpectrumCollection +from specutils import Spectrum, SpectrumList, SpectrumCollection from specutils.io.default_loaders.jwst_reader import identify_jwst_s2d_multi_fits from jdaviz.configs.imviz.plugins.parsers import get_image_data_iterator @@ -226,10 +226,10 @@ def mos_spec1d_parser(app, data_obj, data_labels=None, if not isinstance(data_obj, (list, tuple, SpectrumCollection)): data_obj = [data_obj] - # If the file has multiple objects in it, the Spectrum1D read machinery + # If the file has multiple objects in it, the Spectrum read machinery # will fail to find a reader for it, and we fall back on SpectrumList try: - data_obj = [Spectrum1D.read(x) if _check_is_file(x) else x for x in data_obj] + data_obj = [Spectrum.read(x) if _check_is_file(x) else x for x in data_obj] except IORegistryError: if len(data_obj) == 1: if _check_is_file(data_obj[0]): @@ -330,7 +330,7 @@ def _parse_as_spectrum1d(hdulist, ext, transpose): else: kw = {'wcs': wcs} - return Spectrum1D(flux=data * data_unit, meta=metadata, **kw) + return Spectrum(flux=data * data_unit, meta=metadata, **kw) # Coerce into list-like object if (not isinstance(data_obj, (list, tuple, SpectrumCollection)) or @@ -356,7 +356,7 @@ def _parse_as_spectrum1d(hdulist, ext, transpose): with app.data_collection.delay_link_manager_update(): for index, data in enumerate(data_obj): - # If we got a filepath, first try and parse using the Spectrum1D and + # If we got a filepath, first try and parse using the Spectrum and # SpectrumList parsers, and then fall back to parsing it as a generic # FITS file. @@ -369,7 +369,7 @@ def _parse_as_spectrum1d(hdulist, ext, transpose): with fits.open(data) as hdulist: data = _parse_as_spectrum1d(hdulist, ext, transpose) else: - data = Spectrum1D.read(data) + data = Spectrum.read(data) except IORegistryError: with fits.open(data) as hdulist: data = _parse_as_spectrum1d(hdulist, ext, transpose) @@ -903,7 +903,7 @@ def mos_niriss_parser(app, data_dir, instrument=None, meta[PRIHDR_KEY] = standardize_metadata(temp[0].header) # The wavelength is stored in a WAVELENGTH HDU. This is - # a 2D array, but in order to be able to use Spectrum1D + # a 2D array, but in order to be able to use Spectrum # we use the average wavelength for all image rows if data.shape[0] > data.shape[1]: @@ -914,7 +914,7 @@ def mos_niriss_parser(app, data_dir, instrument=None, else: wav = temp[wav_hdus[sci]].data.mean(axis=0) * u.micron - spec2d = Spectrum1D(data * u.one, spectral_axis=wav, meta=meta) + spec2d = Spectrum(data * u.one, spectral_axis=wav, meta=meta) spec2d.meta['INSTRUME'] = instrument.upper() spec2d.meta['mosviz_row'] = len(spec_labels_2d) diff --git a/jdaviz/configs/mosviz/plugins/viewers.py b/jdaviz/configs/mosviz/plugins/viewers.py index a84d772998..4f5e8e670f 100644 --- a/jdaviz/configs/mosviz/plugins/viewers.py +++ b/jdaviz/configs/mosviz/plugins/viewers.py @@ -7,7 +7,7 @@ from glue_jupyter.bqplot.image import BqplotImageView from glue_jupyter.table import TableViewer from scipy.interpolate import interp1d -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz.core.events import (AddDataToViewerMessage, RemoveDataFromViewerMessage, @@ -71,7 +71,7 @@ def _mark_targets(self): class MosvizProfile2DView(JdavizViewerMixin, BqplotImageView): # Due to limitations in CCDData and 2D data that has spectral and spatial # axes, the default conversion class must handle cubes - default_class = Spectrum1D + default_class = Spectrum # categories: zoom resets, zoom, pan, subset, select tools, shortcuts tools_nested = [ @@ -221,7 +221,7 @@ def set_plot_axes(self): self.figure.axes[1].tick_format = None self.figure.axes[1].label_location = "middle" - # Sync with Spectrum1D viewer (that is also used by other viz). + # Sync with Spectrum viewer (that is also used by other viz). # Make it so y axis label is not covering tick numbers. self.figure.fig_margin["left"] = 95 self.figure.fig_margin["bottom"] = 60 diff --git a/jdaviz/configs/mosviz/tests/test_data_loading.py b/jdaviz/configs/mosviz/tests/test_data_loading.py index 21b0865bc9..cc4fce29c6 100644 --- a/jdaviz/configs/mosviz/tests/test_data_loading.py +++ b/jdaviz/configs/mosviz/tests/test_data_loading.py @@ -5,7 +5,7 @@ import numpy as np import pytest from astropy.nddata import CCDData -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz.utils import PRIHDR_KEY @@ -27,7 +27,7 @@ def test_load_spectrum1d(mosviz_helper, spectrum1d): ).data() assert len(data) == 1 - assert isinstance(data[0], Spectrum1D) + assert isinstance(data[0], Spectrum) with pytest.raises(AttributeError): mosviz_helper.load_1d_spectra([1, 2, 3]) @@ -74,7 +74,7 @@ def test_load_spectrum_collection(mosviz_helper, spectrum_collection): ).data() assert len(data) == 1 - assert isinstance(data[0], Spectrum1D) + assert isinstance(data[0], Spectrum) def test_load_list_of_spectrum1d(mosviz_helper, spectrum1d): @@ -96,7 +96,7 @@ def test_load_list_of_spectrum1d(mosviz_helper, spectrum1d): ).data() assert len(data) == 1 - assert isinstance(data[0], Spectrum1D) + assert isinstance(data[0], Spectrum) def test_load_mos_spectrum2d(mosviz_helper, mos_spectrum2d): diff --git a/jdaviz/configs/specviz/helper.py b/jdaviz/configs/specviz/helper.py index 066456198b..655f8c6245 100644 --- a/jdaviz/configs/specviz/helper.py +++ b/jdaviz/configs/specviz/helper.py @@ -4,7 +4,7 @@ from astropy.utils.decorators import deprecated from regions.core.core import Region from glue.core.subset_group import GroupedSubset -from specutils import SpectralRegion, Spectrum1D +from specutils import SpectralRegion, Spectrum from jdaviz.core.helpers import ConfigHelper from jdaviz.core.events import RedshiftMessage @@ -17,13 +17,13 @@ def _apply_redshift_to_spectra(spectra, redshift): flux = spectra.flux # This is a hack around inability to input separate redshift with - # a SpectralAxis instance in Spectrum1D + # a SpectralAxis instance in Spectrum spaxis = spectra.spectral_axis.value * spectra.spectral_axis.unit mask = spectra.mask uncertainty = spectra.uncertainty - output_spectra = Spectrum1D(flux, spectral_axis=spaxis, - redshift=redshift, mask=mask, - uncertainty=uncertainty) + output_spectra = Spectrum(flux, spectral_axis=spaxis, + redshift=redshift, mask=mask, + uncertainty=uncertainty) return output_spectra @@ -49,13 +49,13 @@ def load_data(self, data, data_label=None, format=None, show_in_viewer=True, Parameters ---------- - data : str, `~specutils.Spectrum1D`, or `~specutils.SpectrumList` - Spectrum1D, SpectrumList, or path to compatible data file. + data : str, `~specutils.Spectrum`, or `~specutils.SpectrumList` + Spectrum, SpectrumList, or path to compatible data file. data_label : str The Glue data label found in the ``DataCollection``. format : str Loader format specification used to indicate data format in - `~specutils.Spectrum1D.read` io method. + `~specutils.Spectrum.read` io method. show_in_viewer : bool Show data in viewer(s). concat_by_file : bool @@ -98,7 +98,7 @@ def get_spectra(self, data_label=None, spectral_subset=None, apply_slider_redshi if data_label is not None: spectrum = get_data_method(data_label=data_label, spectral_subset=spectral_subset, - cls=Spectrum1D) + cls=Spectrum) spectra[data_label] = spectrum else: for layer_state in viewer.state.layers: @@ -107,7 +107,7 @@ def get_spectra(self, data_label=None, spectral_subset=None, apply_slider_redshi if lyr.label == spectral_subset: spectrum = get_data_method(data_label=lyr.data.label, spectral_subset=spectral_subset, - cls=Spectrum1D) + cls=Spectrum) spectra[lyr.data.label] = spectrum else: continue @@ -120,11 +120,11 @@ def get_spectra(self, data_label=None, spectral_subset=None, apply_slider_redshi isinstance(all_subsets[lyr.label], SpectralRegion)): spectrum = get_data_method(data_label=lyr.data.label, spectral_subset=lyr.label, - cls=Spectrum1D) + cls=Spectrum) spectra[f'{lyr.data.label} ({lyr.label})'] = spectrum else: spectrum = get_data_method(data_label=lyr.label, - cls=Spectrum1D) + cls=Spectrum) spectra[lyr.label] = spectrum if not apply_slider_redshift: @@ -133,7 +133,7 @@ def get_spectra(self, data_label=None, spectral_subset=None, apply_slider_redshi return spectra else: output_spectra = {} - # We need to create new Spectrum1D outputs with the redshifts set + # We need to create new Spectrum outputs with the redshifts set for key in spectra.keys(): output_spectra[key] = _apply_redshift_to_spectra(spectra[key], self._redshift) @@ -310,7 +310,7 @@ def get_data(self, data_label=None, spectral_subset=None, cls=None, Provide a label to retrieve a specific data set from data_collection. spectral_subset : str, optional Spectral subset applied to data. - cls : `~specutils.Spectrum1D`, optional + cls : `~specutils.Spectrum`, optional The type that data will be returned as. use_display_units: bool, optional Whether to convert to the display units defined in the plugin. diff --git a/jdaviz/configs/specviz/plugins/line_analysis/line_analysis.py b/jdaviz/configs/specviz/plugins/line_analysis/line_analysis.py index b95dbc332f..f364c3e51d 100644 --- a/jdaviz/configs/specviz/plugins/line_analysis/line_analysis.py +++ b/jdaviz/configs/specviz/plugins/line_analysis/line_analysis.py @@ -6,7 +6,7 @@ from glue_jupyter.common.toolbar_vuetify import read_icon from traitlets import Bool, List, Float, Unicode, observe from astropy import units as u -from specutils import analysis, Spectrum1D +from specutils import analysis, Spectrum from jdaviz.core.events import (AddDataMessage, RemoveDataMessage, @@ -313,7 +313,7 @@ def _uncertainty(result): if (flux_unit.is_equivalent(u.Jy) or flux_unit.is_equivalent(u.Jy / solid_angle_in_flux_unit)): # Perform integration in frequency space - freq_spec = Spectrum1D( + freq_spec = Spectrum( spectral_axis=spec_subtracted.spectral_axis.to(u.Hz, equivalencies=u.spectral()), flux=spec_subtracted.flux, @@ -349,7 +349,7 @@ def _uncertainty(result): elif (flux_unit.is_equivalent(u.Unit('W/(m2 m)')) or flux_unit.is_equivalent(u.Unit(f'W/(m2 m {solid_angle_string})'))): # Perform integration in wavelength space using MKS unit (meters) - wave_spec = Spectrum1D( + wave_spec = Spectrum( spectral_axis=spec_subtracted.spectral_axis.to(u.m, equivalencies=u.spectral()), flux=spec_subtracted.flux, diff --git a/jdaviz/configs/specviz/plugins/line_analysis/tests/test_line_analysis.py b/jdaviz/configs/specviz/plugins/line_analysis/tests/test_line_analysis.py index 6b077a14ca..24a0ab7ea3 100644 --- a/jdaviz/configs/specviz/plugins/line_analysis/tests/test_line_analysis.py +++ b/jdaviz/configs/specviz/plugins/line_analysis/tests/test_line_analysis.py @@ -5,7 +5,7 @@ from astropy.tests.helper import assert_quantity_allclose from numpy.testing import assert_allclose from regions import RectanglePixelRegion, PixCoord -from specutils import Spectrum1D, SpectralRegion +from specutils import Spectrum, SpectralRegion from jdaviz.configs.specviz.plugins.line_analysis.line_analysis import _coerce_unit from jdaviz.core.custom_units_and_equivs import PIX2 @@ -480,8 +480,8 @@ def test_invalid_subset(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d, data_label="right_spectrum") # 5000-7000 - sp2 = Spectrum1D(spectral_axis=spectrum1d.spectral_axis - 1000*spectrum1d.spectral_axis.unit, - flux=spectrum1d.flux * 1.25) + sp2 = Spectrum(spectral_axis=spectrum1d.spectral_axis - 1000*spectrum1d.spectral_axis.unit, + flux=spectrum1d.flux * 1.25) specviz_helper.load_data(sp2, data_label="left_spectrum") # apply subset that overlaps on left_spectrum, but not right_spectrum diff --git a/jdaviz/configs/specviz/plugins/line_analysis/tests/test_lineflux.py b/jdaviz/configs/specviz/plugins/line_analysis/tests/test_lineflux.py index 44fe58070a..0326219a9a 100644 --- a/jdaviz/configs/specviz/plugins/line_analysis/tests/test_lineflux.py +++ b/jdaviz/configs/specviz/plugins/line_analysis/tests/test_lineflux.py @@ -3,7 +3,7 @@ from glue.viewers.profile.state import FUNCTIONS as COLLAPSE_FUNCTIONS import numpy as np import pytest -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz import Cubeviz @@ -40,17 +40,17 @@ def _gauss_with_unity_area(x, mean, sigma): # unit-flux gaussian in frequency space freq = np.arange(1, 2, 0.001)*u.Hz flux_freq = _gauss_with_unity_area(freq.value, mn, sig)*1.0E26*u.Jy -fnu_freq = Spectrum1D(spectral_axis=freq, flux=flux_freq) +fnu_freq = Spectrum(spectral_axis=freq, flux=flux_freq) unit_flux_gaussian_test_cases.append(fnu_freq) -fnu_wave = Spectrum1D(spectral_axis=fnu_freq.wavelength, flux=flux_freq) +fnu_wave = Spectrum(spectral_axis=fnu_freq.wavelength, flux=flux_freq) unit_flux_gaussian_test_cases.append(fnu_wave) # unit-flux gaussian in wavelength space lam = np.arange(1, 2, 0.001)*u.m flux_wave = _gauss_with_unity_area(lam.value, mn, sig)*1.0*u.W/u.m**2/u.m -flam_wave = Spectrum1D(spectral_axis=lam, flux=flux_wave) +flam_wave = Spectrum(spectral_axis=lam, flux=flux_wave) unit_flux_gaussian_test_cases.append(flam_wave) -flam_freq = Spectrum1D(spectral_axis=flam_wave.frequency, flux=flux_wave) +flam_freq = Spectrum(spectral_axis=flam_wave.frequency, flux=flux_wave) unit_flux_gaussian_test_cases.append(flam_freq) @@ -118,7 +118,7 @@ def test_unit_gaussian_mixed_units_per_steradian(specviz_helper): # test changed from Surface Brightness to Flux, # u.erg/u.s/u.cm**2/u.Angstrom/u.sr in untranslatable units (check unit_conversion.py) flx_wave = _gauss_with_unity_area(lam_a.value, mn, sig)*1E3*u.erg/u.s/u.cm**2/u.Angstrom - fl_wave = Spectrum1D(spectral_axis=lam_a, flux=flx_wave) + fl_wave = Spectrum(spectral_axis=lam_a, flux=flx_wave) specviz_helper.load_data(fl_wave) lineflux_result = _calculate_line_flux(specviz_helper) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 8af49c2bc3..61ced1e840 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -6,7 +6,7 @@ from astropy.io.registry import IORegistryError from astropy.nddata import StdDevUncertainty from astropy.io import fits -from specutils import Spectrum1D, SpectrumList, SpectrumCollection +from specutils import Spectrum, SpectrumList, SpectrumCollection from jdaviz.core.events import SnackbarMessage from jdaviz.core.registries import data_parser_registry @@ -21,17 +21,17 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v concat_by_file=False, cache=None, local_path=os.curdir, timeout=None, load_as_list=False): """ - Loads a data file or `~specutils.Spectrum1D` object into Specviz. + Loads a data file or `~specutils.Spectrum` object into Specviz. Parameters ---------- - data : str, `~specutils.Spectrum1D`, or `~specutils.SpectrumList` - Spectrum1D, SpectrumList, or path to compatible data file. + data : str, `~specutils.Spectrum`, or `~specutils.SpectrumList` + Spectrum, SpectrumList, or path to compatible data file. data_label : str The Glue data label found in the ``DataCollection``. format : str Loader format specification used to indicate data format in - `~specutils.Spectrum1D.read` io method. + `~specutils.Spectrum.read` io method. concat_by_file : bool If True and there is more than one available extension, concatenate the extensions within each spectrum file passed to the parser and @@ -65,7 +65,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v if isinstance(data, SpectrumCollection): raise TypeError("SpectrumCollection detected." " Please provide a Spectrum1D or SpectrumList") - elif isinstance(data, Spectrum1D): + elif isinstance(data, Spectrum): # Handle the possibility of 2D spectra by splitting into separate spectra if data.flux.ndim == 1: data_label = [data_label] @@ -79,7 +79,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v elif isinstance(data, list): # special processing for HDUList if isinstance(data, fits.HDUList): - data = [Spectrum1D.read(data)] + data = [Spectrum.read(data)] data_label = [data_label] else: # list treated as SpectrumList if not an HDUList @@ -97,7 +97,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v "returned an empty list") elif path.is_file(): try: - data = Spectrum1D.read(str(path), format=format) + data = Spectrum.read(str(path), format=format) if data.flux.ndim == 2: data = split_spectrum_with_2D_flux_array(data) else: @@ -235,7 +235,7 @@ def group_spectra_by_filename(datasets): def combine_lists_to_1d_spectrum(wl, fnu, dfnu, wave_units, flux_units): """ - Combine lists of 1D spectra into a composite `~specutils.Spectrum1D` object. + Combine lists of 1D spectra into a composite `~specutils.Spectrum` object. Parameters ---------- @@ -248,7 +248,7 @@ def combine_lists_to_1d_spectrum(wl, fnu, dfnu, wave_units, flux_units): Returns ------- - spec : `~specutils.Spectrum1D` + spec : `~specutils.Spectrum` Composite 1D spectrum. """ wlallarr = np.array(wl) @@ -266,8 +266,8 @@ def combine_lists_to_1d_spectrum(wl, fnu, dfnu, wave_units, flux_units): else: unc = None - spec = Spectrum1D(flux=fnuall * flux_units, spectral_axis=wlall * wave_units, - uncertainty=unc) + spec = Spectrum(flux=fnuall * flux_units, spectral_axis=wlall * wave_units, + uncertainty=unc) return spec @@ -293,7 +293,7 @@ def split_spectrum_with_2D_flux_array(data): unc = data.uncertainty[i, :] if data.mask is not None: mask = data.mask[i, :] - new_data.append(Spectrum1D(flux=data.flux[i, :], spectral_axis=data.spectral_axis, - uncertainty=unc, mask=mask, meta=data.meta)) + new_data.append(Spectrum(flux=data.flux[i, :], spectral_axis=data.spectral_axis, + uncertainty=unc, mask=mask, meta=data.meta)) return new_data diff --git a/jdaviz/configs/specviz/plugins/unit_conversion/tests/test_unit_conversion.py b/jdaviz/configs/specviz/plugins/unit_conversion/tests/test_unit_conversion.py index 9dbc4dd800..6b77d2dce0 100644 --- a/jdaviz/configs/specviz/plugins/unit_conversion/tests/test_unit_conversion.py +++ b/jdaviz/configs/specviz/plugins/unit_conversion/tests/test_unit_conversion.py @@ -2,7 +2,7 @@ import pytest from astropy import units as u from astropy.nddata import InverseVariance -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz.core.custom_units_and_equivs import SPEC_PHOTON_FLUX_DENSITY_UNITS @@ -36,7 +36,7 @@ def test_value_error_exception(specviz_helper, spectrum1d, new_spectral_axis, ne def test_initialize_specviz_sb(specviz_helper, spectrum1d): - spec_sb = Spectrum1D(spectrum1d.flux/u.sr, spectrum1d.spectral_axis) + spec_sb = Spectrum(spectrum1d.flux/u.sr, spectrum1d.spectral_axis) specviz_helper.load_data(spec_sb, data_label="Test 1D Spectrum") plg = specviz_helper.plugins["Unit Conversion"] assert plg._obj.flux_unit == "Jy" @@ -118,7 +118,7 @@ def test_non_stddev_uncertainty(specviz_helper): var = stddev ** 2 inv_var = np.ones(len(flux)) / var wavelength = np.linspace(1, 5, len(flux)) * u.um - spec = Spectrum1D( + spec = Spectrum( flux, uncertainty=InverseVariance(inv_var), spectral_axis=wavelength @@ -147,7 +147,7 @@ def test_flux_unit_choices(specviz_helper, flux_unit, expected_choices): convertable flux units in the dropdown is correct. """ - spec = Spectrum1D([1, 2, 3] * flux_unit, [4, 5, 6] * u.um) + spec = Spectrum([1, 2, 3] * flux_unit, [4, 5, 6] * u.um) specviz_helper.load_data(spec) uc_plg = specviz_helper.plugins['Unit Conversion'] diff --git a/jdaviz/configs/specviz/plugins/viewers.py b/jdaviz/configs/specviz/plugins/viewers.py index baf6372f06..6dd221cc29 100644 --- a/jdaviz/configs/specviz/plugins/viewers.py +++ b/jdaviz/configs/specviz/plugins/viewers.py @@ -3,7 +3,7 @@ import numpy as np from astropy import table from matplotlib.colors import cnames -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz.core.events import SpectralMarksChangedMessage, LineIdentifyMessage from jdaviz.core.registries import viewer_registry @@ -27,7 +27,7 @@ class SpecvizProfileView(JdavizProfileView): ['jdaviz:sidebar_plot', 'jdaviz:sidebar_export'] ] - default_class = Spectrum1D + default_class = Spectrum spectral_lines = None _state_cls = FreezableProfileViewerState _default_profile_subset_type = 'spectral' diff --git a/jdaviz/configs/specviz/tests/test_helper.py b/jdaviz/configs/specviz/tests/test_helper.py index 927046d8a5..376bab35a0 100644 --- a/jdaviz/configs/specviz/tests/test_helper.py +++ b/jdaviz/configs/specviz/tests/test_helper.py @@ -5,7 +5,7 @@ from astropy import units as u from astropy.io import fits from astropy.tests.helper import assert_quantity_allclose -from specutils import Spectrum1D, SpectrumList, SpectrumCollection, SpectralRegion +from specutils import Spectrum, SpectrumList, SpectrumCollection, SpectralRegion from astropy.utils.data import download_file from jdaviz.app import Application @@ -33,7 +33,7 @@ def test_load_spectrum1d(self): data = self.spec_app.get_data() - assert isinstance(data, Spectrum1D) + assert isinstance(data, Spectrum) def test_load_hdulist(self): # Create a fake fits file with a 1D spectrum for testing. @@ -52,8 +52,8 @@ def test_load_hdulist(self): self.label = "Test 1D Spectrum" self.spec_app.load_data(fake_hdulist) data = self.spec_app.get_data(data_label=self.label) - # HDUList should load as Spectrum1D - assert isinstance(data, Spectrum1D) + # HDUList should load as Spectrum + assert isinstance(data, Spectrum) def test_load_spectrum_list_no_labels(self): # now load three more spectra from a SpectrumList, without labels @@ -410,15 +410,15 @@ def test_load_spectrum_list_directory_concat(tmpdir, specviz_helper): def test_load_2d_flux(specviz_helper): # Test loading a spectrum with a 2D flux, which should be split into separate # 1D Spectrum1D objects to load in Specviz. - spec = Spectrum1D(spectral_axis=np.linspace(4000, 6000, 10)*u.Angstrom, - flux=np.ones((4, 10))*u.Unit("1e-17 erg / (Angstrom cm2 s)")) + spec = Spectrum(spectral_axis=np.linspace(4000, 6000, 10)*u.Angstrom, + flux=np.ones((4, 10))*u.Unit("1e-17 erg / (Angstrom cm2 s)")) specviz_helper.load_data(spec, data_label="test") assert len(specviz_helper.app.data_collection) == 4 assert specviz_helper.app.data_collection[0].label == "test [0]" - spec2 = Spectrum1D(spectral_axis=np.linspace(4000, 6000, 10)*u.Angstrom, - flux=np.ones((2, 10))*u.Unit("1e-17 erg / (Angstrom cm2 s)")) + spec2 = Spectrum(spectral_axis=np.linspace(4000, 6000, 10)*u.Angstrom, + flux=np.ones((2, 10))*u.Unit("1e-17 erg / (Angstrom cm2 s)")) # Make sure 2D spectra in a SpectrumList also get split properly. spec_list = SpectrumList([spec, spec2]) @@ -472,11 +472,11 @@ def test_spectra_partial_overlap(specviz_helper): wave_1 = np.linspace(6000, 7000, 10) * u.AA flux_1 = ([1200] * wave_1.size) * u.nJy - sp_1 = Spectrum1D(flux=flux_1, spectral_axis=wave_1) + sp_1 = Spectrum(flux=flux_1, spectral_axis=wave_1) wave_2 = wave_1 + (800 * u.AA) flux_2 = ([60] * wave_2.size) * u.nJy - sp_2 = Spectrum1D(flux=flux_2, spectral_axis=wave_2) + sp_2 = Spectrum(flux=flux_2, spectral_axis=wave_2) specviz_helper.load_data(sp_1, data_label='left') specviz_helper.load_data(sp_2, data_label='right') @@ -495,10 +495,10 @@ def test_spectra_partial_overlap(specviz_helper): def test_spectra_incompatible_flux(specviz_helper): """https://github.com/spacetelescope/jdaviz/issues/2459""" wav = [1.1, 1.2, 1.3] * u.um - sp1 = Spectrum1D(flux=[1, 1.1, 1] * (u.MJy / u.sr), spectral_axis=wav) - sp2 = Spectrum1D(flux=[1, 1, 1.1] * (u.MJy), spectral_axis=wav) + sp1 = Spectrum(flux=[1, 1.1, 1] * (u.MJy / u.sr), spectral_axis=wav) + sp2 = Spectrum(flux=[1, 1, 1.1] * (u.MJy), spectral_axis=wav) flux3 = ([1, 1.1, 1] * u.MJy).to(u.erg / u.s / u.cm / u.cm / u.AA, u.spectral_density(wav)) - sp3 = Spectrum1D(flux=flux3, spectral_axis=wav) + sp3 = Spectrum(flux=flux3, spectral_axis=wav) specviz_helper.load_data(sp2, data_label="2") # OK specviz_helper.load_data(sp1, data_label="1") # Not OK diff --git a/jdaviz/configs/specviz/tests/test_viewers.py b/jdaviz/configs/specviz/tests/test_viewers.py index 28981fbaea..2a4228298a 100644 --- a/jdaviz/configs/specviz/tests/test_viewers.py +++ b/jdaviz/configs/specviz/tests/test_viewers.py @@ -2,7 +2,7 @@ import numpy as np import pytest import warnings -from specutils import Spectrum1D +from specutils import Spectrum @pytest.mark.parametrize( @@ -18,7 +18,7 @@ def test_spectrum_viewer_axis_labels(specviz_helper, input_unit, y_axis_label): flux = np.arange(1, 10) * input_unit spectral_axis = np.arange(1, 10) * u.um - spec = Spectrum1D(flux, spectral_axis) + spec = Spectrum(flux, spectral_axis) with warnings.catch_warnings(): warnings.filterwarnings("ignore", message=".*contains multiple slashes, which is discouraged by the FITS standard.*") # noqa diff --git a/jdaviz/configs/specviz2d/helper.py b/jdaviz/configs/specviz2d/helper.py index 87522333cb..8959acd700 100644 --- a/jdaviz/configs/specviz2d/helper.py +++ b/jdaviz/configs/specviz2d/helper.py @@ -38,12 +38,12 @@ def load_data(self, spectrum_2d=None, spectrum_1d=None, spectrum_1d_label=None, ---------- spectrum_2d: str A spectrum as translatable container objects (e.g., - ``Spectrum1D``) that can be read by glue-jupyter. Alternatively, + ``Spectrum``) that can be read by glue-jupyter. Alternatively, can be a string file path. - spectrum_1d: str or Spectrum1D + spectrum_1d: str or Spectrum A spectrum as translatable container objects (e.g., - ``Spectrum1D``) that can be read by glue-jupyter. Alternatively, + ``Spectrum``) that can be read by glue-jupyter. Alternatively, can be a string file path. spectrum_1d_label : str @@ -182,7 +182,7 @@ def get_data(self, data_label=None, spectral_subset=None, cls=None): Provide a label to retrieve a specific data set from data_collection. spectral_subset : str, optional Spectral subset applied to data. - cls : `~specutils.Spectrum1D`, `~astropy.nddata.CCDData`, optional + cls : `~specutils.Spectrum`, `~astropy.nddata.CCDData`, optional The type that data will be returned as. Returns diff --git a/jdaviz/configs/specviz2d/plugins/parsers.py b/jdaviz/configs/specviz2d/plugins/parsers.py index 199e0fd622..662671d4eb 100644 --- a/jdaviz/configs/specviz2d/plugins/parsers.py +++ b/jdaviz/configs/specviz2d/plugins/parsers.py @@ -1,6 +1,6 @@ from pathlib import Path -from specutils import Spectrum1D +from specutils import Spectrum from astropy.io import fits import astropy.units as u import numpy as np @@ -62,7 +62,7 @@ def spec2d_1d_parser(app, data_obj, data_label=None, show_in_viewer=True): metadata = standardize_metadata(header) metadata[PRIHDR_KEY] = standardize_metadata(prihdr) - data_obj = Spectrum1D(flux, spectral_axis=spectral_axis, meta=metadata) + data_obj = Spectrum(flux, spectral_axis=spectral_axis, meta=metadata) data_label = app.return_data_label(data_label, alt_name="specviz2d_data") app.data_collection[data_label] = data_obj diff --git a/jdaviz/configs/specviz2d/plugins/spectral_extraction/tests/test_spectral_extraction.py b/jdaviz/configs/specviz2d/plugins/spectral_extraction/tests/test_spectral_extraction.py index 5f4cecd774..211ecf937a 100644 --- a/jdaviz/configs/specviz2d/plugins/spectral_extraction/tests/test_spectral_extraction.py +++ b/jdaviz/configs/specviz2d/plugins/spectral_extraction/tests/test_spectral_extraction.py @@ -8,7 +8,7 @@ import numpy as np from packaging.version import Version from specreduce import tracing, background, extract -from specutils import Spectrum1D +from specutils import Spectrum GWCS_LT_0_18_1 = Version(gwcs.__version__) < Version('0.18.1') @@ -109,11 +109,11 @@ def test_plugin(specviz2d_helper): pext.import_bg(bg) assert pext.bg_width == 4 bg_img = pext.export_bg_img() - assert isinstance(bg_img, Spectrum1D) + assert isinstance(bg_img, Spectrum) bg_spec = pext.export_bg_spectrum() - assert isinstance(bg_spec, Spectrum1D) + assert isinstance(bg_spec, Spectrum) bg_sub = pext.export_bg_sub() - assert isinstance(bg_sub, Spectrum1D) + assert isinstance(bg_sub, Spectrum) # interact with extraction section, check marks pext.ext_width = 1 @@ -131,11 +131,11 @@ def test_plugin(specviz2d_helper): pext.import_extract(ext) assert pext.ext_width == 2 sp_ext = pext.export_extract_spectrum() - assert isinstance(sp_ext, Spectrum1D) + assert isinstance(sp_ext, Spectrum) pext.ext_type_selected = 'Horne' sp_ext = pext.export_extract_spectrum() - assert isinstance(sp_ext, Spectrum1D) + assert isinstance(sp_ext, Spectrum) # test API calls for step in ['trace', 'bg', 'ext']: @@ -207,9 +207,9 @@ def test_horne_extract_self_profile(specviz2d_helper): spec2d[:, ii] = gaus wave = np.arange(0, spec2d.shape[1], 1) - objectspec = Spectrum1D(spectral_axis=wave*u.m, - flux=spec2d*u.Jy, - uncertainty=VarianceUncertainty(spec2dvar*u.Jy*u.Jy)) + objectspec = Spectrum(spectral_axis=wave*u.m, + flux=spec2d*u.Jy, + uncertainty=VarianceUncertainty(spec2dvar*u.Jy*u.Jy)) specviz2d_helper.load_data(objectspec) pext = specviz2d_helper.app.get_tray_item_from_name('spectral-extraction') diff --git a/jdaviz/configs/specviz2d/tests/test_helper.py b/jdaviz/configs/specviz2d/tests/test_helper.py index a6eb3a203b..d03ff48cf3 100644 --- a/jdaviz/configs/specviz2d/tests/test_helper.py +++ b/jdaviz/configs/specviz2d/tests/test_helper.py @@ -1,4 +1,4 @@ -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz import Specviz @@ -10,7 +10,7 @@ def test_helper(specviz2d_helper, mos_spectrum2d): returned_data = specviz2d_helper.get_data("Spectrum 2D") assert len(returned_data.shape) == 1 - assert isinstance(returned_data, Spectrum1D) + assert isinstance(returned_data, Spectrum) def test_plugin_user_apis(specviz2d_helper): diff --git a/jdaviz/conftest.py b/jdaviz/conftest.py index 748a519905..aefd05b706 100644 --- a/jdaviz/conftest.py +++ b/jdaviz/conftest.py @@ -12,7 +12,7 @@ from astropy.io import fits from astropy.nddata import CCDData, StdDevUncertainty from astropy.wcs import WCS -from specutils import Spectrum1D, SpectrumCollection, SpectrumList +from specutils import Spectrum, SpectrumCollection, SpectrumList from jdaviz import __version__, Cubeviz, Imviz, Mosviz, Specviz, Specviz2d, Rampviz from jdaviz.configs.imviz.tests.utils import create_wfi_image_model @@ -208,7 +208,7 @@ def _create_spectrum1d_with_spectral_unit(spectralunit=u.AA): meta = dict(header=dict(FILENAME="jdaviz-test-file.fits")) - return Spectrum1D(spectral_axis=spec_axis, flux=flux, uncertainty=uncertainty, meta=meta) + return Spectrum(spectral_axis=spec_axis, flux=flux, uncertainty=uncertainty, meta=meta) @pytest.fixture @@ -244,8 +244,8 @@ def multi_order_spectrum_list(spectrum1d, spectral_orders=10): spec_axis.value / 500) * u.Jy uncertainty = StdDevUncertainty(np.abs(np.random.randn(len(spec_axis.value))) * u.Jy) meta = dict(header=dict(FILENAME="jdaviz-test-multi-order-file.fits")) - spectrum1d = Spectrum1D(spectral_axis=spec_axis, flux=flux, - uncertainty=uncertainty, meta=meta) + spectrum1d = Spectrum(spectral_axis=spec_axis, flux=flux, + uncertainty=uncertainty, meta=meta) sc.append(spectrum1d) @@ -265,12 +265,12 @@ def _create_spectrum1d_cube_with_fluxunit(fluxunit=u.Jy, shape=(2, 2, 4), with_u if with_uncerts: uncert = StdDevUncertainty(np.abs(np.random.normal(flux) * fluxunit)) - return Spectrum1D(flux=flux, - uncertainty=uncert, - wcs=w, - meta=wcs_dict) + return Spectrum(flux=flux, + uncertainty=uncert, + wcs=w, + meta=wcs_dict) else: - return Spectrum1D(flux=flux, wcs=w, meta=wcs_dict) + return Spectrum(flux=flux, wcs=w, meta=wcs_dict) @pytest.fixture @@ -297,7 +297,7 @@ def spectrum1d_cube_largest(): w = WCS(wcs_dict) flux = np.zeros((20, 30, 3001), dtype=np.float32) # nx=20 ny=30 nz=3001 flux[1:11, 5:15, :] = 1 # Bright corner - return Spectrum1D(flux=flux * u.Jy, wcs=w, meta=wcs_dict) + return Spectrum(flux=flux * u.Jy, wcs=w, meta=wcs_dict) @pytest.fixture @@ -335,19 +335,19 @@ def mos_spectrum1d(mos_spectrum2d): 10*np.exp(-0.001*(spec_axis.value-6563)**2) + spec_axis.value/500) * u.Jy - return Spectrum1D(spectral_axis=spec_axis, flux=flux) + return Spectrum(spectral_axis=spec_axis, flux=flux) @pytest.fixture def spectrum2d(): ''' - A simple 2D Spectrum1D with a center "trace" array rising from 0 to 10 + A simple 2D Spectrum with a center "trace" array rising from 0 to 10 with two "zero array" buffers above and below ''' data = np.zeros((5, 10)) data[3] = np.arange(10) - return Spectrum1D(flux=data*u.MJy, spectral_axis=data[3]*u.um) + return Spectrum(flux=data*u.MJy, spectral_axis=data[3]*u.um) def _generate_mos_spectrum2d(): @@ -367,15 +367,15 @@ def _generate_mos_spectrum2d(): @pytest.fixture def mos_spectrum2d(): ''' - A specially defined 2D (spatial) Spectrum1D whose wavelength range matches the + A specially defined 2D (spatial) Spectrum 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 + TODO: This should be reformed to match the global Spectrum 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) + return Spectrum(data, wcs=wcs, meta=header) @pytest.fixture diff --git a/jdaviz/core/data_formats.py b/jdaviz/core/data_formats.py index 32f464f704..7da07906a6 100644 --- a/jdaviz/core/data_formats.py +++ b/jdaviz/core/data_formats.py @@ -7,7 +7,7 @@ from astropy.wcs import WCS from specutils.io.registers import identify_spectrum_format -from specutils import Spectrum1D, SpectrumList, SpectrumCollection +from specutils import Spectrum, SpectrumList, SpectrumCollection from stdatamodels import asdf_in_fits from jdaviz.core.config import list_configurations @@ -27,7 +27,7 @@ # get formats table for specutils objects formats_table = astropy.io.registry.get_formats(readwrite='Read') formats_table.add_index('Data class') -formats_table = formats_table.loc[['Spectrum1D', 'SpectrumList']] +formats_table = formats_table.loc[['Spectrum', 'SpectrumList']] formats_table.sort(['Data class', 'Format']) file_to_config_mapping = {i: default_mapping.get( @@ -161,7 +161,7 @@ def identify_helper(filename, ext=1): The HDUList of the file opened to identify the helper """ supported_dtypes = [ - Spectrum1D, + Spectrum, SpectrumList, SpectrumCollection, CCDData @@ -238,7 +238,7 @@ def identify_helper(filename, ext=1): return (['specviz'], hdul) # If the data could be spectral: - for cls in [Spectrum1D, SpectrumList]: + for cls in [Spectrum, SpectrumList]: if cls in possible_formats.keys(): recognized_spectrum_format = possible_formats[cls][0].lower() diff --git a/jdaviz/core/helpers.py b/jdaviz/core/helpers.py index 44242d1a01..7ee62a0cf1 100644 --- a/jdaviz/core/helpers.py +++ b/jdaviz/core/helpers.py @@ -23,7 +23,7 @@ import astropy.units as u from astropy.utils.decorators import deprecated from regions.core.core import Region -from specutils import Spectrum1D, SpectralRegion +from specutils import Spectrum, SpectralRegion from jdaviz.app import Application from jdaviz.core.events import SnackbarMessage, ExitBatchLoadMessage, SliceSelectSliceMessage @@ -470,7 +470,7 @@ def toggle_api_hints(self, enabled=None): def _handle_display_units(self, data, use_display_units=True): if use_display_units: - if isinstance(data, Spectrum1D): + if isinstance(data, Spectrum): spectral_unit = self.app._get_display_unit('spectral') if not spectral_unit: return data @@ -510,10 +510,11 @@ def _handle_display_units(self, data, use_display_units=True): spectral_unit) * u.Unit(spectral_unit)) - data = Spectrum1D(spectral_axis=new_spec, - flux=new_y, - uncertainty=new_uncert, - mask=data.mask) + data = Spectrum(spectral_axis=new_spec, + flux=new_y, + uncertainty=new_uncert, + mask=data.mask, + spectral_axis_index=data.meta['spectral_axis_index']) else: # pragma: nocover raise NotImplementedError(f"converting {data.__class__.__name__} to display units is not supported") # noqa return data @@ -558,7 +559,7 @@ def _get_data(self, data_label=None, spatial_subset=None, spectral_subset=None, if 'Trace' in data.meta: cls = None elif data.ndim == 2 and self.app.config == "specviz2d": - cls = Spectrum1D + cls = Spectrum elif data.ndim == 2: cls = CCDData elif data.ndim in [1, 3]: @@ -566,10 +567,10 @@ def _get_data(self, data_label=None, spatial_subset=None, spectral_subset=None, cls = NDDataArray else: # for cubeviz, specviz, mosviz, this must be a spectrum: - cls = Spectrum1D + cls = Spectrum object_kwargs = {} - if cls == Spectrum1D: + if cls == Spectrum: object_kwargs['statistic'] = None if not spatial_subset and not mask_subset: @@ -643,7 +644,7 @@ def get_data(self, data_label=None, cls=None, use_display_units=False, **kwargs) ---------- data_label : str, optional Provide a label to retrieve a specific data set from data_collection. - cls : `~specutils.Spectrum1D`, `~astropy.nddata.CCDData`, optional + cls : `~specutils.Spectrum`, `~astropy.nddata.CCDData`, optional The type that data will be returned as. use_display_units : bool, optional Whether to convert to the display units defined in the plugin. diff --git a/jdaviz/core/launcher.py b/jdaviz/core/launcher.py index c59f079488..2d1c672984 100644 --- a/jdaviz/core/launcher.py +++ b/jdaviz/core/launcher.py @@ -71,7 +71,7 @@ def _launch_config_with_data(config, data=None, show=True, filepath=None, **kwar config : str (path-like) Name for a local data file. data : str or any Jdaviz-compatible data - A filepath or Jdaviz-compatible data object (such as Spectrum1D or CCDData) + A filepath or Jdaviz-compatible data object (such as Spectrum or CCDData) show : bool Determines whether to immediately show the application filepath : str diff --git a/jdaviz/core/marks.py b/jdaviz/core/marks.py index 870da67412..d8c39d19f1 100644 --- a/jdaviz/core/marks.py +++ b/jdaviz/core/marks.py @@ -4,7 +4,7 @@ from bqplot import LinearScale from bqplot.marks import Lines, Label, Scatter from glue.core import HubListener -from specutils import Spectrum1D +from specutils import Spectrum from jdaviz.core.events import GlobalDisplayUnitChanged from jdaviz.core.events import (SliceToolStateMessage, LineIdentifyMessage, @@ -130,9 +130,9 @@ def set_y_unit(self, unit=None): unit = u.Unit(unit) if self.yunit is not None and not np.all([s == 0 for s in self.y.shape]): - if self.viewer.default_class is Spectrum1D: + if self.viewer.default_class is Spectrum: - spec = self.viewer.state.reference_data.get_object(cls=Spectrum1D) + spec = self.viewer.state.reference_data.get_object(cls=Spectrum) pixar_sr = spec.meta.get('PIXAR_SR', 1) cube_wave = self.x * self.xunit @@ -184,7 +184,7 @@ def _update_reference_data(self, reference_data): if reference_data is None or self.viewer.jdaviz_app.config == 'rampviz': return - self._update_unit(reference_data.get_object(cls=Spectrum1D).spectral_axis.unit) + self._update_unit(reference_data.get_object(cls=Spectrum).spectral_axis.unit) def _update_unit(self, new_unit): # the x-units may have changed. We want to convert the internal self.x diff --git a/jdaviz/core/template_mixin.py b/jdaviz/core/template_mixin.py index a678570a95..7d5406ff1f 100644 --- a/jdaviz/core/template_mixin.py +++ b/jdaviz/core/template_mixin.py @@ -32,7 +32,7 @@ from glue_jupyter.widgets.linked_dropdown import get_choices as _get_glue_choices from photutils.aperture import CircularAperture, EllipticalAperture, RectangularAperture from regions import PixelRegion -from specutils import Spectrum1D +from specutils import Spectrum from specutils.manipulation import extract_region from traitlets import Any, Bool, Dict, Float, HasTraits, List, Unicode, observe @@ -2216,8 +2216,8 @@ def selected_min_max(self, dataset): """ if self.is_multiselect: # pragma: no cover raise TypeError("This action cannot be done when multiselect is active") - if not isinstance(dataset, Spectrum1D): # pragma: no cover - raise TypeError("dataset must be a Spectrum1D object") + if not isinstance(dataset, Spectrum): # pragma: no cover + raise TypeError("dataset must be a Spectrum object") if self.selected_obj is None: return np.nanmin(dataset.spectral_axis), np.nanmax(dataset.spectral_axis) @@ -3135,6 +3135,7 @@ def _get_continuum(self, dataset, spectral_subset, update_marks=False, per_pixel return None, None, None spectral_axis = full_spectrum.spectral_axis + spectral_axis_index = full_spectrum.spectral_axis_index if spectral_axis.unit == u.pix: # plugin should be disabled so not get this far, but can still get here # before the disabled message is set @@ -3239,18 +3240,19 @@ def _get_continuum(self, dataset, spectral_subset, update_marks=False, per_pixel min_x = min(spectral_axis.value) if per_pixel: # full_spectrum.flux is a cube, so we want to act on all spaxels independently - continuum_y = full_spectrum.flux[:, :, continuum_mask].value + continuum_y = np.take(full_spectrum.flux, continuum_mask, axis=spectral_axis_index).value # noqa def fit_continuum(continuum_y_spaxel): return np.polyfit(continuum_x-min_x, continuum_y_spaxel, deg=1) # compute the linear fit for each spaxel independently, along the spectral axis - slopes_intercepts = np.apply_along_axis(fit_continuum, 2, continuum_y) - slopes = slopes_intercepts[:, :, 0] - intercepts = slopes_intercepts[:, :, 1] + slopes_intercepts = np.apply_along_axis(fit_continuum, spectral_axis_index, continuum_y) + slopes = np.take(slopes_intercepts, 0, spectral_axis_index) + intercepts = np.take(slopes_intercepts, 1, spectral_axis_index) # spectrum.spectral_axis is an array, but we need our continuum to have the same # shape as the fluxes in the cube, so let's just duplicate to the correct shape + print(spectrum.flux.shape) spectral_axis_cube = np.zeros(spectrum.flux.shape) spectral_axis_cube[:, :] = spectrum.spectral_axis.value @@ -3570,7 +3572,7 @@ def default_data_cls(self): return NDData if 'is_trace' in self.filters: return None - return Spectrum1D + return Spectrum def _get_dc_item(self, selected): if selected not in self.labels: diff --git a/jdaviz/tests/test_subsets.py b/jdaviz/tests/test_subsets.py index b00dd5f6be..d25808133d 100644 --- a/jdaviz/tests/test_subsets.py +++ b/jdaviz/tests/test_subsets.py @@ -8,7 +8,7 @@ from regions import (PixCoord, CirclePixelRegion, CircleSkyRegion, RectanglePixelRegion, EllipsePixelRegion, CircleAnnulusPixelRegion) from numpy.testing import assert_allclose -from specutils import SpectralRegion, Spectrum1D +from specutils import SpectralRegion, Spectrum from astropy.nddata import NDData from jdaviz.utils import get_subset_type, MultiMaskSubsetState @@ -156,7 +156,7 @@ def test_region_from_subset_3d(cubeviz_helper): def test_region_from_subset_profile(cubeviz_helper, spectral_cube_wcs): - data = Spectrum1D(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) + data = Spectrum(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj cubeviz_helper.load_data(data, data_label='Test 1D Flux') @@ -205,7 +205,7 @@ def test_region_from_subset_profile(cubeviz_helper, spectral_cube_wcs): def test_disjoint_spectral_subset(cubeviz_helper, spectral_cube_wcs): subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj - data = Spectrum1D(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) + data = Spectrum(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) cubeviz_helper.load_data(data, data_label="Test Flux") spectral_axis_unit = u.Unit(cubeviz_helper.plugins['Unit Conversion'].spectral_unit.selected) @@ -791,7 +791,7 @@ def test_delete_subsets(cubeviz_helper, spectral_cube_wcs): """ Test that the toolbar selections get reset when the subset being actively edited gets deleted. """ - data = Spectrum1D(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) + data = Spectrum(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) cubeviz_helper.load_data(data, data_label="Test Flux") dc = cubeviz_helper.app.data_collection @@ -821,7 +821,7 @@ class TestRegionsFromSubsets: def test_get_regions_from_subsets_cubeviz(self, cubeviz_helper, spectral_cube_wcs): """ Basic tests for retrieving Sky Regions from spatial subsets in Cubeviz. """ - data = Spectrum1D(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) + data = Spectrum(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) cubeviz_helper.load_data(data) # basic test, a single circular region diff --git a/notebooks/MosvizExample.ipynb b/notebooks/MosvizExample.ipynb index 2b667033e8..a033fdb97b 100644 --- a/notebooks/MosvizExample.ipynb +++ b/notebooks/MosvizExample.ipynb @@ -53,7 +53,7 @@ "source": [ "But before we can use it, we need some data.\n", "\n", - "The Mosviz parsers accept lists of `Spectrum1D` and `CCDData` for 1D, 2D, and image data, respectively. Alternatively, users can also provide lists of file paths and Mosviz will internally attempt to parse them as their respective data types." + "The Mosviz parsers accept lists of `Spectrum` and `CCDData` for 1D, 2D, and image data, respectively. Alternatively, users can also provide lists of file paths and Mosviz will internally attempt to parse them as their respective data types." ] }, { @@ -96,7 +96,7 @@ "fn = download_file(example_data, cache=True)\n", "with ZipFile(fn, 'r') as sample_data_zip:\n", " sample_data_zip.extractall(data_dir)\n", - " \n", + "\n", "data_dir = (pathlib.Path(data_dir) / 'mosviz_nirspec_data_0.3' / 'level3')" ] }, diff --git a/pyproject.toml b/pyproject.toml index 87cffe5ede..5951a3ae37 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ dependencies = [ "ipywidgets>=8.0.6", "solara>=1.40.0", "pyyaml>=5.4.1", - "specutils>=1.18", + "specutils>=2.0", "specreduce>=1.4.1", "photutils>=1.4", "glue-astronomy>=0.10",