Esempio n. 1
0
def test_high_level_wrapper(wcsobj, request):
    if request.node.callspec.params['wcsobj'] in ('gwcs_4d_identity_units',
                                                  'gwcs_stokes_lookup'):
        pytest.importorskip("astropy", minversion="4.0dev0")

    # Remove the bounding box because the type test is a little broken with the
    # bounding box.
    del wcsobj._pipeline[0][1].bounding_box

    hlvl = HighLevelWCSWrapper(wcsobj)

    pixel_input = [3] * wcsobj.pixel_n_dim

    # If the model expects units we have to pass in units
    if wcsobj.forward_transform.uses_quantity:
        pixel_input *= u.pix

    wc1 = hlvl.pixel_to_world(*pixel_input)
    wc2 = wcsobj(*pixel_input, with_units=True)

    assert type(wc1) is type(wc2)

    if isinstance(wc1, (list, tuple)):
        for w1, w2 in zip(wc1, wc2):
            _compare_frame_output(w1, w2)
    else:
        _compare_frame_output(wc1, wc2)
Esempio n. 2
0
def test_spectral_cube(spectral_cube_3d_fitswcs):

    wcs = ReorderedLowLevelWCS(spectral_cube_3d_fitswcs,
                               pixel_order=[1, 2, 0],
                               world_order=[2, 0, 1])

    assert wcs.pixel_n_dim == 3
    assert wcs.world_n_dim == 3
    assert tuple(wcs.world_axis_physical_types) == ('em.freq', 'pos.eq.ra',
                                                    'pos.eq.dec')
    assert tuple(wcs.world_axis_units) == ('Hz', 'deg', 'deg')
    assert tuple(wcs.pixel_axis_names) == ('', '', '')
    assert tuple(wcs.world_axis_names) == ('Frequency', 'Right Ascension',
                                           'Declination')
    assert_equal(wcs.axis_correlation_matrix,
                 np.array([[0, 1, 0], [1, 0, 1], [1, 0, 1]]))

    assert wcs.pixel_shape == (7, 3, 6)
    assert wcs.array_shape == (6, 3, 7)
    assert wcs.pixel_bounds == ((1, 7), (1, 2.5), (-1, 5))

    pixel_scalar = (1.3, 2.3, 4.3)
    world_scalar = (-1.91e10, 5.4, -9.4)
    assert_allclose(wcs.pixel_to_world_values(*pixel_scalar), world_scalar)
    assert_allclose(wcs.array_index_to_world_values(*pixel_scalar[::-1]),
                    world_scalar)
    assert_allclose(wcs.world_to_pixel_values(*world_scalar), pixel_scalar)
    assert_allclose(wcs.world_to_array_index_values(*world_scalar), [4, 2, 1])

    pixel_array = (np.array([1.3, 1.4]), np.array([2.3,
                                                   2.4]), np.array([4.3, 4.4]))
    world_array = (np.array([-1.91e10, -1.88e10]), np.array([5.4, 5.2]),
                   np.array([-9.4, -9.2]))
    assert_allclose(wcs.pixel_to_world_values(*pixel_array), world_array)
    assert_allclose(wcs.array_index_to_world_values(*pixel_array[::-1]),
                    world_array)
    assert_allclose(wcs.world_to_pixel_values(*world_array), pixel_array)
    assert_allclose(wcs.world_to_array_index_values(*world_array),
                    [[4, 4], [2, 2], [1, 1]])

    wcs_hl = HighLevelWCSWrapper(wcs)

    spectral, celestial = wcs_hl.pixel_to_world(*pixel_scalar)
    assert isinstance(spectral, Quantity)
    assert_quantity_allclose(spectral, world_scalar[0] * u.Hz)
    assert isinstance(celestial, SkyCoord)
    assert_quantity_allclose(celestial.ra, world_scalar[1] * u.deg)
    assert_quantity_allclose(celestial.dec, world_scalar[2] * u.deg)

    spectral, celestial = wcs_hl.pixel_to_world(*pixel_array)
    assert isinstance(spectral, Quantity)
    assert_quantity_allclose(spectral, world_array[0] * u.Hz)
    assert isinstance(celestial, SkyCoord)
    assert_quantity_allclose(celestial.ra, world_array[1] * u.deg)
    assert_quantity_allclose(celestial.dec, world_array[2] * u.deg)

    assert str(wcs) == EXPECTED_SPECTRAL_CUBE_REPR
    assert EXPECTED_SPECTRAL_CUBE_REPR in repr(wcs)
Esempio n. 3
0
def test_2d(celestial_wcs):

    # Upsample along the first pixel dimension and downsample along the second
    # pixel dimension.
    wcs = ResampledLowLevelWCS(celestial_wcs, [0.4, 3])

    # The following shouldn't change compared to the original WCS
    assert wcs.pixel_n_dim == 2
    assert wcs.world_n_dim == 2
    assert tuple(wcs.world_axis_physical_types) == ('pos.eq.ra', 'pos.eq.dec')
    assert tuple(wcs.world_axis_units) == ('deg', 'deg')
    assert tuple(wcs.pixel_axis_names) == ('', '')
    assert tuple(wcs.world_axis_names) == ('Right Ascension', 'Declination')
    assert_equal(wcs.axis_correlation_matrix, np.ones((2, 2)))

    # Shapes and bounds should be floating-point if needed
    assert_allclose(wcs.pixel_shape, (15, 7 / 3))
    assert_allclose(wcs.array_shape, (7 / 3, 15))
    assert_allclose(wcs.pixel_bounds, ((-2.5, 12.5), (1 / 3, 7 / 3)))

    pixel_scalar = (2.3, 4.3)
    world_scalar = (12.16, 13.8)
    assert_allclose(wcs.pixel_to_world_values(*pixel_scalar), world_scalar)
    assert_allclose(wcs.array_index_to_world_values(*pixel_scalar[::-1]),
                    world_scalar)
    assert_allclose(wcs.world_to_pixel_values(*world_scalar), pixel_scalar)
    assert_allclose(wcs.world_to_array_index_values(*world_scalar), [4, 2])

    pixel_array = (np.array([2.3, 2.4]), np.array([4.3, 4.4]))
    world_array = (np.array([12.16, 12.08]), np.array([13.8, 14.4]))
    assert_allclose(wcs.pixel_to_world_values(*pixel_array), world_array)
    assert_allclose(wcs.array_index_to_world_values(*pixel_array[::-1]),
                    world_array)
    assert_allclose(wcs.world_to_pixel_values(*world_array), pixel_array)
    assert_allclose(wcs.world_to_array_index_values(*world_array),
                    [[4, 4], [2, 2]])

    wcs_hl = HighLevelWCSWrapper(wcs)

    celestial = wcs_hl.pixel_to_world(*pixel_scalar)
    assert isinstance(celestial, SkyCoord)
    assert_quantity_allclose(celestial.ra, world_scalar[0] * u.deg)
    assert_quantity_allclose(celestial.dec, world_scalar[1] * u.deg)

    celestial = wcs_hl.pixel_to_world(*pixel_array)
    assert isinstance(celestial, SkyCoord)
    assert_quantity_allclose(celestial.ra, world_array[0] * u.deg)
    assert_quantity_allclose(celestial.dec, world_array[1] * u.deg)

    assert str(wcs) == EXPECTED_2D_REPR
    assert EXPECTED_2D_REPR in repr(wcs)
Esempio n. 4
0
def test_wcs_type_transform_regression():
    wcs = WCS(TARGET_HEADER)
    sliced_wcs = SlicedLowLevelWCS(wcs, np.s_[1:-1, 1:-1])
    ax = plt.subplot(1, 1, 1, projection=wcs)
    ax.get_transform(sliced_wcs)

    high_wcs = HighLevelWCSWrapper(sliced_wcs)
    ax.get_transform(sliced_wcs)
Esempio n. 5
0
    def _slice_wcs(self, item):
        if self.wcs is None:
            return None

        try:
            llwcs = SlicedLowLevelWCS(self.wcs.low_level_wcs, item)
            return HighLevelWCSWrapper(llwcs)
        except Exception as err:
            self._handle_wcs_slicing_error(err, item)
Esempio n. 6
0
    def combined_wcs(self):
        """
        A `~astropy.wcs.wcsapi.BaseHighLevelWCS` object which combines ``.wcs`` with ``.extra_coords``.
        """
        if not self.extra_coords.wcs:
            return self.wcs

        mapping = list(range(self.wcs.pixel_n_dim)) + list(self.extra_coords.mapping)
        return HighLevelWCSWrapper(
            CompoundLowLevelWCS(self.wcs.low_level_wcs, self._extra_coords.wcs, mapping=mapping)
        )
Esempio n. 7
0
    def wcs(self, wcs):
        if self._wcs is not None and wcs is not None:
            raise ValueError(
                "You can only set the wcs attribute with a WCS if no WCS is present."
            )

        if wcs is None or isinstance(wcs, BaseHighLevelWCS):
            self._wcs = wcs
        elif isinstance(wcs, BaseLowLevelWCS):
            self._wcs = HighLevelWCSWrapper(wcs)
        else:
            raise TypeError(
                "The wcs argument must implement either the high or"
                " low level WCS API.")
Esempio n. 8
0
def test_nddata_init_data_nddata_subclass():
    uncert = StdDevUncertainty(3)
    # There might be some incompatible subclasses of NDData around.
    bnd = BadNDDataSubclass(False, True, 3, 2, 'gollum', 100)
    # Before changing the NDData init this would not have raised an error but
    # would have lead to a compromised nddata instance
    with pytest.raises(TypeError):
        NDData(bnd)

    # but if it has no actual incompatible attributes it passes
    bnd_good = BadNDDataSubclass(np.array([1, 2]), uncert, 3, HighLevelWCSWrapper(WCS(naxis=1)),
                                 {'enemy': 'black knight'}, u.km)
    nd = NDData(bnd_good)
    assert nd.unit == bnd_good.unit
    assert nd.meta == bnd_good.meta
    assert nd.uncertainty == bnd_good.uncertainty
    assert nd.mask == bnd_good.mask
    assert nd.wcs is bnd_good.wcs
    assert nd.data is bnd_good.data
Esempio n. 9
0
    def _stokes_slice(self, stokes_ix, normalize=False):
        """Return a 3D NDCube (wavelength, coord1, coord2) for a given Stokes parameter"""

        # Construct the WCS object for the smaller 3D cube.
        # This function should only called if the
        d_sh = self.data.shape
        wcs_slice = [0] * self.wcs.pixel_n_dim
        wcs_slice[0] = stokes_ix
        wcs_slice[1] = slice(0, d_sh[1])
        wcs_slice[2] = slice(0, d_sh[2])
        wcs_slice[3] = slice(0, d_sh[3])
        #print(wcs_slice)
        wcs_slice = SlicedLowLevelWCS(self.wcs.low_level_wcs, wcs_slice)
        #newcube = StokesParamCube(self.data[stokes_ix,:,:,:], HighLevelWCSWrapper(wcs_slice), self._stokes_axis[stokes_ix])
        #cube_meta = {'stokes': self._stokes_axis[stokes_ix]}

        cube_meta = self.meta.copy()
        cube_meta['stokes'] = self._stokes_axis[stokes_ix]
        newcube = StokesParamCube(self.data[stokes_ix, :, :, :],
                                  HighLevelWCSWrapper(wcs_slice),
                                  meta=cube_meta)

        # Normalize the spectra if wanted.
        if stokes_ix != 0:
            if self.normalize is True:
                # Normalize by I
                I = self._stokes_slice(0)
                newcube = StokesParamCube(newcube.data / I.data,
                                          newcube.wcs,
                                          self._stokes_axis[stokes_ix],
                                          meta=newcube.meta)
            elif self.normalize:
                # normalize by non-zero float
                # TODO: sanity check input
                newcube = StokesParamCube(newcube.data / self.normalize,
                                          newcube.wcs,
                                          self._stokes_axis[stokes_ix],
                                          meta=newcube.meta)

        #newcube.meta = {'stokes': self._stokes_axis[stokes_ix]}

        return newcube
Esempio n. 10
0
def test_stokes_wrapper(gwcs_stokes_lookup):
    pytest.importorskip("astropy", minversion="4.0dev0")

    hlvl = HighLevelWCSWrapper(gwcs_stokes_lookup)

    pixel_input = [0, 1, 2, 3]

    out = hlvl.pixel_to_world(pixel_input * u.pix)

    assert list(out) == ['I', 'Q', 'U', 'V']

    pixel_input = [
        [0, 1, 2, 3],
        [0, 1, 2, 3],
        [0, 1, 2, 3],
        [0, 1, 2, 3],
    ]

    out = hlvl.pixel_to_world(pixel_input * u.pix)

    expected = np.array([['I', 'Q', 'U', 'V'], ['I', 'Q', 'U', 'V'],
                         ['I', 'Q', 'U', 'V'], ['I', 'Q', 'U', 'V']],
                        dtype=object)

    assert (out == expected).all()

    pixel_input = [-1, 4]

    out = hlvl.pixel_to_world(pixel_input * u.pix)

    assert np.isnan(out).all()

    pixel_input = [[-1, 4], [1, 2]]

    out = hlvl.pixel_to_world(pixel_input * u.pix)

    assert np.isnan(np.array(out[0], dtype=float)).all()
    assert (out[1] == np.array(['Q', 'U'], dtype=object)).all()

    out = hlvl.pixel_to_world(1 * u.pix)

    assert out == 'Q'
Esempio n. 11
0
File: cube.py Progetto: sunpy/ndcube
def get_crop_item_from_points(points, wcs, crop_by_values):
    """
    Find slice item that crops to minimum cube in array-space containing specified world points.

    Parameters
    ----------
    points : iterable of iterables
        Each iterable represents a point in real world space.
        Each element in a point gives the real world coordinate value of the point
        in high-level coordinate objects or quantities.
        (Must be consistenly high or low level within and across points.)
        Objects must be in the order required by
        wcs.world_to_array_index/world_to_array_index_values.

    wcs : `~astropy.wcs.wcsapi.BaseHighLevelWCS`, `~astropy.wcs.wcsapi.BaseLowLevelWCS`
        The WCS to use to convert the world coordinates to array indices.

    crop_by_values : `bool`
        Denotes whether cropping is done using high-level objects or "values",
        i.e. low-level objects.

    Returns
    -------
    item : `tuple` of `slice`
        The slice item for each axis of the cube which, when applied to the cube,
        will return the minimum cube in array-index-space that contains all the
        input world points.
    """
    # Define a list of lists to hold the array indices of the points
    # where each inner list gives the index of all points for that array axis.
    combined_points_array_idx = [[]] * wcs.pixel_n_dim
    # For each point compute the corresponding array indices.
    for point in points:
        # Get the arrays axes associated with each element in point.
        if crop_by_values:
            point_inputs_array_axes = []
            for i in range(wcs.world_n_dim):
                pix_axes = np.array(
                    wcs_utils.world_axis_to_pixel_axes(
                        i, wcs.axis_correlation_matrix))
                point_inputs_array_axes.append(
                    tuple(
                        wcs_utils.convert_between_array_and_pixel_axes(
                            pix_axes, wcs.pixel_n_dim)))
            point_inputs_array_axes = tuple(point_inputs_array_axes)
        else:
            point_inputs_array_axes = wcs_utils.array_indices_for_world_objects(
                HighLevelWCSWrapper(wcs))
        # Get indices of array axes which correspond to only None inputs in point
        # as well as those that correspond to a coord.
        point_indices_with_inputs = []
        array_axes_with_input = []
        for i, coord in enumerate(point):
            if coord is not None:
                point_indices_with_inputs.append(i)
                array_axes_with_input.append(point_inputs_array_axes[i])
        array_axes_with_input = set(chain.from_iterable(array_axes_with_input))
        array_axes_without_input = set(range(
            wcs.pixel_n_dim)) - array_axes_with_input
        # Slice out the axes that do not correspond to a coord
        # from the WCS and the input point.
        wcs_slice = np.array([slice(None)] * wcs.pixel_n_dim)
        if len(array_axes_without_input):
            wcs_slice[np.array(list(array_axes_without_input))] = 0
        sliced_wcs = SlicedLowLevelWCS(wcs, slices=tuple(wcs_slice))
        sliced_point = np.array(
            point, dtype=object)[np.array(point_indices_with_inputs)]
        # Derive the array indices of the input point and place each index
        # in the list corresponding to its axis.
        if crop_by_values:
            point_array_indices = sliced_wcs.world_to_array_index_values(
                *sliced_point)
            # If returned value is a 0-d array, convert to a length-1 tuple.
            if isinstance(point_array_indices,
                          np.ndarray) and point_array_indices.ndim == 0:
                point_array_indices = (point_array_indices.item(), )
            else:
                # Convert from scalar arrays to scalars
                point_array_indices = tuple(a.item()
                                            for a in point_array_indices)
        else:
            point_array_indices = HighLevelWCSWrapper(
                sliced_wcs).world_to_array_index(*sliced_point)
            # If returned value is a 0-d array, convert to a length-1 tuple.
            if isinstance(point_array_indices,
                          np.ndarray) and point_array_indices.ndim == 0:
                point_array_indices = (point_array_indices.item(), )
        for axis, index in zip(array_axes_with_input, point_array_indices):
            combined_points_array_idx[
                axis] = combined_points_array_idx[axis] + [index]
    # Define slice item with which to slice cube.
    item = []
    result_is_scalar = True
    for axis_indices in combined_points_array_idx:
        if axis_indices == []:
            result_is_scalar = False
            item.append(slice(None))
        else:
            min_idx = min(axis_indices)
            max_idx = max(axis_indices) + 1
            if max_idx - min_idx == 1:
                item.append(min_idx)
            else:
                item.append(slice(min_idx, max_idx))
                result_is_scalar = False
    # If item will result in a scalar cube, raise an error as this is not currently supported.
    if result_is_scalar:
        raise ValueError(
            "Input points causes cube to be cropped to a single pixel. "
            "This is not supported.")
    return tuple(item)
Esempio n. 12
0
def as_high_level_wcs(wcs):
    return HighLevelWCSWrapper(SlicedLowLevelWCS(wcs, Ellipsis))
Esempio n. 13
0
    def __init__(self, data1=None, data2=None, cids1=None, cids2=None):

        wcs1, wcs2 = data1.coords, data2.coords

        forwards = backwards = None
        if wcs1.pixel_n_dim == wcs2.pixel_n_dim and wcs1.world_n_dim == wcs2.world_n_dim:
            if (wcs1.world_axis_physical_types.count(None) == 0
                    and wcs2.world_axis_physical_types.count(None) == 0):

                # The easiest way to check if the WCSes are compatible is to simply try and
                # see if values can be transformed for a single pixel. In future we might
                # find that this requires optimization performance-wise, but for now let's
                # not do premature optimization.

                pixel_cids1, pixel_cids2, forwards, backwards = get_cids_and_functions(
                    wcs1, wcs2, data1.pixel_component_ids[::-1],
                    data2.pixel_component_ids[::-1])

                self._physical_types_1 = wcs1.world_axis_physical_types
                self._physical_types_2 = wcs2.world_axis_physical_types

        if not forwards or not backwards:
            # A generalized APE 14-compatible way
            # Handle also the extra-spatial axes such as those of the time and wavelength dimensions

            wcs1_celestial_physical_types = wcs2_celestial_physical_types = []

            slicing_axes1 = slicing_axes2 = []

            cids1 = data1.pixel_component_ids
            cids2 = data2.pixel_component_ids

            if wcs1.has_celestial and wcs2.has_celestial:
                wcs1_celestial_physical_types = wcs1.celestial.world_axis_physical_types
                wcs2_celestial_physical_types = wcs2.celestial.world_axis_physical_types

                cids1_celestial = [
                    cids1[wcs1.wcs.naxis - wcs1.wcs.lng - 1],
                    cids1[wcs1.wcs.naxis - wcs1.wcs.lat - 1]
                ]
                cids2_celestial = [
                    cids2[wcs2.wcs.naxis - wcs2.wcs.lng - 1],
                    cids2[wcs2.wcs.naxis - wcs2.wcs.lat - 1]
                ]

                if wcs1.celestial.wcs.lng > wcs1.celestial.wcs.lat:
                    cids1_celestial = cids1_celestial[::-1]

                if wcs2.celestial.wcs.lng > wcs2.celestial.wcs.lat:
                    cids2_celestial = cids2_celestial[::-1]

                slicing_axes1 = [
                    cids1_celestial[0].axis, cids1_celestial[1].axis
                ]
                slicing_axes2 = [
                    cids2_celestial[0].axis, cids2_celestial[1].axis
                ]

            wcs1_sliced_physical_types = wcs2_sliced_physical_types = []

            if wcs1_celestial_physical_types is not None:
                wcs1_sliced_physical_types = wcs1_celestial_physical_types

            if wcs2_celestial_physical_types is not None:
                wcs2_sliced_physical_types = wcs2_celestial_physical_types

            for i, physical_type1 in enumerate(wcs1.world_axis_physical_types):
                for j, physical_type2 in enumerate(
                        wcs2.world_axis_physical_types):
                    if physical_type1 == physical_type2:
                        if physical_type1 not in wcs1_sliced_physical_types:
                            slicing_axes1.append(wcs1.world_n_dim - i - 1)
                            wcs1_sliced_physical_types.append(physical_type1)
                        if physical_type2 not in wcs2_sliced_physical_types:
                            slicing_axes2.append(wcs2.world_n_dim - j - 1)
                            wcs2_sliced_physical_types.append(physical_type2)

            slicing_axes1 = sorted(slicing_axes1, key=str, reverse=True)
            slicing_axes2 = sorted(slicing_axes2, key=str, reverse=True)

            # Generate slices for the wcs slicing
            slices1 = [slice(None)] * wcs1.world_n_dim
            slices2 = [slice(None)] * wcs2.world_n_dim

            for i in range(wcs1.world_n_dim):
                if i not in slicing_axes1:
                    slices1[i] = 0

            for j in range(wcs2.world_n_dim):
                if j not in slicing_axes2:
                    slices2[j] = 0

            wcs1_sliced = SlicedLowLevelWCS(wcs1, tuple(slices1))
            wcs2_sliced = SlicedLowLevelWCS(wcs2, tuple(slices2))
            wcs1_final = HighLevelWCSWrapper(copy.copy(wcs1_sliced))
            wcs2_final = HighLevelWCSWrapper(copy.copy(wcs2_sliced))

            cids1_sliced = [cids1[x] for x in slicing_axes1]
            cids1_sliced = sorted(cids1_sliced, key=str, reverse=True)

            cids2_sliced = [cids2[x] for x in slicing_axes2]
            cids2_sliced = sorted(cids2_sliced, key=str, reverse=True)

            pixel_cids1, pixel_cids2, forwards, backwards = get_cids_and_functions(
                wcs1_final, wcs2_final, cids1_sliced, cids2_sliced)

            self._physical_types_1 = wcs1_sliced_physical_types
            self._physical_types_2 = wcs2_sliced_physical_types

        if pixel_cids1 is None:
            raise IncompatibleWCS(
                "Can't create WCS link between {0} and {1}".format(
                    data1.label, data2.label))

        super(WCSLink, self).__init__(pixel_cids1,
                                      pixel_cids2,
                                      forwards=forwards,
                                      backwards=backwards)

        self.data1 = data1
        self.data2 = data2
Esempio n. 14
0
def test_celestial_spectral_ape14(spectral_wcs, celestial_wcs):

    wcs = CompoundLowLevelWCS(spectral_wcs, celestial_wcs)

    assert wcs.pixel_n_dim == 3
    assert wcs.world_n_dim == 3
    assert tuple(wcs.world_axis_physical_types) == ('em.freq', 'pos.eq.ra',
                                                    'pos.eq.dec')
    assert tuple(wcs.world_axis_units) == ('Hz', 'deg', 'deg')
    assert tuple(wcs.pixel_axis_names) == ('', '', '')
    assert tuple(wcs.world_axis_names) == ('Frequency', 'Right Ascension',
                                           'Declination')
    assert_equal(wcs.axis_correlation_matrix,
                 np.array([[1, 0, 0], [0, 1, 1], [0, 1, 1]]))

    # If any of the individual shapes are None, return None overall
    assert wcs.pixel_shape is None
    assert wcs.array_shape is None
    assert wcs.pixel_bounds is None

    # Set the shape and bounds on the spectrum and test again
    spectral_wcs.pixel_shape = (3, )
    spectral_wcs.pixel_bounds = [(1, 2)]
    assert wcs.pixel_shape == (3, 6, 7)
    assert wcs.array_shape == (7, 6, 3)
    assert wcs.pixel_bounds == ((1, 2), (-1, 5), (1, 7))

    pixel_scalar = (2.3, 4.3, 1.3)
    world_scalar = (-1.91e10, 5.4, -9.4)
    assert_allclose(wcs.pixel_to_world_values(*pixel_scalar), world_scalar)
    assert_allclose(wcs.array_index_to_world_values(*pixel_scalar[::-1]),
                    world_scalar)
    assert_allclose(wcs.world_to_pixel_values(*world_scalar), pixel_scalar)
    assert_allclose(wcs.world_to_array_index_values(*world_scalar), [1, 4, 2])

    pixel_array = (np.array([2.3, 2.4]), np.array([4.3,
                                                   4.4]), np.array([1.3, 1.4]))
    world_array = (np.array([-1.91e10, -1.88e10]), np.array([5.4, 5.2]),
                   np.array([-9.4, -9.2]))
    assert_allclose(wcs.pixel_to_world_values(*pixel_array), world_array)
    assert_allclose(wcs.array_index_to_world_values(*pixel_array[::-1]),
                    world_array)
    assert_allclose(wcs.world_to_pixel_values(*world_array), pixel_array)
    assert_allclose(wcs.world_to_array_index_values(*world_array),
                    [[1, 1], [4, 4], [2, 2]])

    wcs_hl = HighLevelWCSWrapper(wcs)

    spectral, celestial = wcs_hl.pixel_to_world(*pixel_scalar)
    assert isinstance(spectral, Quantity)
    assert_quantity_allclose(spectral, world_scalar[0] * u.Hz)
    assert isinstance(celestial, SkyCoord)
    assert_quantity_allclose(celestial.ra, world_scalar[1] * u.deg)
    assert_quantity_allclose(celestial.dec, world_scalar[2] * u.deg)

    spectral, celestial = wcs_hl.pixel_to_world(*pixel_array)
    assert isinstance(spectral, Quantity)
    assert_quantity_allclose(spectral, world_array[0] * u.Hz)
    assert isinstance(celestial, SkyCoord)
    assert_quantity_allclose(celestial.ra, world_array[1] * u.deg)
    assert_quantity_allclose(celestial.dec, world_array[2] * u.deg)

    assert str(wcs) == EXPECTED_CELESTIAL_SPECTRAL_APE14_REPR
    assert EXPECTED_CELESTIAL_SPECTRAL_APE14_REPR in repr(wcs)