diff --git a/CHANGES.rst b/CHANGES.rst index d26aac50df..433168bdce 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -114,6 +114,8 @@ Specviz Specviz2d ^^^^^^^^^ +- Fix subset linking/displaying between pixel/wavelength in Specviz2d viewers. [#2736] + 4.1.1 (2025-01-31) ================== @@ -747,6 +749,8 @@ Specviz display label for the y axis in spectral viewer. Previously it was hard coded to always display ``flux density`` no matter the input unit. [#2703] +Specviz2d +^^^^^^^^^ 3.8.2 (2024-02-23) ================== diff --git a/jdaviz/app.py b/jdaviz/app.py index 93d44aa55c..184e44ef28 100644 --- a/jdaviz/app.py +++ b/jdaviz/app.py @@ -766,8 +766,22 @@ def _link_new_data(self, reference_data=None, data_to_be_linked=None): linked_data.ndim < 3 and # Cube linking requires special logic. See below ref_data.ndim < 3) ): - links = [LinkSame(linked_data.components[0], ref_data.components[0]), - LinkSame(linked_data.components[1], ref_data.components[1])] + if self.config == 'specviz2d': + links = [] + if linked_data.ndim == 2: + # extracted image added to data collection + ref_wavelength_component = ref_data.components[1] + else: + # extracted spectrum added to data collection + ref_wavelength_component = ref_data.components[3] + links += [LinkSameWithUnits(linked_data.components[0], ref_data.components[1])] + + links += [LinkSameWithUnits(linked_data.components[0], ref_data.components[0]), + LinkSameWithUnits(linked_data.components[1], ref_wavelength_component)] + else: + links = [LinkSame(linked_data.components[0], ref_data.components[0]), + LinkSame(linked_data.components[1], ref_data.components[1])] + dc.add_link(links) return diff --git a/jdaviz/tests/test_subsets.py b/jdaviz/tests/test_subsets.py index b00dd5f6be..0492214b8b 100644 --- a/jdaviz/tests/test_subsets.py +++ b/jdaviz/tests/test_subsets.py @@ -1,9 +1,11 @@ import numpy as np import pytest from astropy import units as u +from astropy.wcs import WCS from astropy.tests.helper import assert_quantity_allclose from astropy.utils.data import get_pkg_data_filename -from glue.core.roi import CircularROI, CircularAnnulusROI, EllipticalROI, RectangularROI +from glue.core.roi import CircularROI, CircularAnnulusROI, EllipticalROI, RectangularROI, XRangeROI + from glue.core.subset_group import GroupedSubset from regions import (PixCoord, CirclePixelRegion, CircleSkyRegion, RectanglePixelRegion, EllipsePixelRegion, CircleAnnulusPixelRegion) @@ -740,6 +742,104 @@ def test_only_overlapping_in_specviz2d(specviz2d_helper, mos_spectrum2d): assert reg[1].lower.value == 7600 and reg[1].upper.value == 7800 +def test_draw2d_linking_specviz2d(specviz2d_helper): + # custom test data to predict values for different viewers + header = { + 'WCSAXES': 2, + 'CRPIX1': 0.0, 'CRPIX2': 8.5, + 'CDELT1': 1E-06, 'CDELT2': 7.5E-05, + 'CUNIT1': 'm', 'CUNIT2': 'deg', + 'CTYPE1': 'WAVE', 'CTYPE2': 'OFFSET', + 'CRVAL1': 0.0, 'CRVAL2': 5.0, + 'RADESYS': 'ICRS', 'SPECSYS': 'BARYCENT'} + wcs = WCS(header) + + x_values = np.linspace(0, 10, 128) + y_values = np.linspace(0, 5, 256) + + # Create a continuous 2D + data = np.sin(x_values[:, np.newaxis]) * np.cos(y_values) * u.one + spectrum_data = Spectrum1D(data, wcs=wcs, meta=header) + + specviz2d_helper.load_data(spectrum_2d=spectrum_data) + viewer_1d = specviz2d_helper.app.get_viewer( + specviz2d_helper._default_spectrum_viewer_reference_name) + viewer_2d = specviz2d_helper.app.get_viewer( + specviz2d_helper._default_spectrum_2d_viewer_reference_name) + + # create subset in 2d viewer, want data in 1d viewer + viewer_2d.apply_roi(XRangeROI(60, 80)) + subset_drawn_2d = viewer_1d.native_marks[-1] + + # get x and y components to compute subset mask + y1 = subset_drawn_2d.y + x1 = subset_drawn_2d.x + + subset_highlighted_region1 = x1[np.isfinite(y1)] + min_value_subset1 = np.min(subset_highlighted_region1) + max_value_subset1 = np.max(subset_highlighted_region1) + + tolerance1 = 1e-6 + expected_min1 = 6.e-5 + expected_max1 = 8.e-05 + + assert np.allclose(min_value_subset1, expected_min1, atol=tolerance1) + assert np.allclose(max_value_subset1, expected_max1, atol=tolerance1) + + +''' +def test_draw1d_linking_specviz2d(specviz2d_helper): + # custom test data to predict values for different viewers + header = { + 'WCSAXES': 2, + + 'CRPIX1': 0.0, 'CRPIX2': 8.5, + 'CDELT1': 1E-06, 'CDELT2': 7.5E-05, + 'CUNIT1': 'm', 'CUNIT2': 'deg', + 'CTYPE1': 'WAVE', 'CTYPE2': 'OFFSET', + 'CRVAL1': 0.0, 'CRVAL2': 5.0, + 'RADESYS': 'ICRS', 'SPECSYS': 'BARYCENT'} + wcs = WCS(header) + + x_values = np.linspace(0, 10, 128) + y_values = np.linspace(0, 5, 256) + + # Create a continuous 2D image + data = np.sin(x_values[:, np.newaxis]) * np.cos(y_values) * u.Jy + spectrum_data = Spectrum1D(data, wcs=wcs, meta=header) + + specviz2d_helper.load_data(spectrum_2d=spectrum_data) + se = specviz2d_helper.plugins['Spectral Extraction'] + se.export_extract() + + viewer_1d = specviz2d_helper.app.get_viewer( + specviz2d_helper._default_spectrum_viewer_reference_name) + viewer_2d = specviz2d_helper.app.get_viewer( + specviz2d_helper._default_spectrum_2d_viewer_reference_name) + + # subset drawn in 1d viewer, want data in 2d viewer + spec_reg = SpectralRegion(0. * u.m, 10000000 * u.m) + spec_reg = SpectralRegion(0.0001 * u.m, .0002 * u.m) + st = specviz2d_helper.plugins['Subset Tools'] + st.import_region(spec_reg) + + subset_drawn_1d = viewer_2d.native_marks[-1] + + subset_highlighted_region2 = np.atleast_1d(np.nonzero(subset_drawn_1d))[1] + + # Get the start and stop indices + min_value_subset2 = np.min(subset_highlighted_region2) + max_value_subset2 = np.max(subset_highlighted_region2) + + tolerance2 = 2 + expected_min2 = 209 + expected_max2 = 300 + + assert np.allclose(min_value_subset2, expected_min2, atol=tolerance2) + assert np.allclose(max_value_subset2, expected_max2, atol=tolerance2) +''' + + def test_multi_mask_subset(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) subset_plugin = specviz_helper.plugins['Subset Tools']._obj