Skip to main content

xcell/
microenv.rs

1//! Stage 4 of xCell: `microenvironmentScores`.
2//!
3//! Appends three aggregate rows — `ImmuneScore`, `StromaScore`, and
4//! `MicroenvironmentScore` — to the spillover-adjusted scores.
5
6use gsva::EnrichmentResult;
7
8/// Immune cell types summed into `ImmuneScore` (then divided by 1.5), in xCell's
9/// listing order.
10const IMMUNE: [&str; 10] = [
11    "B-cells",
12    "CD4+ T-cells",
13    "CD8+ T-cells",
14    "DC",
15    "Eosinophils",
16    "Macrophages",
17    "Monocytes",
18    "Mast cells",
19    "Neutrophils",
20    "NK cells",
21];
22
23/// Stromal cell types summed into `StromaScore` (then divided by 2).
24const STROMA: [&str; 3] = ["Adipocytes", "Endothelial cells", "Fibroblasts"];
25
26/// Mirrors xCell 1.1.0 `microenvironmentScores`: `ImmuneScore = Σ immune / 1.5`,
27/// `StromaScore = Σ stroma / 2`, `MicroenvironmentScore = Immune + Stroma`,
28/// appended as three extra rows.
29pub fn microenvironment_scores(adjusted: &EnrichmentResult) -> EnrichmentResult {
30    let nsamp = adjusted.samples.len();
31    let row_of = |name: &str| adjusted.gene_sets.iter().position(|g| g == name);
32
33    let mut immune = vec![0.0f64; nsamp];
34    for &ct in &IMMUNE {
35        if let Some(i) = row_of(ct) {
36            let base = i * nsamp;
37            for (j, v) in immune.iter_mut().enumerate() {
38                *v += adjusted.scores[base + j];
39            }
40        }
41    }
42    for v in &mut immune {
43        *v /= 1.5;
44    }
45
46    let mut stroma = vec![0.0f64; nsamp];
47    for &ct in &STROMA {
48        if let Some(i) = row_of(ct) {
49            let base = i * nsamp;
50            for (j, v) in stroma.iter_mut().enumerate() {
51                *v += adjusted.scores[base + j];
52            }
53        }
54    }
55    for v in &mut stroma {
56        *v /= 2.0;
57    }
58
59    let mut gene_sets = adjusted.gene_sets.clone();
60    let mut scores = adjusted.scores.clone();
61    gene_sets.push("ImmuneScore".into());
62    scores.extend_from_slice(&immune);
63    gene_sets.push("StromaScore".into());
64    scores.extend_from_slice(&stroma);
65    gene_sets.push("MicroenvironmentScore".into());
66    for j in 0..nsamp {
67        scores.push(immune[j] + stroma[j]);
68    }
69
70    EnrichmentResult {
71        gene_sets,
72        samples: adjusted.samples.clone(),
73        scores,
74    }
75}