comparison DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/lib/arraypad.py @ 87:2a2c65a20a8b

Add Python libs and headers
author Chris Cannam
date Wed, 25 Feb 2015 14:05:22 +0000
parents
children
comparison
equal deleted inserted replaced
86:413a9d26189e 87:2a2c65a20a8b
1 """
2 The arraypad module contains a group of functions to pad values onto the edges
3 of an n-dimensional array.
4
5 """
6 from __future__ import division, absolute_import, print_function
7
8 import numpy as np
9 from numpy.compat import long
10
11
12 __all__ = ['pad']
13
14
15 ###############################################################################
16 # Private utility functions.
17
18
19 def _arange_ndarray(arr, shape, axis, reverse=False):
20 """
21 Create an ndarray of `shape` with increments along specified `axis`
22
23 Parameters
24 ----------
25 arr : ndarray
26 Input array of arbitrary shape.
27 shape : tuple of ints
28 Shape of desired array. Should be equivalent to `arr.shape` except
29 `shape[axis]` which may have any positive value.
30 axis : int
31 Axis to increment along.
32 reverse : bool
33 If False, increment in a positive fashion from 1 to `shape[axis]`,
34 inclusive. If True, the bounds are the same but the order reversed.
35
36 Returns
37 -------
38 padarr : ndarray
39 Output array sized to pad `arr` along `axis`, with linear range from
40 1 to `shape[axis]` along specified `axis`.
41
42 Notes
43 -----
44 The range is deliberately 1-indexed for this specific use case. Think of
45 this algorithm as broadcasting `np.arange` to a single `axis` of an
46 arbitrarily shaped ndarray.
47
48 """
49 initshape = tuple(1 if i != axis else shape[axis]
50 for (i, x) in enumerate(arr.shape))
51 if not reverse:
52 padarr = np.arange(1, shape[axis] + 1)
53 else:
54 padarr = np.arange(shape[axis], 0, -1)
55 padarr = padarr.reshape(initshape)
56 for i, dim in enumerate(shape):
57 if padarr.shape[i] != dim:
58 padarr = padarr.repeat(dim, axis=i)
59 return padarr
60
61
62 def _round_ifneeded(arr, dtype):
63 """
64 Rounds arr inplace if destination dtype is integer.
65
66 Parameters
67 ----------
68 arr : ndarray
69 Input array.
70 dtype : dtype
71 The dtype of the destination array.
72
73 """
74 if np.issubdtype(dtype, np.integer):
75 arr.round(out=arr)
76
77
78 def _prepend_const(arr, pad_amt, val, axis=-1):
79 """
80 Prepend constant `val` along `axis` of `arr`.
81
82 Parameters
83 ----------
84 arr : ndarray
85 Input array of arbitrary shape.
86 pad_amt : int
87 Amount of padding to prepend.
88 val : scalar
89 Constant value to use. For best results should be of type `arr.dtype`;
90 if not `arr.dtype` will be cast to `arr.dtype`.
91 axis : int
92 Axis along which to pad `arr`.
93
94 Returns
95 -------
96 padarr : ndarray
97 Output array, with `pad_amt` constant `val` prepended along `axis`.
98
99 """
100 if pad_amt == 0:
101 return arr
102 padshape = tuple(x if i != axis else pad_amt
103 for (i, x) in enumerate(arr.shape))
104 if val == 0:
105 return np.concatenate((np.zeros(padshape, dtype=arr.dtype), arr),
106 axis=axis)
107 else:
108 return np.concatenate(((np.zeros(padshape) + val).astype(arr.dtype),
109 arr), axis=axis)
110
111
112 def _append_const(arr, pad_amt, val, axis=-1):
113 """
114 Append constant `val` along `axis` of `arr`.
115
116 Parameters
117 ----------
118 arr : ndarray
119 Input array of arbitrary shape.
120 pad_amt : int
121 Amount of padding to append.
122 val : scalar
123 Constant value to use. For best results should be of type `arr.dtype`;
124 if not `arr.dtype` will be cast to `arr.dtype`.
125 axis : int
126 Axis along which to pad `arr`.
127
128 Returns
129 -------
130 padarr : ndarray
131 Output array, with `pad_amt` constant `val` appended along `axis`.
132
133 """
134 if pad_amt == 0:
135 return arr
136 padshape = tuple(x if i != axis else pad_amt
137 for (i, x) in enumerate(arr.shape))
138 if val == 0:
139 return np.concatenate((arr, np.zeros(padshape, dtype=arr.dtype)),
140 axis=axis)
141 else:
142 return np.concatenate(
143 (arr, (np.zeros(padshape) + val).astype(arr.dtype)), axis=axis)
144
145
146 def _prepend_edge(arr, pad_amt, axis=-1):
147 """
148 Prepend `pad_amt` to `arr` along `axis` by extending edge values.
149
150 Parameters
151 ----------
152 arr : ndarray
153 Input array of arbitrary shape.
154 pad_amt : int
155 Amount of padding to prepend.
156 axis : int
157 Axis along which to pad `arr`.
158
159 Returns
160 -------
161 padarr : ndarray
162 Output array, extended by `pad_amt` edge values appended along `axis`.
163
164 """
165 if pad_amt == 0:
166 return arr
167
168 edge_slice = tuple(slice(None) if i != axis else 0
169 for (i, x) in enumerate(arr.shape))
170
171 # Shape to restore singleton dimension after slicing
172 pad_singleton = tuple(x if i != axis else 1
173 for (i, x) in enumerate(arr.shape))
174 edge_arr = arr[edge_slice].reshape(pad_singleton)
175 return np.concatenate((edge_arr.repeat(pad_amt, axis=axis), arr),
176 axis=axis)
177
178
179 def _append_edge(arr, pad_amt, axis=-1):
180 """
181 Append `pad_amt` to `arr` along `axis` by extending edge values.
182
183 Parameters
184 ----------
185 arr : ndarray
186 Input array of arbitrary shape.
187 pad_amt : int
188 Amount of padding to append.
189 axis : int
190 Axis along which to pad `arr`.
191
192 Returns
193 -------
194 padarr : ndarray
195 Output array, extended by `pad_amt` edge values prepended along
196 `axis`.
197
198 """
199 if pad_amt == 0:
200 return arr
201
202 edge_slice = tuple(slice(None) if i != axis else arr.shape[axis] - 1
203 for (i, x) in enumerate(arr.shape))
204
205 # Shape to restore singleton dimension after slicing
206 pad_singleton = tuple(x if i != axis else 1
207 for (i, x) in enumerate(arr.shape))
208 edge_arr = arr[edge_slice].reshape(pad_singleton)
209 return np.concatenate((arr, edge_arr.repeat(pad_amt, axis=axis)),
210 axis=axis)
211
212
213 def _prepend_ramp(arr, pad_amt, end, axis=-1):
214 """
215 Prepend linear ramp along `axis`.
216
217 Parameters
218 ----------
219 arr : ndarray
220 Input array of arbitrary shape.
221 pad_amt : int
222 Amount of padding to prepend.
223 end : scalar
224 Constal value to use. For best results should be of type `arr.dtype`;
225 if not `arr.dtype` will be cast to `arr.dtype`.
226 axis : int
227 Axis along which to pad `arr`.
228
229 Returns
230 -------
231 padarr : ndarray
232 Output array, with `pad_amt` values prepended along `axis`. The
233 prepended region ramps linearly from the edge value to `end`.
234
235 """
236 if pad_amt == 0:
237 return arr
238
239 # Generate shape for final concatenated array
240 padshape = tuple(x if i != axis else pad_amt
241 for (i, x) in enumerate(arr.shape))
242
243 # Generate an n-dimensional array incrementing along `axis`
244 ramp_arr = _arange_ndarray(arr, padshape, axis,
245 reverse=True).astype(np.float64)
246
247 # Appropriate slicing to extract n-dimensional edge along `axis`
248 edge_slice = tuple(slice(None) if i != axis else 0
249 for (i, x) in enumerate(arr.shape))
250
251 # Shape to restore singleton dimension after slicing
252 pad_singleton = tuple(x if i != axis else 1
253 for (i, x) in enumerate(arr.shape))
254
255 # Extract edge, reshape to original rank, and extend along `axis`
256 edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis)
257
258 # Linear ramp
259 slope = (end - edge_pad) / float(pad_amt)
260 ramp_arr = ramp_arr * slope
261 ramp_arr += edge_pad
262 _round_ifneeded(ramp_arr, arr.dtype)
263
264 # Ramp values will most likely be float, cast them to the same type as arr
265 return np.concatenate((ramp_arr.astype(arr.dtype), arr), axis=axis)
266
267
268 def _append_ramp(arr, pad_amt, end, axis=-1):
269 """
270 Append linear ramp along `axis`.
271
272 Parameters
273 ----------
274 arr : ndarray
275 Input array of arbitrary shape.
276 pad_amt : int
277 Amount of padding to append.
278 end : scalar
279 Constal value to use. For best results should be of type `arr.dtype`;
280 if not `arr.dtype` will be cast to `arr.dtype`.
281 axis : int
282 Axis along which to pad `arr`.
283
284 Returns
285 -------
286 padarr : ndarray
287 Output array, with `pad_amt` values appended along `axis`. The
288 appended region ramps linearly from the edge value to `end`.
289
290 """
291 if pad_amt == 0:
292 return arr
293
294 # Generate shape for final concatenated array
295 padshape = tuple(x if i != axis else pad_amt
296 for (i, x) in enumerate(arr.shape))
297
298 # Generate an n-dimensional array incrementing along `axis`
299 ramp_arr = _arange_ndarray(arr, padshape, axis,
300 reverse=False).astype(np.float64)
301
302 # Slice a chunk from the edge to calculate stats on
303 edge_slice = tuple(slice(None) if i != axis else -1
304 for (i, x) in enumerate(arr.shape))
305
306 # Shape to restore singleton dimension after slicing
307 pad_singleton = tuple(x if i != axis else 1
308 for (i, x) in enumerate(arr.shape))
309
310 # Extract edge, reshape to original rank, and extend along `axis`
311 edge_pad = arr[edge_slice].reshape(pad_singleton).repeat(pad_amt, axis)
312
313 # Linear ramp
314 slope = (end - edge_pad) / float(pad_amt)
315 ramp_arr = ramp_arr * slope
316 ramp_arr += edge_pad
317 _round_ifneeded(ramp_arr, arr.dtype)
318
319 # Ramp values will most likely be float, cast them to the same type as arr
320 return np.concatenate((arr, ramp_arr.astype(arr.dtype)), axis=axis)
321
322
323 def _prepend_max(arr, pad_amt, num, axis=-1):
324 """
325 Prepend `pad_amt` maximum values along `axis`.
326
327 Parameters
328 ----------
329 arr : ndarray
330 Input array of arbitrary shape.
331 pad_amt : int
332 Amount of padding to prepend.
333 num : int
334 Depth into `arr` along `axis` to calculate maximum.
335 Range: [1, `arr.shape[axis]`] or None (entire axis)
336 axis : int
337 Axis along which to pad `arr`.
338
339 Returns
340 -------
341 padarr : ndarray
342 Output array, with `pad_amt` values appended along `axis`. The
343 prepended region is the maximum of the first `num` values along
344 `axis`.
345
346 """
347 if pad_amt == 0:
348 return arr
349
350 # Equivalent to edge padding for single value, so do that instead
351 if num == 1:
352 return _prepend_edge(arr, pad_amt, axis)
353
354 # Use entire array if `num` is too large
355 if num is not None:
356 if num >= arr.shape[axis]:
357 num = None
358
359 # Slice a chunk from the edge to calculate stats on
360 max_slice = tuple(slice(None) if i != axis else slice(num)
361 for (i, x) in enumerate(arr.shape))
362
363 # Shape to restore singleton dimension after slicing
364 pad_singleton = tuple(x if i != axis else 1
365 for (i, x) in enumerate(arr.shape))
366
367 # Extract slice, calculate max, reshape to add singleton dimension back
368 max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton)
369
370 # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt`
371 return np.concatenate((max_chunk.repeat(pad_amt, axis=axis), arr),
372 axis=axis)
373
374
375 def _append_max(arr, pad_amt, num, axis=-1):
376 """
377 Pad one `axis` of `arr` with the maximum of the last `num` elements.
378
379 Parameters
380 ----------
381 arr : ndarray
382 Input array of arbitrary shape.
383 pad_amt : int
384 Amount of padding to append.
385 num : int
386 Depth into `arr` along `axis` to calculate maximum.
387 Range: [1, `arr.shape[axis]`] or None (entire axis)
388 axis : int
389 Axis along which to pad `arr`.
390
391 Returns
392 -------
393 padarr : ndarray
394 Output array, with `pad_amt` values appended along `axis`. The
395 appended region is the maximum of the final `num` values along `axis`.
396
397 """
398 if pad_amt == 0:
399 return arr
400
401 # Equivalent to edge padding for single value, so do that instead
402 if num == 1:
403 return _append_edge(arr, pad_amt, axis)
404
405 # Use entire array if `num` is too large
406 if num is not None:
407 if num >= arr.shape[axis]:
408 num = None
409
410 # Slice a chunk from the edge to calculate stats on
411 end = arr.shape[axis] - 1
412 if num is not None:
413 max_slice = tuple(
414 slice(None) if i != axis else slice(end, end - num, -1)
415 for (i, x) in enumerate(arr.shape))
416 else:
417 max_slice = tuple(slice(None) for x in arr.shape)
418
419 # Shape to restore singleton dimension after slicing
420 pad_singleton = tuple(x if i != axis else 1
421 for (i, x) in enumerate(arr.shape))
422
423 # Extract slice, calculate max, reshape to add singleton dimension back
424 max_chunk = arr[max_slice].max(axis=axis).reshape(pad_singleton)
425
426 # Concatenate `arr` with `max_chunk`, extended along `axis` by `pad_amt`
427 return np.concatenate((arr, max_chunk.repeat(pad_amt, axis=axis)),
428 axis=axis)
429
430
431 def _prepend_mean(arr, pad_amt, num, axis=-1):
432 """
433 Prepend `pad_amt` mean values along `axis`.
434
435 Parameters
436 ----------
437 arr : ndarray
438 Input array of arbitrary shape.
439 pad_amt : int
440 Amount of padding to prepend.
441 num : int
442 Depth into `arr` along `axis` to calculate mean.
443 Range: [1, `arr.shape[axis]`] or None (entire axis)
444 axis : int
445 Axis along which to pad `arr`.
446
447 Returns
448 -------
449 padarr : ndarray
450 Output array, with `pad_amt` values prepended along `axis`. The
451 prepended region is the mean of the first `num` values along `axis`.
452
453 """
454 if pad_amt == 0:
455 return arr
456
457 # Equivalent to edge padding for single value, so do that instead
458 if num == 1:
459 return _prepend_edge(arr, pad_amt, axis)
460
461 # Use entire array if `num` is too large
462 if num is not None:
463 if num >= arr.shape[axis]:
464 num = None
465
466 # Slice a chunk from the edge to calculate stats on
467 mean_slice = tuple(slice(None) if i != axis else slice(num)
468 for (i, x) in enumerate(arr.shape))
469
470 # Shape to restore singleton dimension after slicing
471 pad_singleton = tuple(x if i != axis else 1
472 for (i, x) in enumerate(arr.shape))
473
474 # Extract slice, calculate mean, reshape to add singleton dimension back
475 mean_chunk = arr[mean_slice].mean(axis).reshape(pad_singleton)
476 _round_ifneeded(mean_chunk, arr.dtype)
477
478 # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt`
479 return np.concatenate((mean_chunk.repeat(pad_amt, axis).astype(arr.dtype),
480 arr), axis=axis)
481
482
483 def _append_mean(arr, pad_amt, num, axis=-1):
484 """
485 Append `pad_amt` mean values along `axis`.
486
487 Parameters
488 ----------
489 arr : ndarray
490 Input array of arbitrary shape.
491 pad_amt : int
492 Amount of padding to append.
493 num : int
494 Depth into `arr` along `axis` to calculate mean.
495 Range: [1, `arr.shape[axis]`] or None (entire axis)
496 axis : int
497 Axis along which to pad `arr`.
498
499 Returns
500 -------
501 padarr : ndarray
502 Output array, with `pad_amt` values appended along `axis`. The
503 appended region is the maximum of the final `num` values along `axis`.
504
505 """
506 if pad_amt == 0:
507 return arr
508
509 # Equivalent to edge padding for single value, so do that instead
510 if num == 1:
511 return _append_edge(arr, pad_amt, axis)
512
513 # Use entire array if `num` is too large
514 if num is not None:
515 if num >= arr.shape[axis]:
516 num = None
517
518 # Slice a chunk from the edge to calculate stats on
519 end = arr.shape[axis] - 1
520 if num is not None:
521 mean_slice = tuple(
522 slice(None) if i != axis else slice(end, end - num, -1)
523 for (i, x) in enumerate(arr.shape))
524 else:
525 mean_slice = tuple(slice(None) for x in arr.shape)
526
527 # Shape to restore singleton dimension after slicing
528 pad_singleton = tuple(x if i != axis else 1
529 for (i, x) in enumerate(arr.shape))
530
531 # Extract slice, calculate mean, reshape to add singleton dimension back
532 mean_chunk = arr[mean_slice].mean(axis=axis).reshape(pad_singleton)
533 _round_ifneeded(mean_chunk, arr.dtype)
534
535 # Concatenate `arr` with `mean_chunk`, extended along `axis` by `pad_amt`
536 return np.concatenate(
537 (arr, mean_chunk.repeat(pad_amt, axis).astype(arr.dtype)), axis=axis)
538
539
540 def _prepend_med(arr, pad_amt, num, axis=-1):
541 """
542 Prepend `pad_amt` median values along `axis`.
543
544 Parameters
545 ----------
546 arr : ndarray
547 Input array of arbitrary shape.
548 pad_amt : int
549 Amount of padding to prepend.
550 num : int
551 Depth into `arr` along `axis` to calculate median.
552 Range: [1, `arr.shape[axis]`] or None (entire axis)
553 axis : int
554 Axis along which to pad `arr`.
555
556 Returns
557 -------
558 padarr : ndarray
559 Output array, with `pad_amt` values prepended along `axis`. The
560 prepended region is the median of the first `num` values along `axis`.
561
562 """
563 if pad_amt == 0:
564 return arr
565
566 # Equivalent to edge padding for single value, so do that instead
567 if num == 1:
568 return _prepend_edge(arr, pad_amt, axis)
569
570 # Use entire array if `num` is too large
571 if num is not None:
572 if num >= arr.shape[axis]:
573 num = None
574
575 # Slice a chunk from the edge to calculate stats on
576 med_slice = tuple(slice(None) if i != axis else slice(num)
577 for (i, x) in enumerate(arr.shape))
578
579 # Shape to restore singleton dimension after slicing
580 pad_singleton = tuple(x if i != axis else 1
581 for (i, x) in enumerate(arr.shape))
582
583 # Extract slice, calculate median, reshape to add singleton dimension back
584 med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton)
585 _round_ifneeded(med_chunk, arr.dtype)
586
587 # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt`
588 return np.concatenate(
589 (med_chunk.repeat(pad_amt, axis).astype(arr.dtype), arr), axis=axis)
590
591
592 def _append_med(arr, pad_amt, num, axis=-1):
593 """
594 Append `pad_amt` median values along `axis`.
595
596 Parameters
597 ----------
598 arr : ndarray
599 Input array of arbitrary shape.
600 pad_amt : int
601 Amount of padding to append.
602 num : int
603 Depth into `arr` along `axis` to calculate median.
604 Range: [1, `arr.shape[axis]`] or None (entire axis)
605 axis : int
606 Axis along which to pad `arr`.
607
608 Returns
609 -------
610 padarr : ndarray
611 Output array, with `pad_amt` values appended along `axis`. The
612 appended region is the median of the final `num` values along `axis`.
613
614 """
615 if pad_amt == 0:
616 return arr
617
618 # Equivalent to edge padding for single value, so do that instead
619 if num == 1:
620 return _append_edge(arr, pad_amt, axis)
621
622 # Use entire array if `num` is too large
623 if num is not None:
624 if num >= arr.shape[axis]:
625 num = None
626
627 # Slice a chunk from the edge to calculate stats on
628 end = arr.shape[axis] - 1
629 if num is not None:
630 med_slice = tuple(
631 slice(None) if i != axis else slice(end, end - num, -1)
632 for (i, x) in enumerate(arr.shape))
633 else:
634 med_slice = tuple(slice(None) for x in arr.shape)
635
636 # Shape to restore singleton dimension after slicing
637 pad_singleton = tuple(x if i != axis else 1
638 for (i, x) in enumerate(arr.shape))
639
640 # Extract slice, calculate median, reshape to add singleton dimension back
641 med_chunk = np.median(arr[med_slice], axis=axis).reshape(pad_singleton)
642 _round_ifneeded(med_chunk, arr.dtype)
643
644 # Concatenate `arr` with `med_chunk`, extended along `axis` by `pad_amt`
645 return np.concatenate(
646 (arr, med_chunk.repeat(pad_amt, axis).astype(arr.dtype)), axis=axis)
647
648
649 def _prepend_min(arr, pad_amt, num, axis=-1):
650 """
651 Prepend `pad_amt` minimum values along `axis`.
652
653 Parameters
654 ----------
655 arr : ndarray
656 Input array of arbitrary shape.
657 pad_amt : int
658 Amount of padding to prepend.
659 num : int
660 Depth into `arr` along `axis` to calculate minimum.
661 Range: [1, `arr.shape[axis]`] or None (entire axis)
662 axis : int
663 Axis along which to pad `arr`.
664
665 Returns
666 -------
667 padarr : ndarray
668 Output array, with `pad_amt` values prepended along `axis`. The
669 prepended region is the minimum of the first `num` values along
670 `axis`.
671
672 """
673 if pad_amt == 0:
674 return arr
675
676 # Equivalent to edge padding for single value, so do that instead
677 if num == 1:
678 return _prepend_edge(arr, pad_amt, axis)
679
680 # Use entire array if `num` is too large
681 if num is not None:
682 if num >= arr.shape[axis]:
683 num = None
684
685 # Slice a chunk from the edge to calculate stats on
686 min_slice = tuple(slice(None) if i != axis else slice(num)
687 for (i, x) in enumerate(arr.shape))
688
689 # Shape to restore singleton dimension after slicing
690 pad_singleton = tuple(x if i != axis else 1
691 for (i, x) in enumerate(arr.shape))
692
693 # Extract slice, calculate min, reshape to add singleton dimension back
694 min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton)
695
696 # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt`
697 return np.concatenate((min_chunk.repeat(pad_amt, axis=axis), arr),
698 axis=axis)
699
700
701 def _append_min(arr, pad_amt, num, axis=-1):
702 """
703 Append `pad_amt` median values along `axis`.
704
705 Parameters
706 ----------
707 arr : ndarray
708 Input array of arbitrary shape.
709 pad_amt : int
710 Amount of padding to append.
711 num : int
712 Depth into `arr` along `axis` to calculate minimum.
713 Range: [1, `arr.shape[axis]`] or None (entire axis)
714 axis : int
715 Axis along which to pad `arr`.
716
717 Returns
718 -------
719 padarr : ndarray
720 Output array, with `pad_amt` values appended along `axis`. The
721 appended region is the minimum of the final `num` values along `axis`.
722
723 """
724 if pad_amt == 0:
725 return arr
726
727 # Equivalent to edge padding for single value, so do that instead
728 if num == 1:
729 return _append_edge(arr, pad_amt, axis)
730
731 # Use entire array if `num` is too large
732 if num is not None:
733 if num >= arr.shape[axis]:
734 num = None
735
736 # Slice a chunk from the edge to calculate stats on
737 end = arr.shape[axis] - 1
738 if num is not None:
739 min_slice = tuple(
740 slice(None) if i != axis else slice(end, end - num, -1)
741 for (i, x) in enumerate(arr.shape))
742 else:
743 min_slice = tuple(slice(None) for x in arr.shape)
744
745 # Shape to restore singleton dimension after slicing
746 pad_singleton = tuple(x if i != axis else 1
747 for (i, x) in enumerate(arr.shape))
748
749 # Extract slice, calculate min, reshape to add singleton dimension back
750 min_chunk = arr[min_slice].min(axis=axis).reshape(pad_singleton)
751
752 # Concatenate `arr` with `min_chunk`, extended along `axis` by `pad_amt`
753 return np.concatenate((arr, min_chunk.repeat(pad_amt, axis=axis)),
754 axis=axis)
755
756
757 def _pad_ref(arr, pad_amt, method, axis=-1):
758 """
759 Pad `axis` of `arr` by reflection.
760
761 Parameters
762 ----------
763 arr : ndarray
764 Input array of arbitrary shape.
765 pad_amt : tuple of ints, length 2
766 Padding to (prepend, append) along `axis`.
767 method : str
768 Controls method of reflection; options are 'even' or 'odd'.
769 axis : int
770 Axis along which to pad `arr`.
771
772 Returns
773 -------
774 padarr : ndarray
775 Output array, with `pad_amt[0]` values prepended and `pad_amt[1]`
776 values appended along `axis`. Both regions are padded with reflected
777 values from the original array.
778
779 Notes
780 -----
781 This algorithm does not pad with repetition, i.e. the edges are not
782 repeated in the reflection. For that behavior, use `method='symmetric'`.
783
784 The modes 'reflect', 'symmetric', and 'wrap' must be padded with a
785 single function, lest the indexing tricks in non-integer multiples of the
786 original shape would violate repetition in the final iteration.
787
788 """
789 # Implicit booleanness to test for zero (or None) in any scalar type
790 if pad_amt[0] == 0 and pad_amt[1] == 0:
791 return arr
792
793 ##########################################################################
794 # Prepended region
795
796 # Slice off a reverse indexed chunk from near edge to pad `arr` before
797 ref_slice = tuple(slice(None) if i != axis else slice(pad_amt[0], 0, -1)
798 for (i, x) in enumerate(arr.shape))
799
800 ref_chunk1 = arr[ref_slice]
801
802 # Shape to restore singleton dimension after slicing
803 pad_singleton = tuple(x if i != axis else 1
804 for (i, x) in enumerate(arr.shape))
805 if pad_amt[0] == 1:
806 ref_chunk1 = ref_chunk1.reshape(pad_singleton)
807
808 # Memory/computationally more expensive, only do this if `method='odd'`
809 if 'odd' in method and pad_amt[0] > 0:
810 edge_slice1 = tuple(slice(None) if i != axis else 0
811 for (i, x) in enumerate(arr.shape))
812 edge_chunk = arr[edge_slice1].reshape(pad_singleton)
813 ref_chunk1 = 2 * edge_chunk - ref_chunk1
814 del edge_chunk
815
816 ##########################################################################
817 # Appended region
818
819 # Slice off a reverse indexed chunk from far edge to pad `arr` after
820 start = arr.shape[axis] - pad_amt[1] - 1
821 end = arr.shape[axis] - 1
822 ref_slice = tuple(slice(None) if i != axis else slice(start, end)
823 for (i, x) in enumerate(arr.shape))
824 rev_idx = tuple(slice(None) if i != axis else slice(None, None, -1)
825 for (i, x) in enumerate(arr.shape))
826 ref_chunk2 = arr[ref_slice][rev_idx]
827
828 if pad_amt[1] == 1:
829 ref_chunk2 = ref_chunk2.reshape(pad_singleton)
830
831 if 'odd' in method:
832 edge_slice2 = tuple(slice(None) if i != axis else -1
833 for (i, x) in enumerate(arr.shape))
834 edge_chunk = arr[edge_slice2].reshape(pad_singleton)
835 ref_chunk2 = 2 * edge_chunk - ref_chunk2
836 del edge_chunk
837
838 # Concatenate `arr` with both chunks, extending along `axis`
839 return np.concatenate((ref_chunk1, arr, ref_chunk2), axis=axis)
840
841
842 def _pad_sym(arr, pad_amt, method, axis=-1):
843 """
844 Pad `axis` of `arr` by symmetry.
845
846 Parameters
847 ----------
848 arr : ndarray
849 Input array of arbitrary shape.
850 pad_amt : tuple of ints, length 2
851 Padding to (prepend, append) along `axis`.
852 method : str
853 Controls method of symmetry; options are 'even' or 'odd'.
854 axis : int
855 Axis along which to pad `arr`.
856
857 Returns
858 -------
859 padarr : ndarray
860 Output array, with `pad_amt[0]` values prepended and `pad_amt[1]`
861 values appended along `axis`. Both regions are padded with symmetric
862 values from the original array.
863
864 Notes
865 -----
866 This algorithm DOES pad with repetition, i.e. the edges are repeated.
867 For a method that does not repeat edges, use `method='reflect'`.
868
869 The modes 'reflect', 'symmetric', and 'wrap' must be padded with a
870 single function, lest the indexing tricks in non-integer multiples of the
871 original shape would violate repetition in the final iteration.
872
873 """
874 # Implicit booleanness to test for zero (or None) in any scalar type
875 if pad_amt[0] == 0 and pad_amt[1] == 0:
876 return arr
877
878 ##########################################################################
879 # Prepended region
880
881 # Slice off a reverse indexed chunk from near edge to pad `arr` before
882 sym_slice = tuple(slice(None) if i != axis else slice(0, pad_amt[0])
883 for (i, x) in enumerate(arr.shape))
884 rev_idx = tuple(slice(None) if i != axis else slice(None, None, -1)
885 for (i, x) in enumerate(arr.shape))
886 sym_chunk1 = arr[sym_slice][rev_idx]
887
888 # Shape to restore singleton dimension after slicing
889 pad_singleton = tuple(x if i != axis else 1
890 for (i, x) in enumerate(arr.shape))
891 if pad_amt[0] == 1:
892 sym_chunk1 = sym_chunk1.reshape(pad_singleton)
893
894 # Memory/computationally more expensive, only do this if `method='odd'`
895 if 'odd' in method and pad_amt[0] > 0:
896 edge_slice1 = tuple(slice(None) if i != axis else 0
897 for (i, x) in enumerate(arr.shape))
898 edge_chunk = arr[edge_slice1].reshape(pad_singleton)
899 sym_chunk1 = 2 * edge_chunk - sym_chunk1
900 del edge_chunk
901
902 ##########################################################################
903 # Appended region
904
905 # Slice off a reverse indexed chunk from far edge to pad `arr` after
906 start = arr.shape[axis] - pad_amt[1]
907 end = arr.shape[axis]
908 sym_slice = tuple(slice(None) if i != axis else slice(start, end)
909 for (i, x) in enumerate(arr.shape))
910 sym_chunk2 = arr[sym_slice][rev_idx]
911
912 if pad_amt[1] == 1:
913 sym_chunk2 = sym_chunk2.reshape(pad_singleton)
914
915 if 'odd' in method:
916 edge_slice2 = tuple(slice(None) if i != axis else -1
917 for (i, x) in enumerate(arr.shape))
918 edge_chunk = arr[edge_slice2].reshape(pad_singleton)
919 sym_chunk2 = 2 * edge_chunk - sym_chunk2
920 del edge_chunk
921
922 # Concatenate `arr` with both chunks, extending along `axis`
923 return np.concatenate((sym_chunk1, arr, sym_chunk2), axis=axis)
924
925
926 def _pad_wrap(arr, pad_amt, axis=-1):
927 """
928 Pad `axis` of `arr` via wrapping.
929
930 Parameters
931 ----------
932 arr : ndarray
933 Input array of arbitrary shape.
934 pad_amt : tuple of ints, length 2
935 Padding to (prepend, append) along `axis`.
936 axis : int
937 Axis along which to pad `arr`.
938
939 Returns
940 -------
941 padarr : ndarray
942 Output array, with `pad_amt[0]` values prepended and `pad_amt[1]`
943 values appended along `axis`. Both regions are padded wrapped values
944 from the opposite end of `axis`.
945
946 Notes
947 -----
948 This method of padding is also known as 'tile' or 'tiling'.
949
950 The modes 'reflect', 'symmetric', and 'wrap' must be padded with a
951 single function, lest the indexing tricks in non-integer multiples of the
952 original shape would violate repetition in the final iteration.
953
954 """
955 # Implicit booleanness to test for zero (or None) in any scalar type
956 if pad_amt[0] == 0 and pad_amt[1] == 0:
957 return arr
958
959 ##########################################################################
960 # Prepended region
961
962 # Slice off a reverse indexed chunk from near edge to pad `arr` before
963 start = arr.shape[axis] - pad_amt[0]
964 end = arr.shape[axis]
965 wrap_slice = tuple(slice(None) if i != axis else slice(start, end)
966 for (i, x) in enumerate(arr.shape))
967 wrap_chunk1 = arr[wrap_slice]
968
969 # Shape to restore singleton dimension after slicing
970 pad_singleton = tuple(x if i != axis else 1
971 for (i, x) in enumerate(arr.shape))
972 if pad_amt[0] == 1:
973 wrap_chunk1 = wrap_chunk1.reshape(pad_singleton)
974
975 ##########################################################################
976 # Appended region
977
978 # Slice off a reverse indexed chunk from far edge to pad `arr` after
979 wrap_slice = tuple(slice(None) if i != axis else slice(0, pad_amt[1])
980 for (i, x) in enumerate(arr.shape))
981 wrap_chunk2 = arr[wrap_slice]
982
983 if pad_amt[1] == 1:
984 wrap_chunk2 = wrap_chunk2.reshape(pad_singleton)
985
986 # Concatenate `arr` with both chunks, extending along `axis`
987 return np.concatenate((wrap_chunk1, arr, wrap_chunk2), axis=axis)
988
989
990 def _normalize_shape(narray, shape):
991 """
992 Private function which does some checks and normalizes the possibly
993 much simpler representations of 'pad_width', 'stat_length',
994 'constant_values', 'end_values'.
995
996 Parameters
997 ----------
998 narray : ndarray
999 Input ndarray
1000 shape : {sequence, int}, optional
1001 The width of padding (pad_width) or the number of elements on the
1002 edge of the narray used for statistics (stat_length).
1003 ((before_1, after_1), ... (before_N, after_N)) unique number of
1004 elements for each axis where `N` is rank of `narray`.
1005 ((before, after),) yields same before and after constants for each
1006 axis.
1007 (constant,) or int is a shortcut for before = after = constant for
1008 all axes.
1009
1010 Returns
1011 -------
1012 _normalize_shape : tuple of tuples
1013 int => ((int, int), (int, int), ...)
1014 [[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...)
1015 ((int1, int2), (int3, int4), ...) => no change
1016 [[int1, int2], ] => ((int1, int2), (int1, int2), ...)
1017 ((int1, int2), ) => ((int1, int2), (int1, int2), ...)
1018 [[int , ], ] => ((int, int), (int, int), ...)
1019 ((int , ), ) => ((int, int), (int, int), ...)
1020
1021 """
1022 normshp = None
1023 shapelen = len(np.shape(narray))
1024 if (isinstance(shape, int)) or shape is None:
1025 normshp = ((shape, shape), ) * shapelen
1026 elif (isinstance(shape, (tuple, list))
1027 and isinstance(shape[0], (tuple, list))
1028 and len(shape) == shapelen):
1029 normshp = shape
1030 for i in normshp:
1031 if len(i) != 2:
1032 fmt = "Unable to create correctly shaped tuple from %s"
1033 raise ValueError(fmt % (normshp,))
1034 elif (isinstance(shape, (tuple, list))
1035 and isinstance(shape[0], (int, float, long))
1036 and len(shape) == 1):
1037 normshp = ((shape[0], shape[0]), ) * shapelen
1038 elif (isinstance(shape, (tuple, list))
1039 and isinstance(shape[0], (int, float, long))
1040 and len(shape) == 2):
1041 normshp = (shape, ) * shapelen
1042 if normshp is None:
1043 fmt = "Unable to create correctly shaped tuple from %s"
1044 raise ValueError(fmt % (shape,))
1045 return normshp
1046
1047
1048 def _validate_lengths(narray, number_elements):
1049 """
1050 Private function which does some checks and reformats pad_width and
1051 stat_length using _normalize_shape.
1052
1053 Parameters
1054 ----------
1055 narray : ndarray
1056 Input ndarray
1057 number_elements : {sequence, int}, optional
1058 The width of padding (pad_width) or the number of elements on the edge
1059 of the narray used for statistics (stat_length).
1060 ((before_1, after_1), ... (before_N, after_N)) unique number of
1061 elements for each axis.
1062 ((before, after),) yields same before and after constants for each
1063 axis.
1064 (constant,) or int is a shortcut for before = after = constant for all
1065 axes.
1066
1067 Returns
1068 -------
1069 _validate_lengths : tuple of tuples
1070 int => ((int, int), (int, int), ...)
1071 [[int1, int2], [int3, int4], ...] => ((int1, int2), (int3, int4), ...)
1072 ((int1, int2), (int3, int4), ...) => no change
1073 [[int1, int2], ] => ((int1, int2), (int1, int2), ...)
1074 ((int1, int2), ) => ((int1, int2), (int1, int2), ...)
1075 [[int , ], ] => ((int, int), (int, int), ...)
1076 ((int , ), ) => ((int, int), (int, int), ...)
1077
1078 """
1079 normshp = _normalize_shape(narray, number_elements)
1080 for i in normshp:
1081 chk = [1 if x is None else x for x in i]
1082 chk = [1 if x >= 0 else -1 for x in chk]
1083 if (chk[0] < 0) or (chk[1] < 0):
1084 fmt = "%s cannot contain negative values."
1085 raise ValueError(fmt % (number_elements,))
1086 return normshp
1087
1088
1089 ###############################################################################
1090 # Public functions
1091
1092
1093 def pad(array, pad_width, mode=None, **kwargs):
1094 """
1095 Pads an array.
1096
1097 Parameters
1098 ----------
1099 array : array_like of rank N
1100 Input array
1101 pad_width : {sequence, int}
1102 Number of values padded to the edges of each axis.
1103 ((before_1, after_1), ... (before_N, after_N)) unique pad widths
1104 for each axis.
1105 ((before, after),) yields same before and after pad for each axis.
1106 (pad,) or int is a shortcut for before = after = pad width for all
1107 axes.
1108 mode : {str, function}
1109 One of the following string values or a user supplied function.
1110
1111 'constant'
1112 Pads with a constant value.
1113 'edge'
1114 Pads with the edge values of array.
1115 'linear_ramp'
1116 Pads with the linear ramp between end_value and the
1117 array edge value.
1118 'maximum'
1119 Pads with the maximum value of all or part of the
1120 vector along each axis.
1121 'mean'
1122 Pads with the mean value of all or part of the
1123 vector along each axis.
1124 'median'
1125 Pads with the median value of all or part of the
1126 vector along each axis.
1127 'minimum'
1128 Pads with the minimum value of all or part of the
1129 vector along each axis.
1130 'reflect'
1131 Pads with the reflection of the vector mirrored on
1132 the first and last values of the vector along each
1133 axis.
1134 'symmetric'
1135 Pads with the reflection of the vector mirrored
1136 along the edge of the array.
1137 'wrap'
1138 Pads with the wrap of the vector along the axis.
1139 The first values are used to pad the end and the
1140 end values are used to pad the beginning.
1141 <function>
1142 Padding function, see Notes.
1143 stat_length : {sequence, int}, optional
1144 Used in 'maximum', 'mean', 'median', and 'minimum'. Number of
1145 values at edge of each axis used to calculate the statistic value.
1146
1147 ((before_1, after_1), ... (before_N, after_N)) unique statistic
1148 lengths for each axis.
1149
1150 ((before, after),) yields same before and after statistic lengths
1151 for each axis.
1152
1153 (stat_length,) or int is a shortcut for before = after = statistic
1154 length for all axes.
1155
1156 Default is ``None``, to use the entire axis.
1157 constant_values : {sequence, int}, optional
1158 Used in 'constant'. The values to set the padded values for each
1159 axis.
1160
1161 ((before_1, after_1), ... (before_N, after_N)) unique pad constants
1162 for each axis.
1163
1164 ((before, after),) yields same before and after constants for each
1165 axis.
1166
1167 (constant,) or int is a shortcut for before = after = constant for
1168 all axes.
1169
1170 Default is 0.
1171 end_values : {sequence, int}, optional
1172 Used in 'linear_ramp'. The values used for the ending value of the
1173 linear_ramp and that will form the edge of the padded array.
1174
1175 ((before_1, after_1), ... (before_N, after_N)) unique end values
1176 for each axis.
1177
1178 ((before, after),) yields same before and after end values for each
1179 axis.
1180
1181 (constant,) or int is a shortcut for before = after = end value for
1182 all axes.
1183
1184 Default is 0.
1185 reflect_type : str {'even', 'odd'}, optional
1186 Used in 'reflect', and 'symmetric'. The 'even' style is the
1187 default with an unaltered reflection around the edge value. For
1188 the 'odd' style, the extented part of the array is created by
1189 subtracting the reflected values from two times the edge value.
1190
1191 Returns
1192 -------
1193 pad : ndarray
1194 Padded array of rank equal to `array` with shape increased
1195 according to `pad_width`.
1196
1197 Notes
1198 -----
1199 .. versionadded:: 1.7.0
1200
1201 For an array with rank greater than 1, some of the padding of later
1202 axes is calculated from padding of previous axes. This is easiest to
1203 think about with a rank 2 array where the corners of the padded array
1204 are calculated by using padded values from the first axis.
1205
1206 The padding function, if used, should return a rank 1 array equal in
1207 length to the vector argument with padded values replaced. It has the
1208 following signature::
1209
1210 padding_func(vector, iaxis_pad_width, iaxis, **kwargs)
1211
1212 where
1213
1214 vector : ndarray
1215 A rank 1 array already padded with zeros. Padded values are
1216 vector[:pad_tuple[0]] and vector[-pad_tuple[1]:].
1217 iaxis_pad_width : tuple
1218 A 2-tuple of ints, iaxis_pad_width[0] represents the number of
1219 values padded at the beginning of vector where
1220 iaxis_pad_width[1] represents the number of values padded at
1221 the end of vector.
1222 iaxis : int
1223 The axis currently being calculated.
1224 kwargs : misc
1225 Any keyword arguments the function requires.
1226
1227 Examples
1228 --------
1229 >>> a = [1, 2, 3, 4, 5]
1230 >>> np.lib.pad(a, (2,3), 'constant', constant_values=(4,6))
1231 array([4, 4, 1, 2, 3, 4, 5, 6, 6, 6])
1232
1233 >>> np.lib.pad(a, (2,3), 'edge')
1234 array([1, 1, 1, 2, 3, 4, 5, 5, 5, 5])
1235
1236 >>> np.lib.pad(a, (2,3), 'linear_ramp', end_values=(5,-4))
1237 array([ 5, 3, 1, 2, 3, 4, 5, 2, -1, -4])
1238
1239 >>> np.lib.pad(a, (2,), 'maximum')
1240 array([5, 5, 1, 2, 3, 4, 5, 5, 5])
1241
1242 >>> np.lib.pad(a, (2,), 'mean')
1243 array([3, 3, 1, 2, 3, 4, 5, 3, 3])
1244
1245 >>> np.lib.pad(a, (2,), 'median')
1246 array([3, 3, 1, 2, 3, 4, 5, 3, 3])
1247
1248 >>> a = [[1,2], [3,4]]
1249 >>> np.lib.pad(a, ((3, 2), (2, 3)), 'minimum')
1250 array([[1, 1, 1, 2, 1, 1, 1],
1251 [1, 1, 1, 2, 1, 1, 1],
1252 [1, 1, 1, 2, 1, 1, 1],
1253 [1, 1, 1, 2, 1, 1, 1],
1254 [3, 3, 3, 4, 3, 3, 3],
1255 [1, 1, 1, 2, 1, 1, 1],
1256 [1, 1, 1, 2, 1, 1, 1]])
1257
1258 >>> a = [1, 2, 3, 4, 5]
1259 >>> np.lib.pad(a, (2,3), 'reflect')
1260 array([3, 2, 1, 2, 3, 4, 5, 4, 3, 2])
1261
1262 >>> np.lib.pad(a, (2,3), 'reflect', reflect_type='odd')
1263 array([-1, 0, 1, 2, 3, 4, 5, 6, 7, 8])
1264
1265 >>> np.lib.pad(a, (2,3), 'symmetric')
1266 array([2, 1, 1, 2, 3, 4, 5, 5, 4, 3])
1267
1268 >>> np.lib.pad(a, (2,3), 'symmetric', reflect_type='odd')
1269 array([0, 1, 1, 2, 3, 4, 5, 5, 6, 7])
1270
1271 >>> np.lib.pad(a, (2,3), 'wrap')
1272 array([4, 5, 1, 2, 3, 4, 5, 1, 2, 3])
1273
1274 >>> def padwithtens(vector, pad_width, iaxis, kwargs):
1275 ... vector[:pad_width[0]] = 10
1276 ... vector[-pad_width[1]:] = 10
1277 ... return vector
1278
1279 >>> a = np.arange(6)
1280 >>> a = a.reshape((2,3))
1281
1282 >>> np.lib.pad(a, 2, padwithtens)
1283 array([[10, 10, 10, 10, 10, 10, 10],
1284 [10, 10, 10, 10, 10, 10, 10],
1285 [10, 10, 0, 1, 2, 10, 10],
1286 [10, 10, 3, 4, 5, 10, 10],
1287 [10, 10, 10, 10, 10, 10, 10],
1288 [10, 10, 10, 10, 10, 10, 10]])
1289 """
1290
1291 narray = np.array(array)
1292 pad_width = _validate_lengths(narray, pad_width)
1293
1294 allowedkwargs = {
1295 'constant': ['constant_values'],
1296 'edge': [],
1297 'linear_ramp': ['end_values'],
1298 'maximum': ['stat_length'],
1299 'mean': ['stat_length'],
1300 'median': ['stat_length'],
1301 'minimum': ['stat_length'],
1302 'reflect': ['reflect_type'],
1303 'symmetric': ['reflect_type'],
1304 'wrap': [],
1305 }
1306
1307 kwdefaults = {
1308 'stat_length': None,
1309 'constant_values': 0,
1310 'end_values': 0,
1311 'reflect_type': 'even',
1312 }
1313
1314 if isinstance(mode, str):
1315 # Make sure have allowed kwargs appropriate for mode
1316 for key in kwargs:
1317 if key not in allowedkwargs[mode]:
1318 raise ValueError('%s keyword not in allowed keywords %s' %
1319 (key, allowedkwargs[mode]))
1320
1321 # Set kwarg defaults
1322 for kw in allowedkwargs[mode]:
1323 kwargs.setdefault(kw, kwdefaults[kw])
1324
1325 # Need to only normalize particular keywords.
1326 for i in kwargs:
1327 if i == 'stat_length':
1328 kwargs[i] = _validate_lengths(narray, kwargs[i])
1329 if i in ['end_values', 'constant_values']:
1330 kwargs[i] = _normalize_shape(narray, kwargs[i])
1331 elif mode is None:
1332 raise ValueError('Keyword "mode" must be a function or one of %s.' %
1333 (list(allowedkwargs.keys()),))
1334 else:
1335 # Drop back to old, slower np.apply_along_axis mode for user-supplied
1336 # vector function
1337 function = mode
1338
1339 # Create a new padded array
1340 rank = list(range(len(narray.shape)))
1341 total_dim_increase = [np.sum(pad_width[i]) for i in rank]
1342 offset_slices = [slice(pad_width[i][0],
1343 pad_width[i][0] + narray.shape[i])
1344 for i in rank]
1345 new_shape = np.array(narray.shape) + total_dim_increase
1346 newmat = np.zeros(new_shape, narray.dtype)
1347
1348 # Insert the original array into the padded array
1349 newmat[offset_slices] = narray
1350
1351 # This is the core of pad ...
1352 for iaxis in rank:
1353 np.apply_along_axis(function,
1354 iaxis,
1355 newmat,
1356 pad_width[iaxis],
1357 iaxis,
1358 kwargs)
1359 return newmat
1360
1361 # If we get here, use new padding method
1362 newmat = narray.copy()
1363
1364 # API preserved, but completely new algorithm which pads by building the
1365 # entire block to pad before/after `arr` with in one step, for each axis.
1366 if mode == 'constant':
1367 for axis, ((pad_before, pad_after), (before_val, after_val)) \
1368 in enumerate(zip(pad_width, kwargs['constant_values'])):
1369 newmat = _prepend_const(newmat, pad_before, before_val, axis)
1370 newmat = _append_const(newmat, pad_after, after_val, axis)
1371
1372 elif mode == 'edge':
1373 for axis, (pad_before, pad_after) in enumerate(pad_width):
1374 newmat = _prepend_edge(newmat, pad_before, axis)
1375 newmat = _append_edge(newmat, pad_after, axis)
1376
1377 elif mode == 'linear_ramp':
1378 for axis, ((pad_before, pad_after), (before_val, after_val)) \
1379 in enumerate(zip(pad_width, kwargs['end_values'])):
1380 newmat = _prepend_ramp(newmat, pad_before, before_val, axis)
1381 newmat = _append_ramp(newmat, pad_after, after_val, axis)
1382
1383 elif mode == 'maximum':
1384 for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \
1385 in enumerate(zip(pad_width, kwargs['stat_length'])):
1386 newmat = _prepend_max(newmat, pad_before, chunk_before, axis)
1387 newmat = _append_max(newmat, pad_after, chunk_after, axis)
1388
1389 elif mode == 'mean':
1390 for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \
1391 in enumerate(zip(pad_width, kwargs['stat_length'])):
1392 newmat = _prepend_mean(newmat, pad_before, chunk_before, axis)
1393 newmat = _append_mean(newmat, pad_after, chunk_after, axis)
1394
1395 elif mode == 'median':
1396 for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \
1397 in enumerate(zip(pad_width, kwargs['stat_length'])):
1398 newmat = _prepend_med(newmat, pad_before, chunk_before, axis)
1399 newmat = _append_med(newmat, pad_after, chunk_after, axis)
1400
1401 elif mode == 'minimum':
1402 for axis, ((pad_before, pad_after), (chunk_before, chunk_after)) \
1403 in enumerate(zip(pad_width, kwargs['stat_length'])):
1404 newmat = _prepend_min(newmat, pad_before, chunk_before, axis)
1405 newmat = _append_min(newmat, pad_after, chunk_after, axis)
1406
1407 elif mode == 'reflect':
1408 for axis, (pad_before, pad_after) in enumerate(pad_width):
1409 # Recursive padding along any axis where `pad_amt` is too large
1410 # for indexing tricks. We can only safely pad the original axis
1411 # length, to keep the period of the reflections consistent.
1412 if ((pad_before > 0) or
1413 (pad_after > 0)) and newmat.shape[axis] == 1:
1414 # Extending singleton dimension for 'reflect' is legacy
1415 # behavior; it really should raise an error.
1416 newmat = _prepend_edge(newmat, pad_before, axis)
1417 newmat = _append_edge(newmat, pad_after, axis)
1418 continue
1419
1420 method = kwargs['reflect_type']
1421 safe_pad = newmat.shape[axis] - 1
1422 while ((pad_before > safe_pad) or (pad_after > safe_pad)):
1423 offset = 0
1424 pad_iter_b = min(safe_pad,
1425 safe_pad * (pad_before // safe_pad))
1426 pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad))
1427 newmat = _pad_ref(newmat, (pad_iter_b,
1428 pad_iter_a), method, axis)
1429 pad_before -= pad_iter_b
1430 pad_after -= pad_iter_a
1431 if pad_iter_b > 0:
1432 offset += 1
1433 if pad_iter_a > 0:
1434 offset += 1
1435 safe_pad += pad_iter_b + pad_iter_a
1436 newmat = _pad_ref(newmat, (pad_before, pad_after), method, axis)
1437
1438 elif mode == 'symmetric':
1439 for axis, (pad_before, pad_after) in enumerate(pad_width):
1440 # Recursive padding along any axis where `pad_amt` is too large
1441 # for indexing tricks. We can only safely pad the original axis
1442 # length, to keep the period of the reflections consistent.
1443 method = kwargs['reflect_type']
1444 safe_pad = newmat.shape[axis]
1445 while ((pad_before > safe_pad) or
1446 (pad_after > safe_pad)):
1447 pad_iter_b = min(safe_pad,
1448 safe_pad * (pad_before // safe_pad))
1449 pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad))
1450 newmat = _pad_sym(newmat, (pad_iter_b,
1451 pad_iter_a), method, axis)
1452 pad_before -= pad_iter_b
1453 pad_after -= pad_iter_a
1454 safe_pad += pad_iter_b + pad_iter_a
1455 newmat = _pad_sym(newmat, (pad_before, pad_after), method, axis)
1456
1457 elif mode == 'wrap':
1458 for axis, (pad_before, pad_after) in enumerate(pad_width):
1459 # Recursive padding along any axis where `pad_amt` is too large
1460 # for indexing tricks. We can only safely pad the original axis
1461 # length, to keep the period of the reflections consistent.
1462 safe_pad = newmat.shape[axis]
1463 while ((pad_before > safe_pad) or
1464 (pad_after > safe_pad)):
1465 pad_iter_b = min(safe_pad,
1466 safe_pad * (pad_before // safe_pad))
1467 pad_iter_a = min(safe_pad, safe_pad * (pad_after // safe_pad))
1468 newmat = _pad_wrap(newmat, (pad_iter_b, pad_iter_a), axis)
1469
1470 pad_before -= pad_iter_b
1471 pad_after -= pad_iter_a
1472 safe_pad += pad_iter_b + pad_iter_a
1473 newmat = _pad_wrap(newmat, (pad_before, pad_after), axis)
1474
1475 return newmat