diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index fefc8ae..f725a99 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -3,6 +3,8 @@ name: Rust on: push: branches: [ "master" ] + tags: + - '*' pull_request: branches: [ "master" ] @@ -20,3 +22,35 @@ jobs: run: cargo build --verbose - name: Run tests run: cargo test --all --verbose + + release: + runs-on: ubuntu-latest + if: "startsWith(github.ref, 'refs/tags/')" + needs: build + environment: release + permissions: + id-token: write + steps: + - name: Install cargo binstall + uses: cargo-bins/cargo-binstall@main + - name: cargo-release Cache + id: cargo_release_cache + uses: actions/cache@v3 + with: + path: ~/.cargo/bin/cargo-release + key: ${{ runner.os }}-cargo-release + - name: Install cargo release + if: steps.cargo_release_cache.outputs.cache-hit != 'true' + run: cargo binstall cargo-release + - name: cargo login + run: cargo login + - name: "cargo release publish" + run: |- + cargo release \ + publish \ + --workspace \ + --all-features \ + --allow-branch HEAD \ + --no-confirm \ + --no-verify \ + --execute diff --git a/Cargo.lock b/Cargo.lock index a95f80e..c1bb697 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -639,7 +639,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "webgestalt" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bincode", "clap", @@ -649,7 +649,7 @@ dependencies = [ [[package]] name = "webgestalt_lib" -version = "0.1.0" +version = "0.1.1" dependencies = [ "ahash", "csv", diff --git a/Cargo.toml b/Cargo.toml index 5b83e0a..29c8be8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "webgestalt" -version = "0.1.0" +version = "0.1.1" authors = ["John Elizarraras"] edition = "2021" rust-version = "1.63.0" @@ -16,7 +16,7 @@ repository = "https://github.com/bzhanglab/webgestalt_rust" bincode = "1.3.3" clap = { version = "4.4.15", features = ["derive"] } owo-colors = { version = "4.0.0", features = ["supports-colors"] } -webgestalt_lib = { path = "webgestalt_lib" } +webgestalt_lib = { version = "0.1.0", path = "webgestalt_lib" } [profile.release] opt-level = 3 diff --git a/src/main.rs b/src/main.rs index 21a9f2f..940d7dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -123,10 +123,10 @@ fn main() { "webgestalt_lib/data/test.rnk".to_owned(), ); let gmt = webgestalt_lib::readers::read_gmt_file( - "webgestalt_lib/data/test.gmt".to_owned(), + "webgestalt_lib/data/ktest.gmt".to_owned(), ); let start = Instant::now(); - webgestalt_lib::methods::gsea::gsea( + let res = webgestalt_lib::methods::gsea::gsea( gene_list.unwrap(), gmt.unwrap(), GSEAConfig::default(), @@ -137,7 +137,7 @@ fn main() { } Some(ExampleOptions::Ora) => { let (gmt, gene_list, reference) = webgestalt_lib::readers::read_ora_files( - "webgestalt_lib/data/test.gmt".to_owned(), + "webgestalt_lib/data/ktest.gmt".to_owned(), "webgestalt_lib/data/genelist.txt".to_owned(), "webgestalt_lib/data/reference.txt".to_owned(), ); diff --git a/webgestalt_lib/Cargo.toml b/webgestalt_lib/Cargo.toml index dfb75ff..bf5d9d5 100644 --- a/webgestalt_lib/Cargo.toml +++ b/webgestalt_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webgestalt_lib" -version = "0.1.0" +version = "0.1.1" authors = ["John Elizarraras"] edition = "2021" rust-version = "1.63.0" diff --git a/webgestalt_lib/src/methods/gsea.rs b/webgestalt_lib/src/methods/gsea.rs index 0315eac..6f3cdb3 100644 --- a/webgestalt_lib/src/methods/gsea.rs +++ b/webgestalt_lib/src/methods/gsea.rs @@ -92,6 +92,7 @@ impl RankListItem { /// Run GSEA for one analyte set. /// /// Returns a [`GSEAResult`], which does not have FDR. +/// /// # Parameters /// /// - `analytes` - Vector containing the names of the analytes @@ -195,18 +196,32 @@ fn analyte_set_p( .collect(); let down: Vec = es_iter // down scores .par_iter() - .filter(|&x| *x < 0_f64) + .filter(|&x| *x <= 0_f64) .copied() .collect(); let up_len = up.len(); let down_len = down.len(); - let up_avg: f64 = up.par_iter().sum::() / (up_len as f64 + 0.000001) + 0.000001; // up average - let down_avg: f64 = down.par_iter().sum::() / (down_len as f64 + 0.000001) - 0.000001; // down average + let up_avg: f64 = if up.is_empty() { + 0.000001 + } else { + up.par_iter().sum::() / (up_len as f64 + 0.000001) + 0.000001 + }; // up average + let down_avg: f64 = if down.is_empty() { + -0.000001 + } else { + down.par_iter().sum::() / (down_len as f64 - 0.000001) - 0.000001 + }; // down average let mut nes_es: Vec = up.par_iter().map(|x| x / up_avg).collect(); // get all normalized scores for up nes_es.extend(down.par_iter().map(|x| -x / down_avg).collect::>()); // extend with down scores let norm_es: f64 = if real_es >= 0_f64 { // get normalized score for the real run - real_es / up_avg + if up.is_empty() { + 0.0 + } else { + real_es / up_avg + } + } else if down.is_empty() { + 0.0 } else { -real_es / down_avg }; diff --git a/webgestalt_lib/src/readers.rs b/webgestalt_lib/src/readers.rs index 14f0d3e..7cf7729 100644 --- a/webgestalt_lib/src/readers.rs +++ b/webgestalt_lib/src/readers.rs @@ -7,6 +7,19 @@ use std::{ }; use utils::Item; +/// Read GMT file from specified path. For format description, see [broadinstitute.org](https://software.broadinstitute.org/cancer/software/gsea/wiki/index.php/Data_formats#GMT:_Gene_Matrix_Transposed_file_format_.28.2A.gmt.29) +/// +/// # Parameters +/// +/// - `path` - A [`String`] of the path of the GMT to read. +/// +/// # Panics +/// +/// Panics if there is not file at `path`. +/// +/// # Returns +/// +/// If result is `Ok`, returns a [`Vec`] containing the elements of the GMT pub fn read_gmt_file(path: String) -> Result, Box> { let file = File::open(path)?; let mut rdr = csv::ReaderBuilder::new() @@ -21,7 +34,7 @@ pub fn read_gmt_file(path: String) -> Result, Box> { .iter() .map(|x| x.to_string()) .collect::>(); - let id = result.get(0).unwrap().to_owned(); + let id = result.first().unwrap().to_owned(); let url = result.get(1).unwrap().to_owned(); let parts = result[2..].to_vec(); let item = Item { id, url, parts }; @@ -44,7 +57,7 @@ pub fn read_rank_file(path: String) -> Result, Box>(); - let phenotype = result.get(0).unwrap().to_owned(); + let phenotype = result.first().unwrap().to_owned(); let rank = result.get(1).unwrap().to_owned().parse::().unwrap(); let item = RankListItem { analyte: phenotype, @@ -88,7 +101,7 @@ pub fn read_ora_files( .iter() .map(|x| x.to_string()) .collect::>(); - let id = result.get(0).unwrap().to_owned(); + let id = result.first().unwrap().to_owned(); let url = result.get(1).unwrap().to_owned(); let parts = result[2..].to_vec(); for analyte in parts.clone().into_iter() {