use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum ScoreType {
Std,
Pos,
Neg,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RankedList {
pub genes: Vec<String>,
pub scores: Vec<f64>,
}
impl RankedList {
pub fn new(genes: Vec<String>, scores: Vec<f64>) -> Self {
let mut indices: Vec<usize> = (0..genes.len()).collect();
indices.sort_by(|&a, &b| {
scores[b]
.partial_cmp(&scores[a])
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| a.cmp(&b))
});
let sorted_genes = indices.iter().map(|&i| genes[i].clone()).collect();
let sorted_scores = indices.iter().map(|&i| scores[i]).collect();
Self {
genes: sorted_genes,
scores: sorted_scores,
}
}
pub fn len(&self) -> usize {
self.genes.len()
}
pub fn is_empty(&self) -> bool {
self.genes.is_empty()
}
pub fn prepare(&self, gsea_param: f64) -> (Vec<f64>, Vec<i64>, i64) {
let abs_scores: Vec<f64> = self
.scores
.iter()
.map(|&s| s.abs().powf(gsea_param))
.collect();
let sum_abs: f64 = abs_scores.iter().sum();
let mut scale_coeff = (1i64 << 30) as f64 / sum_abs;
if scale_coeff >= 1.0 {
scale_coeff = scale_coeff.floor();
}
let scaled_scores: Vec<i64> = abs_scores
.iter()
.map(|&s| (s * scale_coeff).round_ties_even() as i64)
.collect();
let actual_sum: i64 = scaled_scores.iter().sum();
(abs_scores, scaled_scores, actual_sum)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Pathway {
pub name: String,
pub description: Option<String>,
pub genes: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PathwayDb {
pub pathways: Vec<Pathway>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnrichmentResult {
pub pathway_name: String,
pub size: usize,
pub es: f64,
pub nes: Option<f64>,
pub p_value: f64,
pub padj: Option<f64>,
pub log2err: Option<f64>,
pub leading_edge: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnrichmentResultExport {
pub pathway: String,
pub size: usize,
pub es: f64,
pub nes: Option<f64>,
pub pval: f64,
pub padj: Option<f64>,
pub log2err: Option<f64>,
pub leading_edge: Vec<String>,
}
impl EnrichmentResult {
pub fn export(&self) -> EnrichmentResultExport {
EnrichmentResultExport {
pathway: self.pathway_name.clone(),
size: self.size,
es: self.es,
nes: self.nes,
pval: self.p_value,
padj: self.padj,
log2err: self.log2err,
leading_edge: self.leading_edge.clone(),
}
}
pub fn leading_edge_csv(&self) -> String {
self.leading_edge.join(",")
}
}