7

I want to apply mask on 2D numpy array. But it does not work correctly. Suppose I have

val(lat, lon)  ---> my 2D array (20, 30)


Mask_lat = np.ma.masked_array(lat, mask=latmask)  ---> masked lat (5,)


Mask_lon = np.ma.masked_array(lon, mask =lonmask)   ---> masked lon (8,)


Maks_val = np.ma.masked_array(val, mask=mask_lat_lon) ---> ?

I do not know how can I pass a correct mask_lat_lon to have masked val (5,8). I would appreciate if one guides me.

Thank you in advance.

2
  • my first idea is lonmask&latmask but I don't understand precisely what is masked lat (5,) Commented Jan 18, 2016 at 18:18
  • I don't really understand what you're asking. Could you give a concrete example showing your inputs and your desired output? Commented Jan 18, 2016 at 18:55

1 Answer 1

9

If I understand your question correctly, you have two 1D arrays that represent y and x (lat and long) positions in a 2D array. You want to mask a region based on the x/y position in the 2D array.

The key part to understand is that mask for a 2D array is also 2D.

For example, let's mask a single element of a 2D array:

import numpy as np

z = np.arange(20).reshape(5, 4)
mask = np.zeros(z.shape, dtype=bool)

mask[3, 2] = True

print z
print np.ma.masked_array(z, mask)

This yields:

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]
 [16 17 18 19]]

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 -- 15]
 [16 17 18 19]]

In your case, you have two 1D x and y arrays that you need to create a 2D mask from. For example:

import numpy as np

x = np.linspace(-85, -78, 4)
y = np.linspace(32, 37, 5)
z = np.arange(20).reshape(5, 4)

xmask = (x > -82.6) & (x < -80)
ymask = (y > 33) & (y < 35.6)

print xmask
print ymask

We'd then need to combine them into a single 2D mask using broadcasting:

mask = xmask[np.newaxis, :] & ymask[:, np.newaxis]

Slicing with newaxis (or None, they're the same object) adds a new axis at that position, turning the 1D array into a 2D array. It you have seen this before, it's useful to take a quick look at what xmask[np.newaxis, :] and ymask[:, np.newaxis] look like:

In [14]: xmask
Out[14]: array([False, False,  True, False], dtype=bool)

In [15]: ymask
Out[15]: array([False,  True,  True, False, False], dtype=bool)

In [16]: xmask[np.newaxis, :]
Out[16]: array([[False, False,  True, False]], dtype=bool)

In [17]: ymask[:, np.newaxis]
Out[17]:
array([[False],
       [ True],
       [ True],
       [False],
       [False]], dtype=bool)

mask will then be (keep in mind that True elements are masked):

In [18]: xmask[np.newaxis, :] & ymask[:, np.newaxis]
Out[18]:
array([[False, False, False, False],
       [False, False,  True, False],
       [False, False,  True, False],
       [False, False, False, False],
       [False, False, False, False]], dtype=bool)

Finally, we can create a 2D masked array from z based on this mask:

arr = np.masked_array(z, mask)

Which gives us our final result:

 [[ 0  1  2  3]
  [ 4  5 --  7]
  [ 8  9 -- 11]
  [12 13 14 15]
  [16 17 18 19]]
Sign up to request clarification or add additional context in comments.

2 Comments

How would I change the logic so that when combining the two 1D masks to create the 2D mask, I mask anywhere either of the 1d masks were True. I have a very similar problem except I want to mask certain latitudes for all longitudes and certain longitudes for all latitudes. I have a 1D mask for latitudes and a 1D mask for longitudes.
@Will.Evo, to effectively clip the 2D array by two 1D masks, create mask as shown above, then clipped_z = z[mask]. This creates a 1D array that can then be converted to 2D with clipped_z.reshape(). Appropriate dimensions for reshaping can be obtained with np.sum(xmask) and np.sum(ymask), which count the number of True.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.