Core Algorithm: Hoshida Y, et al. "Subclass Mapping: Identifying Common Subtypes in Independent Disease Data Sets". PLoS ONE (2007).
Original Script:
submap.Rby Broad Institute (Oct. 14, 2008).
The original submap.R relies on the specific old file formats of GenePattern (.gct, .cls), which leads to low running efficiency (with many loops) and cannot directly interface with modern R analysis workflows (like Seurat, Biobase).
This project has undergone Modern Refactoring of the original code, fundamentally improving performance and usability while maintaining complete consistency with the mathematical core.
- Dependency on File I/O: Data must be written out as
.gctand.clstext files to run, which is very cumbersome. - Slow Execution: The original script was designed for data scales from 2008, using many inefficient R loops (
forloops), making it run extremely slowly on today's single-cell or large cohort data. - Memory Overflow: The old version stored large 3D arrays during permutation tests, which easily leads to memory crashes.
- Outdated Visualization: Utilizes basic plotting systems, making it difficult to generate publication-quality images.
- Memory Pass-Through: Directly accepts R
Matrix(expression profiles) andVector(grouping) inputs, without the need for any temporary files. - Blazing Performance:
* Introduced
matrixStats(C++) for matrix operations, speeding up 10-50 times. * Built-inparallelmulti-core computing support. - Result Objectification: Results are returned as a clean
Listobject, containing all P-value matrices and intermediate statistics. - Visualization Upgrade: Automatically generates publication-quality heatmaps with significance annotations based on
ComplexHeatmap.
| Feature | Original Version (2008) | Modern Version (2025) | Notes |
|---|---|---|---|
| Algorithm Core | KS Statistic + Fisher's Combination | KS Statistic + Fisher's Combination | Core algorithm is identical |
| Input Method | File Path (.gct, .cls) | R Objects (Matrix, Vector) | No disk I/O required |
| S2N Calculation | Double Loop + apply | matrixStats::rowMeans2/rowSds |
20x+ faster |
| Permutation Test | Single-threaded | mclapply Multi-core Parallel |
Default 8-core parallel |
| Memory Usage | Extremely high (stores all Permutations for file writing) | Extremely low (only returns Pool statistics) | Avoids large memory crashes |
| Plotting Engine | Base Graphics | ComplexHeatmap |
Automatic legends and annotations |
| Code Volume | ~1000 lines | ~350 lines | Removed a lot of redundant code |
- Expression matrices must be numeric with genes in rows and samples in columns; rownames should be gene IDs and colnames sample IDs.
- Gene identifiers must match between the two datasets; the shared genes after
intersect()should be at leastn_markers * 2. - Avoid duplicated gene IDs and drop any rows with all-zero or missing values to keep S2N stable.
- Group vectors (
group_a,group_b) must align with column order, have the same length as the number of samples, and contain >=2 classes; keep class sizes reasonable (avoid groups of size 1). - Provide log-normalized or otherwise comparable expression values across datasets; do not mix units (e.g., TPM vs raw counts) without normalization.
Simply load submap_modern.R to use.
source("submap_modern.R")
# Prepare data (Standard R objects)
# exp_ref: Gene x Sample matrix (Reference)
# group_ref: Sample grouping vector
# exp_query: Gene x Sample matrix (Query)
# group_query: Sample grouping vector (Query)
# Run analysis
res <- run_submap(
exp_a = exp_ref, group_a = group_ref, # Reference Dataset
exp_b = exp_query, group_b = group_query, # Query Dataset
n_markers = 100, # Recommended 100-300
n_perm = 1000, # Recommended 1000 permutations
n_cores = 8, # Number of parallel cores
weighted_score_type = 1 # 1=Weighted (Recommended), 0=Unweighted
)
write.csv(res$sa_p_matrix, file = file.path(out_dir, "01.SA_P_value_matrix.csv"))
write.csv(res$sa_fdr_matrix, file = file.path(out_dir, "02.SA_FDR_matrix.csv"))
write.csv(res$sa_bonf_matrix, file = file.path(out_dir, "03.SA_Bonferroni_matrix.csv"))
write.csv(res$fisher_stats, file = file.path(out_dir, "04.Fisher_Stats_matrix.csv"))
# Result visualization
plot_submap_heatmap(res,
row_title = "Reference Group",
col_title = "Query Group",
correction_method = "Bonferroni") # Optional FDR/Bonferronilibrary(Matrix)
set.seed(123)
genes <- paste0("G", sprintf("%04d", 1:500))
# Reference dataset: 500 genes x 20 samples, two classes
exp_ref <- matrix(rnorm(length(genes) * 20, mean = 0, sd = 1),
nrow = length(genes),
dimnames = list(genes, paste0("R", 1:20)))
group_ref <- rep(c("Ref_A", "Ref_B"), each = 10)
# Query dataset: 500 genes x 18 samples, two classes
exp_query <- matrix(rnorm(length(genes) * 18, mean = 0, sd = 1),
nrow = length(genes),
dimnames = list(genes, paste0("Q", 1:18)))
group_query <- rep(c("Qry_X", "Qry_Y"), each = 9)
# Optional: convert to Matrix::Matrix for memory efficiency
exp_ref <- Matrix(exp_ref, sparse = TRUE)
exp_query <- Matrix(exp_query, sparse = TRUE)
source("submap_modern.R")
res <- run_submap(
exp_a = exp_ref, group_a = group_ref,
exp_b = exp_query, group_b = group_query,
n_markers = 50, # small toy example
n_perm = 200, # increase (e.g., 1000) for real analysis
n_cores = 4,
weighted_score_type = 1
)
# Inspect and plot
str(res)
plot_submap_heatmap(res, row_title = "Ref", col_title = "Query")The above README is generated by Gemini 3 pro.
As this project does not have significant relevance to my own work, I currently do not have more energy to devote to it. Suggestions and questions are welcome.
Original Author Credit:
- Hoshida Y, Brunet JP, Tamayo P, Golub TR, Mesirov JP
- Broad Institute of MIT and Harvard University
Modern Refactor Author:
- Yuanwei
- Guizhou University