Buckets:
| """ | |
| The arraypad module contains a group of functions to pad values onto the edges | |
| of an n-dimensional array. | |
| """ | |
| import typing | |
| import numpy as np | |
| from numpy._core.overrides import array_function_dispatch | |
| from numpy.lib._index_tricks_impl import ndindex | |
| __all__ = ['pad'] | |
| ############################################################################### | |
| # Private utility functions. | |
| def _round_if_needed(arr, dtype): | |
| """ | |
| Rounds arr inplace if destination dtype is integer. | |
| Parameters | |
| ---------- | |
| arr : ndarray | |
| Input array. | |
| dtype : dtype | |
| The dtype of the destination array. | |
| """ | |
| if np.issubdtype(dtype, np.integer): | |
| arr.round(out=arr) | |
| def _slice_at_axis(sl, axis): | |
| """ | |
| Construct tuple of slices to slice an array in the given dimension. | |
| Parameters | |
| ---------- | |
| sl : slice | |
| The slice for the given dimension. | |
| axis : int | |
| The axis to which `sl` is applied. All other dimensions are left | |
| "unsliced". | |
| Returns | |
| ------- | |
| sl : tuple of slices | |
| A tuple with slices matching `shape` in length. | |
| Examples | |
| -------- | |
| >>> np._slice_at_axis(slice(None, 3, -1), 1) | |
| (slice(None, None, None), slice(None, 3, -1), (...,)) | |
| """ | |
| return (slice(None),) * axis + (sl,) + (...,) | |
| def _view_roi(array, original_area_slice, axis): | |
| """ | |
| Get a view of the current region of interest during iterative padding. | |
| When padding multiple dimensions iteratively corner values are | |
| unnecessarily overwritten multiple times. This function reduces the | |
| working area for the first dimensions so that corners are excluded. | |
| Parameters | |
| ---------- | |
| array : ndarray | |
| The array with the region of interest. | |
| original_area_slice : tuple of slices | |
| Denotes the area with original values of the unpadded array. | |
| axis : int | |
| The currently padded dimension assuming that `axis` is padded before | |
| `axis` + 1. | |
| Returns | |
| ------- | |
| roi : ndarray | |
| The region of interest of the original `array`. | |
| """ | |
| axis += 1 | |
| sl = (slice(None),) * axis + original_area_slice[axis:] | |
| return array[sl] | |
| def _pad_simple(array, pad_width, fill_value=None): | |
| """ | |
| Pad array on all sides with either a single value or undefined values. | |
| Parameters | |
| ---------- | |
| array : ndarray | |
| Array to grow. | |
| pad_width : sequence of tuple[int, int] | |
| Pad width on both sides for each dimension in `arr`. | |
| fill_value : scalar, optional | |
| If provided the padded area is filled with this value, otherwise | |
| the pad area left undefined. | |
| Returns | |
| ------- | |
| padded : ndarray | |
| The padded array with the same dtype as`array`. Its order will default | |
| to C-style if `array` is not F-contiguous. | |
| original_area_slice : tuple | |
| A tuple of slices pointing to the area of the original array. | |
| """ | |
| # Allocate grown array | |
| new_shape = tuple( | |
| left + size + right | |
| for size, (left, right) in zip(array.shape, pad_width) | |
| ) | |
| order = 'F' if array.flags.fnc else 'C' # Fortran and not also C-order | |
| padded = np.empty(new_shape, dtype=array.dtype, order=order) | |
| if fill_value is not None: | |
| padded.fill(fill_value) | |
| # Copy old array into correct space | |
| original_area_slice = tuple( | |
| slice(left, left + size) | |
| for size, (left, right) in zip(array.shape, pad_width) | |
| ) | |
| padded[original_area_slice] = array | |
| return padded, original_area_slice | |
| def _set_pad_area(padded, axis, width_pair, value_pair): | |
| """ | |
| Set empty-padded area in given dimension. | |
| Parameters | |
| ---------- | |
| padded : ndarray | |
| Array with the pad area which is modified inplace. | |
| axis : int | |
| Dimension with the pad area to set. | |
| width_pair : (int, int) | |
| Pair of widths that mark the pad area on both sides in the given | |
| dimension. | |
| value_pair : tuple of scalars or ndarrays | |
| Values inserted into the pad area on each side. It must match or be | |
| broadcastable to the shape of `arr`. | |
| """ | |
| left_slice = _slice_at_axis(slice(None, width_pair[0]), axis) | |
| padded[left_slice] = value_pair[0] | |
| right_slice = _slice_at_axis( | |
| slice(padded.shape[axis] - width_pair[1], None), axis) | |
| padded[right_slice] = value_pair[1] | |
| def _get_edges(padded, axis, width_pair): | |
| """ | |
| Retrieve edge values from empty-padded array in given dimension. | |
| Parameters | |
| ---------- | |
| padded : ndarray | |
| Empty-padded array. | |
| axis : int | |
| Dimension in which the edges are considered. | |
| width_pair : (int, int) | |
| Pair of widths that mark the pad area on both sides in the given | |
| dimension. | |
| Returns | |
| ------- | |
| left_edge, right_edge : ndarray | |
| Edge values of the valid area in `padded` in the given dimension. Its | |
| shape will always match `padded` except for the dimension given by | |
| `axis` which will have a length of 1. | |
| """ | |
| left_index = width_pair[0] | |
| left_slice = _slice_at_axis(slice(left_index, left_index + 1), axis) | |
| left_edge = padded[left_slice] | |
| right_index = padded.shape[axis] - width_pair[1] | |
| right_slice = _slice_at_axis(slice(right_index - 1, right_index), axis) | |
| right_edge = padded[right_slice] | |
| return left_edge, right_edge | |
| def _get_linear_ramps(padded, axis, width_pair, end_value_pair): | |
| """ | |
| Construct linear ramps for empty-padded array in given dimension. | |
| Parameters | |
| ---------- | |
| padded : ndarray | |
| Empty-padded array. | |
| axis : int | |
| Dimension in which the ramps are constructed. | |
| width_pair : (int, int) | |
| Pair of widths that mark the pad area on both sides in the given | |
| dimension. | |
| end_value_pair : (scalar, scalar) | |
| End values for the linear ramps which form the edge of the fully padded | |
| array. These values are included in the linear ramps. | |
| Returns | |
| ------- | |
| left_ramp, right_ramp : ndarray | |
| Linear ramps to set on both sides of `padded`. | |
| """ | |
| edge_pair = _get_edges(padded, axis, width_pair) | |
| left_ramp, right_ramp = ( | |
| np.linspace( | |
| start=end_value, | |
| stop=edge.squeeze(axis), # Dimension is replaced by linspace | |
| num=width, | |
| endpoint=False, | |
| dtype=padded.dtype, | |
| axis=axis | |
| ) | |
| for end_value, edge, width in zip( | |
| end_value_pair, edge_pair, width_pair | |
| ) | |
| ) | |
| # Reverse linear space in appropriate dimension | |
| right_ramp = right_ramp[_slice_at_axis(slice(None, None, -1), axis)] | |
| return left_ramp, right_ramp | |
| def _get_stats(padded, axis, width_pair, length_pair, stat_func): | |
| """ | |
| Calculate statistic for the empty-padded array in given dimension. | |
| Parameters | |
| ---------- | |
| padded : ndarray | |
| Empty-padded array. | |
| axis : int | |
| Dimension in which the statistic is calculated. | |
| width_pair : (int, int) | |
| Pair of widths that mark the pad area on both sides in the given | |
| dimension. | |
| length_pair : 2-element sequence of None or int | |
| Gives the number of values in valid area from each side that is | |
| taken into account when calculating the statistic. If None the entire | |
| valid area in `padded` is considered. | |
| stat_func : function | |
| Function to compute statistic. The expected signature is | |
| ``stat_func(x: ndarray, axis: int, keepdims: bool) -> ndarray``. | |
| Returns | |
| ------- | |
| left_stat, right_stat : ndarray | |
| Calculated statistic for both sides of `padded`. | |
| """ | |
| # Calculate indices of the edges of the area with original values | |
| left_index = width_pair[0] | |
| right_index = padded.shape[axis] - width_pair[1] | |
| # as well as its length | |
| max_length = right_index - left_index | |
| # Limit stat_lengths to max_length | |
| left_length, right_length = length_pair | |
| if left_length is None or max_length < left_length: | |
| left_length = max_length | |
| if right_length is None or max_length < right_length: | |
| right_length = max_length | |
| if (left_length == 0 or right_length == 0) \ | |
| and stat_func in {np.amax, np.amin}: | |
| # amax and amin can't operate on an empty array, | |
| # raise a more descriptive warning here instead of the default one | |
| raise ValueError("stat_length of 0 yields no value for padding") | |
| # Calculate statistic for the left side | |
| left_slice = _slice_at_axis( | |
| slice(left_index, left_index + left_length), axis) | |
| left_chunk = padded[left_slice] | |
| left_stat = stat_func(left_chunk, axis=axis, keepdims=True) | |
| _round_if_needed(left_stat, padded.dtype) | |
| if left_length == right_length == max_length: | |
| # return early as right_stat must be identical to left_stat | |
| return left_stat, left_stat | |
| # Calculate statistic for the right side | |
| right_slice = _slice_at_axis( | |
| slice(right_index - right_length, right_index), axis) | |
| right_chunk = padded[right_slice] | |
| right_stat = stat_func(right_chunk, axis=axis, keepdims=True) | |
| _round_if_needed(right_stat, padded.dtype) | |
| return left_stat, right_stat | |
| def _set_reflect_both(padded, axis, width_pair, method, | |
| original_period, include_edge=False): | |
| """ | |
| Pad `axis` of `arr` with reflection. | |
| Parameters | |
| ---------- | |
| padded : ndarray | |
| Input array of arbitrary shape. | |
| axis : int | |
| Axis along which to pad `arr`. | |
| width_pair : (int, int) | |
| Pair of widths that mark the pad area on both sides in the given | |
| dimension. | |
| method : str | |
| Controls method of reflection; options are 'even' or 'odd'. | |
| original_period : int | |
| Original length of data on `axis` of `arr`. | |
| include_edge : bool | |
| If true, edge value is included in reflection, otherwise the edge | |
| value forms the symmetric axis to the reflection. | |
| Returns | |
| ------- | |
| pad_amt : tuple of ints, length 2 | |
| New index positions of padding to do along the `axis`. If these are | |
| both 0, padding is done in this dimension. | |
| """ | |
| left_pad, right_pad = width_pair | |
| old_length = padded.shape[axis] - right_pad - left_pad | |
| if include_edge: | |
| # Avoid wrapping with only a subset of the original area | |
| # by ensuring period can only be a multiple of the original | |
| # area's length. | |
| old_length = old_length // original_period * original_period | |
| # Edge is included, we need to offset the pad amount by 1 | |
| edge_offset = 1 | |
| else: | |
| # Avoid wrapping with only a subset of the original area | |
| # by ensuring period can only be a multiple of the original | |
| # area's length. | |
| old_length = ((old_length - 1) // (original_period - 1) | |
| * (original_period - 1) + 1) | |
| edge_offset = 0 # Edge is not included, no need to offset pad amount | |
| old_length -= 1 # but must be omitted from the chunk | |
| if left_pad > 0: | |
| # Pad with reflected values on left side: | |
| # First limit chunk size which can't be larger than pad area | |
| chunk_length = min(old_length, left_pad) | |
| # Slice right to left, stop on or next to edge, start relative to stop | |
| stop = left_pad - edge_offset | |
| start = stop + chunk_length | |
| left_slice = _slice_at_axis(slice(start, stop, -1), axis) | |
| left_chunk = padded[left_slice] | |
| if method == "odd": | |
| # Negate chunk and align with edge | |
| edge_slice = _slice_at_axis(slice(left_pad, left_pad + 1), axis) | |
| left_chunk = 2 * padded[edge_slice] - left_chunk | |
| # Insert chunk into padded area | |
| start = left_pad - chunk_length | |
| stop = left_pad | |
| pad_area = _slice_at_axis(slice(start, stop), axis) | |
| padded[pad_area] = left_chunk | |
| # Adjust pointer to left edge for next iteration | |
| left_pad -= chunk_length | |
| if right_pad > 0: | |
| # Pad with reflected values on right side: | |
| # First limit chunk size which can't be larger than pad area | |
| chunk_length = min(old_length, right_pad) | |
| # Slice right to left, start on or next to edge, stop relative to start | |
| start = -right_pad + edge_offset - 2 | |
| stop = start - chunk_length | |
| right_slice = _slice_at_axis(slice(start, stop, -1), axis) | |
| right_chunk = padded[right_slice] | |
| if method == "odd": | |
| # Negate chunk and align with edge | |
| edge_slice = _slice_at_axis( | |
| slice(-right_pad - 1, -right_pad), axis) | |
| right_chunk = 2 * padded[edge_slice] - right_chunk | |
| # Insert chunk into padded area | |
| start = padded.shape[axis] - right_pad | |
| stop = start + chunk_length | |
| pad_area = _slice_at_axis(slice(start, stop), axis) | |
| padded[pad_area] = right_chunk | |
| # Adjust pointer to right edge for next iteration | |
| right_pad -= chunk_length | |
| return left_pad, right_pad | |
| def _set_wrap_both(padded, axis, width_pair, original_period): | |
| """ | |
| Pad `axis` of `arr` with wrapped values. | |
| Parameters | |
| ---------- | |
| padded : ndarray | |
| Input array of arbitrary shape. | |
| axis : int | |
| Axis along which to pad `arr`. | |
| width_pair : (int, int) | |
| Pair of widths that mark the pad area on both sides in the given | |
| dimension. | |
| original_period : int | |
| Original length of data on `axis` of `arr`. | |
| Returns | |
| ------- | |
| pad_amt : tuple of ints, length 2 | |
| New index positions of padding to do along the `axis`. If these are | |
| both 0, padding is done in this dimension. | |
| """ | |
| left_pad, right_pad = width_pair | |
| period = padded.shape[axis] - right_pad - left_pad | |
| # Avoid wrapping with only a subset of the original area by ensuring period | |
| # can only be a multiple of the original area's length. | |
| period = period // original_period * original_period | |
| # If the current dimension of `arr` doesn't contain enough valid values | |
| # (not part of the undefined pad area) we need to pad multiple times. | |
| # Each time the pad area shrinks on both sides which is communicated with | |
| # these variables. | |
| new_left_pad = 0 | |
| new_right_pad = 0 | |
| if left_pad > 0: | |
| # Pad with wrapped values on left side | |
| # First slice chunk from left side of the non-pad area. | |
| # Use min(period, left_pad) to ensure that chunk is not larger than | |
| # pad area. | |
| slice_end = left_pad + period | |
| slice_start = slice_end - min(period, left_pad) | |
| right_slice = _slice_at_axis(slice(slice_start, slice_end), axis) | |
| right_chunk = padded[right_slice] | |
| if left_pad > period: | |
| # Chunk is smaller than pad area | |
| pad_area = _slice_at_axis(slice(left_pad - period, left_pad), axis) | |
| new_left_pad = left_pad - period | |
| else: | |
| # Chunk matches pad area | |
| pad_area = _slice_at_axis(slice(None, left_pad), axis) | |
| padded[pad_area] = right_chunk | |
| if right_pad > 0: | |
| # Pad with wrapped values on right side | |
| # First slice chunk from right side of the non-pad area. | |
| # Use min(period, right_pad) to ensure that chunk is not larger than | |
| # pad area. | |
| slice_start = -right_pad - period | |
| slice_end = slice_start + min(period, right_pad) | |
| left_slice = _slice_at_axis(slice(slice_start, slice_end), axis) | |
| left_chunk = padded[left_slice] | |
| if right_pad > period: | |
| # Chunk is smaller than pad area | |
| pad_area = _slice_at_axis( | |
| slice(-right_pad, -right_pad + period), axis) | |
| new_right_pad = right_pad - period | |
| else: | |
| # Chunk matches pad area | |
| pad_area = _slice_at_axis(slice(-right_pad, None), axis) | |
| padded[pad_area] = left_chunk | |
| return new_left_pad, new_right_pad | |
| def _as_pairs(x, ndim, as_index=False): | |
| """ | |
| Broadcast `x` to an array with the shape (`ndim`, 2). | |
| A helper function for `pad` that prepares and validates arguments like | |
| `pad_width` for iteration in pairs. | |
| Parameters | |
| ---------- | |
| x : {None, scalar, array-like} | |
| The object to broadcast to the shape (`ndim`, 2). | |
| ndim : int | |
| Number of pairs the broadcasted `x` will have. | |
| as_index : bool, optional | |
| If `x` is not None, try to round each element of `x` to an integer | |
| (dtype `np.intp`) and ensure every element is positive. | |
| Returns | |
| ------- | |
| pairs : nested iterables, shape (`ndim`, 2) | |
| The broadcasted version of `x`. | |
| Raises | |
| ------ | |
| ValueError | |
| If `as_index` is True and `x` contains negative elements. | |
| Or if `x` is not broadcastable to the shape (`ndim`, 2). | |
| """ | |
| if x is None: | |
| # Pass through None as a special case, otherwise np.round(x) fails | |
| # with an AttributeError | |
| return ((None, None),) * ndim | |
| x = np.array(x) | |
| if as_index: | |
| x = np.round(x).astype(np.intp, copy=False) | |
| if x.ndim < 3: | |
| # Optimization: Possibly use faster paths for cases where `x` has | |
| # only 1 or 2 elements. `np.broadcast_to` could handle these as well | |
| # but is currently slower | |
| if x.size == 1: | |
| # x was supplied as a single value | |
| x = x.ravel() # Ensure x[0] works for x.ndim == 0, 1, 2 | |
| if as_index and x < 0: | |
| raise ValueError("index can't contain negative values") | |
| return ((x[0], x[0]),) * ndim | |
| if x.size == 2 and x.shape != (2, 1): | |
| # x was supplied with a single value for each side | |
| # but except case when each dimension has a single value | |
| # which should be broadcasted to a pair, | |
| # e.g. [[1], [2]] -> [[1, 1], [2, 2]] not [[1, 2], [1, 2]] | |
| x = x.ravel() # Ensure x[0], x[1] works | |
| if as_index and (x[0] < 0 or x[1] < 0): | |
| raise ValueError("index can't contain negative values") | |
| return ((x[0], x[1]),) * ndim | |
| if as_index and x.min() < 0: | |
| raise ValueError("index can't contain negative values") | |
| # Converting the array with `tolist` seems to improve performance | |
| # when iterating and indexing the result (see usage in `pad`) | |
| return np.broadcast_to(x, (ndim, 2)).tolist() | |
| def _pad_dispatcher(array, pad_width, mode=None, **kwargs): | |
| return (array,) | |
| ############################################################################### | |
| # Public functions | |
| def pad(array, pad_width, mode='constant', **kwargs): | |
| """ | |
| Pad an array. | |
| Parameters | |
| ---------- | |
| array : array_like of rank N | |
| The array to pad. | |
| pad_width : {sequence, array_like, int, dict} | |
| Number of values padded to the edges of each axis. | |
| ``((before_1, after_1), ... (before_N, after_N))`` unique pad widths | |
| for each axis. | |
| ``(before, after)`` or ``((before, after),)`` yields same before | |
| and after pad for each axis. | |
| ``(pad,)`` or ``int`` is a shortcut for before = after = pad width | |
| for all axes. | |
| If a ``dict``, each key is an axis and its corresponding value is an ``int`` or | |
| ``int`` pair describing the padding ``(before, after)`` or ``pad`` width for | |
| that axis. | |
| mode : str or function, optional | |
| One of the following string values or a user supplied function. | |
| 'constant' (default) | |
| Pads with a constant value. | |
| 'edge' | |
| Pads with the edge values of array. | |
| 'linear_ramp' | |
| Pads with the linear ramp between end_value and the | |
| array edge value. | |
| 'maximum' | |
| Pads with the maximum value of all or part of the | |
| vector along each axis. | |
| 'mean' | |
| Pads with the mean value of all or part of the | |
| vector along each axis. | |
| 'median' | |
| Pads with the median value of all or part of the | |
| vector along each axis. | |
| 'minimum' | |
| Pads with the minimum value of all or part of the | |
| vector along each axis. | |
| 'reflect' | |
| Pads with the reflection of the vector mirrored on | |
| the first and last values of the vector along each | |
| axis. | |
| 'symmetric' | |
| Pads with the reflection of the vector mirrored | |
| along the edge of the array. | |
| 'wrap' | |
| Pads with the wrap of the vector along the axis. | |
| The first values are used to pad the end and the | |
| end values are used to pad the beginning. | |
| 'empty' | |
| Pads with undefined values. | |
| <function> | |
| Padding function, see Notes. | |
| stat_length : sequence or int, optional | |
| Used in 'maximum', 'mean', 'median', and 'minimum'. Number of | |
| values at edge of each axis used to calculate the statistic value. | |
| ``((before_1, after_1), ... (before_N, after_N))`` unique statistic | |
| lengths for each axis. | |
| ``(before, after)`` or ``((before, after),)`` yields same before | |
| and after statistic lengths for each axis. | |
| ``(stat_length,)`` or ``int`` is a shortcut for | |
| ``before = after = statistic`` length for all axes. | |
| Default is ``None``, to use the entire axis. | |
| constant_values : sequence or scalar, optional | |
| Used in 'constant'. The values to set the padded values for each | |
| axis. | |
| ``((before_1, after_1), ... (before_N, after_N))`` unique pad constants | |
| for each axis. | |
| ``(before, after)`` or ``((before, after),)`` yields same before | |
| and after constants for each axis. | |
| ``(constant,)`` or ``constant`` is a shortcut for | |
| ``before = after = constant`` for all axes. | |
| Default is 0. | |
| end_values : sequence or scalar, optional | |
| Used in 'linear_ramp'. The values used for the ending value of the | |
| linear_ramp and that will form the edge of the padded array. | |
| ``((before_1, after_1), ... (before_N, after_N))`` unique end values | |
| for each axis. | |
| ``(before, after)`` or ``((before, after),)`` yields same before | |
| and after end values for each axis. | |
| ``(constant,)`` or ``constant`` is a shortcut for | |
| ``before = after = constant`` for all axes. | |
| Default is 0. | |
| reflect_type : {'even', 'odd'}, optional | |
| Used in 'reflect', and 'symmetric'. The 'even' style is the | |
| default with an unaltered reflection around the edge value. For | |
| the 'odd' style, the extended part of the array is created by | |
| subtracting the reflected values from two times the edge value. | |
| Returns | |
| ------- | |
| pad : ndarray | |
| Padded array of rank equal to `array` with shape increased | |
| according to `pad_width`. | |
| Notes | |
| ----- | |
| For an array with rank greater than 1, some of the padding of later | |
| axes is calculated from padding of previous axes. This is easiest to | |
| think about with a rank 2 array where the corners of the padded array | |
| are calculated by using padded values from the first axis. | |
| The padding function, if used, should modify a rank 1 array in-place. It | |
| has the following signature:: | |
| padding_func(vector, iaxis_pad_width, iaxis, kwargs) | |
| where | |
| vector : ndarray | |
| A rank 1 array already padded with zeros. Padded values are | |
| vector[:iaxis_pad_width[0]] and vector[-iaxis_pad_width[1]:]. | |
| iaxis_pad_width : tuple | |
| A 2-tuple of ints, iaxis_pad_width[0] represents the number of | |
| values padded at the beginning of vector where | |
| iaxis_pad_width[1] represents the number of values padded at | |
| the end of vector. | |
| iaxis : int | |
| The axis currently being calculated. | |
| kwargs : dict | |
| Any keyword arguments the function requires. | |
| Examples | |
| -------- | |
| >>> import numpy as np | |
| >>> a = [1, 2, 3, 4, 5] | |
| >>> np.pad(a, (2, 3), 'constant', constant_values=(4, 6)) | |
| array([4, 4, 1, ..., 6, 6, 6]) | |
| >>> np.pad(a, (2, 3), 'edge') | |
| array([1, 1, 1, ..., 5, 5, 5]) | |
| >>> np.pad(a, (2, 3), 'linear_ramp', end_values=(5, -4)) | |
| array([ 5, 3, 1, 2, 3, 4, 5, 2, -1, -4]) | |
| >>> np.pad(a, (2,), 'maximum') | |
| array([5, 5, 1, 2, 3, 4, 5, 5, 5]) | |
| >>> np.pad(a, (2,), 'mean') | |
| array([3, 3, 1, 2, 3, 4, 5, 3, 3]) | |
| >>> np.pad(a, (2,), 'median') | |
| array([3, 3, 1, 2, 3, 4, 5, 3, 3]) | |
| >>> a = [[1, 2], [3, 4]] | |
| >>> np.pad(a, ((3, 2), (2, 3)), 'minimum') | |
| array([[1, 1, 1, 2, 1, 1, 1], | |
| [1, 1, 1, 2, 1, 1, 1], | |
| [1, 1, 1, 2, 1, 1, 1], | |
| [1, 1, 1, 2, 1, 1, 1], | |
| [3, 3, 3, 4, 3, 3, 3], | |
| [1, 1, 1, 2, 1, 1, 1], | |
| [1, 1, 1, 2, 1, 1, 1]]) | |
| >>> a = [1, 2, 3, 4, 5] | |
| >>> np.pad(a, (2, 3), 'reflect') | |
| array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2]) | |
| >>> np.pad(a, (2, 3), 'reflect', reflect_type='odd') | |
| array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]) | |
| >>> np.pad(a, (2, 3), 'symmetric') | |
| array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3]) | |
| >>> np.pad(a, (2, 3), 'symmetric', reflect_type='odd') | |
| array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7]) | |
| >>> np.pad(a, (2, 3), 'wrap') | |
| array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3]) | |
| >>> def pad_with(vector, pad_width, iaxis, kwargs): | |
| ... pad_value = kwargs.get('padder', 10) | |
| ... vector[:pad_width[0]] = pad_value | |
| ... vector[-pad_width[1]:] = pad_value | |
| >>> a = np.arange(6) | |
| >>> a = a.reshape((2, 3)) | |
| >>> np.pad(a, 2, pad_with) | |
| array([[10, 10, 10, 10, 10, 10, 10], | |
| [10, 10, 10, 10, 10, 10, 10], | |
| [10, 10, 0, 1, 2, 10, 10], | |
| [10, 10, 3, 4, 5, 10, 10], | |
| [10, 10, 10, 10, 10, 10, 10], | |
| [10, 10, 10, 10, 10, 10, 10]]) | |
| >>> np.pad(a, 2, pad_with, padder=100) | |
| array([[100, 100, 100, 100, 100, 100, 100], | |
| [100, 100, 100, 100, 100, 100, 100], | |
| [100, 100, 0, 1, 2, 100, 100], | |
| [100, 100, 3, 4, 5, 100, 100], | |
| [100, 100, 100, 100, 100, 100, 100], | |
| [100, 100, 100, 100, 100, 100, 100]]) | |
| >>> a = np.arange(1, 7).reshape(2, 3) | |
| >>> np.pad(a, {1: (1, 2)}) | |
| array([[0, 1, 2, 3, 0, 0], | |
| [0, 4, 5, 6, 0, 0]]) | |
| >>> np.pad(a, {-1: 2}) | |
| array([[0, 0, 1, 2, 3, 0, 0], | |
| [0, 0, 4, 5, 6, 0, 0]]) | |
| >>> np.pad(a, {0: (3, 0)}) | |
| array([[0, 0, 0], | |
| [0, 0, 0], | |
| [0, 0, 0], | |
| [1, 2, 3], | |
| [4, 5, 6]]) | |
| >>> np.pad(a, {0: (3, 0), 1: 2}) | |
| array([[0, 0, 0, 0, 0, 0, 0], | |
| [0, 0, 0, 0, 0, 0, 0], | |
| [0, 0, 0, 0, 0, 0, 0], | |
| [0, 0, 1, 2, 3, 0, 0], | |
| [0, 0, 4, 5, 6, 0, 0]]) | |
| """ | |
| array = np.asarray(array) | |
| if isinstance(pad_width, dict): | |
| seq = [(0, 0)] * array.ndim | |
| for axis, width in pad_width.items(): | |
| match width: | |
| case int(both): | |
| seq[axis] = both, both | |
| case tuple((int(before), int(after))): | |
| seq[axis] = before, after | |
| case _ as invalid: | |
| typing.assert_never(invalid) | |
| pad_width = seq | |
| pad_width = np.asarray(pad_width) | |
| if not pad_width.dtype.kind == 'i': | |
| raise TypeError('`pad_width` must be of integral type.') | |
| # Broadcast to shape (array.ndim, 2) | |
| pad_width = _as_pairs(pad_width, array.ndim, as_index=True) | |
| if callable(mode): | |
| # Old behavior: Use user-supplied function with np.apply_along_axis | |
| function = mode | |
| # Create a new zero padded array | |
| padded, _ = _pad_simple(array, pad_width, fill_value=0) | |
| # And apply along each axis | |
| for axis in range(padded.ndim): | |
| # Iterate using ndindex as in apply_along_axis, but assuming that | |
| # function operates inplace on the padded array. | |
| # view with the iteration axis at the end | |
| view = np.moveaxis(padded, axis, -1) | |
| # compute indices for the iteration axes, and append a trailing | |
| # ellipsis to prevent 0d arrays decaying to scalars (gh-8642) | |
| inds = ndindex(view.shape[:-1]) | |
| inds = (ind + (Ellipsis,) for ind in inds) | |
| for ind in inds: | |
| function(view[ind], pad_width[axis], axis, kwargs) | |
| return padded | |
| # Make sure that no unsupported keywords were passed for the current mode | |
| allowed_kwargs = { | |
| 'empty': [], 'edge': [], 'wrap': [], | |
| 'constant': ['constant_values'], | |
| 'linear_ramp': ['end_values'], | |
| 'maximum': ['stat_length'], | |
| 'mean': ['stat_length'], | |
| 'median': ['stat_length'], | |
| 'minimum': ['stat_length'], | |
| 'reflect': ['reflect_type'], | |
| 'symmetric': ['reflect_type'], | |
| } | |
| try: | |
| unsupported_kwargs = set(kwargs) - set(allowed_kwargs[mode]) | |
| except KeyError: | |
| raise ValueError(f"mode '{mode}' is not supported") from None | |
| if unsupported_kwargs: | |
| raise ValueError("unsupported keyword arguments for mode " | |
| f"'{mode}': {unsupported_kwargs}") | |
| stat_functions = {"maximum": np.amax, "minimum": np.amin, | |
| "mean": np.mean, "median": np.median} | |
| # Create array with final shape and original values | |
| # (padded area is undefined) | |
| padded, original_area_slice = _pad_simple(array, pad_width) | |
| # And prepare iteration over all dimensions | |
| # (zipping may be more readable than using enumerate) | |
| axes = range(padded.ndim) | |
| if mode == "constant": | |
| values = kwargs.get("constant_values", 0) | |
| values = _as_pairs(values, padded.ndim) | |
| for axis, width_pair, value_pair in zip(axes, pad_width, values): | |
| roi = _view_roi(padded, original_area_slice, axis) | |
| _set_pad_area(roi, axis, width_pair, value_pair) | |
| elif mode == "empty": | |
| pass # Do nothing as _pad_simple already returned the correct result | |
| elif array.size == 0: | |
| # Only modes "constant" and "empty" can extend empty axes, all other | |
| # modes depend on `array` not being empty | |
| # -> ensure every empty axis is only "padded with 0" | |
| for axis, width_pair in zip(axes, pad_width): | |
| if array.shape[axis] == 0 and any(width_pair): | |
| raise ValueError( | |
| f"can't extend empty axis {axis} using modes other than " | |
| "'constant' or 'empty'" | |
| ) | |
| # passed, don't need to do anything more as _pad_simple already | |
| # returned the correct result | |
| elif mode == "edge": | |
| for axis, width_pair in zip(axes, pad_width): | |
| roi = _view_roi(padded, original_area_slice, axis) | |
| edge_pair = _get_edges(roi, axis, width_pair) | |
| _set_pad_area(roi, axis, width_pair, edge_pair) | |
| elif mode == "linear_ramp": | |
| end_values = kwargs.get("end_values", 0) | |
| end_values = _as_pairs(end_values, padded.ndim) | |
| for axis, width_pair, value_pair in zip(axes, pad_width, end_values): | |
| roi = _view_roi(padded, original_area_slice, axis) | |
| ramp_pair = _get_linear_ramps(roi, axis, width_pair, value_pair) | |
| _set_pad_area(roi, axis, width_pair, ramp_pair) | |
| elif mode in stat_functions: | |
| func = stat_functions[mode] | |
| length = kwargs.get("stat_length") | |
| length = _as_pairs(length, padded.ndim, as_index=True) | |
| for axis, width_pair, length_pair in zip(axes, pad_width, length): | |
| roi = _view_roi(padded, original_area_slice, axis) | |
| stat_pair = _get_stats(roi, axis, width_pair, length_pair, func) | |
| _set_pad_area(roi, axis, width_pair, stat_pair) | |
| elif mode in {"reflect", "symmetric"}: | |
| method = kwargs.get("reflect_type", "even") | |
| include_edge = mode == "symmetric" | |
| for axis, (left_index, right_index) in zip(axes, pad_width): | |
| if array.shape[axis] == 1 and (left_index > 0 or right_index > 0): | |
| # Extending singleton dimension for 'reflect' is legacy | |
| # behavior; it really should raise an error. | |
| edge_pair = _get_edges(padded, axis, (left_index, right_index)) | |
| _set_pad_area( | |
| padded, axis, (left_index, right_index), edge_pair) | |
| continue | |
| roi = _view_roi(padded, original_area_slice, axis) | |
| while left_index > 0 or right_index > 0: | |
| # Iteratively pad until dimension is filled with reflected | |
| # values. This is necessary if the pad area is larger than | |
| # the length of the original values in the current dimension. | |
| left_index, right_index = _set_reflect_both( | |
| roi, axis, (left_index, right_index), | |
| method, array.shape[axis], include_edge | |
| ) | |
| elif mode == "wrap": | |
| for axis, (left_index, right_index) in zip(axes, pad_width): | |
| roi = _view_roi(padded, original_area_slice, axis) | |
| original_period = padded.shape[axis] - right_index - left_index | |
| while left_index > 0 or right_index > 0: | |
| # Iteratively pad until dimension is filled with wrapped | |
| # values. This is necessary if the pad area is larger than | |
| # the length of the original values in the current dimension. | |
| left_index, right_index = _set_wrap_both( | |
| roi, axis, (left_index, right_index), original_period) | |
| return padded | |
Xet Storage Details
- Size:
- 33.5 kB
- Xet hash:
- 7613fc483e4859a85654e435548c7a81cb30050c01aa86db8b0d9f6cb0f674b1
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.