kwarray.util_slices module

Utilities related to slicing

References

https://stackoverflow.com/questions/41153803/zero-padding-slice-past-end-of-array-in-numpy

Todo

  • [ ] Could have a kwarray function to expose this inverse slice

    functionality. Also having a top-level call to apply an embedded slice would be good.

kwarray.util_slices.padded_slice(data, slices, pad=None, padkw=None, return_info=False)[source]

Allows slices with out-of-bound coordinates. Any out of bounds coordinate will be sampled via padding.

Parameters:
  • data (Sliceable) – data to slice into. Any channels must be the last dimension.

  • slices (slice | Tuple[slice, …]) – slice for each dimensions

  • ndim (int) – number of spatial dimensions

  • pad (List[int|Tuple]) – additional padding of the slice

  • padkw (Dict) – if unspecified defaults to {'mode': 'constant'}

  • return_info (bool, default=False) – if True, return extra information about the transform.

Note

Negative slices have a different meaning here then they usually do. Normally, they indicate a wrap-around or a reversed stride, but here they index into out-of-bounds space (which depends on the pad mode). For example a slice of -2:1 literally samples two pixels to the left of the data and one pixel from the data, so you get two padded values and one data value.

SeeAlso:

embed_slice - finds the embedded slice and padding

Returns:

data_sliced: subregion of the input data (possibly with padding,

depending on if the original slice went out of bounds)

Tuple[Sliceable, Dict] :

data_sliced : as above

transform : information on how to return to the original coordinates

Currently a dict containing:
st_dims: a list indicating the low and high space-time

coordinate values of the returned data slice.

The structure of this dictionary mach change in the future

Return type:

Sliceable

Example

>>> import kwarray
>>> data = np.arange(5)
>>> slices = [slice(-2, 7)]
>>> data_sliced = kwarray.padded_slice(data, slices)
>>> print(ub.urepr(data_sliced, with_dtype=False))
np.array([0, 0, 0, 1, 2, 3, 4, 0, 0])
>>> data_sliced = kwarray.padded_slice(data, slices, pad=[(3, 3)])
>>> print(ub.urepr(data_sliced, with_dtype=False))
np.array([0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 0])
>>> data_sliced = kwarray.padded_slice(data, slice(3, 4), pad=[(1, 0)])
>>> print(ub.urepr(data_sliced, with_dtype=False))
np.array([2, 3])
kwarray.util_slices.apply_embedded_slice(data, data_slice, extra_padding, **padkw)[source]

Apply a precomputed embedded slice.

This is used as a subroutine in padded_slice.

Parameters:
  • data (ndarray) – data to slice

  • data_slice (Tuple[slice])

  • extra_padding (Tuple[slice])

Returns:

ndarray

kwarray.util_slices._apply_padding(array, pad_width, **padkw)[source]

Alternative to numpy pad with different short-cut semantics for the “pad_width” argument.

Unlike numpy pad, you must specify a (start, stop) tuple for each dimension. The shortcut is that you only need to specify this for the leading dimensions. Any unspecified trailing dimension will get an implicit (0, 0) padding.

TODO: does this get exposed as a public function?

kwarray.util_slices.embed_slice(slices, data_dims, pad=None)[source]

Embeds a “padded-slice” inside known data dimension.

Returns the valid data portion of the slice with extra padding for regions outside of the available dimension.

Given a slices for each dimension, image dimensions, and a padding get the corresponding slice from the image and any extra padding needed to achieve the requested window size.

Todo

  • [ ] Add the option to return the inverse slice

Parameters:
  • slices (Tuple[slice, …]) – a tuple of slices for to apply to data data dimension.

  • data_dims (Tuple[int, …]) – n-dimension data sizes (e.g. 2d height, width)

  • pad (int | List[int | Tuple[int, int]]) – extra pad applied to (start / end) / (both) sides of each slice dim

Returns:

data_slice - Tuple[slice] a slice that can be applied to an array

with with shape data_dims. This slice will not correspond to the full window size if the requested slice is out of bounds.

extra_padding - extra padding needed after slicing to achieve

the requested window size.

Return type:

Tuple

Example

>>> # Case where slice is inside the data dims on left edge
>>> import kwarray
>>> slices = (slice(0, 10), slice(0, 10))
>>> data_dims  = [300, 300]
>>> pad        = [10, 5]
>>> a, b = kwarray.embed_slice(slices, data_dims, pad)
>>> print('data_slice = {!r}'.format(a))
>>> print('extra_padding = {!r}'.format(b))
data_slice = (slice(0, 20, None), slice(0, 15, None))
extra_padding = [(10, 0), (5, 0)]

Example

>>> # Case where slice is bigger than the image
>>> import kwarray
>>> slices = (slice(-10, 400), slice(-10, 400))
>>> data_dims  = [300, 300]
>>> pad        = [10, 5]
>>> a, b = kwarray.embed_slice(slices, data_dims, pad)
>>> print('data_slice = {!r}'.format(a))
>>> print('extra_padding = {!r}'.format(b))
data_slice = (slice(0, 300, None), slice(0, 300, None))
extra_padding = [(20, 110), (15, 105)]

Example

>>> # Case where slice is inside than the image
>>> import kwarray
>>> slices = (slice(10, 40), slice(10, 40))
>>> data_dims  = [300, 300]
>>> pad        = None
>>> a, b = kwarray.embed_slice(slices, data_dims, pad)
>>> print('data_slice = {!r}'.format(a))
>>> print('extra_padding = {!r}'.format(b))
data_slice = (slice(10, 40, None), slice(10, 40, None))
extra_padding = [(0, 0), (0, 0)]

Example

>>> # Test error cases
>>> import kwarray
>>> import pytest
>>> slices = (slice(0, 40), slice(10, 40))
>>> data_dims  = [300, 300]
>>> with pytest.raises(ValueError):
>>>     kwarray.embed_slice(slices, data_dims[0:1])
>>> with pytest.raises(ValueError):
>>>     kwarray.embed_slice(slices[0:1], data_dims)
>>> with pytest.raises(ValueError):
>>>     kwarray.embed_slice(slices, data_dims, pad=[(1, 1)])
>>> with pytest.raises(ValueError):
>>>     kwarray.embed_slice(slices, data_dims, pad=[1])
kwarray.util_slices._coerce_pad(pad, ndims)[source]