# Path: src/pys5p/biweight.py
# def biweight(data, axis=None, spread=False):
#     """
#     Calculate Tukey's biweight.
#     Implementation based on Eqn. 7.6 and 7.7 in the SWIR OCAL ATBD.
# 
#     Parameters
#     ----------
#     data   :   array_like
#        input array
#     axis   :   int, optional
#        axis along which the biweight medians are computed.
#         - Note that axis will be ignored when data is a 1-D array.
#     spread :   bool, optional
#        if True, then return also the biweight spread.
# 
#     Returns
#     -------
#     out    :   ndarray or tuple
#        biweight median and biweight spread if parameter "spread" is True
#     """
#     if axis is None or data.ndim == 1:
#         mask = np.isfinite(data)
#         if np.all(~mask):
#             if spread:
#                 return (np.nan, 0.)
#             return np.nan
#         return __biweight(data, spread)
# 
#     # only a single axis!
#     if not isinstance(axis, int):
#         raise TypeError('axis not an integer')
#     if not 0 <= axis < data.ndim:
#         raise ValueError('axis out-of-range')
# 
#     with warnings.catch_warnings():
#         warnings.filterwarnings('ignore', r'All-NaN (slice|axis) encountered')
#         return __biweight_axis(data, axis, spread)


from collections import namedtuple
from copy import deepcopy
from pathlib import PurePath
from h5py import Dataset
from .biweight import biweight
import numpy as np
               or self.value[data_sel].ndim <= max(axis):
                return self
            perc = np.nanpercentile(self.value[data_sel], vperc,
                                    axis=axis, keepdims=keepdims)
        if len(vperc) == 3:
            self.value = perc[1, ...]
            self.error = [perc[0, ...], perc[2, ...]]
        else:
            self.value = perc[0, ...]

        # adjust the coordinates
        if keepdims:
            key = self.coords._fields[axis]
            if self.coords[axis][0] == 0:
                dims = [0]
            else:
                dims = np.median(self.coords[axis], keepdims=keepdims)
            self.coords = self.coords._replace(**{key: dims})
        else:
            keys = []
            dims = []
            for ii in range(self.value.ndim+len(axis)):
                if ii not in axis:
                    keys.append(self.coords._fields[ii])
                    dims.append(self.coords[ii][:])
            coords_namedtuple = namedtuple('Coords', keys)
            self.coords = coords_namedtuple._make(dims)

        return self


# Path: src/pys5p/biweight.py
# def biweight(data, axis=None, spread=False):
#     """
#     Calculate Tukey's biweight.
#     Implementation based on Eqn. 7.6 and 7.7 in the SWIR OCAL ATBD.
# 
#     Parameters
#     ----------
#     data   :   array_like
#        input array
#     axis   :   int, optional
#        axis along which the biweight medians are computed.
#         - Note that axis will be ignored when data is a 1-D array.
#     spread :   bool, optional
#        if True, then return also the biweight spread.
# 
#     Returns
#     -------
#     out    :   ndarray or tuple
#        biweight median and biweight spread if parameter "spread" is True
#     """
#     if axis is None or data.ndim == 1:
#         mask = np.isfinite(data)
#         if np.all(~mask):
#             if spread:
#                 return (np.nan, 0.)
#             return np.nan
#         return __biweight(data, spread)
# 
#     # only a single axis!
#     if not isinstance(axis, int):
#         raise TypeError('axis not an integer')
#     if not 0 <= axis < data.ndim:
#         raise ValueError('axis out-of-range')
# 
#     with warnings.catch_warnings():
#         warnings.filterwarnings('ignore', r'All-NaN (slice|axis) encountered')
#         return __biweight_axis(data, axis, spread)


# Path: src/pys5p/s5p_msm.py
from collections import namedtuple
from copy import deepcopy
from pathlib import PurePath
from h5py import Dataset
from .biweight import biweight
import numpy as np

               or self.value[data_sel].ndim <= max(axis):
                return self
            perc = np.nanpercentile(self.value[data_sel], vperc,
                                    axis=axis, keepdims=keepdims)
        if len(vperc) == 3:
            self.value = perc[1, ...]
            self.error = [perc[0, ...], perc[2, ...]]
        else:
            self.value = perc[0, ...]

        # adjust the coordinates
        if keepdims:
            key = self.coords._fields[axis]
            if self.coords[axis][0] == 0:
                dims = [0]
            else:
                dims = np.median(self.coords[axis], keepdims=keepdims)
            self.coords = self.coords._replace(**{key: dims})
        else:
            keys = []
            dims = []
            for ii in range(self.value.ndim+len(axis)):
                if ii not in axis:
                    keys.append(self.coords._fields[ii])
                    dims.append(self.coords[ii][:])
            coords_namedtuple = namedtuple('Coords', keys)
            self.coords = coords_namedtuple._make(dims)

        return self


    def biweight(self, data_sel=None, axis=0, keepdims=False):