Q:

Updating elements in multiply indexed np.array

I have a 2D numpy array and need to update a selection of elements via multiple layers of indexing.  The obvious way to do this for me does not work since it seems numpy is only updating a copy of the array and not the array itself:
import numpy as np

# Create an array and indices that should be updated
arr = np.arange(9).reshape(3,3)
idx = np.array([[0,2], [1,1],[2,0]])
bool_idx = np.array([True, True, False])

# This line does not work as intended since the original array stays unchanged
arr[idx[:,0],idx[:,1]][bool_idx] = -1 * arr[idx[:,0],idx[:,1]][bool_idx]

This is the resulting output:
>>> arr
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

However, I expected this output:
>>> arr
array([[0, 1, -2],
       [3, -4, 5],
       [6, 7, 8]])

A:

We need to mask the indices with the given mask and then index into arr and assign new values.  For indexing, we can use tuple(masked_indices) to index or use the two columns of the index-array for integer-indexing, thus giving us two methods. 
Method #1 :
arr[tuple(idx[bool_idx].T)] *= -1

Method #2 :
idx_masked = idx[bool_idx]
arr[idx_masked[:,0],idx_masked[:,1]] *= -1

Why didn't the original method work? 
On LHS you were doing arr[idx[:,0],idx[:,1]][bool_idx], which is esssentially two steps : arr[idx[:,0],idx[:,1]], which under the hoods calls arr.__getitem__(indexer)*.  When indexer is a slice, the regularity of the elements allows NumPy to return a view (by modifying the strides and offset).  When indexer is an arbitrary boolean mask or arbitrary array of integers, there is in general no regularity to the elements selected, so there is no way to return a view.  Let's call arr[idx[:,0],idx[:,1]] as arr2.  
In the next step, with the combined arr[idx[:,0],idx[:,1]][bool_idx], i.e. arr2[bool_idx], under the hoods it calls arr2.__setitem__(mask), which is implemented to modify arr2 and as such doesn't propagate back to arr. 
*Inspiration from - https://stackoverflow.com/a/38768993/.
More info on __getitem__,__setitem__. 
Why did the methods posted in this post work? 
Because both directly used the indexer on arr with arr.__setitem__(indexer) that modifies arr.