Mercurial > hg > vamp-build-and-test
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 |