# Boolean masking on multiple axes with numpy

X[mask1, mask2] is described in Boolean Array Indexing Doc as the equivalent of

In : X[mask1.nonzero(), mask2.nonzero()]
Out: array([1, 5])
In : X[[0,1], [0,1]]
Out: array([1, 5])


In effect it is giving you X[0,0] and X[1,1] (pairing the 0s and 1s).

In : X[[,], [0,1]]
Out:
array([[1, 2],
[4, 5]])


np.ix_ is a handy tool for creating the right mix of dimensions

In : np.ix_([0,1],[0,1])
Out:
(array([,
]), array([[0, 1]]))
In : X[np.ix_([0,1],[0,1])]
Out:
array([[1, 2],
[4, 5]])


That's effectively a column vector for the 1st axis and row vector for the second, together defining the desired rectangle of values.

But trying to broadcast boolean arrays like this does not work: X[mask1[:,None], mask2]

But that reference section says:

Combining multiple Boolean indexing arrays or a Boolean with an integer indexing array can best be understood with the obj.nonzero() analogy. The function ix_ also supports boolean arrays and will work without any surprises.

In : X[np.ix_(mask1, mask2)]
Out:
array([[1, 2],
[4, 5]])
Out:
(array([,
], dtype=int32), array([[0, 1]], dtype=int32))


The boolean section of ix_:

    if issubdtype(new.dtype, _nx.bool_):
new, = new.nonzero()


So it works with a mix like X[np.ix_(mask1, [0,2])]