You can just use the 3 argument form of np.where for this:
>>> import numpy as np
>>> x = np.array([1,2,31,32,4,0,3,0,0,0])
>>> z = np.array([99] * len(x))
>>> y = np.where(x != 0, x, z)
>>> y
array([ 1, 2, 31, 32, 4, 99, 3, 99, 99, 99])
Answer from mgilson on Stack OverflowYou can just use the 3 argument form of np.where for this:
>>> import numpy as np
>>> x = np.array([1,2,31,32,4,0,3,0,0,0])
>>> z = np.array([99] * len(x))
>>> y = np.where(x != 0, x, z)
>>> y
array([ 1, 2, 31, 32, 4, 99, 3, 99, 99, 99])
You're on the right track. Instead of using masked_where, you can find the values in x that aren't 0 using the != operator for ndarrays:
>>> import numpy as np
>>> x = np.array([1,2,31,32,4,0,3,0,0,0])
>>> y = x != 0 # create a boolean array of indices i where x[i] != 0
>>> y
array([ True, True, True, True, True, False, True, False, False, False], dtype=bool)
>>> z = np.array([99] * len(x))
>>> z
array([99, 99, 99, 99, 99, 99, 99, 99, 99, 99])
>>> z[y] = x[y]
>>> z
array([ 1, 2, 31, 32, 4, 99, 3, 99, 99, 99])
Why don't you use imshow instead?
You can plot a 2D image by doing:
plt.imshow(Image1, cmap='gray') # I would add interpolation='none'
Afterwards, you can easily overlay the segmentation by doing:
plt.imshow(Image2_mask, cmap='jet', alpha=0.5) # interpolation='none'
Changing the alpha will change the opacity of the overlay.
Additionaly, why do you create 2 masks? Only one should be enough, you can do:
Image2_mask = ma.masked_array(Image2 > 0, Image2)
Practical example:
import numpy as np
mask = np.zeros((10,10))
mask[3:-3, 3:-3] = 1 # white square in black background
im = mask + np.random.randn(10,10) * 0.01 # random image
masked = np.ma.masked_where(mask == 0, mask)
import matplotlib.pyplot as plt
plt.figure()
plt.subplot(1,2,1)
plt.imshow(im, 'gray', interpolation='none')
plt.subplot(1,2,2)
plt.imshow(im, 'gray', interpolation='none')
plt.imshow(masked, 'jet', interpolation='none', alpha=0.7)
plt.show()

Completing the Imanol Luengo's answer : masking image could be directly handled in imshow alpha option by putting an alpla image ie.
plt.imshow(Image1, cmap='gray') # I would add interpolation='none'
plt.imshow(Image2, cmap='jet', alpha=0.5*(Image2>0) ) # interpolation='none'
Your issue is trying to work with lists or object arrays.
Numpy is simply not designed for that. Use a flat array instead.
# convert subixs to a flat array
flat_subixs = np.concatenate(subixs)
# compute the lengths once
lengths = np.array([len(l) for l in subixs])
arr = np.repeat(overlay, lengths)
print(arr)
msk = (overlay == 1) | (overlay == 3)
arr[flat_subixs[np.repeat(msk, lengths)]] = np.repeat([44, 48, 47], lengths[msk])
print(arr)
Output:
[0 0 0 0 1 1 1 4 3]
[ 0 0 0 0 44 44 48 4 47]
This way all the slow computations (concatenation and lengths) are performed only once, and all other operations are vectorized.
If you want to mutate overlay this is also possible, just create arr once in the end:
msk = (overlay == 1) | (overlay == 3)
overlay[msk] = [44, 48, 47]
# eventually add other transforms here
# finally create "arr" once
arr = np.repeat(overlay, lengths)
print(arr)
# [ 0 0 0 0 44 44 48 4 47]
import numpy as np
new_value = [44, 48, 47]
msk = (overlay == 1) | (overlay == 3)
overlay[msk] = new_value
subixs = [[0, 1, 2, 3], [4, 5], [6], [7], [8]]
subixs = np.asarray(subixs, dtype=object)
arr_ixs = sum(subixs[msk], []) # Flatten the list of lists
# Get lengths of each selected sublist
lengths = np.array([len(lst) for lst in subixs[msk]])
# Repeat values accordingly
new_arr_value = np.repeat(new_value, lengths)
# Assign values
arr[arr_ixs] = new_arr_value
Explanation:
lengthsgives how many times each value should be repeated based on the size of the sublist.np.repeatvectorizes the expansion ofnew_valueto the desired length.This avoids any explicit Python loops for expansion.
I don't think it is possible.
In your first example, the values of the a and b views are interwoven, as can be seen from this variation:
In [51]: c=np.arange(10).reshape(5,2)
In [52]: a, b = c[:,0], c[:,1]
In [53]: a
Out[53]: array([0, 2, 4, 6, 8])
In [54]: c.flatten()
Out[54]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
The data buffer for c and a start at the same memory point; b starts at 4 bytes into that buffer.
In [55]: c.__array_interface__
Out[55]:
{'strides': None,
'data': (172552624, False),...}
In [56]: a.__array_interface__
Out[56]:
{'strides': (8,),
'data': (172552624, False),...}
In [57]: b.__array_interface__
Out[57]:
{'strides': (8,),
'data': (172552628, False),...}
Even if the a,b split were by rows, b would start just further along in the same shared data buffer.
From the .flags we see that c is C-contiguous, b is not. But b values are accessed with constant strides in that shared data buffer.
When a and b are created separately, their data buffers are entirely separate. The numpy striding mechanism cannot step back and forth between these two data buffers. A 2d composite of a and b has to work with its own data buffer.
I can imagine writing a class that ends up looking like what you want. The indexing_tricks file that defines np.c_ might give you ideas (e.g. a class with a custom __getitem__ method). But it wouldn't have the speed advantages of a regular 2d array. And it might be hard to implement all of the ndarray functionality.
While @hpaulj's answer is the correct one, for your particular case, and more as an exercise in understanding numpy memory layout than as anything with practical applications, here's how you can get a view of two 1-D arrays as columns of a common array:
>>> from numpy.lib.stride_tricks import as_strided
>>> a = np.arange(10)
>>> b = np.arange(20, 30)
>>> col_stride = (b.__array_interface__['data'][0] -
a.__array_interface__['data'][0])
>>> c = as_strided(a, shape=(10, 2), strides=(a.strides[0], col_stride))
>>> c
array([[ 0, 20],
[ 1, 21],
[ 2, 22],
[ 3, 23],
[ 4, 24],
[ 5, 25],
[ 6, 26],
[ 7, 27],
[ 8, 28],
[ 9, 29]])
>>> c[4, 1] = 0
>>> c[6, 0] = 0
>>> a
array([0, 1, 2, 3, 4, 5, 0, 7, 8, 9])
>>> b
array([20, 21, 22, 23, 0, 25, 26, 27, 28, 29])
There are many things that can go wrong here, mainly that the array b has not had its reference count increased, so if you delete it its memory will be released, but the view will still be accessing it. It can also not be extended to more than two 1-D arrays, and requires that both 1-D arrays have the same stride.
Of course, just because you can do it doesn't mean you should do it! And you should definitely not do this.

