Skip to content

Commit 3c15118

Browse files
committed
Improve and add more viewport test
1 parent a03c0d6 commit 3c15118

File tree

1 file changed

+88
-16
lines changed

1 file changed

+88
-16
lines changed

src/astro_image_display_api/widget_api_test.py

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from astropy.coordinates import SkyCoord # noqa: E402
77
from astropy.io import fits # noqa: E402
8-
from astropy.nddata import NDData # noqa: E402
8+
from astropy.nddata import CCDData, NDData # noqa: E402
99
from astropy.table import Table, vstack # noqa: E402
1010
from astropy import units as u # noqa: E402
1111
from astropy.wcs import WCS # noqa: E402
@@ -31,6 +31,7 @@ def wcs(self):
3131
w = WCS(naxis=2)
3232

3333
# Set up an "Airy's zenithal" projection
34+
# Note: WCS is 1-based, not 0-based
3435
w.wcs.crpix = [-234.75, 8.3393]
3536
w.wcs.cdelt = np.array([-0.066667, 0.066667])
3637
w.wcs.crval = [0, -90]
@@ -101,12 +102,12 @@ def test_set_get_center_xy(self, data):
101102

102103
def test_set_get_center_world(self, data, wcs):
103104
self.image.load_image(NDData(data=data, wcs=wcs), image_label='test')
104-
self.image.set_viewport(center=SkyCoord(*wcs.crval, unit='deg'), image_label='test')
105+
self.image.set_viewport(center=SkyCoord(*wcs.wcs.crval, unit='deg'), image_label='test')
105106

106107
vport = self.image.get_viewport(image_label='test')
107108
assert isinstance(vport['center'], SkyCoord)
108-
assert vport['center'].ra.deg == pytest.approx(wcs.crval[0])
109-
assert vport['center'].dec.deg == pytest.approx(wcs.crval[1])
109+
assert vport['center'].ra.deg == pytest.approx(wcs.wcs.crval[0])
110+
assert vport['center'].dec.deg == pytest.approx(wcs.wcs.crval[1])
110111

111112
def test_set_get_fov_pixel(self, data):
112113
# Set data first, since that is needed to determine zoom level
@@ -124,10 +125,14 @@ def test_set_get_fov_world(self, data, wcs):
124125
# Set the FOV in world coordinates
125126
self.image.set_viewport(fov=0.1 * u.deg, image_label='test')
126127
vport = self.image.get_viewport(image_label='test')
127-
assert isinstance(vport['fov'], SkyCoord)
128-
assert vport['fov'].deg == pytest.approx(0.1)
128+
assert isinstance(vport['fov'], u.Quantity)
129+
assert len(np.atleast_1d(vport['fov'])) == 1
130+
assert vport['fov'].unit.physical_type == 'angle'
131+
fov_degree = vport['fov'].to(u.degree).value
132+
assert fov_degree == pytest.approx(0.1)
129133

130134
def test_set_get_viewport_errors(self, data, wcs):
135+
# Test several of the expected errors that can be raised
131136
self.image.load_image(NDData(data=data, wcs=wcs), image_label='test')
132137

133138
# fov can be float or an angular Qunatity
@@ -154,25 +159,64 @@ def test_set_get_viewport_errors(self, data, wcs):
154159
# If there are multiple images loaded, the image_label must be provided
155160
self.image.load_image(data, image_label='another test')
156161

157-
with pytest.raises(ValueError, match='[Ii]mage label.*not provided'):
162+
with pytest.raises(ValueError, match='Multiple catalog styles defined'):
158163
self.image.get_viewport()
159164

160-
def test_viewport_is_defined_aster_loading_image(self, data):
165+
# setting sky_or_pixel to something other than 'sky' or 'pixel' or None
166+
# should raise an error
167+
with pytest.raises(ValueError, match='[Ss]ky_or_pixel must be'):
168+
self.image.get_viewport(sky_or_pixel='not a valid value')
169+
170+
def test_set_get_viewport_errors_because_no_wcs(self, data):
171+
# Check that errors are raised when they should be when calling
172+
# get_viewport when no WCS is present.
173+
174+
# Load the data without a WCS
175+
self.image.load_image(data, image_label='test')
176+
177+
# Set the viewport with a SkyCoord center
178+
with pytest.raises(TypeError, match='Center must be a tuple'):
179+
self.image.set_viewport(center=SkyCoord(ra=10, dec=20, unit='deg'), image_label='test')
180+
181+
# Set the viewport with a Quantity fov
182+
with pytest.raises(TypeError, match='FOV must be a float'):
183+
self.image.set_viewport(fov=100 * u.arcmin, image_label='test')
184+
185+
# Try getting the viewport as sky
186+
with pytest.raises(ValueError, match='WCS is not set'):
187+
self.image.get_viewport(image_label='test', sky_or_pixel='sky')
188+
189+
@pytest.mark.parametrize("world", [True, False])
190+
def test_viewport_is_defined_after_loading_image(self, tmp_path, data, wcs, world):
161191
# Check that the viewport is set to a default value when an image
162192
# is loaded, even if no viewport is explicitly set.
163-
self.image.load_image(data)
193+
194+
# Load the image from FITS to ensure that at least one image with WCS
195+
# has been loaded from FITS.
196+
wcs = wcs if world else None
197+
ccd = CCDData(data=data, unit="adu", wcs=wcs)
198+
199+
ccd_path = tmp_path / 'test.fits'
200+
ccd.write(ccd_path)
201+
self.image.load_image(ccd_path)
164202

165203
# Getting the viewport should not fail...
166204
vport = self.image.get_viewport()
167205

168206
assert 'center' in vport
169-
# No world, so center should be a tuple
170-
assert isinstance(vport['center'], tuple)
207+
171208
assert 'fov' in vport
172-
# fov should be a float since no WCS
173-
assert isinstance(vport['fov'], numbers.Real)
174209
assert 'image_label' in vport
175210
assert vport['image_label'] is None
211+
if world:
212+
assert isinstance(vport['center'], SkyCoord)
213+
# fov should be a Quantity since WCS is present
214+
assert isinstance(vport['fov'], u.Quantity)
215+
else:
216+
# No world, so center should be a tuple
217+
assert isinstance(vport['center'], tuple)
218+
# fov should be a float since no WCS
219+
assert isinstance(vport['fov'], numbers.Real)
176220

177221
def test_set_get_view_port_no_image_label(self, data):
178222
# If there is only one image, the viewport should be able to be set
@@ -220,13 +264,15 @@ def test_get_viewport_sky_or_pixel(self, data, wcs):
220264
# Load the data with a WCS
221265
self.image.load_image(NDData(data=data, wcs=wcs), image_label='test')
222266

223-
input_center = SkyCoord(*wcs.val, unit='deg')
267+
input_center = SkyCoord(*wcs.wcs.crval, unit='deg')
224268
input_fov = 2 * u.arcmin
225269
self.image.set_viewport(center=input_center, fov=input_fov, image_label='test')
226270

227271
# Get the viewport in pixel coordinates
228272
vport_pixel = self.image.get_viewport(image_label='test', sky_or_pixel='pixel')
229-
assert vport_pixel['center'] == wcs.crpix
273+
# The WCS set up for the tests is 1-based, rather than the usual 0-based,
274+
# so we need to subtract 1 from the pixel coordinates.
275+
assert all(vport_pixel['center'] == (wcs.wcs.crpix - 1))
230276
# tbh, not at all sure what the fov should be in pixel coordinates,
231277
# so just check that it is a float.
232278
assert isinstance(vport_pixel['fov'], numbers.Real)
@@ -254,7 +300,33 @@ def test_get_viewport_no_sky_or_pixel(self, data, wcs, sky_or_pixel):
254300
assert vport['fov'].unit.physical_type == "angle"
255301
case 'pixel':
256302
assert isinstance(vport['center'], tuple)
257-
assert isinstance(vport['fov'], float)
303+
assert isinstance(vport['fov'], numbers.Real)
304+
305+
def test_get_viewport_with_wcs_set_pixel_or_world(self, data, wcs):
306+
# Check that the viewport can be retrieved in both pixel and world
307+
# after setting with the opposite if the WCS is set.
308+
# Load the data with a WCS
309+
self.image.load_image(NDData(data=data, wcs=wcs), image_label='test')
310+
311+
# Set the viewport in world coordinates
312+
input_center = SkyCoord(*wcs.wcs.crval, unit='deg')
313+
input_fov = 2 * u.arcmin
314+
self.image.set_viewport(center=input_center, fov=input_fov, image_label='test')
315+
316+
# Get the viewport in pixel coordinates
317+
vport_pixel = self.image.get_viewport(image_label='test', sky_or_pixel='pixel')
318+
assert all(vport_pixel['center'] == (wcs.wcs.crpix - 1))
319+
assert isinstance(vport_pixel['fov'], numbers.Real)
320+
321+
# Set the viewport in pixel coordinates
322+
input_center_pixel = (wcs.wcs.crpix[0], wcs.wcs.crpix[1])
323+
input_fov_pixel = 100 # in pixels
324+
self.image.set_viewport(center=input_center_pixel, fov=input_fov_pixel, image_label='test')
325+
326+
# Get the viewport in world coordinates
327+
vport_world = self.image.get_viewport(image_label='test', sky_or_pixel='sky')
328+
assert vport_world['center'] == wcs.pixel_to_world(*input_center_pixel)
329+
assert isinstance(vport_world['fov'], u.Quantity)
258330

259331
def test_viewport_round_trips(self, data, wcs):
260332
# Check that the viewport retrieved with get can be used to set

0 commit comments

Comments
 (0)