Reputation: 2508
The title is a bit misleading, I hope it will be clear from the picture and description. I have an array (or arrays) of 0s and 1s where the ones form a kind of a diagonal in the array/matrix as seen on the following figure.
I would like to get to know the indices of the elements with a value of 0 below this 'diagonal'. How can I do that? The diagonal is not necessarily a diagonal (as seen), however, it is continuous and intercepts (ie there is always a separation between the upper
and lower
triangle). I have been thinking of some smart mask but since the zeros up and down are the same zeros and there is not necessarily a clear threshold (eg above 1 in columns), I couldn't solve it.
An example array is this:
example = np.array(
[[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0.],
[0., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
This would yield indices like:
[ 2, 12],
[ 2, 13],
[ 3, 11],
[ 3, 12],
[ 3, 13],
...
[13, 1],
[13, 2],
[13, 3],
[13, 4],
[13, 5],
..
[13, 12],
[13, 13]
Thanks.
Upvotes: 1
Views: 1097
Reputation: 13049
You can use np.cumsum
to add up the values going along the row to that point; you want the indices where your array is equal to zero but the cumulative sum going along the row is greater than zero.
np.argwhere((example == 0) & (np.cumsum(example,axis=1) > 0))
giving:
array([[ 2, 12],
[ 2, 13],
[ 3, 11],
[ 3, 12],
[ 3, 13],
...etc...
Note also that accumulating down a column would work equally (but may be marginally more expensive for a large array, in terms of efficiency of memory access). This would use axis=0
instead of axis=1
.
Upvotes: 4
Reputation: 29732
One way using scipy.ndimage.label
:
conn = [[0,1,0], [1,1,1], [0,1,0]]
arr, _ = label(1-example, conn)
This will automatically label the flipped ones, considering all the connected non-zeros (calculated using conn
) as a single label. Note that conn
is a cross-like array; non-zeros are considered as a whole if they are adjacent by up-down and left-right, but not diagonally.:
array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 2, 2],
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 2, 2, 2],
[1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 2, 2, 2, 2],
[1, 1, 1, 1, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2],
[1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2],
[1, 1, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2],
[1, 1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2],
[1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2],
[0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]])
Then you can find the second label (i.e. lower triangle-like)
np.argwhere(arr==2)
Output:
array([[ 2, 12],
[ 2, 13],
[ 3, 11],
...
[13, 11],
[13, 12],
[13, 13]], dtype=int64)
Upvotes: 2