Indexed assignment can obscure some details, which I think are clearer with the getitem
equivalent.
In [88]: arr = np.arange(25).reshape(5,5)
In [89]: arr
Out[89]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
In [90]: coord = [[2,3],[1,2]]
In [91]: arr[coord]
FutureWarning: Using a non-tuple sequence for multidimensional indexing
is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the
future this will be interpreted as an array index, `arr[np.array(seq)]`,
which will result either in an error or a different result.
Out[91]: array([11, 17])
Correct indexing for a pair of points, applying [2,3] for 1st axis, [1,2] to 2nd:
In [92]: coord = ([2,3],[1,2])
In [93]: arr[coord]
Out[93]: array([11, 17])
In [94]: arr[[2,3], [1,2]]
Out[94]: array([11, 17])
Historically numpy
was a bit sloppy, and interpreted a list of lists like a tuple of lists (under certain circumstances). Newer versions are trying to remove this inconsistency.
In [95]: coord = [[2,3]]
In [96]: arr[coord]
FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.
Out[96]:
array([[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
In [97]: coord = ([2,3],) # clearer - pick 2 rows, e.g. arr[[2,3],:]
In [98]: arr[coord]
Out[98]:
array([[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
In [99]: arr[2,3] # pick one point
Out[99]: 13
In [100]: coord = (2,3)
In [101]: arr[coord]
Out[101]: 13
With the array, there's none of this confusing lists for tuples:
In [102]: coord = np.array([[2,3], [1,2]])
In [103]: arr[coord]
Out[103]:
array([[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]],
[[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]]])
This picks a (2,2) block of rows. Your arr[coord]=30
obscured this pattern, since there were duplicates in the rows selection (and assignment is buffered). (for unbuffered assignment, test np.add.at(t,coord,30)
).
If we explicitly tell it that coord
applies to the 1st dimension, we the same array style of indexing:
In [111]: coord = [[2,3],[1,2]]
In [112]: arr[coord,:]
Out[112]:
array([[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]],
[[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]]])
Note the difference in shape if I use this last [coord,]
with the 1 element list:
In [117]: coord = [[2,3]]
In [118]: arr[coord,]
Out[118]:
array([[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]])
In [119]: _.shape
Out[119]: (1, 2, 5)
So make coord
a tuple rather than a list, if you want each element to apply to a different dimension. Or use an array if you want it applied to just one dimension, or be explicit with the [coord,:]
like notation.
If you take this array, transpose it, and split that into a tuple, you get index arrays for the 2 dimensions:
In [120]: coord = np.array([[2,3],[1,2]])
In [121]: coord
Out[121]:
array([[2, 3],
[1, 2]])
In [123]: tuple(coord.T)
Out[123]: (array([2, 1]), array([3, 2]))
In [124]: arr[tuple(coord.T)]
Out[124]: array([13, 7])
and with 4 points:
In [125]: coord = np.array([[2,3],[1,2],[0,0],[3,4]])
In [126]: arr[tuple(coord.T)]
Out[126]: array([13, 7, 0, 19])
I don't know if this will help or not, but np.where
is often used to select points in an array:
The condition - multiples of 4:
In [135]: arr%4==0
Out[135]:
array([[ True, False, False, False, True],
[False, False, False, True, False],
[False, False, True, False, False],
[False, True, False, False, False],
[ True, False, False, False, True]])
Indices of these points - a tuple with an array for each dimension. That can be used directly as an index:
In [136]: np.where(arr%4==0)
Out[136]: (array([0, 0, 1, 2, 3, 4, 4]), array([0, 4, 3, 2, 1, 0, 4]))
In [137]: arr[_]
Out[137]: array([ 0, 4, 8, 12, 16, 20, 24])
argwhere
applies np.transpose
to that tuple, making a (n,2) array:
In [138]: np.argwhere(arr%4==0)
Out[138]:
array([[0, 0],
[0, 4],
[1, 3],
[2, 2],
[3, 1],
[4, 0],
[4, 4]])
Those are the coordinates of the individual elements, but they can't be used directly as indices, except iteratively:
In [144]: [arr[i,j] for i,j in np.argwhere(arr%4==0)]
Out[144]: [0, 4, 8, 12, 16, 20, 24]
I think you are generating coordinates in this argwhere
style, but you really need them in the where
style - as a tuple of arrays.