radio-astro-tools / radio-beam

A simple toolkit for reading and manipulating beams from astrophysical radio spectral data cubes.
https://radio-beam.readthedocs.io/en/latest/
BSD 3-Clause "New" or "Revised" License
26 stars 21 forks source link

Invalid slice error #110

Open keflavich opened 2 years ago

keflavich commented 2 years ago

I've encountered a strange invalid slice error with a beam list. I'm not sure I can reproduce a MWE, but I'm reporting this because I'm sure we'll eventually find a cause.

>>> np.nanmedian(spec)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/scratch/local/42000842/ipykernel_40160/2236068460.py in <module>
----> 1 np.nanmedian(spec)

<__array_function__ internals> in nanmedian(*args, **kwargs)

/blue/adamginsburg/adamginsburg/repos/astropy/astropy/units/quantity.py in __array_function__(self, function, types, args, kwargs)
   1673         # implementation.
   1674         if function in SUBCLASS_SAFE_FUNCTIONS:
-> 1675             return super().__array_function__(function, types, args, kwargs)
   1676 
   1677         elif function in FUNCTION_HELPERS:

~/.local/lib/python3.9/site-packages/numpy/lib/nanfunctions.py in nanmedian(a, axis, out, overwrite_input, keepdims)
   1117         return np.nanmean(a, axis, out=out, keepdims=keepdims)
   1118 
-> 1119     r, k = function_base._ureduce(a, func=_nanmedian, axis=axis, out=out,
   1120                                   overwrite_input=overwrite_input)
   1121     if keepdims and keepdims is not np._NoValue:

~/.local/lib/python3.9/site-packages/numpy/lib/function_base.py in _ureduce(a, func, **kwargs)
   3562         keepdim = (1,) * a.ndim
   3563 
-> 3564     r = func(a, **kwargs)
   3565     return r, keepdim
   3566 

~/.local/lib/python3.9/site-packages/numpy/lib/nanfunctions.py in _nanmedian(a, axis, out, overwrite_input)
    985         part = a.ravel()
    986         if out is None:
--> 987             return _nanmedian1d(part, overwrite_input)
    988         else:
    989             out[...] = _nanmedian1d(part, overwrite_input)

~/.local/lib/python3.9/site-packages/numpy/lib/nanfunctions.py in _nanmedian1d(arr1d, overwrite_input)
    972         return arr1d[-1]
    973 
--> 974     return np.median(arr1d_parsed, overwrite_input=overwrite_input)
    975 
    976 

<__array_function__ internals> in median(*args, **kwargs)

/blue/adamginsburg/adamginsburg/repos/astropy/astropy/units/quantity.py in __array_function__(self, function, types, args, kwargs)
   1673         # implementation.
   1674         if function in SUBCLASS_SAFE_FUNCTIONS:
-> 1675             return super().__array_function__(function, types, args, kwargs)
   1676 
   1677         elif function in FUNCTION_HELPERS:

~/.local/lib/python3.9/site-packages/numpy/lib/function_base.py in median(a, axis, out, overwrite_input, keepdims)
   3653 
   3654     """
-> 3655     r, k = _ureduce(a, func=_median, axis=axis, out=out,
   3656                     overwrite_input=overwrite_input)
   3657     if keepdims:

~/.local/lib/python3.9/site-packages/numpy/lib/function_base.py in _ureduce(a, func, **kwargs)
   3562         keepdim = (1,) * a.ndim
   3563 
-> 3564     r = func(a, **kwargs)
   3565     return r, keepdim
   3566 

~/.local/lib/python3.9/site-packages/numpy/lib/function_base.py in _median(a, axis, out, overwrite_input)
   3708     if np.issubdtype(a.dtype, np.inexact) and sz > 0:
   3709         # warn and return nans like mean would
-> 3710         rout = mean(part[indexer], axis=axis, out=out)
   3711         return np.lib.utils._median_nancheck(part, rout, axis, out)
   3712     else:

/blue/adamginsburg/adamginsburg/repos/spectral-cube/spectral_cube/lower_dimensional_structures.py in __getitem__(self, key)
   1116 
   1117     def __getitem__(self, key):
-> 1118         new_qty = super(VaryingResolutionOneDSpectrum, self).__getitem__(key)
   1119 
   1120         # use the goodbeams_mask setter here because it checks size

/blue/adamginsburg/adamginsburg/repos/spectral-cube/spectral_cube/lower_dimensional_structures.py in __getitem__(self, key, **kwargs)
    751         # keeping it here.
    752         try:
--> 753             kwargs['beams'] = self.beams[key]
    754         except (AttributeError, TypeError):
    755             pass

/blue/adamginsburg/adamginsburg/repos/radio-beam/radio_beam/multiple_beams.py in __getitem__(self, view)
    147                          meta=[x for ii,x in zip(view, self.meta) if ii])
    148         else:
--> 149             raise ValueError("Invalid slice")
    150 
    151     def __array_finalize__(self, obj):

ValueError: Invalid slice

Debug work:

> /blue/adamginsburg/adamginsburg/repos/radio-beam/radio_beam/multiple_beams.py(149)__getitem__()
    147                          meta=[x for ii,x in zip(view, self.meta) if ii])
    148         else:
--> 149             raise ValueError("Invalid slice")
    150 
    151     def __array_finalize__(self, obj):

ipdb>  u
> /blue/adamginsburg/adamginsburg/repos/spectral-cube/spectral_cube/lower_dimensional_structures.py(753)__getitem__()
    751         # keeping it here.
    752         try:
--> 753             kwargs['beams'] = self.beams[key]
    754         except (AttributeError, TypeError):
    755             pass

ipdb>  key
(slice(1919, 1921, None),)
ipdb>  self.beams.shape
(3840,)
ipdb>  self.beams[1919:1921]
<Beams [8.1078265e-14, 8.1087094e-14] sr>
ipdb>  self.beams(slice(1919,1921))
*** TypeError: 'Beams' object is not callable
ipdb>  self.beams[slice(1919,1921)]
<Beams [8.1078265e-14, 8.1087094e-14] sr>
ipdb>  self.beams[(slice(1919,1921),)]
*** ValueError: Invalid slice

so the problem is that we're passing a list of slices instead of a single slice here.

A workaround is to do something like:

if len(key) == 1:
    key=key[0]

in the lower_dimensional_structures call, but this is fundamentally a beams issue because we're using isinstance here: https://github.com/radio-astro-tools/radio-beam/blob/master/radio_beam/multiple_beams.py#L129-L149