Tom
Tom

Reputation: 175

How do I access elements of a 2d array based on two where clauses?

I have the following ndarray:

[[  3 271]
 [  4 271]
 [375 271]
 [  3 216]
 [375 216]
 [  0   0]
 [  0 546]
 [378 546]
 [378   0]
 [  1 182]
 [  2 181]
 [376 181]
 [377 182]
 [377 544]
 [376 545]]

Essentially a bunch of X,Y coordinates/points. I'd like to be able to select X,Y coordinates "near" a given point on both axes.

For example, given a target point of [3, 271], I'd first retrieve all other points at this Y location (271), to then be able to select rows -/+ 3 on the X axis. For the above, that should yield:

[  3 271]
[  4 271]

I've gotten as far as getting all rows with the same Y value like this:

index_on_y = points[:,1] == point[1]
shared_y = points[index_on_y]

This returns:

shared_y:
[[  3 271]
 [  4 271]
 [375 271]]

How do I now select all rows from this array where the X value (column 0) can be anything between 0-6? I've tried various combinations of slicing/indexing/np.where but I've not been able to get the desired result. The below is as far as I got, but I know it is incorrect; just don't know what the right (and most efficient) way of doing it would be:

def nearby_contour_points_x(self, point, points, radius):
    index_on_y = points[:,1] == point[1] # correct
    shared_y = points[index_on_y] # correct
    x_vals = shared_y[:,0] # not good?

    index_on_x = np.where(np.logical_or(x_vals <= (point[0] - radius), x_vals <= (point[0] + radius)))
    return shared_y[index_on_x]

Ideally, I wouldn't have to first group on one of the axes.

Upvotes: 0

Views: 96

Answers (2)

wwii
wwii

Reputation: 23743

With a as the array in your example.

target = np.array([3, 271])

Subtract the target

diff = a - target

y (column one) must be the same as the target - this results in a boolean array of shape a.shape[0]:

y_rows = diff[:,1] == 0

x is within a range of the target - this results in a boolean array of shape a.shape[0]:

x_rows = np.logical_and(diff[:,0] <= 6, diff[:,0] >= 0)

Make a mask for boolean indexing - its shape will be (15,) - a.shape[0], allowing it to broadcast along the rows

mask = np.logical_and(x_rows, y_rows)

>>> a[mask]
array([[  3, 271],
       [  4, 271]])

Foregoing the initial subtraction and a little more generalized:

x_rows = np.logical_and(a[:,0] >= target[0] - 3, a[:,0] <= target[0] + 3)
y_rows = a[:,1] == target[1]
mask = np.logical_and(x_rows, y_rows)

Upvotes: 1

f5r5e5d
f5r5e5d

Reputation: 3706

perhaps an abuse of isclose but works

ys = np.array([[  3, 271],
 [  4, 271],
 [375, 271]])

np.compress(np.all(np.isclose(ys, [3,271], rtol=0, atol=3), axis=1), ys, axis=0)
Out[273]: 
array([[  3, 271],
       [  4, 271]])

Upvotes: 0

Related Questions