Reputation: 284
Let N
be an odd positive integer. I want to create a square 2D grid of shape N x N
where the center element is N
, the surrounding 8-neighborhood has value N-1
, the elements around that neighborhood have value N-2
etc., so that finally the "outer shell" of the array has value N//2
. I can accomplish this using np.pad
in a for loop that iteratively adds "shells" to the array:
def pad_decreasing(N):
assert N % 2 == 1
a = np.array([[N]])
for n in range(N-1, N//2, -1):
a = np.pad(a, 1, mode='constant', constant_values=n)
return a
Example output:
In: pad_decreasing(5)
Out:
array([[3, 3, 3, 3, 3],
[3, 4, 4, 4, 3],
[3, 4, 5, 4, 3],
[3, 4, 4, 4, 3],
[3, 3, 3, 3, 3]])
Question. Can I accomplish this in a "vectorized" form that doesn't resort to for loops. This code is fairly slow for N
large.
Upvotes: 2
Views: 586
Reputation: 215057
The distance between the center and any point in the grid can be written as np.maximum(np.abs(row - center), np.abs(col - center))
; Then N minus this distance gives the onion you need:
N = 5
# the x and y coordinate of the center point
center = (N - 1) / 2
# the coordinates of the square array
row, col = np.ogrid[:N, :N]
# N - distance gives the result
N - np.maximum(np.abs(row - center), np.abs(col - center))
# array([[3, 3, 3, 3, 3],
# [3, 4, 4, 4, 3],
# [3, 4, 5, 4, 3],
# [3, 4, 4, 4, 3],
# [3, 3, 3, 3, 3]])
Upvotes: 4