|
""" |
|
The arraypad module contains a group of functions to pad values onto the edges |
|
of an n-dimensional array. |
|
|
|
""" |
|
from __future__ import division, absolute_import, print_function |
|
|
|
import numpy as np |
|
from numpy.compat import long |
|
|
|
|
|
__all__ = ['pad'] |
|
|
|
|
|
|
|
|
|
|
|
|
|
def _arange_ndarray(arr, shape, axis, reverse=False): |
|
""" |
|
Create an ndarray of `shape` with increments along specified `axis` |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
shape : tuple of ints |
|
Shape of desired array. Should be equivalent to `arr.shape` except |
|
`shape[axis]` which may have any positive value. |
|
axis : int |
|
Axis to increment along. |
|
reverse : bool |
|
If False, increment in a positive fashion from 1 to `shape[axis]`, |
|
inclusive. If True, the bounds are the same but the order reversed. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array sized to pad `arr` along `axis`, with linear range from |
|
1 to `shape[axis]` along specified `axis`. |
|
|
|
Notes |
|
----- |
|
The range is deliberately 1-indexed for this specific use case. Think of |
|
this algorithm as broadcasting `np.arange` to a single `axis` of an |
|
arbitrarily shaped ndarray. |
|
|
|
""" |
|
initshape = tuple(1 if i != axis else shape[axis] |
|
for (i, x) in enumerate(arr.shape)) |
|
if not reverse: |
|
padarr = np.arange(1, shape[axis] + 1) |
|
else: |
|
padarr = np.arange(shape[axis], 0, -1) |
|
padarr = padarr.reshape(initshape) |
|
for i, dim in enumerate(shape): |
|
if padarr.shape[i] != dim: |
|
padarr = padarr.repeat(dim, axis=i) |
|
return padarr |
|
|
|
|
|
def _round_ifneeded(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 _prepend_const(arr, pad_amt, val, axis=-1): |
|
""" |
|
Prepend constant `val` along `axis` of `arr`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to prepend. |
|
val : scalar |
|
Constant value to use. For best results should be of type `arr.dtype`; |
|
if not `arr.dtype` will be cast to `arr.dtype`. |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` constant `val` prepended along `axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
padshape = tuple(x if i != axis else pad_amt |
|
for (i, x) in enumerate(arr.shape)) |
|
if val == 0: |
|
return np.concatenate((np.zeros(padshape, dtype=arr.dtype), arr), |
|
axis=axis) |
|
else: |
|
return np.concatenate(((np.zeros(padshape) + val).astype(arr.dtype), |
|
arr), axis=axis) |
|
|
|
|
|
def _append_const(arr, pad_amt, val, axis=-1): |
|
""" |
|
Append constant `val` along `axis` of `arr`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to append. |
|
val : scalar |
|
Constant value to use. For best results should be of type `arr.dtype`; |
|
if not `arr.dtype` will be cast to `arr.dtype`. |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` constant `val` appended along `axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
padshape = tuple(x if i != axis else pad_amt |
|
for (i, x) in enumerate(arr.shape)) |
|
if val == 0: |
|
return np.concatenate((arr, np.zeros(padshape, dtype=arr.dtype)), |
|
axis=axis) |
|
else: |
|
return np.concatenate( |
|
(arr, (np.zeros(padshape) + val).astype(arr.dtype)), axis=axis) |
|
|
|
|
|
def _prepend_edge(arr, pad_amt, axis=-1): |
|
""" |
|
Prepend `pad_amt` to `arr` along `axis` by extending edge values. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to prepend. |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, extended by `pad_amt` edge values appended along `axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
edge_slice = tuple(slice(None) if i != axis else 0 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
edge_arr = arr[edge_slice].reshape(pad_singleton) |
|
return np.concatenate((edge_arr.repeat(pad_amt, axis=axis), arr), |
|
axis=axis) |
|
|
|
|
|
def _append_edge(arr, pad_amt, axis=-1): |
|
""" |
|
Append `pad_amt` to `arr` along `axis` by extending edge values. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to append. |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, extended by `pad_amt` edge values prepended along |
|
`axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
edge_slice = tuple(slice(None) if i != axis else arr.shape[axis] - 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
edge_arr = arr[edge_slice].reshape(pad_singleton) |
|
return np.concatenate((arr, edge_arr.repeat(pad_amt, axis=axis)), |
|
axis=axis) |
|
|
|
|
|
def _prepend_ramp(arr, pad_amt, end, axis=-1): |
|
""" |
|
Prepend linear ramp along `axis`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to prepend. |
|
end : scalar |
|
Constal value to use. For best results should be of type `arr.dtype`; |
|
if not `arr.dtype` will be cast to `arr.dtype`. |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values prepended along `axis`. The |
|
prepended region ramps linearly from the edge value to `end`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
padshape = tuple(x if i != axis else pad_amt |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
ramp_arr = _arange_ndarray(arr, padshape, axis, |
|
reverse=True).astype(np.float64) |
|
|
|
|
|
edge_slice = tuple(slice(None) if i != axis else 0 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis) |
|
|
|
|
|
slope = (end - edge_pad) / float(pad_amt) |
|
ramp_arr = ramp_arr * slope |
|
ramp_arr += edge_pad |
|
_round_ifneeded(ramp_arr, arr.dtype) |
|
|
|
|
|
return np.concatenate((ramp_arr.astype(arr.dtype), arr), axis=axis) |
|
|
|
|
|
def _append_ramp(arr, pad_amt, end, axis=-1): |
|
""" |
|
Append linear ramp along `axis`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to append. |
|
end : scalar |
|
Constal value to use. For best results should be of type `arr.dtype`; |
|
if not `arr.dtype` will be cast to `arr.dtype`. |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values appended along `axis`. The |
|
appended region ramps linearly from the edge value to `end`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
padshape = tuple(x if i != axis else pad_amt |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
ramp_arr = _arange_ndarray(arr, padshape, axis, |
|
reverse=False).astype(np.float64) |
|
|
|
|
|
edge_slice = tuple(slice(None) if i != axis else -1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis) |
|
|
|
|
|
slope = (end - edge_pad) / float(pad_amt) |
|
ramp_arr = ramp_arr * slope |
|
ramp_arr += edge_pad |
|
_round_ifneeded(ramp_arr, arr.dtype) |
|
|
|
|
|
return np.concatenate((arr, ramp_arr.astype(arr.dtype)), axis=axis) |
|
|
|
|
|
def _prepend_max(arr, pad_amt, num, axis=-1): |
|
""" |
|
Prepend `pad_amt` maximum values along `axis`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to prepend. |
|
num : int |
|
Depth into `arr` along `axis` to calculate maximum. |
|
Range: [1, `arr.shape[axis]`] or None (entire axis) |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values appended along `axis`. The |
|
prepended region is the maximum of the first `num` values along |
|
`axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
if num == 1: |
|
return _prepend_edge(arr, pad_amt, axis) |
|
|
|
|
|
if num is not None: |
|
if num >= arr.shape[axis]: |
|
num = None |
|
|
|
|
|
max_slice = tuple(slice(None) if i != axis else slice(num) |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton) |
|
|
|
|
|
return np.concatenate((max_chunk.repeat(pad_amt, axis=axis), arr), |
|
axis=axis) |
|
|
|
|
|
def _append_max(arr, pad_amt, num, axis=-1): |
|
""" |
|
Pad one `axis` of `arr` with the maximum of the last `num` elements. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to append. |
|
num : int |
|
Depth into `arr` along `axis` to calculate maximum. |
|
Range: [1, `arr.shape[axis]`] or None (entire axis) |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values appended along `axis`. The |
|
appended region is the maximum of the final `num` values along `axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
if num == 1: |
|
return _append_edge(arr, pad_amt, axis) |
|
|
|
|
|
if num is not None: |
|
if num >= arr.shape[axis]: |
|
num = None |
|
|
|
|
|
end = arr.shape[axis] - 1 |
|
if num is not None: |
|
max_slice = tuple( |
|
slice(None) if i != axis else slice(end, end - num, -1) |
|
for (i, x) in enumerate(arr.shape)) |
|
else: |
|
max_slice = tuple(slice(None) for x in arr.shape) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton) |
|
|
|
|
|
return np.concatenate((arr, max_chunk.repeat(pad_amt, axis=axis)), |
|
axis=axis) |
|
|
|
|
|
def _prepend_mean(arr, pad_amt, num, axis=-1): |
|
""" |
|
Prepend `pad_amt` mean values along `axis`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to prepend. |
|
num : int |
|
Depth into `arr` along `axis` to calculate mean. |
|
Range: [1, `arr.shape[axis]`] or None (entire axis) |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values prepended along `axis`. The |
|
prepended region is the mean of the first `num` values along `axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
if num == 1: |
|
return _prepend_edge(arr, pad_amt, axis) |
|
|
|
|
|
if num is not None: |
|
if num >= arr.shape[axis]: |
|
num = None |
|
|
|
|
|
mean_slice = tuple(slice(None) if i != axis else slice(num) |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
mean_chunk = arr[mean_slice].mean(axis).reshape(pad_singleton) |
|
_round_ifneeded(mean_chunk, arr.dtype) |
|
|
|
|
|
return np.concatenate((mean_chunk.repeat(pad_amt, axis).astype(arr.dtype), |
|
arr), axis=axis) |
|
|
|
|
|
def _append_mean(arr, pad_amt, num, axis=-1): |
|
""" |
|
Append `pad_amt` mean values along `axis`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to append. |
|
num : int |
|
Depth into `arr` along `axis` to calculate mean. |
|
Range: [1, `arr.shape[axis]`] or None (entire axis) |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values appended along `axis`. The |
|
appended region is the maximum of the final `num` values along `axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
if num == 1: |
|
return _append_edge(arr, pad_amt, axis) |
|
|
|
|
|
if num is not None: |
|
if num >= arr.shape[axis]: |
|
num = None |
|
|
|
|
|
end = arr.shape[axis] - 1 |
|
if num is not None: |
|
mean_slice = tuple( |
|
slice(None) if i != axis else slice(end, end - num, -1) |
|
for (i, x) in enumerate(arr.shape)) |
|
else: |
|
mean_slice = tuple(slice(None) for x in arr.shape) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
mean_chunk = arr[mean_slice].mean(axis=axis).reshape(pad_singleton) |
|
_round_ifneeded(mean_chunk, arr.dtype) |
|
|
|
|
|
return np.concatenate( |
|
(arr, mean_chunk.repeat(pad_amt, axis).astype(arr.dtype)), axis=axis) |
|
|
|
|
|
def _prepend_med(arr, pad_amt, num, axis=-1): |
|
""" |
|
Prepend `pad_amt` median values along `axis`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to prepend. |
|
num : int |
|
Depth into `arr` along `axis` to calculate median. |
|
Range: [1, `arr.shape[axis]`] or None (entire axis) |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values prepended along `axis`. The |
|
prepended region is the median of the first `num` values along `axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
if num == 1: |
|
return _prepend_edge(arr, pad_amt, axis) |
|
|
|
|
|
if num is not None: |
|
if num >= arr.shape[axis]: |
|
num = None |
|
|
|
|
|
med_slice = tuple(slice(None) if i != axis else slice(num) |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton) |
|
_round_ifneeded(med_chunk, arr.dtype) |
|
|
|
|
|
return np.concatenate( |
|
(med_chunk.repeat(pad_amt, axis).astype(arr.dtype), arr), axis=axis) |
|
|
|
|
|
def _append_med(arr, pad_amt, num, axis=-1): |
|
""" |
|
Append `pad_amt` median values along `axis`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to append. |
|
num : int |
|
Depth into `arr` along `axis` to calculate median. |
|
Range: [1, `arr.shape[axis]`] or None (entire axis) |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values appended along `axis`. The |
|
appended region is the median of the final `num` values along `axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
if num == 1: |
|
return _append_edge(arr, pad_amt, axis) |
|
|
|
|
|
if num is not None: |
|
if num >= arr.shape[axis]: |
|
num = None |
|
|
|
|
|
end = arr.shape[axis] - 1 |
|
if num is not None: |
|
med_slice = tuple( |
|
slice(None) if i != axis else slice(end, end - num, -1) |
|
for (i, x) in enumerate(arr.shape)) |
|
else: |
|
med_slice = tuple(slice(None) for x in arr.shape) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton) |
|
_round_ifneeded(med_chunk, arr.dtype) |
|
|
|
|
|
return np.concatenate( |
|
(arr, med_chunk.repeat(pad_amt, axis).astype(arr.dtype)), axis=axis) |
|
|
|
|
|
def _prepend_min(arr, pad_amt, num, axis=-1): |
|
""" |
|
Prepend `pad_amt` minimum values along `axis`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to prepend. |
|
num : int |
|
Depth into `arr` along `axis` to calculate minimum. |
|
Range: [1, `arr.shape[axis]`] or None (entire axis) |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values prepended along `axis`. The |
|
prepended region is the minimum of the first `num` values along |
|
`axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
if num == 1: |
|
return _prepend_edge(arr, pad_amt, axis) |
|
|
|
|
|
if num is not None: |
|
if num >= arr.shape[axis]: |
|
num = None |
|
|
|
|
|
min_slice = tuple(slice(None) if i != axis else slice(num) |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton) |
|
|
|
|
|
return np.concatenate((min_chunk.repeat(pad_amt, axis=axis), arr), |
|
axis=axis) |
|
|
|
|
|
def _append_min(arr, pad_amt, num, axis=-1): |
|
""" |
|
Append `pad_amt` median values along `axis`. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : int |
|
Amount of padding to append. |
|
num : int |
|
Depth into `arr` along `axis` to calculate minimum. |
|
Range: [1, `arr.shape[axis]`] or None (entire axis) |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt` values appended along `axis`. The |
|
appended region is the minimum of the final `num` values along `axis`. |
|
|
|
""" |
|
if pad_amt == 0: |
|
return arr |
|
|
|
|
|
if num == 1: |
|
return _append_edge(arr, pad_amt, axis) |
|
|
|
|
|
if num is not None: |
|
if num >= arr.shape[axis]: |
|
num = None |
|
|
|
|
|
end = arr.shape[axis] - 1 |
|
if num is not None: |
|
min_slice = tuple( |
|
slice(None) if i != axis else slice(end, end - num, -1) |
|
for (i, x) in enumerate(arr.shape)) |
|
else: |
|
min_slice = tuple(slice(None) for x in arr.shape) |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
|
|
min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton) |
|
|
|
|
|
return np.concatenate((arr, min_chunk.repeat(pad_amt, axis=axis)), |
|
axis=axis) |
|
|
|
|
|
def _pad_ref(arr, pad_amt, method, axis=-1): |
|
""" |
|
Pad `axis` of `arr` by reflection. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : tuple of ints, length 2 |
|
Padding to (prepend, append) along `axis`. |
|
method : str |
|
Controls method of reflection; options are 'even' or 'odd'. |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt[0]` values prepended and `pad_amt[1]` |
|
values appended along `axis`. Both regions are padded with reflected |
|
values from the original array. |
|
|
|
Notes |
|
----- |
|
This algorithm does not pad with repetition, i.e. the edges are not |
|
repeated in the reflection. For that behavior, use `method='symmetric'`. |
|
|
|
The modes 'reflect', 'symmetric', and 'wrap' must be padded with a |
|
single function, lest the indexing tricks in non-integer multiples of the |
|
original shape would violate repetition in the final iteration. |
|
|
|
""" |
|
|
|
if pad_amt[0] == 0 and pad_amt[1] == 0: |
|
return arr |
|
|
|
|
|
|
|
|
|
|
|
ref_slice = tuple(slice(None) if i != axis else slice(pad_amt[0], 0, -1) |
|
for (i, x) in enumerate(arr.shape)) |
|
|
|
ref_chunk1 = arr[ref_slice] |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
if pad_amt[0] == 1: |
|
ref_chunk1 = ref_chunk1.reshape(pad_singleton) |
|
|
|
|
|
if 'odd' in method and pad_amt[0] > 0: |
|
edge_slice1 = tuple(slice(None) if i != axis else 0 |
|
for (i, x) in enumerate(arr.shape)) |
|
edge_chunk = arr[edge_slice1].reshape(pad_singleton) |
|
ref_chunk1 = 2 * edge_chunk - ref_chunk1 |
|
del edge_chunk |
|
|
|
|
|
|
|
|
|
|
|
start = arr.shape[axis] - pad_amt[1] - 1 |
|
end = arr.shape[axis] - 1 |
|
ref_slice = tuple(slice(None) if i != axis else slice(start, end) |
|
for (i, x) in enumerate(arr.shape)) |
|
rev_idx = tuple(slice(None) if i != axis else slice(None, None, -1) |
|
for (i, x) in enumerate(arr.shape)) |
|
ref_chunk2 = arr[ref_slice][rev_idx] |
|
|
|
if pad_amt[1] == 1: |
|
ref_chunk2 = ref_chunk2.reshape(pad_singleton) |
|
|
|
if 'odd' in method: |
|
edge_slice2 = tuple(slice(None) if i != axis else -1 |
|
for (i, x) in enumerate(arr.shape)) |
|
edge_chunk = arr[edge_slice2].reshape(pad_singleton) |
|
ref_chunk2 = 2 * edge_chunk - ref_chunk2 |
|
del edge_chunk |
|
|
|
|
|
return np.concatenate((ref_chunk1, arr, ref_chunk2), axis=axis) |
|
|
|
|
|
def _pad_sym(arr, pad_amt, method, axis=-1): |
|
""" |
|
Pad `axis` of `arr` by symmetry. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : tuple of ints, length 2 |
|
Padding to (prepend, append) along `axis`. |
|
method : str |
|
Controls method of symmetry; options are 'even' or 'odd'. |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt[0]` values prepended and `pad_amt[1]` |
|
values appended along `axis`. Both regions are padded with symmetric |
|
values from the original array. |
|
|
|
Notes |
|
----- |
|
This algorithm DOES pad with repetition, i.e. the edges are repeated. |
|
For a method that does not repeat edges, use `method='reflect'`. |
|
|
|
The modes 'reflect', 'symmetric', and 'wrap' must be padded with a |
|
single function, lest the indexing tricks in non-integer multiples of the |
|
original shape would violate repetition in the final iteration. |
|
|
|
""" |
|
|
|
if pad_amt[0] == 0 and pad_amt[1] == 0: |
|
return arr |
|
|
|
|
|
|
|
|
|
|
|
sym_slice = tuple(slice(None) if i != axis else slice(0, pad_amt[0]) |
|
for (i, x) in enumerate(arr.shape)) |
|
rev_idx = tuple(slice(None) if i != axis else slice(None, None, -1) |
|
for (i, x) in enumerate(arr.shape)) |
|
sym_chunk1 = arr[sym_slice][rev_idx] |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
if pad_amt[0] == 1: |
|
sym_chunk1 = sym_chunk1.reshape(pad_singleton) |
|
|
|
|
|
if 'odd' in method and pad_amt[0] > 0: |
|
edge_slice1 = tuple(slice(None) if i != axis else 0 |
|
for (i, x) in enumerate(arr.shape)) |
|
edge_chunk = arr[edge_slice1].reshape(pad_singleton) |
|
sym_chunk1 = 2 * edge_chunk - sym_chunk1 |
|
del edge_chunk |
|
|
|
|
|
|
|
|
|
|
|
start = arr.shape[axis] - pad_amt[1] |
|
end = arr.shape[axis] |
|
sym_slice = tuple(slice(None) if i != axis else slice(start, end) |
|
for (i, x) in enumerate(arr.shape)) |
|
sym_chunk2 = arr[sym_slice][rev_idx] |
|
|
|
if pad_amt[1] == 1: |
|
sym_chunk2 = sym_chunk2.reshape(pad_singleton) |
|
|
|
if 'odd' in method: |
|
edge_slice2 = tuple(slice(None) if i != axis else -1 |
|
for (i, x) in enumerate(arr.shape)) |
|
edge_chunk = arr[edge_slice2].reshape(pad_singleton) |
|
sym_chunk2 = 2 * edge_chunk - sym_chunk2 |
|
del edge_chunk |
|
|
|
|
|
return np.concatenate((sym_chunk1, arr, sym_chunk2), axis=axis) |
|
|
|
|
|
def _pad_wrap(arr, pad_amt, axis=-1): |
|
""" |
|
Pad `axis` of `arr` via wrapping. |
|
|
|
Parameters |
|
---------- |
|
arr : ndarray |
|
Input array of arbitrary shape. |
|
pad_amt : tuple of ints, length 2 |
|
Padding to (prepend, append) along `axis`. |
|
axis : int |
|
Axis along which to pad `arr`. |
|
|
|
Returns |
|
------- |
|
padarr : ndarray |
|
Output array, with `pad_amt[0]` values prepended and `pad_amt[1]` |
|
values appended along `axis`. Both regions are padded wrapped values |
|
from the opposite end of `axis`. |
|
|
|
Notes |
|
----- |
|
This method of padding is also known as 'tile' or 'tiling'. |
|
|
|
The modes 'reflect', 'symmetric', and 'wrap' must be padded with a |
|
single function, lest the indexing tricks in non-integer multiples of the |
|
original shape would violate repetition in the final iteration. |
|
|
|
""" |
|
|
|
if pad_amt[0] == 0 and pad_amt[1] == 0: |
|
return arr |
|
|
|
|
|
|
|
|
|
|
|
start = arr.shape[axis] - pad_amt[0] |
|
end = arr.shape[axis] |
|
wrap_slice = tuple(slice(None) if i != axis else slice(start, end) |
|
for (i, x) in enumerate(arr.shape)) |
|
wrap_chunk1 = arr[wrap_slice] |
|
|
|
|
|
pad_singleton = tuple(x if i != axis else 1 |
|
for (i, x) in enumerate(arr.shape)) |
|
if pad_amt[0] == 1: |
|
wrap_chunk1 = wrap_chunk1.reshape(pad_singleton) |
|
|
|
|
|
|
|
|
|
|
|
wrap_slice = tuple(slice(None) if i != axis else slice(0, pad_amt[1]) |
|
for (i, x) in enumerate(arr.shape)) |
|
wrap_chunk2 = arr[wrap_slice] |
|
|
|
if pad_amt[1] == 1: |
|
wrap_chunk2 = wrap_chunk2.reshape(pad_singleton) |
|
|
|
|
|
return np.concatenate((wrap_chunk1, arr, wrap_chunk2), axis=axis) |
|
|
|
|
|
def _normalize_shape(narray, shape): |
|
""" |
|
Private function which does some checks and normalizes the possibly |
|
much simpler representations of 'pad_width', 'stat_length', |
|
'constant_values', 'end_values'. |
|
|
|
Parameters |
|
---------- |
|
narray : ndarray |
|
Input ndarray |
|
shape : {sequence, int}, optional |
|
The width of padding (pad_width) or the number of elements on the |
|
edge of the narray used for statistics (stat_length). |
|
((before_1, after_1), ... (before_N, after_N)) unique number of |
|
elements for each axis where `N` is rank of `narray`. |
|
((before, after),) yields same before and after constants for each |
|
axis. |
|
(constant,) or int is a shortcut for before = after = constant for |
|
all axes. |
|
|
|
Returns |
|
------- |
|
_normalize_shape : tuple of tuples |
|
int => ((int, int), (int, int), ...) |
|
[[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...) |
|
((int1, int2), (int3, int4), ...) => no change |
|
[[int1, int2], ] => ((int1, int2), (int1, int2), ...) |
|
((int1, int2), ) => ((int1, int2), (int1, int2), ...) |
|
[[int , ], ] => ((int, int), (int, int), ...) |
|
((int , ), ) => ((int, int), (int, int), ...) |
|
|
|
""" |
|
normshp = None |
|
shapelen = len(np.shape(narray)) |
|
if (isinstance(shape, int)) or shape is None: |
|
normshp = ((shape, shape), ) * shapelen |
|
elif (isinstance(shape, (tuple, list)) |
|
and isinstance(shape[0], (tuple, list)) |
|
and len(shape) == shapelen): |
|
normshp = shape |
|
for i in normshp: |
|
if len(i) != 2: |
|
fmt = "Unable to create correctly shaped tuple from %s" |
|
raise ValueError(fmt % (normshp,)) |
|
elif (isinstance(shape, (tuple, list)) |
|
and isinstance(shape[0], (int, float, long)) |
|
and len(shape) == 1): |
|
normshp = ((shape[0], shape[0]), ) * shapelen |
|
elif (isinstance(shape, (tuple, list)) |
|
and isinstance(shape[0], (int, float, long)) |
|
and len(shape) == 2): |
|
normshp = (shape, ) * shapelen |
|
if normshp is None: |
|
fmt = "Unable to create correctly shaped tuple from %s" |
|
raise ValueError(fmt % (shape,)) |
|
return normshp |
|
|
|
|
|
def _validate_lengths(narray, number_elements): |
|
""" |
|
Private function which does some checks and reformats pad_width and |
|
stat_length using _normalize_shape. |
|
|
|
Parameters |
|
---------- |
|
narray : ndarray |
|
Input ndarray |
|
number_elements : {sequence, int}, optional |
|
The width of padding (pad_width) or the number of elements on the edge |
|
of the narray used for statistics (stat_length). |
|
((before_1, after_1), ... (before_N, after_N)) unique number of |
|
elements for each axis. |
|
((before, after),) yields same before and after constants for each |
|
axis. |
|
(constant,) or int is a shortcut for before = after = constant for all |
|
axes. |
|
|
|
Returns |
|
------- |
|
_validate_lengths : tuple of tuples |
|
int => ((int, int), (int, int), ...) |
|
[[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...) |
|
((int1, int2), (int3, int4), ...) => no change |
|
[[int1, int2], ] => ((int1, int2), (int1, int2), ...) |
|
((int1, int2), ) => ((int1, int2), (int1, int2), ...) |
|
[[int , ], ] => ((int, int), (int, int), ...) |
|
((int , ), ) => ((int, int), (int, int), ...) |
|
|
|
""" |
|
normshp = _normalize_shape(narray, number_elements) |
|
for i in normshp: |
|
chk = [1 if x is None else x for x in i] |
|
chk = [1 if x >= 0 else -1 for x in chk] |
|
if (chk[0] < 0) or (chk[1] < 0): |
|
fmt = "%s cannot contain negative values." |
|
raise ValueError(fmt % (number_elements,)) |
|
return normshp |
|
|
|
|
|
|
|
|
|
|
|
|
|
def pad(array, pad_width, mode=None, **kwargs): |
|
""" |
|
Pads an array. |
|
|
|
Parameters |
|
---------- |
|
array : array_like of rank N |
|
Input array |
|
pad_width : {sequence, int} |
|
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),) yields same before and after pad for each axis. |
|
(pad,) or int is a shortcut for before = after = pad width for all |
|
axes. |
|
mode : {str, function} |
|
One of the following string values or a user supplied function. |
|
|
|
'constant' |
|
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. |
|
<function> |
|
Padding function, see Notes. |
|
stat_length : {sequence, 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),) 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, int}, 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),) yields same before and after constants for each |
|
axis. |
|
|
|
(constant,) or int is a shortcut for before = after = constant for |
|
all axes. |
|
|
|
Default is 0. |
|
end_values : {sequence, int}, 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),) yields same before and after end values for each |
|
axis. |
|
|
|
(constant,) or int is a shortcut for before = after = end value for |
|
all axes. |
|
|
|
Default is 0. |
|
reflect_type : str {'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 extented 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 |
|
----- |
|
.. versionadded:: 1.7.0 |
|
|
|
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 return a rank 1 array equal in |
|
length to the vector argument with padded values replaced. 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[:pad_tuple[0]] and vector[-pad_tuple[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 : misc |
|
Any keyword arguments the function requires. |
|
|
|
Examples |
|
-------- |
|
>>> a = [1, 2, 3, 4, 5] |
|
>>> np.lib.pad(a, (2,3), 'constant', constant_values=(4,6)) |
|
array([4, 4, 1, 2, 3, 4, 5, 6, 6, 6]) |
|
|
|
>>> np.lib.pad(a, (2,3), 'edge') |
|
array([1, 1, 1, 2, 3, 4, 5, 5, 5, 5]) |
|
|
|
>>> np.lib.pad(a, (2,3), 'linear_ramp', end_values=(5,-4)) |
|
array([ 5, 3, 1, 2, 3, 4, 5, 2, -1, -4]) |
|
|
|
>>> np.lib.pad(a, (2,), 'maximum') |
|
array([5, 5, 1, 2, 3, 4, 5, 5, 5]) |
|
|
|
>>> np.lib.pad(a, (2,), 'mean') |
|
array([3, 3, 1, 2, 3, 4, 5, 3, 3]) |
|
|
|
>>> np.lib.pad(a, (2,), 'median') |
|
array([3, 3, 1, 2, 3, 4, 5, 3, 3]) |
|
|
|
>>> a = [[1,2], [3,4]] |
|
>>> np.lib.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.lib.pad(a, (2,3), 'reflect') |
|
array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2]) |
|
|
|
>>> np.lib.pad(a, (2,3), 'reflect', reflect_type='odd') |
|
array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]) |
|
|
|
>>> np.lib.pad(a, (2,3), 'symmetric') |
|
array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3]) |
|
|
|
>>> np.lib.pad(a, (2,3), 'symmetric', reflect_type='odd') |
|
array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7]) |
|
|
|
>>> np.lib.pad(a, (2,3), 'wrap') |
|
array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3]) |
|
|
|
>>> def padwithtens(vector, pad_width, iaxis, kwargs): |
|
... vector[:pad_width[0]] = 10 |
|
... vector[-pad_width[1]:] = 10 |
|
... return vector |
|
|
|
>>> a = np.arange(6) |
|
>>> a = a.reshape((2,3)) |
|
|
|
>>> np.lib.pad(a, 2, padwithtens) |
|
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]]) |
|
""" |
|
|
|
narray = np.array(array) |
|
pad_width = _validate_lengths(narray, pad_width) |
|
|
|
allowedkwargs = { |
|
'constant': ['constant_values'], |
|
'edge': [], |
|
'linear_ramp': ['end_values'], |
|
'maximum': ['stat_length'], |
|
'mean': ['stat_length'], |
|
'median': ['stat_length'], |
|
'minimum': ['stat_length'], |
|
'reflect': ['reflect_type'], |
|
'symmetric': ['reflect_type'], |
|
'wrap': [], |
|
} |
|
|
|
kwdefaults = { |
|
'stat_length': None, |
|
'constant_values': 0, |
|
'end_values': 0, |
|
'reflect_type': 'even', |
|
} |
|
|
|
if isinstance(mode, str): |
|
|
|
for key in kwargs: |
|
if key not in allowedkwargs[mode]: |
|
raise ValueError('%s keyword not in allowed keywords %s' % |
|
(key, allowedkwargs[mode])) |
|
|
|
|
|
for kw in allowedkwargs[mode]: |
|
kwargs.setdefault(kw, kwdefaults[kw]) |
|
|
|
|
|
for i in kwargs: |
|
if i == 'stat_length': |
|
kwargs[i] = _validate_lengths(narray, kwargs[i]) |
|
if i in ['end_values', 'constant_values']: |
|
kwargs[i] = _normalize_shape(narray, kwargs[i]) |
|
elif mode is None: |
|
raise ValueError('Keyword "mode" must be a function or one of %s.' % |
|
(list(allowedkwargs.keys()),)) |
|
else: |
|
|
|
|
|
function = mode |
|
|
|
|
|
rank = list(range(len(narray.shape))) |
|
total_dim_increase = [np.sum(pad_width[i]) for i in rank] |
|
offset_slices = [slice(pad_width[i][0], |
|
pad_width[i][0] + narray.shape[i]) |
|
for i in rank] |
|
new_shape = np.array(narray.shape) + total_dim_increase |
|
newmat = np.zeros(new_shape, narray.dtype) |
|
|
|
|
|
newmat[offset_slices] = narray |
|
|
|
|
|
for iaxis in rank: |
|
np.apply_along_axis(function, |
|
iaxis, |
|
newmat, |
|
pad_width[iaxis], |
|
iaxis, |
|
kwargs) |
|
return newmat |
|
|
|
|
|
newmat = narray.copy() |
|
|
|
|
|
|
|
if mode == 'constant': |
|
for axis, ((pad_before, pad_after), (before_val, after_val)) \ |
|
in enumerate(zip(pad_width, kwargs['constant_values'])): |
|
newmat = _prepend_const(newmat, pad_before, before_val, axis) |
|
newmat = _append_const(newmat, pad_after, after_val, axis) |
|
|
|
elif mode == 'edge': |
|
for axis, (pad_before, pad_after) in enumerate(pad_width): |
|
newmat = _prepend_edge(newmat, pad_before, axis) |
|
newmat = _append_edge(newmat, pad_after, axis) |
|
|
|
elif mode == 'linear_ramp': |
|
for axis, ((pad_before, pad_after), (before_val, after_val)) \ |
|
in enumerate(zip(pad_width, kwargs['end_values'])): |
|
newmat = _prepend_ramp(newmat, pad_before, before_val, axis) |
|
newmat = _append_ramp(newmat, pad_after, after_val, axis) |
|
|
|
elif mode == 'maximum': |
|
for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ |
|
in enumerate(zip(pad_width, kwargs['stat_length'])): |
|
newmat = _prepend_max(newmat, pad_before, chunk_before, axis) |
|
newmat = _append_max(newmat, pad_after, chunk_after, axis) |
|
|
|
elif mode == 'mean': |
|
for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ |
|
in enumerate(zip(pad_width, kwargs['stat_length'])): |
|
newmat = _prepend_mean(newmat, pad_before, chunk_before, axis) |
|
newmat = _append_mean(newmat, pad_after, chunk_after, axis) |
|
|
|
elif mode == 'median': |
|
for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ |
|
in enumerate(zip(pad_width, kwargs['stat_length'])): |
|
newmat = _prepend_med(newmat, pad_before, chunk_before, axis) |
|
newmat = _append_med(newmat, pad_after, chunk_after, axis) |
|
|
|
elif mode == 'minimum': |
|
for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \ |
|
in enumerate(zip(pad_width, kwargs['stat_length'])): |
|
newmat = _prepend_min(newmat, pad_before, chunk_before, axis) |
|
newmat = _append_min(newmat, pad_after, chunk_after, axis) |
|
|
|
elif mode == 'reflect': |
|
for axis, (pad_before, pad_after) in enumerate(pad_width): |
|
|
|
|
|
|
|
if ((pad_before > 0) or |
|
(pad_after > 0)) and newmat.shape[axis] == 1: |
|
|
|
|
|
newmat = _prepend_edge(newmat, pad_before, axis) |
|
newmat = _append_edge(newmat, pad_after, axis) |
|
continue |
|
|
|
method = kwargs['reflect_type'] |
|
safe_pad = newmat.shape[axis] - 1 |
|
while ((pad_before > safe_pad) or (pad_after > safe_pad)): |
|
offset = 0 |
|
pad_iter_b = min(safe_pad, |
|
safe_pad * (pad_before // safe_pad)) |
|
pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad)) |
|
newmat = _pad_ref(newmat, (pad_iter_b, |
|
pad_iter_a), method, axis) |
|
pad_before -= pad_iter_b |
|
pad_after -= pad_iter_a |
|
if pad_iter_b > 0: |
|
offset += 1 |
|
if pad_iter_a > 0: |
|
offset += 1 |
|
safe_pad += pad_iter_b + pad_iter_a |
|
newmat = _pad_ref(newmat, (pad_before, pad_after), method, axis) |
|
|
|
elif mode == 'symmetric': |
|
for axis, (pad_before, pad_after) in enumerate(pad_width): |
|
|
|
|
|
|
|
method = kwargs['reflect_type'] |
|
safe_pad = newmat.shape[axis] |
|
while ((pad_before > safe_pad) or |
|
(pad_after > safe_pad)): |
|
pad_iter_b = min(safe_pad, |
|
safe_pad * (pad_before // safe_pad)) |
|
pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad)) |
|
newmat = _pad_sym(newmat, (pad_iter_b, |
|
pad_iter_a), method, axis) |
|
pad_before -= pad_iter_b |
|
pad_after -= pad_iter_a |
|
safe_pad += pad_iter_b + pad_iter_a |
|
newmat = _pad_sym(newmat, (pad_before, pad_after), method, axis) |
|
|
|
elif mode == 'wrap': |
|
for axis, (pad_before, pad_after) in enumerate(pad_width): |
|
|
|
|
|
|
|
safe_pad = newmat.shape[axis] |
|
while ((pad_before > safe_pad) or |
|
(pad_after > safe_pad)): |
|
pad_iter_b = min(safe_pad, |
|
safe_pad * (pad_before // safe_pad)) |
|
pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad)) |
|
newmat = _pad_wrap(newmat, (pad_iter_b, pad_iter_a), axis) |
|
|
|
pad_before -= pad_iter_b |
|
pad_after -= pad_iter_a |
|
safe_pad += pad_iter_b + pad_iter_a |
|
newmat = _pad_wrap(newmat, (pad_before, pad_after), axis) |
|
|
|
return newmat |
|
|