0

I am trying to build a code that can be given an matrix of nans and not break. I wrote a simplified version here that recreates the problem. I am using numpy version 1.23.5

Basically the code takes a grid of nans and creates a annulus mask to apply to the grid and then take the median of what ever is in the annulus. This code does not produce the error as is.

from math import floor
from scipy.signal import convolve
import numpy as np

in_radius = 10
out_radius = 31
box_size = 5

box=np.ones((box_size,box_size))
padding=floor(box_size/2)

y,x=np.ogrid[-1*out_radius:out_radius+1,-1*out_radius:out_radius+1]
grid_mask=np.logical_or(x**2+y**2<in_radius**2,x**2+y**2>out_radius**2)

grid = np.empty((67,67),)
grid[:] = np.nan

smoothed=convolve(grid,box,method='direct',mode='valid') / 2

noisepix=np.ma.masked_array(smoothed,grid_mask)
median_signal = np.ma.median(noisepix)

The last line will produce a nan, which is fine.

However if I change out_radius to anything smaller than 28, numpy is unable to perform the calculation of the median. Here is the code that produces the error:

in_radius = 10
out_radius = 28
box_size = 5

box=np.ones((box_size,box_size))
padding=floor(box_size/2)

y,x=np.ogrid[-1*out_radius:out_radius+1,-1*out_radius:out_radius+1]
grid_mask=np.logical_or(x**2+y**2<in_radius**2,x**2+y**2>out_radius**2)

grid = np.empty((61,61),)
grid[:] = np.nan

smoothed=convolve(grid,box,method='direct',mode='valid') / 2

noisepix=np.ma.masked_array(smoothed,grid_mask)
median_signal = np.ma.median(noisepix)

The full error message is:

MaskError                                 Traceback (most recent call last)
/var/folders/89/zgv9nv5563n89pzs55bv6mzm0000gq/T/ipykernel_17229/2791888929.py in <module>
     21 
     22 noisepix=np.ma.masked_array(smoothed,grid_mask)
---> 23 median_signal = np.ma.median(noisepix)

~/opt/anaconda3/lib/python3.9/site-packages/numpy/ma/extras.py in median(a, axis, out, overwrite_input, keepdims)
    733             return m
    734 
--> 735     r, k = _ureduce(a, func=_median, axis=axis, out=out,
    736                     overwrite_input=overwrite_input)
    737     if keepdims:

~/opt/anaconda3/lib/python3.9/site-packages/numpy/lib/function_base.py in _ureduce(a, func, **kwargs)
   3723         keepdim = (1,) * a.ndim
   3724 
-> 3725     r = func(a, **kwargs)
   3726     return r, keepdim
   3727 

~/opt/anaconda3/lib/python3.9/site-packages/numpy/ma/extras.py in _median(a, axis, out, overwrite_input)
    779             if not odd:
    780                 s = np.true_divide(s, 2., casting='safe', out=out)
--> 781             s = np.lib.utils._median_nancheck(asorted, s, axis)
    782         else:
    783             s = mid.mean(out=out)

~/opt/anaconda3/lib/python3.9/site-packages/numpy/lib/utils.py in _median_nancheck(data, result, axis)
   1052             return data.dtype.type(np.nan)
   1053 
-> 1054         result[n] = np.nan
   1055     return result
   1056 

~/opt/anaconda3/lib/python3.9/site-packages/numpy/ma/core.py in __setitem__(self, indx, value)
   3344         """
   3345         if self is masked:
-> 3346             raise MaskError('Cannot alter the masked element.')
   3347         _data = self._data
   3348         _mask = self._mask

MaskError: Cannot alter the masked element.

I am trying to understand why this is happening for one size of outer radius and not the other.

I know that I can work around this by replacing the array of nans with zeros or something and just compensating for it. I am more after why this is happening in some case and not in others

loberhel
  • 1
  • 1
  • 1
    Do you realize that both cases are entirely masked with `nan` data values? Does `median` in such a case make sense? Without `axis` median works on the `ravel`, flat, array. The 28 case works if I specify an axis. – hpaulj Jun 26 '23 at 17:57
  • The error occurs deep in the `ma` code. Exactly why would require studying that code in some detail. It's not your fault, except that you are asking for the median of a totally masked array. `ma` is not heavily used, so I'm not surprised that some 'edge' case like this could be buggy. – hpaulj Jun 26 '23 at 17:59

0 Answers0