def test_unbroadcast(): x = np.array([1, 2, 3]) y = np.broadcast_to(x, (2, 4, 3)) z = misc.unbroadcast(y) assert z.shape == (3, ) np.testing.assert_equal(z, x) x = np.ones((3, 5)) y = np.broadcast_to(x, (5, 3, 5)) z = misc.unbroadcast(y) assert z.shape == (3, 5)
def test_pixel_to_pixel_correlated(): wcs_in = WCS(naxis=2) wcs_in.wcs.ctype = 'DEC--TAN', 'RA---TAN' wcs_in.wcs.set() wcs_out = WCS(naxis=2) wcs_out.wcs.ctype = 'GLON-CAR', 'GLAT-CAR' wcs_out.wcs.set() # First try with scalars x, y = pixel_to_pixel(wcs_in, wcs_out, 1, 2) assert x.shape == () assert y.shape == () # Now try with broadcasted arrays x = np.linspace(10, 20, 10) y = np.linspace(10, 20, 20) Y1, X1 = np.meshgrid(y, x, indexing='ij', copy=False) Y2, X2 = pixel_to_pixel(wcs_in, wcs_out, X1, Y1) # The final arrays should have the correct shape assert X2.shape == (20, 10) assert Y2.shape == (20, 10) # and there are no efficiency gains here since the celestial axes are correlated assert unbroadcast(X2).shape == (20, 10)
def test_pixel_to_pixel_1d(): # Simple test to make sure that when WCS only returns one world coordinate # this still works correctly (since this requires special treatment behind # the scenes). wcs_in = WCS(naxis=1) wcs_in.wcs.ctype = 'COORD1', wcs_in.wcs.cunit = 'nm', wcs_in.wcs.set() wcs_out = WCS(naxis=1) wcs_out.wcs.ctype = 'COORD2', wcs_out.wcs.cunit = 'cm', wcs_out.wcs.set() # First try with a scalar x = pixel_to_pixel(wcs_in, wcs_out, 1) assert x.shape == () # Next with a regular array x = np.linspace(10, 20, 10) x = pixel_to_pixel(wcs_in, wcs_out, x) assert x.shape == (10,) # And now try with a broadcasted array x = np.broadcast_to(np.linspace(10, 20, 10), (4, 10)) x = pixel_to_pixel(wcs_in, wcs_out, x) assert x.shape == (4, 10) # The broadcasting of the input should be retained assert unbroadcast(x).shape == (10,)
def test_pixel_to_pixel(): wcs_in = WCS(naxis=3) wcs_in.wcs.ctype = 'DEC--TAN', 'FREQ', 'RA---TAN' wcs_in.wcs.set() wcs_out = WCS(naxis=3) wcs_out.wcs.ctype = 'GLON-CAR', 'GLAT-CAR', 'FREQ' wcs_out.wcs.set() # First try with scalars with pytest.warns(AstropyUserWarning, match='No observer defined on WCS'): x, y, z = pixel_to_pixel(wcs_in, wcs_out, 1, 2, 3) assert x.shape == () assert y.shape == () assert z.shape == () # Now try with broadcasted arrays x = np.linspace(10, 20, 10) y = np.linspace(10, 20, 20) z = np.linspace(10, 20, 30) Z1, Y1, X1 = np.meshgrid(z, y, x, indexing='ij', copy=False) with pytest.warns(AstropyUserWarning, match='No observer defined on WCS'): X2, Y2, Z2 = pixel_to_pixel(wcs_in, wcs_out, X1, Y1, Z1) # The final arrays should have the correct shape assert X2.shape == (30, 20, 10) assert Y2.shape == (30, 20, 10) assert Z2.shape == (30, 20, 10) # But behind the scenes should also be broadcasted assert unbroadcast(X2).shape == (30, 1, 10) assert unbroadcast(Y2).shape == (30, 1, 10) assert unbroadcast(Z2).shape == (20, 1) # We can put the values back through the function to ensure round-tripping with pytest.warns(AstropyUserWarning, match='No observer defined on WCS'): X3, Y3, Z3 = pixel_to_pixel(wcs_out, wcs_in, X2, Y2, Z2) # The final arrays should have the correct shape assert X2.shape == (30, 20, 10) assert Y2.shape == (30, 20, 10) assert Z2.shape == (30, 20, 10) # But behind the scenes should also be broadcasted assert unbroadcast(X3).shape == (30, 1, 10) assert unbroadcast(Y3).shape == (20, 1) assert unbroadcast(Z3).shape == (30, 1, 10) # And these arrays should match the input assert_allclose(X1, X3) assert_allclose(Y1, Y3) assert_allclose(Z1, Z3)
def pixel_to_pixel(wcs_in, wcs_out, *inputs): """ Transform pixel coordinates in a dataset with a WCS to pixel coordinates in another dataset with a different WCS. This function is designed to efficiently deal with input pixel arrays that are broadcasted views of smaller arrays, and is compatible with any APE14-compliant WCS. Parameters ---------- wcs_in : `~astropy.wcs.wcsapi.BaseHighLevelWCS` A WCS object for the original dataset which complies with the high-level shared APE 14 WCS API. wcs_out : `~astropy.wcs.wcsapi.BaseHighLevelWCS` A WCS object for the target dataset which complies with the high-level shared APE 14 WCS API. *inputs : Scalars or arrays giving the pixel coordinates to transform. """ # Shortcut for scalars if np.isscalar(inputs[0]): world_outputs = wcs_in.pixel_to_world(*inputs) if not isinstance(world_outputs, (tuple, list)): world_outputs = (world_outputs,) return wcs_out.world_to_pixel(*world_outputs) # Remember original shape original_shape = inputs[0].shape matrix = _pixel_to_pixel_correlation_matrix(wcs_in, wcs_out) split_info = _split_matrix(matrix) outputs = [None] * wcs_out.pixel_n_dim for (pixel_in_indices, pixel_out_indices) in split_info: pixel_inputs = [] for ipix in range(wcs_in.pixel_n_dim): if ipix in pixel_in_indices: pixel_inputs.append(unbroadcast(inputs[ipix])) else: pixel_inputs.append(inputs[ipix].flat[0]) pixel_inputs = np.broadcast_arrays(*pixel_inputs) world_outputs = wcs_in.pixel_to_world(*pixel_inputs) if not isinstance(world_outputs, (tuple, list)): world_outputs = (world_outputs,) pixel_outputs = wcs_out.world_to_pixel(*world_outputs) if wcs_out.pixel_n_dim == 1: pixel_outputs = (pixel_outputs,) for ipix in range(wcs_out.pixel_n_dim): if ipix in pixel_out_indices: outputs[ipix] = np.broadcast_to(pixel_outputs[ipix], original_shape) return outputs[0] if wcs_out.pixel_n_dim == 1 else outputs