@@ -92,38 +92,159 @@ def test_load(self, data, tmp_path, load_type):
9292
9393 self .image .load_image (load_arg )
9494
95- def test_center_on (self ):
96- self .image .center_on ((10 , 10 )) # X, Y
95+ def test_set_get_center_xy (self , data ):
96+ self .image .load_image (data , image_label = 'test' )
97+ self .image .set_viewport (center = (10 , 10 ), image_label = 'test' ) # X, Y
98+ vport = self .image .get_viewport (image_label = 'test' )
99+ assert vport ['center' ] == (10 , 10 )
100+ assert vport ['image_label' ] == 'test'
101+
102+ def test_set_get_center_world (self , data , wcs ):
103+ 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+
106+ vport = self .image .get_viewport (image_label = 'test' )
107+ 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 ])
110+
111+ def test_set_get_fov_pixel (self , data ):
112+ # Set data first, since that is needed to determine zoom level
113+ self .image .load_image (data , image_label = 'test' )
97114
98- def test_offset_by (self , data , wcs ):
99- self .image .offset_by (10 , 10 ) # dX, dY
115+ self .image .set_viewport (fov = 100 , image_label = 'test' )
116+ vport = self .image .get_viewport (image_label = 'test' )
117+ assert vport ['fov' ] == 100
118+ assert vport ['image_label' ] == 'test'
100119
101- # Testing offset by WCS requires a WCS. The viewer will (or ought to
102- # have) taken care of setting up the WCS internally if initialized with
103- # an NDData that has a WCS.
104- ndd = NDData (data = data , wcs = wcs )
105- self .image .load_image (ndd )
120+ def test_set_get_fov_world (self , data , wcs ):
121+ # Set data first, since that is needed to determine zoom level
122+ self .image .load_image (NDData (data = data , wcs = wcs ), image_label = 'test' )
106123
107- self .image .offset_by (10 * u .arcmin , 10 * u .arcmin )
124+ # Set the FOV in world coordinates
125+ self .image .set_viewport (fov = 0.1 * u .deg , image_label = 'test' )
126+ vport = self .image .get_viewport (image_label = 'test' )
127+ assert isinstance (vport ['fov' ], SkyCoord )
128+ assert vport ['fov' ].deg == pytest .approx (0.1 )
108129
109- # A mix of pixel and sky should produce an error
110- with pytest .raises (u .UnitConversionError , match = 'are not convertible' ):
111- self .image .offset_by (10 * u .arcmin , 10 )
130+ def test_set_get_viewport_errors (self , data , wcs ):
131+ self .image .load_image (NDData (data = data , wcs = wcs ), image_label = 'test' )
112132
113- # A mix of inconsistent units should produce an error
114- with pytest .raises (u .UnitConversionError , match = 'are not convertible ' ):
115- self .image .offset_by ( 1 * u .arcsec , 1 * u . AA )
133+ # fov can be float or an angular Qunatity
134+ with pytest .raises (u .UnitTypeError , match = '[Ii]ncorrect unit for fov ' ):
135+ self .image .set_viewport ( fov = 100 * u .meter , image_label = 'test' )
116136
117- def test_zoom_level (self , data ):
118- # Set data first, since that is needed to determine zoom level
137+ # try an fov that is completely the wrong type
138+ with pytest .raises (TypeError , match = '[Ii]nvalid value for fov' ):
139+ self .image .set_viewport (fov = 'not a valid value' , image_label = 'test' )
140+
141+ # center can be a SkyCoord or a tuple of floats. Try a value that is neither
142+ with pytest .raises (TypeError , match = '[Ii]nvalid value for center' ):
143+ self .image .set_viewport (center = 'not a valid value' , image_label = 'test' )
144+
145+ # Check that an error is raised if a label is provided that does not
146+ # match an image that is loaded.
147+ with pytest .raises (ValueError , match = '[Ii]mage label.*not found' ):
148+ self .image .set_viewport (center = (10 , 10 ), fov = 100 , image_label = 'not a valid label' )
149+
150+ # Getting a viewport for an image_label that does not exist should raise an error
151+ with pytest .raises (ValueError , match = '[Ii]mage label.*not found' ):
152+ self .image .get_viewport (image_label = 'not a valid label' )
153+
154+ # If there are multiple images loaded, the image_label must be provided
155+ self .image .load_image (data , image_label = 'another test' )
156+
157+ with pytest .raises (ValueError , match = '[Ii]mage label.*not provided' ):
158+ self .image .get_viewport ()
159+
160+ def test_set_get_view_port_no_image_label (self , data ):
161+ # If there is only one image, the viewport should be able to be set
162+ # and retrieved without an image label.
163+
164+ # Add an image without an image label
119165 self .image .load_image (data )
120- self .image .zoom_level = 5
121- assert self .image .zoom_level == 5
122166
123- def test_zoom (self ):
124- self .image .zoom_level = 3
125- self .image .zoom (2 )
126- assert self .image .zoom_level == 6 # 3 x 2
167+ # Getting the viewport should not fail...
168+ vport = self .image .get_viewport ()
169+ assert 'center' in vport
170+ assert 'fov' in vport
171+ assert 'image_label' in vport
172+ assert vport ['image_label' ] is None
173+
174+ # Set the viewport without an image label
175+ self .image .set_viewport (center = (10 , 10 ), fov = 100 )
176+
177+ # Getting the viewport again should return the same values
178+ vport = self .image .get_viewport ()
179+ assert vport ['center' ] == (10 , 10 )
180+ assert vport ['fov' ] == 100
181+ assert vport ['image_label' ] is None
182+
183+ def test_set_get_viewport_single_label (self , data ):
184+ # If there is only one image, the viewport should be able to be set
185+ # and retrieved with an image label.
186+
187+ # Add an image with an image label
188+ self .image .load_image (data , image_label = 'test' )
189+
190+ # Getting the viewport should not fail...
191+ vport = self .image .get_viewport (image_label = 'test' )
192+ assert 'center' in vport
193+ assert 'fov' in vport
194+ assert 'image_label' in vport
195+ assert vport ['image_label' ] == 'test'
196+
197+ # Set the viewport with an image label
198+ self .image .set_viewport (center = (10 , 10 ), fov = 100 , image_label = 'test' )
199+
200+ # Getting the viewport again should return the same values
201+ vport = self .image .get_viewport (image_label = 'test' )
202+ assert vport ['center' ] == (10 , 10 )
203+ assert vport ['fov' ] == 100
204+ assert vport ['image_label' ] == 'test'
205+
206+ def test_get_viewport_sky_or_pixel (self , data , wcs ):
207+ # Check that the viewport can be retrieved in both pixel and world
208+ # coordinates, depending on the WCS of the image.
209+
210+ # Load the data with a WCS
211+ self .image .load_image (NDData (data = data , wcs = wcs ), image_label = 'test' )
212+
213+ input_center = SkyCoord (* wcs .val , unit = 'deg' )
214+ input_fov = 2 * u .arcmin
215+ self .image .set_viewport (center = input_center , fov = input_fov , image_label = 'test' )
216+
217+ # Get the viewport in pixel coordinates
218+ vport_pixel = self .image .get_viewport (image_label = 'test' , sky_or_pixel = 'pixel' )
219+ assert vport_pixel ['center' ] == wcs .crpix
220+ # tbh, not at all sure what the fov should be in pixel coordinates,
221+ # so just check that it is a float.
222+ assert isinstance (vport_pixel ['fov' ], float )
223+
224+ # Get the viewport in world coordinates
225+ vport_world = self .image .get_viewport (image_label = 'test' , sky_or_pixel = 'sky' )
226+ assert vport_world ['center' ] == input_center
227+ assert vport_world ['fov' ] == input_fov
228+
229+ @pytest .mark .parametrize ("sky_or_pixel" , ['sky' , 'pixel' ])
230+ def test_get_viewport_no_sky_or_pixel (self , data , wcs , sky_or_pixel ):
231+ # Check that get_viewport returns the correct "default" sky_or_pixel
232+ # value when the result ought to be unambiguous.
233+ if sky_or_pixel == 'sky' :
234+ use_wcs = wcs
235+ else :
236+ use_wcs = None
237+
238+ self .image .load_image (NDData (data = data , wcs = use_wcs ), image_label = 'test' )
239+
240+ vport = self .image .get_viewport (image_label = 'test' )
241+ match sky_or_pixel :
242+ case 'sky' :
243+ assert isinstance (vport ['center' ], SkyCoord )
244+ assert vport ['fov' ].unit .physical_type == "angle"
245+ case 'pixel' :
246+ assert isinstance (vport ['center' ], tuple )
247+ assert isinstance (vport ['fov' ], float )
127248
128249 def test_marker_properties (self ):
129250 # Set the marker style
0 commit comments