From 906ff3a7219e9b1f3f889e0d489a30a87edd4219 Mon Sep 17 00:00:00 2001 From: radwinskis Date: Wed, 19 Jan 2022 16:49:21 -0700 Subject: [PATCH] New functions and updated readme --- README.md | 39 +++++++++++++++++++-- RSAbs/absorptions_depth.py | 23 +++++++++++++ RSAbs/seek_absorptions_depth.py | 60 +++++++++++++++++++++++++++++++++ setup.py | 4 +-- 4 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 RSAbs/absorptions_depth.py create mode 100644 RSAbs/seek_absorptions_depth.py diff --git a/README.md b/README.md index 62fe1c9..62f2e50 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,13 @@ One can install RSAbs using pip or by copying the GitHub repo to their working d pip install RSAbs ``` ## Function Parameters -There are two functions which make up the RSAbs package. +There are four functions which make up the RSAbs package. 1) ```sh absorptions(spectra_df, wavelength_df, integrity='ASD_CR') ``` -spectra_df: dataframe with spectra as columns +Functionality: creates DataFrame of all absorption wavelength positions + +spectra_df: dataframe with spectra as columns (leave out wavelength column, if applicable) wavelength_df: dataframe with wavelength as column @@ -40,6 +42,9 @@ If you desire compatibility with another sensor/data type, please let me know. 2) ```sh seek_absorptions(absorptions_df, start_wavelength, end_wavelength, wavelength_unit='nanometer') ``` + +Functionality: creates narrowed down DataFrame of absorption wavelength positions in a given wavelength range, and only returns data for samples that contain an absorption in the given range. + absorptions_df: dataframe from absorptions() function start_wavelength: starting wavelength value for range of interest (smaller wavelength) @@ -48,6 +53,36 @@ end_wavelength: ending wavelength value for range of interest (larger wavelength wavelength_unit: specify unit of wavelength. Options: 'nanometer' OR 'micrometer'. PLEASE ensure these are chosen correctly. Default is 'nanometer'. +3) ```sh + absorptions_depth(spectra_df, integrity='ASD_CR') + ``` + +Functionality: creates DataFrame of all absorption depths + +spectra_df: dataframe with spectra as columns (leave out wavelength column, if applicable) + +integrity: spectra type, indicates resolution and continuum removal status. Options: 'ASD_CR' for continuum removed ASD data, 'ASD_normal' for non-continuum-removed ASD data, or 'HyMap_CR' for continuum-removed HyMap data. Default is 'ASD_CR' + +4) ```sh + seek_absorptions_depth(spectra_df, wavelength_df, integrity='ASD_CR', start_wavelength=350, end_wavelength=2500, wavelength_unit='nanometer') + ``` + +Functionality: creates narrowed down DataFrame of absorption depths in a given wavelength range, +and only returns data for samples that contain an absorption in the given wavelength range. + +spectra_df: dataframe with spectra as columns (leave out wavelength column, if applicable) + +wavelength_df: dataframe with wavelength as column + +integrity: spectra type, indicates resolution and continuum removal status. Options: 'ASD_CR' for continuum removed ASD data, 'ASD_normal' for non-continuum-removed ASD data, or 'HyMap_CR' for continuum-removed HyMap data. Default is 'ASD_CR' + +start_wavelength: starting wavelength value for range of interest (smaller wavelength) + +end_wavelength: ending wavelength value for range of interest (larger wavelength) + +wavelength_unit: specify unit of wavelength. Options: 'nanometer' OR 'micrometer'. PLEASE ensure these are chosen correctly. Default is 'nanometer'. + + ## Usage To use the functions, either import the RSAbs package and use diff --git a/RSAbs/absorptions_depth.py b/RSAbs/absorptions_depth.py new file mode 100644 index 0000000..144ba09 --- /dev/null +++ b/RSAbs/absorptions_depth.py @@ -0,0 +1,23 @@ +from scipy.signal import find_peaks +import pandas as pd +import numpy as np +import itertools + +def absorptions_depth(spectra_df, integrity='ASD_CR'): #returns dataframe with the depth of each feature, where the depth is from the top of the convex hull (1.00) minus the value of the absorption minima + if isinstance(spectra_df, pd.DataFrame)==False: #Check whether spectra_df argument is satisfactory + print('Error: spectra_df argument not identified as pd.DataFrame') + def depth_props(spectra_df): + spectra_array = spectra_df.values.flatten() + if integrity=='ASD_CR': + absorps, props = find_peaks(-spectra_array, width = 6, distance = 25, prominence = 0.001) #For using continuum removed spectra + elif integrity=='ASD_Normal': + absorps, props = find_peaks(-spectra_array, width = 5, distance = 15, prominence = 0.001) #For using non-continuum removed spectra + elif integrity=='HyMap_CR': + absorps, props = find_peaks(-spectra_array, width = 3, distance = 5, prominence = 0.001) #For using continuum removed HYMAP spectra + else: + print('Enter integrity argument based on avaiable options:"ASD_CR" for ASD continuum removed spectra, "ASD_Normal" for ASD non-continuum removed spectra, or "HyMap_CR" for HyMap continuum removed spectra. Default is "ASD_CR".') + + depths = props["prominences"] + return pd.Series(depths) #For normal spectra + + return pd.DataFrame(spectra_df.apply(depth_props, axis=0)) \ No newline at end of file diff --git a/RSAbs/seek_absorptions_depth.py b/RSAbs/seek_absorptions_depth.py new file mode 100644 index 0000000..ae6f69d --- /dev/null +++ b/RSAbs/seek_absorptions_depth.py @@ -0,0 +1,60 @@ +from scipy.signal import find_peaks +import pandas as pd +import numpy as np +import itertools + +def seek_absorptions_depth(spectra_df, wavelength_df, integrity='ASD_CR', start_wavelength=350, end_wavelength=2500, wavelength_unit='nanometer'): + if isinstance(spectra_df, pd.DataFrame)==False: #Check whether spectra_df argument is satisfactory + print('Error: spectra_df argument not identified as pd.DataFrame') + if isinstance(wavelength_df, pd.DataFrame)==False: #Check whether spectra_df argument is satisfactory + print('Error: spectra_df argument not identified as pd.DataFrame') + def abs_features(spectra_df, wavelength_df): + spectra_array = spectra_df.values.flatten() + wavelength_array = wavelength_df.values.flatten() + if integrity=='ASD_CR': + absorps, props = find_peaks(-spectra_array, width = 6, distance = 25, prominence = 0.001) #For using continuum removed spectra + elif integrity=='ASD_Normal': + absorps, props = find_peaks(-spectra_array, width = 5, distance = 15, prominence = 0.001) #For using non-continuum removed spectra + elif integrity=='HyMap_CR': + absorps, props = find_peaks(-spectra_array, width = 3, distance = 5, prominence = 0.001) #For using continuum removed HYMAP spectra + else: + print('Enter integrity argument based on avaiable options:"ASD_CR" for ASD continuum removed spectra, "ASD_Normal" for ASD non-continuum removed spectra, or "HyMap_CR" for HyMap continuum removed spectra. Default is "ASD_CR".') + + absorp_locs = wavelength_array[absorps] + depths = props["prominences"] + return pd.Series(absorp_locs) #For normal spectra + + abs_wvls = pd.DataFrame(spectra_df.apply(abs_features, wavelength_df=wavelength_df, axis=0)) + + def abs_depths(spectra_df, wavelength_df): + spectra_array = spectra_df.values.flatten() + wavelength_array = wavelength_df.values.flatten() + if integrity=='ASD_CR': + absorps, props = find_peaks(-spectra_array, width = 6, distance = 25, prominence = 0.001) #For using continuum removed spectra + elif integrity=='ASD_Normal': + absorps, props = find_peaks(-spectra_array, width = 5, distance = 15, prominence = 0.001) #For using non-continuum removed spectra + elif integrity=='HyMap_CR': + absorps, props = find_peaks(-spectra_array, width = 3, distance = 5, prominence = 0.001) #For using continuum removed HYMAP spectra + else: + print('Enter integrity argument based on avaiable options:"ASD_CR" for ASD continuum removed spectra, "ASD_Normal" for ASD non-continuum removed spectra, or "HyMap_CR" for HyMap continuum removed spectra. Default is "ASD_CR".') + + absorp_locs = wavelength_array[absorps] + depths = props["prominences"] + return pd.Series(depths) #For normal spectra + + abs_depths = pd.DataFrame(spectra_df.apply(abs_depths, wavelength_df=wavelength_df, axis=0)) + + wvls_range = end_wavelength-start_wavelength + if wavelength_unit=='nanometer': + steps = int(wvls_range+1) + elif wavelength_unit=='micrometer': + steps = int(wvls_range*1000+1) + else: + print('Error: Incorrect wavelength_unit argument. Choose from "nanometer" or "micrometer" and ensure they are the correct units. Default is set to nanometer.') + wvls_array = np.linspace(start_wavelength, end_wavelength, num=steps) + seek_samples = abs_wvls.columns[abs_wvls.isin(wvls_array).any()] + samples = abs_wvls[seek_samples] + wvls_of_samples_of_interest = samples[samples[seek_samples].isin(wvls_array)].apply(lambda x: pd.Series(x.dropna().values)) + depths_of_samples_of_interest = abs_depths[seek_samples] + depths_final = depths_of_samples_of_interest[samples[seek_samples].isin(wvls_array)].apply(lambda x: pd.Series(x.dropna().values)) + return depths_final \ No newline at end of file diff --git a/setup.py b/setup.py index 24a06ac..bdf0c33 100644 --- a/setup.py +++ b/setup.py @@ -2,13 +2,13 @@ setup( name = 'RSAbs', packages = ['RSAbs'], - version = '0.7', + version = '0.8', license='MIT', description = 'AUTOMATIC DETECTION OF ABSORPTION FEATURES IN REFLECTANCE SPECTRA', author = 'MARK RADWIN', author_email = 'markradwin@gmail.com', url = 'https://github.com/radwinskis/RSAbs', - download_url = 'https://github.com/radwinskis/RSAbs/archive/refs/tags/v0.7.tar.gz', + download_url = 'https://github.com/radwinskis/RSAbs/archive/refs/tags/v0.8.tar.gz', keywords = ['REFLECTANCE', 'SPECTROSCOPY', 'ABSORPTION', 'DETECTION'], install_requires=[ 'scipy',