Skip to content

Commit

Permalink
some test coverage for wcs-based rotation via glue
Browse files Browse the repository at this point in the history
  • Loading branch information
bmorris3 committed May 10, 2023
1 parent f60bd4e commit 95205d4
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 14 deletions.
2 changes: 1 addition & 1 deletion jdaviz/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -1746,7 +1746,7 @@ def set_data_visibility(self, viewer_reference, data_label, visible=True, replac
is_wcs_only = getattr(layer.layer, 'meta', {}).get('WCS-ONLY', False)
if layer.layer.data.label == data_label and is_wcs_only:
layer.visible = False
viewer_item['wcs_only_layers'].append(data_label)
viewer.state.wcs_only_layers.append(data_label)
selected_items.pop(data_id)

# Sets the plot axes labels to be the units of the most recently
Expand Down
9 changes: 7 additions & 2 deletions jdaviz/configs/imviz/plugins/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ def _nddata_to_glue_data(ndd, data_label):

for attrib, sub_attrib in zip(
['data', 'mask', 'uncertainty'],
['data', None, 'array']
[None, None, 'array']
):
arr = getattr(ndd, attrib)
if arr is None:
Expand All @@ -385,11 +385,16 @@ def _nddata_to_glue_data(ndd, data_label):
raw_arr = arr

if sub_attrib is not None:
# since NDDataArray.uncertainty may be an object like
# StdDevUncertainty, we need to take another attr
# like StdDevUncertainty.array:
base_arr = getattr(raw_arr, sub_attrib)
else:
base_arr = raw_arr
wcs_only = np.all(np.isnan(base_arr))
cur_data.meta.update({'WCS-ONLY': wcs_only})

if 'WCS-ONLY' not in cur_data.meta or not cur_data.meta.get('WCS-ONLY'):
cur_data.meta.update({'WCS-ONLY': wcs_only})

cur_label = f'{data_label}'
comp_label = attrib.upper()
Expand Down
59 changes: 59 additions & 0 deletions jdaviz/configs/imviz/tests/test_wcs_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import pytest
import gwcs
import numpy as np
from astropy import units as u
from astropy.coordinates import ICRS
from astropy.utils.data import get_pkg_data_filename
from astropy.modeling import models
from astropy.wcs import WCS
from gwcs import coordinate_frames as cf
Expand Down Expand Up @@ -104,3 +106,60 @@ def test_simple_gwcs():
1262.0057201165127, 606.2863901330095,
155.2870478938214, -86.89813081941797))
assert not result[-1]


@pytest.mark.remote_data
@pytest.mark.filterwarnings(r"ignore::astropy.wcs.wcs.FITSFixedWarning")
def test_non_wcs_layer_labels(imviz_helper):
# load a real image w/ WCS:
real_image_path = get_pkg_data_filename('tutorials/FITS-images/HorseHead.fits')
imviz_helper.load_data(real_image_path)

# load a WCS-only layer:
ndd = wcs_utils._get_rotated_nddata_from_label(
app=imviz_helper.app,
data_label=imviz_helper.app.data_collection[0].label,
rotation_angle=0*u.deg
)
imviz_helper.load_data(ndd)

# confirm that only the image is labeled:
assert len(imviz_helper.app.state.layer_icons) == 2

# confirm the WCS-only layer is logged:
viewer = imviz_helper.app.get_viewer('imviz-0')
assert len(viewer.state.wcs_only_layers) == 1

# load a second WCS-only layer:
ndd2 = wcs_utils._get_rotated_nddata_from_label(
app=imviz_helper.app,
data_label=imviz_helper.app.data_collection[0].label,
rotation_angle=45*u.deg
)
imviz_helper.load_data(ndd2)
assert len(imviz_helper.app.state.layer_icons) == 3
assert len(viewer.state.wcs_only_layers) == 2

wcs_only_refdata_icon = 'mdi-compass-outline'
wcs_only_not_refdata_icon = 'mdi-compass-off-outline'

for i, data in enumerate(imviz_helper.app.data_collection):
viewer = imviz_helper.app.get_viewer("imviz-0")

if i == 0:
# first entry is image data:
assert imviz_helper.app.state.layer_icons[data.label] == 'a'
assert viewer.state.reference_data.label == data.label
else:
# icon before setting as refdata:
before_icon = imviz_helper.app.state.layer_icons[data.label]

# set as refdata:
imviz_helper.app._change_reference_data(data.label)
assert viewer.state.reference_data.label == data.label

# icon after setting as refdata:
after_icon = imviz_helper.app.state.layer_icons[data.label]

assert before_icon == wcs_only_not_refdata_icon
assert after_icon == wcs_only_refdata_icon
24 changes: 13 additions & 11 deletions jdaviz/configs/imviz/wcs_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,8 @@ def data_outside_gwcs_bounding_box(data, x, y):
return outside_bounding_box


def _get_fits_wcs_from_file(filename):
header = fits.getheader(filename)
def _get_fits_wcs_from_file(filename, ext=None):
header = fits.getheader(filename, ext=ext)
with warnings.catch_warnings():
# Ignore a warning on using DATE-OBS in place of MJD-OBS
warnings.filterwarnings('ignore', message="'datfix' made the change",
Expand Down Expand Up @@ -369,9 +369,9 @@ def rotated_gwcs(
return GWCS(pipeline)


def _prepare_rotated_nddata(wcs, rotation_angle, refdata_shape):
def _prepare_rotated_nddata(image_data, wcs, rotation_angle, refdata_shape):
# get the world coordinates of the central pixel
real_image_shape = np.array(wcs.array_shape)
real_image_shape = np.array(np.shape(image_data))
central_pixel_coord = real_image_shape / 2 * u.pix
central_world_coord = wcs.pixel_to_world(*central_pixel_coord)
rotation_angle = coord.Angle(rotation_angle).wrap_at(360 * u.deg)
Expand Down Expand Up @@ -401,7 +401,7 @@ def _prepare_rotated_nddata(wcs, rotation_angle, refdata_shape):
return ndd


def _get_rotated_nddata_from_fits(filename, rotation_angle, refdata_shape=(2, 2)):
def _get_rotated_nddata_from_fits(filename, rotation_angle, refdata_shape=(2, 2), ext=None):
"""
Create a synthetic NDDataArray which stores GWCS that approximate
the FITS WCS in ``filename`` rotated by ``rotation_angle``.
Expand All @@ -425,12 +425,14 @@ def _get_rotated_nddata_from_fits(filename, rotation_angle, refdata_shape=(2, 2)
Data are all NaNs, wcs are rotated.
"""
# get the FITS WCS from the file:
wcs = _get_fits_wcs_from_file(filename)
wcs = _get_fits_wcs_from_file(filename, ext=ext)

return _prepare_rotated_nddata(wcs, rotation_angle, refdata_shape)


def _get_rotated_nddata_from_label(app, data_label, rotation_angle, refdata_shape=(2, 2)):
def _get_rotated_nddata_from_label(
app, data_label, rotation_angle, refdata_shape=(2, 2), main_component_idx=0
):
"""
Create a synthetic NDDataArray which stores GWCS that approximate
the WCS in the coords attr of the Data object with label ``data_label``
Expand All @@ -457,9 +459,9 @@ def _get_rotated_nddata_from_label(app, data_label, rotation_angle, refdata_shap
Data are all NaNs, wcs are rotated.
"""
# get the WCS from the Data object's coords attribute:
[wcs] = [
data.coords for data in app.data_collection
[data] = [
data for data in app.data_collection
if data.label == data_label
]

return _prepare_rotated_nddata(wcs, rotation_angle, refdata_shape)
image = data[data.main_components[main_component_idx]]
return _prepare_rotated_nddata(image, data.coords, rotation_angle, refdata_shape)

0 comments on commit 95205d4

Please sign in to comment.