The Python Oracle

Fill neighboring elements in numpy array

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
and get $2,000 discount on your first invoice
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Dreamlands

--

Chapters
00:00 Fill Neighboring Elements In Numpy Array
01:16 Accepted Answer Score 5
02:09 Answer 2 Score 1
02:26 Answer 3 Score 0
02:57 Thank you

--

Full question
https://stackoverflow.com/questions/5322...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #numpy #matrix

#avk47



ACCEPTED ANSWER

Score 5


What you are trying to do is essentially binary dilation, but the wrapping poses a problem. Luckily, scipy's grey dilation function has the wrap mode which we can leverage:

from scipy.ndimage.morphology import grey_dilation, generate_binary_structure, iterate_structure

st = generate_binary_structure(2,1)

# st essentially defines "neighbours", 
# and you can expand n times this using iterate_structure(st, n):

# >>> st
# array([[False,  True, False],
#        [ True,  True,  True],
#        [False,  True, False]])

# >>> iterate_structure(st,2)
# array([[False, False,  True, False, False],
#        [False,  True,  True,  True, False],
#        [ True,  True,  True,  True,  True],
#        [False,  True,  True,  True, False],
#        [False, False,  True, False, False]])


a = np.zeros((5,5))
a[4,4] = 1
dist = 1

dilated = grey_dilation(a, footprint = iterate_structure(st,dist), mode='wrap')

And as a function that creates your array for you:

from scipy.ndimage.morphology import grey_dilation, generate_binary_structure, iterate_structure

def create(size, dist, loc):
    a = np.zeros((size,size), dtype=int)
    a[loc] = 1
    st = generate_binary_structure(2,1)
    return grey_dilation(a, footprint = iterate_structure(st,dist), mode='wrap')

Examples: To reproduce your desired inputs and outputs:

>>> create(5, 1, (2,2))
array([[0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0],
       [0, 1, 1, 1, 0],
       [0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0]])

>>> create(5, 2, (2,2))
array([[0, 0, 1, 0, 0],
       [0, 1, 1, 1, 0],
       [1, 1, 1, 1, 1],
       [0, 1, 1, 1, 0],
       [0, 0, 1, 0, 0]])

>>> create(5, 1, (4,4))
array([[0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 1],
       [1, 0, 0, 1, 1]])



ANSWER 2

Score 1


def create(size, dist, loc):
    a = np.zeros((size, size))
    for i in range(-dist, dist + 1):
        for j in range(-dist + abs(i), dist - abs(i) + 1):
            i_ = (i + loc[0]) % size
            j_ = (j + loc[1]) % size
            a[i_, j_] = 1
    return a

create(5, 1, (4, 4))

returns

array([[0., 0., 0., 0., 1.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 1.],
       [1., 0., 0., 1., 1.]])



ANSWER 3

Score 0


This may not be the most efficient solution but you could try iterating through all the elements in the array, check if their distance to the location provided is what you want it to be and if it is, replace that element's value with the value specified. Basic code structure:

# declar my_arr
value = 1
distance = 2
centre_point = (4,4)
for row_index in range(len(my_arr)):
    for col_index in range(len(my_arr[row_index])):
        if distanceToPoint(row_index,col_index,centre_point) <= distance:
            my_arr[row_index][col_index] = value

The distanceToPoint function would be something like this:

def distanceToPoint(x,y,point):
   px,py = point
   dx,dy = px-x,py-y
   if x==px:
       return py-y
   if y==py:
       return px-x
   if abs(dx)==abs(dy):
       return dx
   else:
       return 1000000 #an arbitrarily large amount which should be bigger than distance