Skip to main content
`Ctrl`+`K`

# Slicing and Indexing NDData

## Introduction

This page only deals with peculiarities that apply to `NDData`-like classes. For a tutorial about slicing/indexing see the python documentation and numpy documentation.

Warning

`NDData` and `NDDataRef` enforce almost no restrictions on the properties, so it might happen that some valid but unusual combinations of properties always result in an IndexError or incorrect results. In this case, see Subclassing on how to customize slicing for a particular property.

## Slicing NDDataRef

Unlike `NDData` the class `NDDataRef` implements slicing or indexing. The result will be wrapped inside the same class as the sliced object.

Getting one element:

    >>> import numpy as np
    >>> from astropy.nddata import NDDataRef

    >>> data = np.array([1, 2, 3, 4])
    >>> ndd = NDDataRef(data)
    >>> ndd[1]
    NDDataRef(2)

Getting a sliced portion of the original:

    >>> ndd[1:3]  # Get element 1 (inclusive) to 3 (exclusive)
    NDDataRef([2, 3])

This will return a reference (and as such not a copy) of the original properties, so changing a slice will affect the original:

    >>> ndd_sliced = ndd[1:3]
    >>> ndd_sliced.data[0] = 5
    >>> ndd_sliced
    NDDataRef([5, 3])
    >>> ndd
    NDDataRef([1, 5, 3, 4])

But only the one element that was indexed is affected (for example, `ndd_sliced = ndd[1]`). The element is a scalar and changes will not propagate to the original.

## Slicing NDDataRef Including Attributes

In the case that a `mask`, or `uncertainty` is present, this attribute will be sliced too:

    >>> from astropy.nddata import StdDevUncertainty
    >>> data = np.array([1, 2, 3, 4])
    >>> mask = data > 2
    >>> uncertainty = StdDevUncertainty(np.sqrt(data))
    >>> ndd = NDDataRef(data, mask=mask, uncertainty=uncertainty)
    >>> ndd_sliced = ndd[1:3]

    >>> ndd_sliced.data
    array([2, 3])

    >>> ndd_sliced.mask
    array([False,  True]...)

    >>> ndd_sliced.uncertainty
    StdDevUncertainty([1.41421356, 1.73205081])

`unit` and `meta`, however, will be unaffected.

If any of the attributes are set but do not implement slicing, an info will be printed and the property will be kept as is:

    >>> data = np.array([1, 2, 3, 4])
    >>> mask = False
    >>> uncertainty = StdDevUncertainty(0)
    >>> ndd = NDDataRef(data, mask=mask, uncertainty=uncertainty)
    >>> ndd_sliced = ndd[1:3]
    INFO: uncertainty cannot be sliced. [astropy.nddata.mixins.ndslicing]
    INFO: mask cannot be sliced. [astropy.nddata.mixins.ndslicing]

    >>> ndd_sliced.mask
    False

### Slicing NDData with World Coordinates

If `wcs` is set, it must be either implement `BaseLowLevelWCS` or `BaseHighLevelWCS`. This means that only integer or range slices without a step are supported. So slices like `[::10]` or array or boolean based slices will not work.

If you want to slice an `NDData` object called `ndd` without the WCS you can remove the WCS from the `NDData` object by running:

    >>> ndd.wcs = None

### Removing Masked Data

Warning

If `wcs` is set this will NOT be possible. But you can work around this by setting the wcs attribute to `None` with `ndd.wcs = None` before slicing.

By convention, the `mask` attribute indicates if a point is valid or invalid. So we are able to get all valid data points by slicing with the mask.

#### Examples

To get all of the valid data points by slicing with the mask:

    >>> data = np.array([[1,2,3],[4,5,6],[7,8,9]])
    >>> mask = np.array([[0,1,0],[1,1,1],[0,0,1]], dtype=bool)
    >>> uncertainty = StdDevUncertainty(np.sqrt(data))
    >>> ndd = NDDataRef(data, mask=mask, uncertainty=uncertainty)
    >>> # don't forget that ~ or you'll get the invalid points
    >>> ndd_sliced = ndd[~ndd.mask]
    >>> ndd_sliced
    NDDataRef([1, 3, 7, 8])

    >>> ndd_sliced.mask
    array([False, False, False, False]...)

    >>> ndd_sliced.uncertainty
    StdDevUncertainty([1.        , 1.73205081, 2.64575131, 2.82842712])

Or all invalid points:

    >>> ndd_sliced = ndd[ndd.mask] # without the ~ now!
    >>> ndd_sliced
    NDDataRef([—, —, —, —, —])

    >>> ndd_sliced.mask
    array([ True,  True,  True,  True,  True]...)

    >>> ndd_sliced.uncertainty
    StdDevUncertainty([1.41421356, 2.        , 2.23606798, 2.44948974, 3.        ])

Note

The result of this kind of indexing (boolean indexing) will always be one-dimensional!