import numpy as np
import pandas as pd
from pysptools.abundance_maps import NNLS, FCLS, UCLS
from libpyhat.Unmixing.MLM import LMM, GBM
[docs]
def unmix(
    spectra,
    endmembers,
    unmix_method,
    params=None,
    normalize=False,
    mask=None,
    em_names=None,
):
    """
    Parameters
    ----------
    spectra : libpyhat spectra object
                    This contains spectral information and corresponding
                    wavelength values
    endmembers :
                    Endmember spectra to use for unmixing
    unmix_method : string
                    The name of the unmixing method. See supported_methods
                    variable for the list of possibilities.
    params :        Only relevant to the *non* pysptools methods; contains
    parameter values for methods
    normalize : boolean
                    Only relevant to the pysptools methods; determines
                    whether to normalize before analysis
    mask : array
                    Contains entry for each wvl column to indicate whether
                    to mask
    em_names : list of strings
                    Contains names of the end members
    Returns
    -------
    results : unmixing method results (varies)
                    Includes results from the unmixing algorithm
    """
    supported_methods = ["NNLS", "FCLS", "UCLS", "LMM", "GBM"]
    # set a default value for whether the method is a pysptools method
    is_pysp = False
    try:
        if unmix_method.upper() in supported_methods:
            if unmix_method == "NNLS":
                method = NNLS()
                is_pysp = True
            if unmix_method == "FCLS":
                method = FCLS()
                is_pysp = True
            if unmix_method == "UCLS":
                method = UCLS()
                is_pysp = True
            if unmix_method == "LMM":
                method = LMM(**params)
            if unmix_method == "GBM":
                method = GBM(**params)
        else:
            print(
                f"{unmix_method} is not a supported method.  Supported "
                f"methods are {supported_methods}"
            )
            return 1
    except KeyError:
        print(f"Unable to instantiate class from {unmix_method}.")
        return 1
    # If the user doesn't provide names for the end members, generate
    # generic ones
    if em_names is None:
        em_names = ["EM" + str(i + 1) for i in range(endmembers.shape[0])]
    # If the algorithm the user chose is from pysptools
    if is_pysp:
        # If there is more than one spectrum, set up a data cube
        if len(spectra.shape) == 2:
            spectra = np.expand_dims(spectra, 0)  # pysptools expects a cube
        # Produce results and a column list, which will be combined and
        # returned to the user
        results = method.map(
            np.array(spectra), np.array(endmembers), normalize=normalize, mask=mask
        )
        cols = [
            (unmix_method + " Normalize:" + str(normalize) + " Mask:" + str(mask), i)
            for i in em_names
        ]
    else:  # If the algorithm is *not* from pysptools
        # Same here
        results = method.unmix(spectra, endmembers)
        cols = [(unmix_method + str(params), i) for i in em_names]
    # Combine results into a dataframe and return them to the user
    results = pd.DataFrame(np.squeeze(results), columns=pd.MultiIndex.from_tuples(cols))
    return results