diff --git a/Cargo.toml b/Cargo.toml index 29c8be8..6e056c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "webgestalt" -version = "0.1.1" +version = "0.2.0" authors = ["John Elizarraras"] edition = "2021" rust-version = "1.63.0" diff --git a/src/main.rs b/src/main.rs index 940d7dd..51c6c71 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use owo_colors::{OwoColorize, Stream::Stdout, Style}; use std::io::{BufReader, Write}; use std::{fs::File, time::Instant}; use webgestalt_lib::methods::gsea::GSEAConfig; -use webgestalt_lib::methods::multiomics::{combine_gmts, MultiOmicsMethod, NormalizationMethod}; +use webgestalt_lib::methods::multilist::{combine_gmts, MultiListMethod, NormalizationMethod}; use webgestalt_lib::methods::ora::ORAConfig; use webgestalt_lib::readers::utils::Item; use webgestalt_lib::readers::{read_gmt_file, read_rank_file}; @@ -126,7 +126,7 @@ fn main() { "webgestalt_lib/data/ktest.gmt".to_owned(), ); let start = Instant::now(); - let res = webgestalt_lib::methods::gsea::gsea( + let _res = webgestalt_lib::methods::gsea::gsea( gene_list.unwrap(), gmt.unwrap(), GSEAConfig::default(), @@ -280,13 +280,13 @@ fn main() { Some(NormMethods::MedianValue) => NormalizationMethod::MedianValue, None => panic!("No normalization method chosen."), }; - let method: MultiOmicsMethod = match ora_args.combination { - Some(CombinationMethods::Mean) => MultiOmicsMethod::Mean(norm_method), - Some(CombinationMethods::Max) => MultiOmicsMethod::Max(norm_method), + let method: MultiListMethod = match ora_args.combination { + Some(CombinationMethods::Mean) => MultiListMethod::Mean(norm_method), + Some(CombinationMethods::Max) => MultiListMethod::Max(norm_method), None => panic!("No combination method chosen."), }; let mut combined_list = - webgestalt_lib::methods::multiomics::combine_lists(lists, method); + webgestalt_lib::methods::multilist::combine_lists(lists, method); combined_list.sort_by(|a, b| b.rank.partial_cmp(&a.rank).unwrap()); let mut file = File::create(ora_args.out.clone().unwrap()).unwrap(); println!( diff --git a/webgestalt_lib/Cargo.toml b/webgestalt_lib/Cargo.toml index bf5d9d5..a4de3e2 100644 --- a/webgestalt_lib/Cargo.toml +++ b/webgestalt_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webgestalt_lib" -version = "0.1.1" +version = "0.2.0" authors = ["John Elizarraras"] edition = "2021" rust-version = "1.63.0" diff --git a/webgestalt_lib/README.md b/webgestalt_lib/README.md index 129854b..cdbe716 100644 --- a/webgestalt_lib/README.md +++ b/webgestalt_lib/README.md @@ -6,7 +6,7 @@ Library for performing different types of enrichment analyses. Serves as the und Supported methods include: -- Over-representation analysis (ORA) +- Over-Representation Analysis (ORA) - Gene Set Enrichment Analysis (GSEA) ## Installation @@ -14,10 +14,10 @@ Supported methods include: To use webgestalt_lib in your Rust project, add the following line to your `Cargo.toml`. ```toml -webgestalt_lib = "0.1.0" # change to wanted version +webgestalt_lib = "0.1.1" # change to wanted version ``` -If you are just interested in running an analysis, rather than develop new tools, please use on of the packages mentioned at the beginning of the README. +If you are just interested in running an analysis, rather than develop new tools, please use one of the packages mentioned at the beginning of the README. ## Development Priorities @@ -27,7 +27,7 @@ If you are just interested in running an analysis, rather than develop new tools 3. Fast compilation times - Every package install has to build the library from scratch, so the lower number of dependencies, the better -This crate does not provide any data formatting, or charts to display the results of the analysis. This work has already been done by the [R package](https://github.com/bzhanglab/webgestaltr), and a limited implementation is provided by the Rust CLI. The focus for this library is purely computational. +This crate does not provide any data formatting or charts to display the results of the analysis. This work has already been done by the [R package](https://github.com/bzhanglab/webgestaltr), and a limited implementation is provided by the Rust CLI. The focus for this library is purely computational. ## License diff --git a/webgestalt_lib/src/methods.rs b/webgestalt_lib/src/methods.rs index d1a8ef9..69983e6 100644 --- a/webgestalt_lib/src/methods.rs +++ b/webgestalt_lib/src/methods.rs @@ -1,3 +1,3 @@ pub mod gsea; -pub mod multiomics; +pub mod multilist; pub mod ora; diff --git a/webgestalt_lib/src/methods/multiomics.rs b/webgestalt_lib/src/methods/multilist.rs similarity index 85% rename from webgestalt_lib/src/methods/multiomics.rs rename to webgestalt_lib/src/methods/multilist.rs index ad23a85..ff90061 100644 --- a/webgestalt_lib/src/methods/multiomics.rs +++ b/webgestalt_lib/src/methods/multilist.rs @@ -5,9 +5,13 @@ use super::{ gsea::{GSEAConfig, GSEAResult, RankListItem}, ora::{get_ora, ORAConfig, ORAResult}, }; -use crate::{methods::gsea::gsea, readers::utils::Item}; +use crate::{ + methods::gsea::gsea, + readers::utils::Item, + stat::{adjust, AdjustmentMethod}, +}; -pub enum MultiOmicsMethod { +pub enum MultiListMethod { /// Get the max median ratio of the analyte from any list Max(NormalizationMethod), /// Get the average median ratio of analyte from all the lists @@ -49,7 +53,7 @@ pub enum NormalizationMethod { None, } -/// Run a multiomics analysis, using either the max/mean median ratio or a typical meta analysis +/// Run a multilist analysis, using either the max/mean median ratio or a typical meta analysis /// method /// /// # Parameters @@ -61,8 +65,8 @@ pub enum NormalizationMethod { /// /// Returns a [`Vec>`] containing the results of each analysis. If the method was not meta-analysis, then the outer vector will only have one element. /// If the method was meta-analysis, then the first element will be the results of the meta-analysis, and the rest of the elements will be the results of each analysis run individually. -pub fn multiomic_gsea(jobs: Vec, method: MultiOmicsMethod) -> Vec> { - if let MultiOmicsMethod::Meta(meta_method) = method { +pub fn multilist_gsea(jobs: Vec, method: MultiListMethod) -> Vec> { + if let MultiListMethod::Meta(meta_method) = method { let mut phash: AHashMap> = AHashMap::default(); let mut results: Vec> = Vec::new(); for job in jobs { @@ -119,9 +123,24 @@ pub fn multiomic_gsea(jobs: Vec, method: MultiOmicsMethod) -> Vec, method: MultiOmicsMethod) -> Vec> { +/// Perform multi-list over-representation analysis +/// +/// # Parameters +/// +/// - `jobs` - [`Vec`] containing [`ORAJob`] for each list +/// - `method` - [`MultiListMethod`] detailing how to combine the different lists (i.e. meta-analysis) +/// - `fdr_method` - [`AdjustmentMethod`] of what FDR method to use to adjust p-values +/// +/// # Panics +/// +/// Panics if there is a arithmetic error. +pub fn multilist_ora( + jobs: Vec, + method: MultiListMethod, + fdr_method: AdjustmentMethod, +) -> Vec> { match method { - MultiOmicsMethod::Meta(meta_method) => { + MultiListMethod::Meta(meta_method) => { let mut phash: AHashMap> = AHashMap::default(); let mut results: Vec> = Vec::new(); for job in jobs { @@ -133,33 +152,31 @@ pub fn multiomic_ora(jobs: Vec, method: MultiOmicsMethod) -> Vec = Vec::new(); + let mut meta_p = Vec::new(); match meta_method { MetaAnalysisMethod::Stouffer => { let normal = Normal::new(0.0, 1.0).unwrap(); for set in phash.keys() { - final_result.push(ORAResult { - set: set.clone(), - p: stouffer_with_normal(&phash[set], &normal), - fdr: 0.0, - overlap: 0, - expected: 0.0, - enrichment_ratio: 0.0, - }); + meta_p.push(stouffer_with_normal(&phash[set], &normal)) } } MetaAnalysisMethod::Fisher => { for set in phash.keys() { - final_result.push(ORAResult { - set: set.clone(), - p: fisher(&phash[set]), - fdr: 0.0, - overlap: 0, - expected: 0.0, - enrichment_ratio: 0.0, - }); + meta_p.push(fisher(&phash[set])); } } } + let meta_fdr = adjust(&meta_p, fdr_method); + for (i, set) in phash.keys().enumerate() { + final_result.push(ORAResult { + set: set.clone(), + p: meta_p[i], + fdr: meta_fdr[i], + overlap: 0, + expected: 0.0, + enrichment_ratio: 0.0, + }) + } results.insert(0, final_result); results } @@ -171,12 +188,12 @@ pub fn multiomic_ora(jobs: Vec, method: MultiOmicsMethod) -> Vec>, - combination_method: MultiOmicsMethod, + combination_method: MultiListMethod, ) -> Vec { match combination_method { - MultiOmicsMethod::Max(normalization_method) => max_combine(lists, normalization_method), - MultiOmicsMethod::Mean(normalization_method) => mean_combine(lists, normalization_method), - MultiOmicsMethod::Meta(_) => panic!("Lists can not be combined for meta-analysis"), + MultiListMethod::Max(normalization_method) => max_combine(lists, normalization_method), + MultiListMethod::Mean(normalization_method) => mean_combine(lists, normalization_method), + MultiListMethod::Meta(_) => panic!("Lists can not be combined for meta-analysis"), } } @@ -333,7 +350,7 @@ pub fn combine_gmts(gmts: &Vec>) -> Vec { /// # Examples /// /// ```rust -/// use webgestalt_lib::methods::multiomics::stouffer; +/// use webgestalt_lib::methods::multilist::stouffer; /// let vals: Vec = vec![0.1, 0.01, 0.11, 0.23]; /// let metap: f64 = stouffer(&vals); /// ``` @@ -363,7 +380,7 @@ pub fn fisher(vals: &Vec) -> f64 { /// # Examples /// /// ```rust -/// use webgestalt_lib::methods::multiomics::stouffer_weighted; +/// use webgestalt_lib::methods::multilist::stouffer_weighted; /// let vals: Vec = vec![0.1, 0.01, 0.11, 0.23]; /// let weights: Vec = vec![0.1, 0.2, 0.3, 0.4]; /// let metap: f64 = stouffer_weighted(vals, weights);