From d6745a58dda4fc6f42ada9fd4dd3d45a5177b2e5 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 18 Oct 2024 09:04:10 -0400 Subject: [PATCH 01/16] Add ability to load 2D flux arrays in Specviz by splitting into separate spectra --- jdaviz/configs/specviz/plugins/parsers.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 51fbfc1ee6..1947b0370f 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -56,8 +56,24 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v raise TypeError("SpectrumCollection detected." " Please provide a Spectrum1D or SpectrumList") elif isinstance(data, Spectrum1D): - data_label = [app.return_data_label(data_label, alt_name="specviz_data")] - data = [data] + # Handle the possibility of 2D spectra by splitting into separate spectra + if data.flux.ndim == 1: + data_label = [app.return_data_label(data_label, alt_name="specviz_data")] + data = [data] + elif data.flux.ndim == 2: + temp_data = [] + data_label = [] + for i in range(data.flux.shape[0]): + unc = None + mask = None + if data.uncertainty is not None: + unc = data.uncertainty[i, :] + if mask is not None: + mask = data.mask[i, :] + temp_data.append(Spectrum1D(flux=data.flux[i, :], spectral_axis=data.spectral_axis, + uncertainty=unc)) + data_label.append(f'{app.return_data_label(data_label, alt_name="specviz_data")}[{i}]') # noqa + data = temp_data # No special processing is needed in this case, but we include it for completeness elif isinstance(data, SpectrumList): pass From ccc30fac37605723e0b756bd91dbf11789d1055a Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 18 Oct 2024 09:09:47 -0400 Subject: [PATCH 02/16] Changelog --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index 732515e20b..e67d19118e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -15,6 +15,7 @@ Mosviz Specviz ^^^^^^^ +- Specviz parser will now split a spectrum with a 2D flux array into multiple spectra on load. [#3229] Specviz2d ^^^^^^^^^ From 91242019e11a5c9d5c2b9430c4b28841f66ca22d Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 18 Oct 2024 09:40:53 -0400 Subject: [PATCH 03/16] Handle this in file load case --- jdaviz/configs/specviz/plugins/parsers.py | 39 ++++++++++++++--------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 1947b0370f..04a30c68ab 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -61,19 +61,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v data_label = [app.return_data_label(data_label, alt_name="specviz_data")] data = [data] elif data.flux.ndim == 2: - temp_data = [] - data_label = [] - for i in range(data.flux.shape[0]): - unc = None - mask = None - if data.uncertainty is not None: - unc = data.uncertainty[i, :] - if mask is not None: - mask = data.mask[i, :] - temp_data.append(Spectrum1D(flux=data.flux[i, :], spectral_axis=data.spectral_axis, - uncertainty=unc)) - data_label.append(f'{app.return_data_label(data_label, alt_name="specviz_data")}[{i}]') # noqa - data = temp_data + data, data_label = _split_spectrum_with_2D_flux_array(data) # No special processing is needed in this case, but we include it for completeness elif isinstance(data, SpectrumList): pass @@ -95,8 +83,12 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v if path.is_file(): try: - data = [Spectrum1D.read(str(path), format=format)] - data_label = [app.return_data_label(data_label, alt_name="specviz_data")] + data = Spectrum1D.read(str(path), format=format) + if data.flux.ndim == 2: + data, data_label = split_spectrum_with_2D_flux_array(data) + else: + data = [data] + data_label = [app.return_data_label(data_label, alt_name="specviz_data")] except IORegistryError: # Multi-extension files may throw a registry error @@ -262,3 +254,20 @@ def combine_lists_to_1d_spectrum(wl, fnu, dfnu, wave_units, flux_units): spec = Spectrum1D(flux=fnuall * flux_units, spectral_axis=wlall * wave_units, uncertainty=unc) return spec + + +def split_spectrum_with_2D_flux_array(data): + temp_data = [] + data_label = [] + for i in range(data.flux.shape[0]): + unc = None + mask = None + if data.uncertainty is not None: + unc = data.uncertainty[i, :] + if mask is not None: + mask = data.mask[i, :] + temp_data.append(Spectrum1D(flux=data.flux[i, :], spectral_axis=data.spectral_axis, + uncertainty=unc)) + data_label.append(f'{app.return_data_label(data_label, alt_name="specviz_data")}[{i}]') # noqa + + return temp_data, data_label From aa0cb56233e292e6f003d78b6e831f48b087d0c4 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 18 Oct 2024 09:44:17 -0400 Subject: [PATCH 04/16] Fix typo --- jdaviz/configs/specviz/plugins/parsers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 04a30c68ab..ddc665d9b1 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -61,7 +61,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v data_label = [app.return_data_label(data_label, alt_name="specviz_data")] data = [data] elif data.flux.ndim == 2: - data, data_label = _split_spectrum_with_2D_flux_array(data) + data, data_label = split_spectrum_with_2D_flux_array(data) # No special processing is needed in this case, but we include it for completeness elif isinstance(data, SpectrumList): pass From 180467a9fd4c4de6d15ab8ca7771e950b50e5534 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 18 Oct 2024 10:10:25 -0400 Subject: [PATCH 05/16] Add test and debug --- jdaviz/configs/specviz/plugins/parsers.py | 12 ++++++------ jdaviz/configs/specviz/tests/test_helper.py | 9 +++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index ddc665d9b1..165bc19dd1 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -61,7 +61,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v data_label = [app.return_data_label(data_label, alt_name="specviz_data")] data = [data] elif data.flux.ndim == 2: - data, data_label = split_spectrum_with_2D_flux_array(data) + data, data_label = split_spectrum_with_2D_flux_array(data, data_label, app) # No special processing is needed in this case, but we include it for completeness elif isinstance(data, SpectrumList): pass @@ -85,7 +85,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v try: data = Spectrum1D.read(str(path), format=format) if data.flux.ndim == 2: - data, data_label = split_spectrum_with_2D_flux_array(data) + data, data_label = split_spectrum_with_2D_flux_array(data, data_label, app) else: data = [data] data_label = [app.return_data_label(data_label, alt_name="specviz_data")] @@ -256,9 +256,9 @@ def combine_lists_to_1d_spectrum(wl, fnu, dfnu, wave_units, flux_units): return spec -def split_spectrum_with_2D_flux_array(data): +def split_spectrum_with_2D_flux_array(data, data_label, app): temp_data = [] - data_label = [] + temp_data_label = [] for i in range(data.flux.shape[0]): unc = None mask = None @@ -268,6 +268,6 @@ def split_spectrum_with_2D_flux_array(data): mask = data.mask[i, :] temp_data.append(Spectrum1D(flux=data.flux[i, :], spectral_axis=data.spectral_axis, uncertainty=unc)) - data_label.append(f'{app.return_data_label(data_label, alt_name="specviz_data")}[{i}]') # noqa + temp_data_label.append(f'{app.return_data_label(data_label, alt_name="specviz_data")}[{i}]') # noqa - return temp_data, data_label + return temp_data, temp_data_label diff --git a/jdaviz/configs/specviz/tests/test_helper.py b/jdaviz/configs/specviz/tests/test_helper.py index 6ca8c67064..1a3d6b1dc4 100644 --- a/jdaviz/configs/specviz/tests/test_helper.py +++ b/jdaviz/configs/specviz/tests/test_helper.py @@ -405,6 +405,15 @@ def test_load_spectrum_list_directory_concat(tmpdir, specviz_helper): assert len(specviz_helper.app.data_collection) == 41 +def test_load_spectrum1d_2d_flux(specviz_helper): + spec = Spectrum1D(spectral_axis=np.linspace(4000,6000,100)*u.Angstrom, + flux=np.ones((4,100))*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]" + + def test_plot_uncertainties(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) From 620c6ae5b25d5b8aee4314e03f0ab32f4dc380e3 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 18 Oct 2024 10:29:02 -0400 Subject: [PATCH 06/16] Codestyle again, whoops --- jdaviz/configs/specviz/tests/test_helper.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/specviz/tests/test_helper.py b/jdaviz/configs/specviz/tests/test_helper.py index 1a3d6b1dc4..9552fe1315 100644 --- a/jdaviz/configs/specviz/tests/test_helper.py +++ b/jdaviz/configs/specviz/tests/test_helper.py @@ -406,8 +406,8 @@ def test_load_spectrum_list_directory_concat(tmpdir, specviz_helper): def test_load_spectrum1d_2d_flux(specviz_helper): - spec = Spectrum1D(spectral_axis=np.linspace(4000,6000,100)*u.Angstrom, - flux=np.ones((4,100))*u.Unit("1e-17 erg / (Angstrom cm2 s)")) + spec = Spectrum1D(spectral_axis=np.linspace(4000, 6000, 100)*u.Angstrom, + flux=np.ones((4, 100))*u.Unit("1e-17 erg / (Angstrom cm2 s)")) specviz_helper.load_data(spec, data_label="test") assert len(specviz_helper.app.data_collection) == 4 From 4703b9ddeeed1cecf1afa15065cdf65cbfb8f0e9 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 18 Oct 2024 11:53:27 -0400 Subject: [PATCH 07/16] Add keyword to force Specviz parser to use SpectrumList.read --- jdaviz/configs/specviz/plugins/parsers.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 165bc19dd1..10c9b2015b 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -18,7 +18,8 @@ @data_parser_registry("specviz-spectrum1d-parser") def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_viewer=True, - concat_by_file=False, cache=None, local_path=os.curdir, timeout=None): + 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. @@ -46,6 +47,9 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v remote requests in seconds (passed to `~astropy.utils.data.download_file` or `~astroquery.mast.Conf.timeout`). + load_as_list : bool, optional + Force the parser to load the input file with the `~specutils.SpectrumList` read function + instead of `~specutils.Spectrum1D`. """ spectrum_viewer_reference_name = app._jdaviz_helper._default_spectrum_viewer_reference_name @@ -81,7 +85,12 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v path = pathlib.Path(data) - if path.is_file(): + if path.is_dir() or load_as_list: + data = SpectrumList.read(str(path), format=format) + if data == []: + raise ValueError(f"`specutils.SpectrumList.read('{str(path)}')` " + "returned an empty list") + elif path.is_file(): try: data = Spectrum1D.read(str(path), format=format) if data.flux.ndim == 2: @@ -93,11 +102,6 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v except IORegistryError: # Multi-extension files may throw a registry error data = SpectrumList.read(str(path), format=format) - elif path.is_dir(): - data = SpectrumList.read(str(path), format=format) - if data == []: - raise ValueError(f"`specutils.SpectrumList.read('{str(path)}')` " - "returned an empty list") else: raise FileNotFoundError("No such file: " + str(path)) From fd5dc1767dc2ba1ff8b9b36ae466d9788db6d45e Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Fri, 18 Oct 2024 13:49:10 -0400 Subject: [PATCH 08/16] Add new keyword to helper load_data --- jdaviz/configs/specviz/helper.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/specviz/helper.py b/jdaviz/configs/specviz/helper.py index 7eefe9e212..c13ac67175 100644 --- a/jdaviz/configs/specviz/helper.py +++ b/jdaviz/configs/specviz/helper.py @@ -41,7 +41,8 @@ def __init__(self, *args, **kwargs): handler=self._redshift_listener) def load_data(self, data, data_label=None, format=None, show_in_viewer=True, - concat_by_file=False, cache=None, local_path=None, timeout=None): + concat_by_file=False, cache=None, local_path=None, timeout=None, + load_as_list=False): """ Load data into Specviz. @@ -80,7 +81,8 @@ def load_data(self, data, data_label=None, format=None, show_in_viewer=True, concat_by_file=concat_by_file, cache=cache, local_path=local_path, - timeout=timeout) + timeout=timeout, + load_as_list=load_as_list) def get_spectra(self, data_label=None, spectral_subset=None, apply_slider_redshift="Warn"): """Returns the current data loaded into the main viewer From cec0bea021af58559910e3ad78d3da9cde85a9e3 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Tue, 22 Oct 2024 13:12:42 -0400 Subject: [PATCH 09/16] Implement suggestions from @rileythai Co-authored-by: rileythai --- jdaviz/configs/specviz/plugins/parsers.py | 41 +++++++++++++++++------ 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 10c9b2015b..c4e7719946 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -79,9 +79,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v data = SpectrumList.read(data, format=format) else: # try parsing file_obj as a URI/URL: - data = download_uri_to_path( - data, cache=cache, local_path=local_path, timeout=timeout - ) + data = download_uri_to_path(data, cache=cache, local_path=local_path, timeout=timeout) path = pathlib.Path(data) @@ -105,11 +103,21 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v else: raise FileNotFoundError("No such file: " + str(path)) + # step through SpectrumList and convert any 2D spectra to 1D spectra if isinstance(data, SpectrumList): + new_data = SpectrumList() + for spec in data: + if spec.flux.ndim == 2: + temp_data, _ = split_spectrum_with_2D_flux_array(spec) + new_data.extend(temp_data) + else: + new_data.append(spec) + data = new_data + if not isinstance(data_label, (list, tuple)): temp_labels = [] for i in range(len(data)): - temp_labels.append(f"{data_label} {i}") + temp_labels.append(f"{data_label} [{i}]") data_label = temp_labels elif len(data_label) != len(data): raise ValueError(f"Length of data labels list ({len(data_label)}) is different" @@ -261,17 +269,28 @@ def combine_lists_to_1d_spectrum(wl, fnu, dfnu, wave_units, flux_units): def split_spectrum_with_2D_flux_array(data, data_label, app): - temp_data = [] - temp_data_label = [] + """ + Helper function to split Spectrum1D of 2D flux to a SpectrumList of nD objects. + Parameters + ---------- + data : `~specutils.Spectrum1D` + Spectrum with 2D flux array + Returns + ------- + new_data : `~specutils.SpectrumList` + list of unpacked spectra + """ + new_data = [] + new_data_label = [] for i in range(data.flux.shape[0]): unc = None mask = None if data.uncertainty is not None: unc = data.uncertainty[i, :] - if mask is not None: + if data.mask is not None: mask = data.mask[i, :] - temp_data.append(Spectrum1D(flux=data.flux[i, :], spectral_axis=data.spectral_axis, - uncertainty=unc)) - temp_data_label.append(f'{app.return_data_label(data_label, alt_name="specviz_data")}[{i}]') # noqa + new_data.append(Spectrum1D(flux=data.flux[i, :], spectral_axis=data.spectral_axis, + uncertainty=unc, mask=mask)) + new_data_label.append(f'{app.return_data_label(data_label, alt_name="specviz_data")}[{i}]') # noqa - return temp_data, temp_data_label + return new_data, new_data_label From 505674ef6f31671f2f77c7b274d75841a73a7a41 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Tue, 22 Oct 2024 14:01:46 -0400 Subject: [PATCH 10/16] Add more test coverage, debug --- jdaviz/configs/specviz/plugins/parsers.py | 29 +++++++++------------ jdaviz/configs/specviz/tests/test_helper.py | 16 +++++++++--- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index c4e7719946..a8e005d1ec 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -56,16 +56,18 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v # If no data label is assigned, give it a unique name if not data_label: data_label = app.return_data_label(data, alt_name="specviz_data") + if isinstance(data, SpectrumCollection): raise TypeError("SpectrumCollection detected." " Please provide a Spectrum1D or SpectrumList") elif isinstance(data, Spectrum1D): # Handle the possibility of 2D spectra by splitting into separate spectra if data.flux.ndim == 1: - data_label = [app.return_data_label(data_label, alt_name="specviz_data")] + data_label = [data_label] data = [data] elif data.flux.ndim == 2: - data, data_label = split_spectrum_with_2D_flux_array(data, data_label, app) + data = split_spectrum_with_2D_flux_array(data) + data_label = [f"{data_label} [{i}]" for i in range(len(data))] # No special processing is needed in this case, but we include it for completeness elif isinstance(data, SpectrumList): pass @@ -73,7 +75,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v # special processing for HDUList if isinstance(data, fits.HDUList): data = [Spectrum1D.read(data)] - data_label = [app.return_data_label(data_label, alt_name="specviz_data")] + data_label = [data_label] else: # list treated as SpectrumList if not an HDUList data = SpectrumList.read(data, format=format) @@ -92,7 +94,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v try: data = Spectrum1D.read(str(path), format=format) if data.flux.ndim == 2: - data, data_label = split_spectrum_with_2D_flux_array(data, data_label, app) + data = split_spectrum_with_2D_flux_array(data) else: data = [data] data_label = [app.return_data_label(data_label, alt_name="specviz_data")] @@ -108,17 +110,13 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v new_data = SpectrumList() for spec in data: if spec.flux.ndim == 2: - temp_data, _ = split_spectrum_with_2D_flux_array(spec) - new_data.extend(temp_data) + new_data.extend(split_spectrum_with_2D_flux_array(spec)) else: new_data.append(spec) - data = new_data + data = SpectrumList(new_data) if not isinstance(data_label, (list, tuple)): - temp_labels = [] - for i in range(len(data)): - temp_labels.append(f"{data_label} [{i}]") - data_label = temp_labels + data_label = [f"{data_label} [{i}]" for i in range(len(data))] elif len(data_label) != len(data): raise ValueError(f"Length of data labels list ({len(data_label)}) is different" f" than length of list of data ({len(data)})") @@ -141,7 +139,7 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v # if the concatenated list of uncertanties is all nan (meaning # they were all nan to begin with, or all None), it will be set # to None on the final Spectrum1D - if spec.uncertainty[wlind] is not None: + if spec.uncertainty is not None and spec.uncertainty[wlind] is not None: dfnuallorig.append(spec.uncertainty[wlind].array) else: dfnuallorig.append(np.nan) @@ -268,20 +266,20 @@ def combine_lists_to_1d_spectrum(wl, fnu, dfnu, wave_units, flux_units): return spec -def split_spectrum_with_2D_flux_array(data, data_label, app): +def split_spectrum_with_2D_flux_array(data): """ Helper function to split Spectrum1D of 2D flux to a SpectrumList of nD objects. Parameters ---------- data : `~specutils.Spectrum1D` Spectrum with 2D flux array + Returns ------- new_data : `~specutils.SpectrumList` list of unpacked spectra """ new_data = [] - new_data_label = [] for i in range(data.flux.shape[0]): unc = None mask = None @@ -291,6 +289,5 @@ def split_spectrum_with_2D_flux_array(data, data_label, app): mask = data.mask[i, :] new_data.append(Spectrum1D(flux=data.flux[i, :], spectral_axis=data.spectral_axis, uncertainty=unc, mask=mask)) - new_data_label.append(f'{app.return_data_label(data_label, alt_name="specviz_data")}[{i}]') # noqa - return new_data, new_data_label + return new_data \ No newline at end of file diff --git a/jdaviz/configs/specviz/tests/test_helper.py b/jdaviz/configs/specviz/tests/test_helper.py index 9552fe1315..228e263faa 100644 --- a/jdaviz/configs/specviz/tests/test_helper.py +++ b/jdaviz/configs/specviz/tests/test_helper.py @@ -405,14 +405,22 @@ def test_load_spectrum_list_directory_concat(tmpdir, specviz_helper): assert len(specviz_helper.app.data_collection) == 41 -def test_load_spectrum1d_2d_flux(specviz_helper): - spec = Spectrum1D(spectral_axis=np.linspace(4000, 6000, 100)*u.Angstrom, - flux=np.ones((4, 100))*u.Unit("1e-17 erg / (Angstrom cm2 s)")) +def test_load_2d_flux(specviz_helper): + spec = Spectrum1D(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]" + 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)")) + + spec_list = SpectrumList([spec, spec2]) + specviz_helper.load_data(spec_list, data_label="second test") + + assert len(specviz_helper.app.data_collection) == 10 + assert specviz_helper.app.data_collection[-1].label == "second test [5]" def test_plot_uncertainties(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) From 2147377ea6c67f49b50345d1d94c74d1f84be5cd Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Tue, 22 Oct 2024 14:03:16 -0400 Subject: [PATCH 11/16] Codestyle Codestyle --- jdaviz/configs/specviz/plugins/parsers.py | 2 +- jdaviz/configs/specviz/tests/test_helper.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index a8e005d1ec..06aa04d8b0 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -290,4 +290,4 @@ def split_spectrum_with_2D_flux_array(data): new_data.append(Spectrum1D(flux=data.flux[i, :], spectral_axis=data.spectral_axis, uncertainty=unc, mask=mask)) - return new_data \ No newline at end of file + return new_data diff --git a/jdaviz/configs/specviz/tests/test_helper.py b/jdaviz/configs/specviz/tests/test_helper.py index 228e263faa..ea4e25dd71 100644 --- a/jdaviz/configs/specviz/tests/test_helper.py +++ b/jdaviz/configs/specviz/tests/test_helper.py @@ -414,7 +414,7 @@ def test_load_2d_flux(specviz_helper): 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)")) + flux=np.ones((2, 10))*u.Unit("1e-17 erg / (Angstrom cm2 s)")) spec_list = SpectrumList([spec, spec2]) specviz_helper.load_data(spec_list, data_label="second test") @@ -422,6 +422,7 @@ def test_load_2d_flux(specviz_helper): assert len(specviz_helper.app.data_collection) == 10 assert specviz_helper.app.data_collection[-1].label == "second test [5]" + def test_plot_uncertainties(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) From 47a69b1b7e08438804dbd709b081328b6b607bf4 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Tue, 22 Oct 2024 14:18:07 -0400 Subject: [PATCH 12/16] Apparently need this to standardize the input label --- jdaviz/configs/specviz/plugins/parsers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 06aa04d8b0..1dce93e07c 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -56,6 +56,9 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v # If no data label is assigned, give it a unique name if not data_label: data_label = app.return_data_label(data, alt_name="specviz_data") + else: + # Still need to standardize the label + data_label = app.return_data_label(data_label, alt_name="specviz_data") if isinstance(data, SpectrumCollection): raise TypeError("SpectrumCollection detected." From 44dcb6d60f916759d9b87d8d3db6a1b376ad45ab Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Tue, 22 Oct 2024 15:41:39 -0400 Subject: [PATCH 13/16] One more label handling fix --- jdaviz/configs/specviz/plugins/parsers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 1dce93e07c..8180e38aa3 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -56,8 +56,10 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v # If no data label is assigned, give it a unique name if not data_label: data_label = app.return_data_label(data, alt_name="specviz_data") + # Still need to standardize the label + elif isinstance(data_label, (list, tuple)): + data_label = [app.return_data_label(label, alt_name="specviz_data") for label in data_label] # noqa else: - # Still need to standardize the label data_label = app.return_data_label(data_label, alt_name="specviz_data") if isinstance(data, SpectrumCollection): From fbba848c557bb0ad5fa54736eabc0cf915db03f7 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen <39831871+rosteen@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:40:26 -0400 Subject: [PATCH 14/16] Apply suggestions from code review Co-authored-by: P. L. Lim <2090236+pllim@users.noreply.github.com> --- jdaviz/configs/specviz/plugins/parsers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 8180e38aa3..128d9f595f 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -118,7 +118,6 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v new_data.extend(split_spectrum_with_2D_flux_array(spec)) else: new_data.append(spec) - data = SpectrumList(new_data) if not isinstance(data_label, (list, tuple)): data_label = [f"{data_label} [{i}]" for i in range(len(data))] @@ -274,6 +273,7 @@ def combine_lists_to_1d_spectrum(wl, fnu, dfnu, wave_units, flux_units): def split_spectrum_with_2D_flux_array(data): """ Helper function to split Spectrum1D of 2D flux to a SpectrumList of nD objects. + Parameters ---------- data : `~specutils.Spectrum1D` @@ -282,7 +282,7 @@ def split_spectrum_with_2D_flux_array(data): Returns ------- new_data : `~specutils.SpectrumList` - list of unpacked spectra + List of unpacked spectra. """ new_data = [] for i in range(data.flux.shape[0]): From 8680144e6a1f5c59061d3faf4ecb06bb053f36d5 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Thu, 24 Oct 2024 12:34:32 -0400 Subject: [PATCH 15/16] Add clarity to test and changelog --- CHANGES.rst | 3 ++- jdaviz/configs/specviz/tests/test_helper.py | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index e67d19118e..b06628a43b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -15,7 +15,8 @@ Mosviz Specviz ^^^^^^^ -- Specviz parser will now split a spectrum with a 2D flux array into multiple spectra on load. [#3229] +- Specviz parser will now split a spectrum with a 2D flux array into multiple spectra on load + (useful for certain SDSS file types). [#3229] Specviz2d ^^^^^^^^^ diff --git a/jdaviz/configs/specviz/tests/test_helper.py b/jdaviz/configs/specviz/tests/test_helper.py index ea4e25dd71..8e87125071 100644 --- a/jdaviz/configs/specviz/tests/test_helper.py +++ b/jdaviz/configs/specviz/tests/test_helper.py @@ -406,6 +406,8 @@ 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)")) specviz_helper.load_data(spec, data_label="test") @@ -416,6 +418,7 @@ def test_load_2d_flux(specviz_helper): spec2 = Spectrum1D(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]) specviz_helper.load_data(spec_list, data_label="second test") From f5e2f290a31089725f3cd3d7c3fd968655044824 Mon Sep 17 00:00:00 2001 From: Ricky O'Steen Date: Thu, 24 Oct 2024 13:20:45 -0400 Subject: [PATCH 16/16] Add meta, debug --- jdaviz/configs/specviz/plugins/parsers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jdaviz/configs/specviz/plugins/parsers.py b/jdaviz/configs/specviz/plugins/parsers.py index 128d9f595f..8af49c2bc3 100644 --- a/jdaviz/configs/specviz/plugins/parsers.py +++ b/jdaviz/configs/specviz/plugins/parsers.py @@ -112,12 +112,13 @@ def specviz_spectrum1d_parser(app, data, data_label=None, format=None, show_in_v # step through SpectrumList and convert any 2D spectra to 1D spectra if isinstance(data, SpectrumList): - new_data = SpectrumList() + new_data = [] for spec in data: if spec.flux.ndim == 2: new_data.extend(split_spectrum_with_2D_flux_array(spec)) else: new_data.append(spec) + data = SpectrumList(new_data) if not isinstance(data_label, (list, tuple)): data_label = [f"{data_label} [{i}]" for i in range(len(data))] @@ -293,6 +294,6 @@ def split_spectrum_with_2D_flux_array(data): 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)) + uncertainty=unc, mask=mask, meta=data.meta)) return new_data