Reputation: 307
I have a 570 x 800 matrix with id values. What I would like to do if find the adjacent neighbors for each item. The max number of neighbors would be 8 unless the cell is along a boundary. In that case, there would be three neighbors. I want to append the neighbors to a list. I saw the posting for finding neighbors when each cell has x and y coordinates which was very helpful, but how would modify the code with no coordinates. The ids come in as a string which is fine because I use it as a key in a dictionary. Any help would be appreciated.
Upvotes: 3
Views: 2833
Reputation: 42480
Assuming that what you're trying to do is construct an eight-connected grid on the matrix, and that the position of item in the the matrix defines an x- and y- co-ordinate, you can use something like this:
def eight_connected_neighbours( xmax, ymax, x, y ):
"""The x- and y- components for a single cell in an eight connected grid
Parameters
----------
xmax : int
The width of the grid
ymax: int
The height of the grid
x : int
The x- position of cell to find neighbours of
y : int
The y- position of cell to find neighbours of
Returns
-------
results : list of tuple
A list of (x, y) indices for the neighbours
"""
results = []
for dx in [-1,0,1]:
for dy in [-1,0,1]:
newx = x+dx
newy = y+dy
if (dx == 0 and dy == 0):
continue
if (newx>=0 and newx<xmax and newy >=0 and newy<ymax):
results.append( (newx, newy) )
return results
Upvotes: 5
Reputation: 88168
Let me give an alternate answer with numpy
, which is a library you might want to consider if you're doing anything a bit more heavy duty with your data. The advantage with this method is the extensibility to the number of nearest neighbors with the parameter k
. The setup:
from numpy import *
k = 1
# Create the nearest neighbors
Xidx, Yidx = mgrid[-k:k+1,-k:k+1]
# Remove the center (0,0) index
center = (Xidx==0) & (Yidx==0)
Xidx = Xidx[~center]
Yidx = Yidx[~center]
Now you can access the nearest neighbors with A[Xidx+dx, Yidx+dy]
where dx
and dy
are the offsets for the x
and y
coordinates.
Example
Let's take a random matrix:
A = random.random((5,5))
print A
which for me looks like:
[[ 0.90779297 0.91195651 0.32751438 0.44830373 0.2528675 ]
[ 0.02542108 0.52542962 0.28203009 0.35606998 0.88076027]
[ 0.08955781 0.98903843 0.86881875 0.21246095 0.92005691]
[ 0.57253561 0.08830487 0.06418296 0.59632344 0.53604546]
[ 0.7646322 0.50869651 0.00229266 0.26363367 0.64899637]]
Now we can view the nearest neighbors with
dx, dy = 2,1
print "Cell value A[%i,%i] = %f " % (dx, dy, A[dx,dy])
print "k=%i nearest neighbors: "%k, A[Xidx+dx, Yidx+dy]
Giving:
Cell value A[2,1] = 0.989038
k=1 nearest neighbors: [ 0.02542108 0.52542962 0.28203009 0.08955781 0.86881875 0.57253561 0.08830487 0.06418296]
Bonus
As mentioned, by changing k
you can easily get the next nearest neighbors, and next-next neighbors, etc... In addition, the ability to index a higher order array (say a tensor of rank 3) is now possible by adding an additional variable Zidx
in a similar way.
Caveats
This works nicely when you go to the rightmost and bottom of your matrix - you'll get smaller lists (as you specified you wanted). However, numpy
indexing (and Python) as well, wraps around, so an index of -1
will give you the last element. Thus asking for the offset at 0,0
will still give you eight entries by wrapping around. The other answers here show a good way to check for this.
If you want to grab something on the left side edge (and you really don't want to use an if statement), you might change the index as such (making sure to remove the center element as above):
# Create the nearest neighbors (ON THE LEFT EDGE)
Xidx_left, Yidx_left = mgrid[0:k+1,-k:k+1]
Upvotes: 2
Reputation: 10162
code with no coordinates? Do you mean like this:
XMAX = 800
YMAX = 570
NEIGHBOURS = [(-1, -1), (0, -1), (1, -1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1)]
matrix = range(XMAX * YMAX)
def all_neighbours(m):
for i in xrange(len(m)):
ns = []
y, x = divmod(i, XMAX)
for u, v in NEIGHBOURS:
ux = u + x
vy = v + y
if 0 <= ux < XMAX and 0 <= vy < YMAX:
ns.append(ux + vy * YMAX)
yield i, ns
if __name__ == '__main__':
for field, neighbours in all_neighbours(matrix):
print field, neighbours
Upvotes: 0