This vignette demonstrates the SwitchClass workflow using a colorectal cancer (CRC) plasma proteomics dataset. It illustrates how to preprocess the data, perform label-switch classification to distinguish baseline-aligned and perturbation-aligned molecular responses, and visualize results using UMAP, quadrant plots, boxplots, and pathway enrichment.
Load the preprocessed expression matrix and associated sample
metadata from the CRC plasma proteome study. The dataset includes
healthy control (HC), pre-treatment (Pre), and post-treatment (Post)
groups.
Apply quality filtering to retain proteins consistently detected across
samples, followed by imputation of missing values using PhosR utilities
to obtain a complete expression matrix.
data("CRC_subset")
# log2 transform
expr.log <- log2(as.matrix(CRC_subset$expr) + 1)
rownames(expr.log) <- rownames(CRC_subset$expr)
# filtering
group <- CRC_subset$group
crc.filtered <- PhosR::selectGrps(expr.log, group, percent = 0.1, n = 3)
tmp <- apply(crc.filtered, 2, as.numeric)
rownames(tmp) <- rownames(crc.filtered)
dim(tmp)## [1] 3077 135
# imputation
crc.imputed <- PhosR::tImpute(
PhosR::scImpute(mat = tmp, percent = 0.5, grps = group),
m = 1.8,
s = 0.3
)
labels <- factor(colnames(crc.imputed), levels = colnames(crc.imputed)[order(group)])
p1 <- PhosR::plotQC(crc.filtered, panel = "pca", grps = group, labels = labels) +
ggplot2::scale_color_manual(values = c(HC = "#5AAF59", Pre = "#D3542D", Post = "#E5CA4E")) +
ggplot2::theme_classic() +
ggplot2::theme(
panel.background = ggplot2::element_blank(),
plot.background = ggplot2::element_blank(),
panel.border = ggplot2::element_blank(),
panel.grid = ggplot2::element_blank()
)
p2 <- PhosR::plotQC(crc.imputed, panel = "pca", grps = group, labels = labels) +
ggplot2::scale_color_manual(values = c(HC = "#5AAF59", Pre = "#D3542D", Post = "#E5CA4E")) +
ggplot2::theme_classic() +
ggplot2::theme(
panel.background = ggplot2::element_blank(),
plot.background = ggplot2::element_blank(),
panel.border = ggplot2::element_blank(),
panel.grid = ggplot2::element_blank()
)
ggpubr::ggarrange(p1, p2, ncol=2, nrow=1, common.legend = TRUE, legend="right")Perform differential expression analysis between healthy controls and pre-treatment CRC samples using limma. Identify features showing significant fold-change and adjusted p-value thresholds.
pp <- group[group %in% c("HC","Pre")]
design_DE <- model.matrix(~ 0 + pp)
cancer.pp <- crc.imputed[,group %in% c("HC","Pre")]
fit_DE <- limma::lmFit(cancer.pp, design_DE)
cont_DE <- limma::makeContrasts(pre_vs_HC = ppPre - ppHC, levels = colnames(design_DE))
fit_DE2 <- limma::eBayes(limma::contrasts.fit(fit_DE, cont_DE))
DE.table <- limma::topTable(fit_DE2, number = Inf)
if (nrow(DE.table) == 0L) {
stop("No differential expression results were returned by limma.")
}
DE.table$gene <- rownames(DE.table)
DE.table <- DE.table[order(DE.table$adj.P.Val, DE.table$P.Value), ]
DE.genes <- DE.table$gene[which((DE.table[, "adj.P.Val"] < 0.05) & (abs(DE.table[,"logFC"]) > 0.5849625))]
length(DE.genes)## [1] 1058
Use the SwitchClass algorithm to train random forest classifiers under baseline-aligned and perturbation-aligned label schemes, then compute feature-level directional importance scores.
# Use DE genes to focus the classification
X_bc <- crc.imputed[DE.genes, , drop = FALSE]
# Label schemes: baseline-aligned vs perturbation-aligned
y_rev <- paste0("c", ifelse(group=="HC",1, ifelse(group=="Pre",2,1)))
y_per <- paste0("c", ifelse(group=="HC",1, ifelse(group=="Pre",2,2)))
# run SwitchClass
res <- SwitchClass::label_switch_classify(
X_bc, y_reverse = y_rev, y_persist = y_per,
ntimes = 3, ntree = 100, seed = 1
)
delta <- res$deltaVisualize sample clustering based on UMAP embeddings computed using baseline-aligned, perturbation-aligned, or all features. Consistent color mapping highlights group separation.
res_trip <- umap_triptych_by_delta(
X = X_bc,
delta = delta,
groups = group,
top_n = 100,
palette = c(HC = "#5AAF59", Pre = "#D3542D", Post = "#E5CA4E")
)
# View the combined plot
res_trip$plotCombine directional importance scores with log fold-changes to assign each feature to one of four quadrants, reflecting distinct molecular response behaviors. Plot the scatter to reveal major feature trends.
Hm <- matrixStats::rowMeans2(as.matrix(X_bc[, group == "HC", drop = FALSE]))
Dm <- matrixStats::rowMeans2(as.matrix(X_bc[, group == "Pre", drop = FALSE]))
lfc <- Hm - Dm
out <- plot_delta_vs_fc(delta, lfc, delta_thresh = 0.15, label_top = 8)
df_quad <- out$data # tidy table with quadrants
out$plot # the scatter plotGenerate boxplots for selected representative features from each quadrant to illustrate characteristic expression changes across groups.
genes_order <- c("RASA4","RASA4B","SMYD5","MRPS25","BLM","CPSF6","HBB","MSL1")
palette_crc <- c(HC = "#5AAF59", Pre = "#D3542D", Post = "#E5CA4E")
group <- factor(group, levels = c("HC","Pre", "Post"))
p <- plot_feature_boxplots(
X = X_bc,
group = group,
features = genes_order,
feature_order = genes_order,
palette = palette_crc,
ncol = 4,
title = "Top example genes across groups"
)
p
## 7. Heatmap of Quadrant-Defined Features Create a heatmap showing
standardized expression of genes across samples, grouped by both
quadrants and sample type (HC, Pre, Post).
plot_heatmap_quadrants(
X = crc.imputed,
group = group,
df_quad = df_quad,
cutoff = 0.15,
palette_group = c(HC = "#5AAF59", Pre = "#D3542D", Post = "#E5CA4E")
)Perform over-representation analysis using Reactome gene sets from msigdbr to identify biological pathways enriched within each quadrant. Visualize the top pathways per quadrant as -log10(p-value) barplots.
## R version 4.6.1 (2026-06-24)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 26.04.1 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so; LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: Etc/UTC
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] PhosR_1.23.0 limma_3.99.0 ggpubr_1.0.0 ggplot2_4.0.3
## [5] SwitchClass_0.99.1 BiocStyle_2.41.0
##
## loaded via a namespace (and not attached):
## [1] gridExtra_2.3.1 rlang_1.3.0
## [3] magrittr_2.0.5 otel_0.2.0
## [5] matrixStats_1.5.0 e1071_1.7-17
## [7] compiler_4.6.1 vctrs_0.7.3
## [9] reshape2_1.4.5 stringr_1.6.0
## [11] pkgconfig_2.0.3 shape_1.4.6.1
## [13] fastmap_1.2.0 backports_1.5.1
## [15] XVector_0.53.0 labeling_0.4.3
## [17] rmarkdown_2.32 preprocessCore_1.75.1
## [19] network_1.20.0 purrr_1.2.2
## [21] xfun_0.61 randomForest_4.7-1.2
## [23] cachem_1.1.0 jsonlite_2.0.0
## [25] DelayedArray_0.39.6 irlba_2.3.7
## [27] parallel_4.6.1 broom_1.0.13
## [29] R6_2.6.1 bslib_0.12.0
## [31] stringi_1.8.9 RColorBrewer_1.1-3
## [33] GGally_2.4.0 car_3.1-5
## [35] GenomicRanges_1.65.4 jquerylib_0.1.4
## [37] Rcpp_1.1.2 Seqinfo_1.3.2
## [39] SummarizedExperiment_1.43.0 knitr_1.52
## [41] FNN_1.1.4.1 IRanges_2.47.5
## [43] Matrix_1.7-6 igraph_2.3.3
## [45] tidyselect_1.2.1 abind_1.4-8
## [47] yaml_2.3.12 viridis_0.6.5
## [49] lattice_0.23-1 tibble_3.3.1
## [51] plyr_1.8.9 Biobase_2.73.2
## [53] withr_3.0.3 S7_0.2.2
## [55] coda_0.19-4.1 evaluate_1.0.5
## [57] ggstats_0.14.0 proxy_0.4-29
## [59] circlize_0.4.18 pillar_1.11.1
## [61] BiocManager_1.30.27 MatrixGenerics_1.25.0
## [63] carData_3.0-6 stats4_4.6.1
## [65] generics_0.1.4 S4Vectors_0.51.10
## [67] scales_1.4.0 class_7.3-24
## [69] glue_1.8.1 pheatmap_1.0.13
## [71] maketools_1.3.2 tools_4.6.1
## [73] dendextend_1.19.1 sys_3.4.3
## [75] ggsignif_0.6.4 buildtools_1.0.0
## [77] cowplot_1.2.0 grid_4.6.1
## [79] tidyr_1.3.2 colorspace_2.1-3
## [81] Formula_1.2-6 cli_3.6.6
## [83] ruv_0.9.7.2 S4Arrays_1.13.0
## [85] viridisLite_0.4.3 ggdendro_0.2.0
## [87] dplyr_1.2.1 uwot_0.2.5
## [89] pcaMethods_2.5.0 gtable_0.3.6
## [91] rstatix_1.1.0 sass_0.4.10
## [93] digest_0.6.39 BiocGenerics_0.59.12
## [95] ggrepel_0.9.8 SparseArray_1.13.2
## [97] farver_2.1.2 htmltools_0.5.9
## [99] lifecycle_1.0.5 GlobalOptions_0.1.4
## [101] statnet.common_4.13.0 statmod_1.5.2
## [103] MASS_7.3-66