Skip to content

Commit

Permalink
Merge pull request #2221 from duytnguyendtn/open
Browse files Browse the repository at this point in the history
Add open method to automatically load data into the correct config
  • Loading branch information
duytnguyendtn authored Jun 5, 2023
2 parents 2a35e27 + 61e6ef9 commit 7ffaa26
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 32 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
New Features
------------

- Introduce jdaviz.open to automatically detect the appropriate config and load data [#2221]

Cubeviz
^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions jdaviz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from jdaviz.configs.cubeviz import Cubeviz # noqa: F401
from jdaviz.configs.imviz import Imviz # noqa: F401
from jdaviz.utils import enable_hot_reloading # noqa: F401
from jdaviz.core.data_formats import open # noqa: F401

# Clean up namespace.
del os
Expand Down
4 changes: 3 additions & 1 deletion jdaviz/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
__all__ = ['main']

JDAVIZ_DIR = pathlib.Path(__file__).parent.resolve()
DEFAULT_VERBOSITY = 'warning'
DEFAULT_HISTORY_VERBOSITY = 'info'


def main(filepaths=None, layout='default', instrument=None, browser='default',
theme='light', verbosity='warning', history_verbosity='info',
theme='light', verbosity=DEFAULT_VERBOSITY, history_verbosity=DEFAULT_HISTORY_VERBOSITY,
hotreload=False):
"""
Start a Jdaviz application instance with data loaded from FILENAME.
Expand Down
1 change: 1 addition & 0 deletions jdaviz/configs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .cubeviz import * # noqa
from .specviz import * # noqa
from .specviz2d import * # noqa
from .default import * # noqa
from .mosviz import * # noqa
from .imviz import * # noqa
78 changes: 64 additions & 14 deletions jdaviz/core/data_formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from stdatamodels import asdf_in_fits

from jdaviz.core.config import list_configurations
from jdaviz import configs as jdaviz_configs
from jdaviz.cli import DEFAULT_VERBOSITY, DEFAULT_HISTORY_VERBOSITY

__all__ = [
'guess_dimensionality',
Expand Down Expand Up @@ -156,6 +158,9 @@ def identify_helper(filename, ext=1):
-------
helper_name : str
Name of the best-guess helper for ``filename``.
Fits HDUList : astropy.io.fits.HDUList
The HDUList of the file opened to identify the helper
"""
supported_dtypes = [
Spectrum1D,
Expand All @@ -167,10 +172,12 @@ def identify_helper(filename, ext=1):
if filename.lower().endswith('asdf'):
# ASDF files are only supported in jdaviz for
# Roman WFI 2D images, so suggest imviz:
return 'imviz'
return ('imviz', None)

header = fits.getheader(filename, ext=ext)
data = fits.getdata(filename, ext=ext)
# Must use memmap=False to force close all handles and allow file overwrite
hdul = fits.open(filename, memmap=False)
data = hdul[ext]
header = data.header
wcs = _get_wcs(filename, header)
has_spectral_axis = 'spectral' in wcs.world_axis_object_classes

Expand Down Expand Up @@ -201,10 +208,10 @@ def identify_helper(filename, ext=1):
# could be 2D spectrum or 2D image. break tie with WCS:
if has_spectral_axis:
if n_axes > 1:
return 'specviz2d'
return 'specviz'
return ('specviz2d', hdul)
return ('specviz', hdul)
elif not isinstance(data, fits.BinTableHDU):
return 'imviz'
return ('imviz', hdul)

# Ensure specviz is chosen when ``data`` is a table or recarray
# and there's a "known" spectral column name:
Expand All @@ -230,7 +237,7 @@ def identify_helper(filename, ext=1):

# if at least one spectral column is found:
if sum(found_spectral_columns):
return 'specviz'
return ('specviz', hdul)

# If the data could be spectral:
for cls in [Spectrum1D, SpectrumList]:
Expand All @@ -240,10 +247,10 @@ def identify_helper(filename, ext=1):
# first catch known JWST spectrum types:
if (n_axes == 3 and
recognized_spectrum_format.find('s3d') > -1):
return 'cubeviz'
return ('cubeviz', hdul)
elif (n_axes == 2 and
recognized_spectrum_format.find('x1d') > -1):
return 'specviz'
return ('specviz', hdul)

# we intentionally don't choose specviz2d for
# data recognized as 's2d' as we did with the cases above,
Expand All @@ -253,22 +260,65 @@ def identify_helper(filename, ext=1):
# Use WCS to break the tie below:
elif n_axes == 2:
if has_spectral_axis:
return 'specviz2d'
return 'imviz'
return ('specviz2d', hdul)
return ('imviz', hdul)

elif n_axes == 1:
return 'specviz'
return ('specviz', hdul)

try:
# try using the specutils registry:
valid_format, config = identify_data(filename)
return config
return (config, hdul)
except ValueError:
# if file type not recognized:
pass

if n_axes == 2 and not has_spectral_axis:
# at this point, non-spectral 2D data are likely images:
return 'imviz'
return ('imviz', hdul)

raise ValueError(f"No helper could be auto-identified for {filename}.")


def open(filename, show=True, **kwargs):
'''
Automatically detect the correct configuration based on a given file,
load the data, and display the configuration
Parameters
----------
filename : str (path-like)
Name for a local data file.
show : bool
Determines whether to immediately show the application
All other arguments are interpreted as load_data/load_spectrum arguments for
the autoidentified configuration class
Returns
-------
Jdaviz ConfigHelper : jdaviz.core.helpers.ConfigHelper
The autoidentified ConfigHelper for the given data
'''
# Identify the correct config
helper_str, hdul = identify_helper(filename)
viz_class = getattr(jdaviz_configs, helper_str.capitalize())

# Create config instance
verbosity = kwargs.pop('verbosity', DEFAULT_VERBOSITY)
history_verbosity = kwargs.pop('history_verbosity', DEFAULT_HISTORY_VERBOSITY)
viz_helper = viz_class(verbosity=verbosity, history_verbosity=history_verbosity)

# Load data
data = hdul if (hdul is not None) else filename
if helper_str == "specviz":
viz_helper.load_spectrum(data, **kwargs)
else:
viz_helper.load_data(data, **kwargs)

# Display app
if show:
viz_helper.show()

return viz_helper
41 changes: 41 additions & 0 deletions jdaviz/core/tests/test_autoconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Tests automatic config detection against our example notebook data

from pathlib import Path
from tempfile import TemporaryDirectory

import pytest
from astroquery.mast import Observations
from astropy.utils.data import download_file

from jdaviz import open as jdaviz_open
from jdaviz.configs import Specviz2d, Cubeviz, Imviz # , Specviz


@pytest.mark.remote_data
@pytest.mark.filterwarnings('ignore')
@pytest.mark.parametrize('uris', (
# ("mast:JWST/product/jw02732-o004_t004_miri_ch1-shortmediumlong_x1d.fits", Specviz),
# Specviz check disabled due to https://github.com/spacetelescope/jdaviz/issues/2229
("mast:JWST/product/jw01538-o160_s00004_nirspec_f170lp-g235h-s1600a1-sub2048_s2d.fits", Specviz2d), # noqa
("mast:JWST/product/jw02727-o002_t062_nircam_clear-f090w_i2d.fits", Imviz),
("mast:JWST/product/jw02732-o004_t004_miri_ch1-shortmediumlong_s3d.fits", Cubeviz),
("https://stsci.box.com/shared/static/28a88k1qfipo4yxc4p4d40v4axtlal8y.fits", Cubeviz)
# Check that MaNGA cubes go to cubeviz. This file is originally from:
# https://data.sdss.org/sas/dr14/manga/spectro/redux/v2_1_2/7495/stack/manga-7495-12704-LOGCUBE.fits.gz)
))
def test_autoconfig(uris):
# Setup temporary directory
with TemporaryDirectory(ignore_cleanup_errors=True) as tempdir:
uri = uris[0]
helper_class = uris[1]

if uri.startswith("mast:"):
download_path = str(Path(tempdir) / Path(uri).name)
Observations.download_file(uri, local_path=download_path)
elif uri.startswith("http"):
download_path = download_file(uri, cache=True, timeout=100)

viz_helper = jdaviz_open(download_path, show=False)

assert type(viz_helper) == helper_class
assert len(viz_helper.app.data_collection) > 0
15 changes: 2 additions & 13 deletions jdaviz/core/tests/test_data_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,6 @@ def test_visibility_toggle(imviz_helper):
def test_auto_config_detection(uri, expected_helper):
url = f'https://mast.stsci.edu/api/v0.1/Download/file/?uri={uri}'
fn = download_file(url, timeout=100)
helper_name = identify_helper(fn)
helper_name, hdul = identify_helper(fn)
hdul.close()
assert helper_name == expected_helper


@pytest.mark.remote_data
@pytest.mark.filterwarnings(r"ignore::astropy.wcs.wcs.FITSFixedWarning")
def test_auto_config_manga():
# Check that MaNGA cubes go to cubeviz. This file is
# originally from
# https://data.sdss.org/sas/dr14/manga/spectro/redux/v2_1_2/7495/stack/manga-7495-12704-LOGCUBE.fits.gz
URL = 'https://stsci.box.com/shared/static/28a88k1qfipo4yxc4p4d40v4axtlal8y.fits'
fn = download_file(URL, cache=True, timeout=100)
helper_name = identify_helper(fn)
assert helper_name == 'cubeviz'
9 changes: 8 additions & 1 deletion notebooks/CubevizExample.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@
" cubeviz.load_data(f'{data_dir}/{fn}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively, the data and the configuration can be autodetected and loaded simultaneously by calling `jdaviz.open(f'{data_dir}/{fn}')`"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down Expand Up @@ -225,7 +232,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.8"
"version": "3.10.10"
}
},
"nbformat": 4,
Expand Down
10 changes: 9 additions & 1 deletion notebooks/ImvizExample.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,14 @@
"imviz.show()"
]
},
{
"cell_type": "markdown",
"id": "99d4bdef",
"metadata": {},
"source": [
"Alternatively, the data and the configuration can be autodetected and loaded simultaneously by calling `jdaviz.open(f'{data_dir}/{fn}')`"
]
},
{
"cell_type": "markdown",
"id": "3e78efeb",
Expand Down Expand Up @@ -720,7 +728,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
"version": "3.10.10"
}
},
"nbformat": 4,
Expand Down
10 changes: 9 additions & 1 deletion notebooks/Specviz2dExample.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@
"source": [
"specviz2d.load_data(f'{data_dir}/{fn}')"
]
},
{
"cell_type": "markdown",
"id": "795bc520",
"metadata": {},
"source": [
"Alternatively, the data and the configuration can be autodetected and loaded simultaneously by calling `jdaviz.open(f'{data_dir}/{fn}')`"
]
}
],
"metadata": {
Expand All @@ -114,7 +122,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
"version": "3.10.10"
}
},
"nbformat": 4,
Expand Down
9 changes: 8 additions & 1 deletion notebooks/SpecvizExample.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@
"specviz.load_spectrum(f'{data_dir}/{fn}', \"myfile\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively, the data and the configuration can be autodetected and loaded simultaneously by calling `jdaviz.open(f'{data_dir}/{fn}')`"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down Expand Up @@ -293,7 +300,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
"version": "3.10.10"
}
},
"nbformat": 4,
Expand Down

0 comments on commit 7ffaa26

Please sign in to comment.