def devolatilise(df: pd.DataFrame,
                 exclude=['H2O', 'H2O_PLUS', 'H2O_MINUS', 'CO2', 'LOI'],
                 renorm=True):
    """
    Recalculates components after exclusion of volatile phases (e.g. H2O, CO2).
    """
    keep = [i for i in df.columns if not i in exclude]
    if renorm:
         return renormalise(df.loc[:, keep])
    else:
        return df.loc[:, keep]
def devolatilise(df: pd.DataFrame,
                 exclude=['H2O', 'H2O_PLUS', 'H2O_MINUS', 'CO2', 'LOI'],
                 renorm=True):
    """
    Recalculates components after exclusion of volatile phases (e.g. H2O, CO2).
    """
    keep = [i for i in df.columns if not i in exclude]
    if renorm:
        return renormalise(df.loc[:, keep])
    else:
        return df.loc[:, keep]
def to_weight(df: pd.DataFrame, renorm=True):
    """
    Converts molar quantities to mass quantities of the same order.
    E.g.:
    mol% --> mass%
    mol-ppm --> mass-ppm
    """
    MWs = [pt.formula(c).mass for c in df.columns]
    if renorm:
        return renormalise(df.multiply(MWs))
    else:
        return df.multiply(MWs)
def to_molecular(df: pd.DataFrame, renorm=True):
    """
    Converts mass quantities to molar quantities of the same order.
    E.g.:
    mass% --> mol%
    mass-ppm --> mol-ppm
    """
    MWs = [pt.formula(c).mass for c in df.columns]
    if renorm:
        return renormalise(df.div(MWs))
    else:
        return df.div(MWs)
def to_weight(df: pd.DataFrame, renorm=True):
    """
    Converts molar quantities to mass quantities of the same order.
    E.g.:
    mol% --> mass%
    mol-ppm --> mass-ppm
    """
    MWs = [pt.formula(c).mass for c in df.columns]
    if renorm:
        return renormalise(df.multiply(MWs))
    else:
        return df.multiply(MWs)
def to_molecular(df: pd.DataFrame, renorm=True):
    """
    Converts mass quantities to molar quantities of the same order.
    E.g.:
    mass% --> mol%
    mass-ppm --> mol-ppm
    """
    MWs = [pt.formula(c).mass for c in df.columns]
    if renorm:
         return renormalise(df.div(MWs))
    else:
        return df.div(MWs)
def recalculate_redox(df: pd.DataFrame,
                      to_oxidised=False,
                      renorm=True,
                      total_suffix='T'):
    """
    Recalculates abundances of redox-sensitive components (particularly Fe),
    and normalises a dataframe to contain only one oxide species for a given
    element.
    """
    # Assuming either (a single column) or (FeO + Fe2O3) are reported
    # Fe columns - FeO, Fe2O3, FeOT, Fe2O3T
    FeO = pt.formula("FeO")
    Fe2O3 = pt.formula("Fe2O3")
    dfc = df.copy()
    ox_species = ['Fe2O3', f"Fe2O3{total_suffix}"]
    ox_in_df = [i for i in ox_species if i in dfc.columns]
    red_species = ['FeO', f"FeO{total_suffix}"]
    red_in_df = [i for i in red_species if i in dfc.columns]
    if to_oxidised:
        oxFe = swap_simple_oxide(FeO, Fe2O3)
        Fe2O3T = dfc.loc[:, ox_in_df].fillna(0).sum(axis=1) + \
                 oxFe(dfc.loc[:, red_in_df].fillna(0)).sum(axis=1)
        dfc.loc[:, 'Fe2O3T'] = Fe2O3T
        to_drop = red_in_df + \
                  [i for i in ox_in_df if not i.endswith(total_suffix)]
    else:
        reduceFe = swap_simple_oxide(Fe2O3, FeO)
        FeOT = dfc.loc[:, red_in_df].fillna(0).sum(axis=1) + \
               reduceFe(dfc.loc[:, ox_in_df].fillna(0)).sum(axis=1)
        dfc.loc[:, 'FeOT'] = FeOT
        to_drop = ox_in_df + \
                  [i for i in red_in_df if not i.endswith(total_suffix)]

    dfc = dfc.drop(columns=to_drop)

    if renorm:
        return renormalise(dfc)
    else:
        return dfc
def recalculate_redox(df: pd.DataFrame,
                      to_oxidised=False,
                      renorm=True,
                      total_suffix='T'):
    """
    Recalculates abundances of redox-sensitive components (particularly Fe),
    and normalises a dataframe to contain only one oxide species for a given
    element.
    """
    # Assuming either (a single column) or (FeO + Fe2O3) are reported
    # Fe columns - FeO, Fe2O3, FeOT, Fe2O3T
    FeO = pt.formula("FeO")
    Fe2O3 = pt.formula("Fe2O3")
    dfc = df.copy()
    ox_species = ['Fe2O3', f"Fe2O3{total_suffix}"]
    ox_in_df = [i for i in ox_species if i in dfc.columns]
    red_species = ['FeO', f"FeO{total_suffix}"]
    red_in_df = [i for i in red_species if i in dfc.columns]
    if to_oxidised:
        oxFe = swap_simple_oxide(FeO, Fe2O3)
        Fe2O3T = dfc.loc[:, ox_in_df].fillna(0).sum(axis=1) + \
                 oxFe(dfc.loc[:, red_in_df].fillna(0)).sum(axis=1)
        dfc.loc[:, 'Fe2O3T'] = Fe2O3T
        to_drop = red_in_df + \
                  [i for i in ox_in_df if not i.endswith(total_suffix)]
    else:
        reduceFe = swap_simple_oxide(Fe2O3, FeO)
        FeOT = dfc.loc[:, red_in_df].fillna(0).sum(axis=1) + \
               reduceFe(dfc.loc[:, ox_in_df].fillna(0)).sum(axis=1)
        dfc.loc[:, 'FeOT'] = FeOT
        to_drop = ox_in_df + \
                  [i for i in red_in_df if not i.endswith(total_suffix)]

    dfc = dfc.drop(columns=to_drop)

    if renorm:
        return renormalise(dfc)
    else:
        return dfc
        """
        Olivine-Orthopyroxene-Clinopyroxene
        """
        def __init__(self, *args, **kwargs):
            super().__init__(*args, deterministic=True, **kwargs)

        def build_clsf(self):
            # Build
            clsf = 'thing'
            return clsf


if __name__ == '__main__':
    #%matplotlib inline
    logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
    cm = Geochemistry.TAS(rebuild=False)
    #cm = Petrology.apahnitic()
    fig, ax = plt.subplots(1)
    cm.add_to_axes(ax=ax, alpha=0.4, color='k')
    plt.show()

    from compositions import renormalise
    c2 = Geochemistry.peralkalinity()
    df = pd.DataFrame(index=np.arange(100))
    df['Al2O3'] = np.linspace(20, 50, len(df.index))
    df['Na2O'] = np.linspace(20, 10, len(df.index))
    df['K2O'] = np.linspace(10, 122, len(df.index))
    df['CaO'] = np.linspace(5, 30, len(df.index))
    df = renormalise(df)
    c2.classify(df)
        """
        Olivine-Orthopyroxene-Clinopyroxene
        """
        def __init__(self, *args, **kwargs):
            super().__init__(*args, deterministic=True, **kwargs)

        def build_clsf(self):
            # Build
            clsf = 'thing'
            return clsf


if __name__ == '__main__':
    #%matplotlib inline
    logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
    cm = Geochemistry.TAS(rebuild=False)
    #cm = Petrology.apahnitic()
    fig, ax = plt.subplots(1)
    cm.add_to_axes(ax=ax, alpha=0.4, color='k')
    plt.show()

    from compositions import renormalise
    c2 = Geochemistry.peralkalinity()
    df = pd.DataFrame(index=np.arange(100))
    df['Al2O3'] = np.linspace(20, 50, len(df.index))
    df['Na2O'] = np.linspace(20, 10, len(df.index))
    df['K2O'] = np.linspace(10, 122, len(df.index))
    df['CaO'] = np.linspace(5, 30, len(df.index))
    df = renormalise(df)
    c2.classify(df)