Scores of EMT gene sets have been widely used to quantify the extent
of the epithelial-mesenchmal transition. These scores are particularly
useful for analyzing single-cell or bulk transcriptome samples in the
context of EMT continuum and intermediate EMT states. Analyses with EMT
scores are challenged by complexity arising from divergence of EMT
progression (Groves et al. 2024) and related gene
sets, as well as algorithms underlying the gene set scores. In addition,
it is often difficult to visualize and interpret EMT scores and their
relation to other cellular processes.
EMTscore is a package for analyzing and visualizing the expression of
multiple EMT genesets in bulk or single-cell RNA-sequencing data.
EMTscore computes scores for E and M gene sets. It has options for 4 commonly used E/M gene sets and allow users to use their own gene lists. It also has options for multiple algorithms for computing EMT scores. Importantly, it leverages nonnegative PCA for identifying multiple mesenchymal (M) scores (based on leading PCs). It computes correlations with EMT scores with other gene set scores among samples.
In our examples, we assume that the input data is processed RNA-seq data stored as r data files. For bulk data, the file contains the expression matrix. For single-cell data, the data file contains a seurat object. A cell/sample annotation file should also be provided.
Here we provide a cell annotation file
Groves et al. 2023. The two most important
columns are: one named name, which represents the cell
name, and another named celltype_annotation, which
indicates the cell type classification.
data(cell_annotation_file)
head(cell_annotation_file)
## name source celltype_annotation
## 1 c.COLO668 CCLE A2
## 2 c.CORL24 CCLE A
## 3 c.CORL279 CCLE A
## 4 c.CORL311 CCLE P
## 5 c.CORL47 CCLE A
## 6 c.CORL88 CCLE A2
Here we provide an example bulk gene expression matrix file from Groves et al. 2023. The resulting dataset contains 120 samples and 15,950 genes, with row names representing cell names and column names representing gene symbols.
url <- "https://zenodo.org/records/17353682/files/geneExp.rda"
destfile <- tempfile(fileext = ".rda")
download.file(url, destfile, mode = "wb")
load(destfile)
head(geneExp[, 1:5], 4)
## m.DMS153 m.NCIH60 m.NCIH69 m.NCIH82 m.NCIH128
## A1BG 2.95519898 3.239727011 3.599770170 3.055231198 4.579506618
## A1CF 0.07721193 0.167166221 0.117398456 0.536178723 0.088160029
## A2M 2.26750213 0.122302456 0.085891273 1.586479424 0.064499801
## A2ML1 0.01101060 -0.007241361 -0.005085505 -0.004471288 -0.003818945
dim(geneExp)
## [1] 15950 120
Here, we use a built-in gene set
Panchy_et_al_E_signature and
Panchy_et_al_M_signature Panchy et
al. 2022.
There are several additional options that users can choose from, such
as: Tan_et_al_tumor_E_signature,
Tan_et_al_tumor_M_signature,
Tan_et_al_cell_line_E_signature,
Tan_et_al_cell_line_M_signature Tan et
al. 2014, MSigDB_Hallmark Liberzon
et al. 2015 and GO Gene Ontology
Consortium 2021.
data("Panchy_et_al_E_signature", package = "EMTscore")
data("Panchy_et_al_M_signature", package = "EMTscore")
head(Panchy_et_al_M_signature)
## GeneName
## 1 AKAP12
## 2 AKAP2
## 3 AKT3
## 4 ANGPTL2
## 5 ANK2
## 6 AP1S2
gene_sets <- list(
Panchy_et_al_E_signature = Panchy_et_al_E_signature$GeneName,
Panchy_et_al_M_signature = Panchy_et_al_M_signature$GeneName
)
write_gmt(gene_sets, "EM_signature.gmt")
Gene set scores can be computed with one or more of the following
methods:
nnPCA: nnPCA is a nonnegative PCA based method
(Panchy et al. 2021) . It is preferred because of
its high efficiency and the capacity of generating muliple scores for a
gene set.
AUCell: AUCell is a method based on area
under the curve for gene ranks (Aibar et al. 2017)
.
ssGSEA: ssGSEA is a widely used method based on
Kolmogorov-Smirnov test (Barbie et al. 2009) .
JASMINE: JASMINE is a recently developed method based on
gene ranks (Noreen et al. 2022) .
SCSE: SCSE is another normalized sum-based method
(Pont et al. 2019) .
gmt_file <- system.file("extdata", "EM_signature.gmt", package = "EMTscore")
nnPCA_Result_EMT <- Execute_nnPCA(geneExp, gmt_file,dimension = 1, score_names = "EMT")
AUCell_Result_EMT <- Execute_AUCell(geneExp, gmt_file, score_names = "EMT")
ssGSEA_Result_EMT <- Execute_ssGSVA(geneExp, gmt_file, score_names = "EMT")
JASMINE_Result_EMT <- Execute_JAS(geneExp, gmt_file, score_names = "EMT")
SCSE_Result_EMT <- Execute_SCSE(geneExp, gmt_file, score_names = "EMT")
nnPCA_Result_multiple <- Execute_nnPCA_parallel(geneExp, 'EM_signature.gmt', dimension = 1, cores = 2)
## 121
AUCell_Result_multiple <- Execute_AUCell_parallel(geneExp, 'EM_signature.gmt', cores = 2)
## 121
ssGSEA_Result_multiple <- Execute_ssGSEA_parallel(geneExp, 'EM_signature.gmt', cores = 2)
## 121
JASMINE_Result_multiple <- Execute_JASMINE_parallel(geneExp, 'EM_signature.gmt', cores = 2)
## 121
SCSE_Result_multiple <- Execute_SCSE_parallel(geneExp, 'EM_signature.gmt', cores = 2)
## 121
Here we use nnPCA scores for our plot examples.
data_for_plot <- data_prepare(cell_annotation_file, nnPCA_Result_multiple, merge_colname = "name")
As a fundamental visualization, we plot the M scores against the E scores for all samples. Sample annotations are overlaid to highlight trends across different groups, enabling us to observe patterns of epithelial–mesenchymal variation.
plot1 <- Execute_E_M_plot(
data_for_plot,
E_colname = "Panchy_et_al_E_signature",
M_colname = "Panchy_et_al_M_signature",
celltype_colname = "celltype_annotation",
colors = c("#F87189", "#CE9031", "#A48CF5", "#97A430", "#39A7D0", "#E57D5F",
"#84C7B9", "#E1AF64", "#C26CCF", "#B0BF43", "#57C3E8", "#F29D9E", "#92AAE6")
)
plot1
To comprehensively compare EMT scoring across different computational methods, we generated E–M scatter plots for all methods, including nnPCA, AUCell, ssGSEA, JASMINE, and SCSE. For each method, samples are projected onto the E (epithelial) and M (mesenchymal) score space, and annotations are overlaid to reveal group-level patterns. The main title of each plot indicates the corresponding method.
method_list <- list(
nnPCA = nnPCA_Result_multiple,
AUCell = AUCell_Result_multiple,
ssGSEA = ssGSEA_Result_multiple,
JASMINE = JASMINE_Result_multiple,
SCSE = SCSE_Result_multiple
)
plot_list <- lapply(names(method_list), function(method_name) {
data_for_plot <- data_prepare(
cell_annotation_file,
method_list[[method_name]],
merge_colname = "name"
)
p <- Execute_E_M_plot(
data_for_plot,
E_colname = "Panchy_et_al_E_signature",
M_colname = "Panchy_et_al_M_signature",
celltype_colname = "celltype_annotation",
colors = c("#F87189", "#CE9031", "#A48CF5", "#97A430", "#39A7D0", "#E57D5F",
"#84C7B9", "#E1AF64", "#C26CCF", "#B0BF43", "#57C3E8",
"#F29D9E", "#92AAE6")
)
p + ggtitle(method_name) # 自动添加方法名称作为主标题
})
names(plot_list) <- names(method_list)
combined_plot <- Arrange_plots(plot_list, ncol_per_row = 3)
combined_plot
One useful application of nnPCA-based EMT scores is to examine the potential divergence among M genes. To explore this, we extract the data projected onto multiple principal components, allowing us to capture the main axes of variation within the mesenchymal gene set. We then visualize the samples in this reduced-dimensional space, which helps reveal patterns of heterogeneity, potential subpopulations, or outlier behaviors that may be masked in the full gene expression matrix. This approach provides a more nuanced understanding of EMT dynamics and highlights subtle differences in mesenchymal programs across samples.
# Prepare M gene set and compute nnPCA
gene_set <- list(Panchy_et_al_M_signature = Panchy_et_al_M_signature$GeneName)
write_gmt(gene_set, "M_signature.gmt")
nnPCA_Mscore <- Execute_nnPCA(geneExp, "M_signature.gmt", dimension=2, score_names=c('M1_score','M2_score'))
data_for_plot <- data_prepare(cell_annotation_file, nnPCA_Mscore, merge_colname = "name")
plot2 <- Execute_M_dimension_plot(
data_for_plot,
M1_colname = "M1_score",
M2_colname = "M2_score",
celltype_colname = "celltype_annotation",
colors = c("#F87189", "#CE9031", "#A48CF5", "#97A430", "#39A7D0", "#E57D5F",
"#84C7B9", "#E1AF64", "#C26CCF", "#B0BF43", "#57C3E8", "#F29D9E", "#92AAE6")
)
plot2
We can combine both types of scatter plot to give an overall picture.
combined_plot <- Arrange_plots(
plots_list = list(plot1, plot2),
ncol_per_row = 2,
subtitles = c("E vs M", "M1 vs M2"),
fig_title = "Panchy_et_al"
)
print(combined_plot)
To explore the distribution of epithelial (E) and mesenchymal (M) scores across different cell types, we plotted separate histograms for each score and cell type. This allows us to compare the overall EMT profiles between cell populations, observe shifts in epithelial or mesenchymal programs, and identify cell types enriched for higher or lower E or M scores.
colors = c("#F87189", "#CE9031", "#A48CF5", "#97A430", "#39A7D0", "#E57D5F",
"#84C7B9", "#E1AF64", "#C26CCF", "#B0BF43", "#57C3E8", "#F29D9E", "#92AAE6")
p_hist <- data_for_plot %>%
ggplot( aes(x=M1_score, fill=celltype_annotation)) +
geom_histogram(alpha=0.6, position = 'identity') +
scale_fill_manual(values=colors) +
theme_ipsum() +
labs(fill="")
p_hist
Heatmaps provide an effective way to visualize the expression patterns of individual genes that contribute to each principal component, highlighting variation and clustering across samples.
# Example heatmap
plot_heatmap_function(t(geneExp), Panchy_et_al_M_signature)
Next, we demonstrate the analysis workflow using a separate single-cell RNA-seq dataset Cook et al. 2020.
Users can import single-cell data either as Seurat objects
(RDS format) or as SingleCellExperiment objects
(RDA format). Gene sets can be provided using GMT files for
input. Different scoring methods can be specified via the
method argument. Calculated EMT scores can then be plotted
against pseudotime to examine dynamic changes in epithelial–mesenchymal
states.
#obj <- system.file("extdata", "example_seurat_obj.rds", package = "EMTscore")
#files <- c(obj)
eh = ExperimentHub()
query(eh , 'EMTscoreData')
## ExperimentHub with 12 records
## # snapshotDate(): 2025-12-03
## # $dataprovider: David P. Cook
## # $species: Homo sapiens
## # $rdataclass: SingleCellExperiment
## # additional mcols(): taxonomyid, genome, description, coordinate_1_based, maintainer, rdatadateadded,
## # preparerclass, tags, rdatapath, sourceurl, sourcetype
## # retrieve records with, e.g., 'object[["EH10282"]]'
##
## title
## EH10282 | MCF7_TNF.rda
## EH10283 | MCF7_EGF.rda
## EH10284 | MCF7_TGFB1.rda
## EH10285 | OVCA420_TNF.rda
## EH10286 | OVCA420_EGF.rda
## ... ...
## EH10289 | DU145_EGF.rda
## EH10290 | DU145_TGFB1.rda
## EH10291 | A549_TNF.rda
## EH10292 | A549_EGF.rda
## EH10293 | A549_TGFB1.rda
#A549_TNF <- eh[['EH10291']]
A549_EGF <- eh[['EH10292']]
A549_TGFB1 <- eh[['EH10293']]
gmt <- system.file("extdata", "HALLMARK_EPITHELIAL_MESENCHYMAL_TRANSITION.v2025.1.Hs.gmt", package = "EMTscore")
objects <- list(
A549_TGFB1 = A549_TGFB1,
A549_EGF = A549_EGF
#A549_TNF = A549_TNF
)
#seurat_objs <- add_EMT_score(objects, gmt_file = gmt, emt_name = "EMT_score", method = "AUCell",nnPCA_dim = 1)
#p_AUCell <- plot_EMT_from_objects(seurat_objs, col_name = "Pseudotime", emt_score_col = "EMT_score")
#p_AUCell
#seurat_objs <- add_EMT_score(objects, gmt_file = gmt, emt_name = "EMT_score", method = "SCSE")
#p_SCSE <- plot_EMT_from_objects(seurat_objs, col_name = "Pseudotime", emt_score_col = "EMT_score")
#p_SCSE
#seurat_objs <- add_EMT_score(objects, gmt_file = gmt, emt_name = "EMT_score", method = "ssGSEA")
#p_ssGSEA <- plot_EMT_from_objects(seurat_objs, col_name = "Pseudotime", emt_score_col = "EMT_score")
#p_ssGSEA
#seurat_objs <- add_EMT_score(objects, gmt_file = gmt, emt_name = "EMT_score", method = "Seurat")
#p_Seurat <- plot_EMT_from_objects(seurat_objs, col_name = "Pseudotime", emt_score_col = "EMT_score")
#p_Seurat
seurat_objs <- add_EMT_score(objects, gmt_file = gmt, emt_name = "EMT_score", method = "nnPCA",nnPCA_dim = 1)
p_nnPCA <- plot_EMT_from_objects(seurat_objs, col_name = "Pseudotime", emt_score_col = "EMT_score")
p_nnPCA
#seurat_objs <- add_EMT_score(objects, gmt_file = gmt, emt_name = "EMT_score", method = "JASMINE")
#p_JASMINE <- plot_EMT_from_objects(seurat_objs, col_name = "Pseudotime", emt_score_col = "EMT_score")
#p_JASMINE
We can build simple GMMs for all cells in the E-M space so that we can identify different EMT states. We can also map the existing annotations/clusters to these GMM states. This is particularly helpful to identify clusters that are extreme E/M states or intermediate EMT states.
gmt_file <- system.file("extdata", "EM_signature.gmt", package = "EMTscore")
emt_names = c("Escore", "Mscore")
result <- add_EMT_score_multiple(objects, gmt_file, emt_names, method = "nnPCA", nnPCA_dim = 1, cores = 10)
## 121
## 121
## 121
#save into pdf format
plot_all_clusters <- function(result, method = c("Kmeans", "GMM"),emt_names, n_clusters = 3) {
method <- match.arg(method)
for (name in names(result)) {
cat("Processing:", name, "\n")
obj <- result[[name]]
# Extract E and M signature data
sig_df <- obj@meta.data[, emt_names, drop = FALSE]
colnames(sig_df) <- c("Escore", "Mscore")
# Run clustering
if (method == "GMM") {
cl <- predict_cluster_labels(sig_df, method = "GMM", PC_name = c("Escore", "Mscore"))
} else if (method == "Kmeans") {
cl <- predict_cluster_labels(sig_df, method = "Kmeans", n_clusters = n_clusters, PC_name = c("Escore", "Mscore"))
}
# Scatter plot data
scatter_df <- data.frame(sig_df, Cluster = as.factor(cl))
p1 <- ggplot(scatter_df, aes(x = Escore, y = Mscore, color = Cluster)) +
geom_point(size = 1.5, alpha = 0.8) +
scale_color_brewer(palette = "Set1") +
theme_classic(base_size = 14) +
labs(title = paste0(name, " - ", method, " clustering"), x = "Escore", y = "Mscore")
# Save scatter plot
scatter_file <- paste0(name, "_EM_", tolower(method), ".pdf")
print(p1)
ggsave(scatter_file, plot = p1, width = 6, height = 5)
message("Sved scatter plot: ", scatter_file)
# Sankey data
cl_df <- data.frame(cell = rownames(sig_df), Cluster = as.character(unlist(cl)))
true_df <- data.frame(cell = rownames(obj@meta.data),
TrueLabel = as.character(unlist(obj@meta.data$Time)))
df_merge <- inner_join(cl_df, true_df, by = "cell")
df_count <- df_merge %>%
group_by(Cluster, TrueLabel) %>%
summarise(Freq = n(), .groups = "drop")
# Sankey plot
df_count$TrueLabel <- factor(
df_count$TrueLabel,
levels = c("0d", "8h", "1d", "3d", "7d", "8h_rm", "1d_rm", "3d_rm")
)
p2 <- ggplot(df_count, aes(axis1 = Cluster, axis2 = TrueLabel, y = Freq)) +
geom_alluvium(aes(fill = Cluster), width = 1/12) +
geom_stratum(width = 1/8, fill = "grey90", color = "black") +
geom_text(stat = "stratum", aes(label = after_stat(stratum))) +
scale_x_discrete(limits = c(method, "TrueLabel"), expand = c(.1, .1)) +
scale_fill_brewer(palette = "Set1") +
theme_minimal(base_size = 14) +
labs(title = paste("Sankey Diagram:", method, "Cluster vs True Cell Labels -", name),
y = "Number of Cells", x = "")
sankey_file <- paste0(name, "_EM_Sankey_Diagram_", tolower(method), ".pdf")
print(p2)
ggsave(sankey_file, plot = p2, width = 7, height = 5)
message("Saved Sankey plot: ", sankey_file)
}
message("All plots successfully generated and saved.")
}
#plot_all_clusters(result, method = "Kmeans", emt_name, n_clusters = 3)
# or
plot_all_clusters(result, method = "GMM", emt_names)
## Processing: A549_TGFB1
## fitting ...
## | | | 0% | |= | 1% | |== | 2% | |=== | 2% | |==== | 3% | |===== | 4% | |====== | 5% | |======= | 6% | |======== | 6% | |========= | 7% | |========== | 8% | |========== | 9% | |=========== | 9% | |============ | 10% | |============= | 11% | |============== | 12% | |=============== | 13% | |================ | 13% | |================= | 14% | |================== | 15% | |=================== | 16% | |==================== | 17% | |===================== | 17% | |====================== | 18% | |======================= | 19% | |======================== | 20% | |========================= | 20% | |========================== | 21% | |=========================== | 22% | |============================ | 23% | |============================= | 24% | |============================== | 24% | |============================== | 25% | |=============================== | 26% | |================================ | 27% | |================================= | 28% | |================================== | 28% | |=================================== | 29% | |==================================== | 30% | |===================================== | 31% | |====================================== | 31% | |======================================= | 32% | |======================================== | 33% | |========================================= | 34% | |========================================== | 35% | |=========================================== | 35% | |============================================ | 36% | |============================================= | 37% | |============================================== | 38% | |=============================================== | 39% | |================================================ | 39% | |================================================= | 40% | |================================================== | 41% | |================================================== | 42% | |=================================================== | 43% | |==================================================== | 43% | |===================================================== | 44% | |====================================================== | 45% | |======================================================= | 46% | |======================================================== | 46% | |========================================================= | 47% | |========================================================== | 48% | |=========================================================== | 49% | |============================================================ | 50% | |============================================================= | 50% | |============================================================== | 51% | |=============================================================== | 52% | |================================================================ | 53% | |================================================================= | 54% | |================================================================== | 54% | |=================================================================== | 55% | |==================================================================== | 56% | |===================================================================== | 57% | |====================================================================== | 57% | |======================================================================= | 58% | |======================================================================= | 59% | |======================================================================== | 60% | |========================================================================= | 61% | |========================================================================== | 61% | |=========================================================================== | 62% | |============================================================================ | 63% | |============================================================================= | 64% | |============================================================================== | 65% | |=============================================================================== | 65% | |================================================================================ | 66% | |================================================================================= | 67% | |================================================================================== | 68% | |=================================================================================== | 69% | |==================================================================================== | 69% | |===================================================================================== | 70% | |====================================================================================== | 71% | |======================================================================================= | 72% | |======================================================================================== | 72% | |========================================================================================= | 73% | |========================================================================================== | 74% | |=========================================================================================== | 75% | |=========================================================================================== | 76% | |============================================================================================ | 76% | |============================================================================================= | 77% | |============================================================================================== | 78% | |=============================================================================================== | 79% | |================================================================================================ | 80% | |================================================================================================= | 80% | |================================================================================================== | 81% | |=================================================================================================== | 82% | |==================================================================================================== | 83% | |===================================================================================================== | 83% | |====================================================================================================== | 84% | |======================================================================================================= | 85% | |======================================================================================================== | 86% | |========================================================================================================= | 87% | |========================================================================================================== | 87% | |=========================================================================================================== | 88% | |============================================================================================================ | 89% | |============================================================================================================= | 90% | |============================================================================================================== | 91% | |=============================================================================================================== | 91% | |=============================================================================================================== | 92% | |================================================================================================================ | 93% | |================================================================================================================= | 94% | |================================================================================================================== | 94% | |=================================================================================================================== | 95% | |==================================================================================================================== | 96% | |===================================================================================================================== | 97% | |====================================================================================================================== | 98% | |======================================================================================================================= | 98% | |======================================================================================================================== | 99% | |=========================================================================================================================| 100%
## Processing: A549_EGF
## fitting ...
## | | | 0% | |= | 1% | |== | 2% | |=== | 2% | |==== | 3% | |===== | 4% | |====== | 5% | |======= | 6% | |======== | 6% | |========= | 7% | |========== | 8% | |========== | 9% | |=========== | 9% | |============ | 10% | |============= | 11% | |============== | 12% | |=============== | 13% | |================ | 13% | |================= | 14% | |================== | 15% | |=================== | 16% | |==================== | 17% | |===================== | 17% | |====================== | 18% | |======================= | 19% | |======================== | 20% | |========================= | 20% | |========================== | 21% | |=========================== | 22% | |============================ | 23% | |============================= | 24% | |============================== | 24% | |============================== | 25% | |=============================== | 26% | |================================ | 27% | |================================= | 28% | |================================== | 28% | |=================================== | 29% | |==================================== | 30% | |===================================== | 31% | |====================================== | 31% | |======================================= | 32% | |======================================== | 33% | |========================================= | 34% | |========================================== | 35% | |=========================================== | 35% | |============================================ | 36% | |============================================= | 37% | |============================================== | 38% | |=============================================== | 39% | |================================================ | 39% | |================================================= | 40% | |================================================== | 41% | |================================================== | 42% | |=================================================== | 43% | |==================================================== | 43% | |===================================================== | 44% | |====================================================== | 45% | |======================================================= | 46% | |======================================================== | 46% | |========================================================= | 47% | |========================================================== | 48% | |=========================================================== | 49% | |============================================================ | 50% | |============================================================= | 50% | |============================================================== | 51% | |=============================================================== | 52% | |================================================================ | 53% | |================================================================= | 54% | |================================================================== | 54% | |=================================================================== | 55% | |==================================================================== | 56% | |===================================================================== | 57% | |====================================================================== | 57% | |======================================================================= | 58% | |======================================================================= | 59% | |======================================================================== | 60% | |========================================================================= | 61% | |========================================================================== | 61% | |=========================================================================== | 62% | |============================================================================ | 63% | |============================================================================= | 64% | |============================================================================== | 65% | |=============================================================================== | 65% | |================================================================================ | 66% | |================================================================================= | 67% | |================================================================================== | 68% | |=================================================================================== | 69% | |==================================================================================== | 69% | |===================================================================================== | 70% | |====================================================================================== | 71% | |======================================================================================= | 72% | |======================================================================================== | 72% | |========================================================================================= | 73% | |========================================================================================== | 74% | |=========================================================================================== | 75% | |=========================================================================================== | 76% | |============================================================================================ | 76% | |============================================================================================= | 77% | |============================================================================================== | 78% | |=============================================================================================== | 79% | |================================================================================================ | 80% | |================================================================================================= | 80% | |================================================================================================== | 81% | |=================================================================================================== | 82% | |==================================================================================================== | 83% | |===================================================================================================== | 83% | |====================================================================================================== | 84% | |======================================================================================================= | 85% | |======================================================================================================== | 86% | |========================================================================================================= | 87% | |========================================================================================================== | 87% | |=========================================================================================================== | 88% | |============================================================================================================ | 89% | |============================================================================================================= | 90% | |============================================================================================================== | 91% | |=============================================================================================================== | 91% | |=============================================================================================================== | 92% | |================================================================================================================ | 93% | |================================================================================================================= | 94% | |================================================================================================================== | 94% | |=================================================================================================================== | 95% | |==================================================================================================================== | 96% | |===================================================================================================================== | 97% | |====================================================================================================================== | 98% | |======================================================================================================================= | 98% | |======================================================================================================================== | 99% | |=========================================================================================================================| 100%
To understand which signaling pathways are most strongly associated with the epithelial–mesenchymal transition (EMT) process, we can compute pathway activity scores for each sample and correlate them with EMT scores.
data(nnPCA_Result_EMT)
#data(nnPCA_Result_multiple)
ref_gmt <- system.file("extdata", "TianLab_collected_EMT_fignatures.gmt", package = "EMTscore")
#ref_gmt <- "/home/hwen/project/EMTscore/EMTscore/inst/extdata/TianLab_collected_EMT_fignatures.gmt"
#gmt_file <- "/home/hwen/project/EMTscore/EMTscore/inst/extdata/c2.all.v2025.1.Hs.symbols.gmt"
gmt_file <- system.file("extdata", "c2.all.v2025.1.Hs.symbols.gmt", package = "EMTscore")
filter_gmt_by_reference(
ref_gmt = ref_gmt,
target_gmt = gmt_file,
output_gmt = "filtered.c2.gmt",
cutoff = 0.3, # try 0.2–0.3 first
keep_low_overlap = TRUE
)
filtered_file <- system.file("extdata", "filtered.c2.gmt", package = "EMTscore")
#filtered_file <- "/home/hwen/project/EMTscore/EMTscore/inst/extdata/filtered.c2.gmt"
nnPCA_Result_multiple <- Execute_nnPCA_parallel(geneExp, filtered_file, dimension = 1, cores = 2)
result <- correlate_sample_scores(score_mat1 = nnPCA_Result_multiple, score_mat2 = nnPCA_Result_EMT, method = "pearson")
head(result)
In addition to EMT scores, we can compute other relevant biological scores to further characterize cellular states, such as stemness and senescence. These scores help to assess differences in cell pluripotency, proliferative potential, and aging status.
Here, we use the compute_Signature_score function to
calculate scores for each sample based on predefined gene
signatures:
stemsig.tsv
gene signature file, reflecting cellular pluripotency or stem-like
characteristics.signature_file <- system.file("extdata", "stemsig.tsv", package = "EMTscore")
scores <- compute_Signature_score(geneExp, signature_file , score_name = "stemness_score")
head(scores)
## stemness_score
## m.DMS153 0.5344621
## m.NCIH60 0.1719915
## m.NCIH69 0.3539699
## m.NCIH82 0.4988987
## m.NCIH128 0.4462295
## m.NCIH146 0.3435980
cellular_senescence_sig.tsv gene signature file, reflecting
the cellular aging state.signature_file <- system.file("extdata", "cellular_senescence_sig.tsv", package = "EMTscore")
scores <- compute_Signature_score(geneExp, signature_file, score_name = "senescence_score")
head(scores)
## senescence_score
## m.DMS153 0.3504790
## m.NCIH60 0.1974465
## m.NCIH69 0.1508204
## m.NCIH82 0.2459747
## m.NCIH128 0.2579179
## m.NCIH146 0.3323265
These scores can be used alongside EMT scores for downstream analyses, such as cell-type characterization, correlation analysis, or visualization, providing a more comprehensive view of cellular states.
In this section, we analyze single-cell RNA-seq datasets to compute stemness, senescence and EMT scores for individual cells and investigate their relationship. We first load multiple single-cell datasets and compute the scores using predefined gene signatures:
#obj <- system.file("extdata", "example_seurat_obj.rds", package = "EMTscore")
#files <- c(obj)
signature_file1 <- system.file("extdata", "stemsig.tsv", package = "EMTscore")
signature_file2 <- system.file("extdata", "cellular_senescence_sig.tsv", package = "EMTscore")
signature_files <- c(signature_file1, signature_file2)
result <- compute_Signature_score_SingleCell(objects, signature_files, score_name = c("Stemness_Score", "Senescence_Score"))
head(result$A549_TGFB1@meta.data)
## orig.ident nCount_RNA nFeature_RNA percent.mito Sample CellLine Treatment Time Doublet S.Score
## Mix1_AAAGCAACACTTCGAA Mix1 16979 3679 0.04505352 A549_TGFB1_3d A549 TGFB1 3d Singlet 0.4410757
## Mix1_AACTCTTCACAGCCCA Mix1 14496 3380 0.02384398 A549_TGFB1_3d A549 TGFB1 3d Singlet 0.0162727
## Mix1_AAGCCGCAGGAATCGC Mix1 30190 4554 0.03075295 A549_TGFB1_3d A549 TGFB1 3d Singlet 1.4221480
## Mix1_ACACTGAGTAACGCGA Mix1 21772 3886 0.05087156 A549_TGFB1_3d A549 TGFB1 3d Singlet -0.4427886
## Mix1_ACACTGATCAACGCTA Mix1 18431 3724 0.03013713 A549_TGFB1_3d A549 TGFB1 3d Singlet 0.4270298
## Mix1_ACAGCTAAGTAGTGCG Mix1 15720 3439 0.04594268 A549_TGFB1_7d A549 TGFB1 7d Singlet -0.1178486
## G2M.Score Phase Mix SCT_snn_res.0.8 SCT_snn_res.0.1 RNA_snn_res.0.1 seurat_clusters RNA_snn_res.0.05
## Mix1_AAAGCAACACTTCGAA -1.3621855 S Mix1 9 0 0 0 0
## Mix1_AACTCTTCACAGCCCA 0.6234093 G2M Mix1 9 0 0 0 0
## Mix1_AAGCCGCAGGAATCGC -1.6454059 S Mix1 9 0 0 0 0
## Mix1_ACACTGAGTAACGCGA -1.6124782 G1 Mix1 9 0 0 0 0
## Mix1_ACACTGATCAACGCTA -1.0752030 S Mix1 9 0 0 0 0
## Mix1_ACAGCTAAGTAGTGCG -0.8602084 G1 Mix1 9 0 0 0 0
## Cluster RNA_snn_res.0.5 Pseudotime ident Stemness_Score Senescence_Score
## Mix1_AAAGCAACACTTCGAA 0 0 0.6281110 0 0.4635481 0.3779163
## Mix1_AACTCTTCACAGCCCA 0 0 0.7151993 0 0.6010640 0.3955835
## Mix1_AAGCCGCAGGAATCGC 0 0 0.6609553 0 0.5913980 0.4448066
## Mix1_ACACTGAGTAACGCGA 0 0 0.6928316 0 0.5245502 0.3813141
## Mix1_ACACTGATCAACGCTA 0 0 0.6511502 0 0.5971261 0.3474779
## Mix1_ACAGCTAAGTAGTGCG 0 0 0.7630827 0 0.6023427 0.4776218
gmt_file <- system.file("extdata", "EM_signature.gmt", package = "EMTscore")
EMscore_result <- add_EMT_score_multiple(objects, gmt_file,emt_names = c("Escore", "Mscore"),
method = "nnPCA",
nnPCA_dim = 1, cores = 2)
## 121
## 121
## 121
head(EMscore_result$A549_TGFB1@meta.data)
## orig.ident nCount_RNA nFeature_RNA percent.mito Sample CellLine Treatment Time Doublet S.Score
## Mix1_AAAGCAACACTTCGAA Mix1 16979 3679 0.04505352 A549_TGFB1_3d A549 TGFB1 3d Singlet 0.4410757
## Mix1_AACTCTTCACAGCCCA Mix1 14496 3380 0.02384398 A549_TGFB1_3d A549 TGFB1 3d Singlet 0.0162727
## Mix1_AAGCCGCAGGAATCGC Mix1 30190 4554 0.03075295 A549_TGFB1_3d A549 TGFB1 3d Singlet 1.4221480
## Mix1_ACACTGAGTAACGCGA Mix1 21772 3886 0.05087156 A549_TGFB1_3d A549 TGFB1 3d Singlet -0.4427886
## Mix1_ACACTGATCAACGCTA Mix1 18431 3724 0.03013713 A549_TGFB1_3d A549 TGFB1 3d Singlet 0.4270298
## Mix1_ACAGCTAAGTAGTGCG Mix1 15720 3439 0.04594268 A549_TGFB1_7d A549 TGFB1 7d Singlet -0.1178486
## G2M.Score Phase Mix SCT_snn_res.0.8 SCT_snn_res.0.1 RNA_snn_res.0.1 seurat_clusters RNA_snn_res.0.05
## Mix1_AAAGCAACACTTCGAA -1.3621855 S Mix1 9 0 0 0 0
## Mix1_AACTCTTCACAGCCCA 0.6234093 G2M Mix1 9 0 0 0 0
## Mix1_AAGCCGCAGGAATCGC -1.6454059 S Mix1 9 0 0 0 0
## Mix1_ACACTGAGTAACGCGA -1.6124782 G1 Mix1 9 0 0 0 0
## Mix1_ACACTGATCAACGCTA -1.0752030 S Mix1 9 0 0 0 0
## Mix1_ACAGCTAAGTAGTGCG -0.8602084 G1 Mix1 9 0 0 0 0
## Cluster RNA_snn_res.0.5 Pseudotime ident Escore Mscore
## Mix1_AAAGCAACACTTCGAA 0 0 0.6281110 0 -1.4364078 0.6190105
## Mix1_AACTCTTCACAGCCCA 0 0 0.7151993 0 -1.0305298 1.8686877
## Mix1_AAGCCGCAGGAATCGC 0 0 0.6609553 0 -0.3128221 2.0484137
## Mix1_ACACTGAGTAACGCGA 0 0 0.6928316 0 -1.8769122 0.2067999
## Mix1_ACACTGATCAACGCTA 0 0 0.6511502 0 -1.0547855 0.1678808
## Mix1_ACAGCTAAGTAGTGCG 0 0 0.7630827 0 -1.4521419 0.9370016
gmt_file <- system.file("extdata", "M_signature.gmt", package = "EMTscore")
Mscore_result <- add_EMT_score(objects, gmt_file,emt_name = c("Mscore_PC1", "Mscore_PC2"),
method = "nnPCA",
nnPCA_dim = 2)
head(Mscore_result$A549_TGFB1@meta.data)
## orig.ident nCount_RNA nFeature_RNA percent.mito Sample CellLine Treatment Time Doublet S.Score
## Mix1_AAAGCAACACTTCGAA Mix1 16979 3679 0.04505352 A549_TGFB1_3d A549 TGFB1 3d Singlet 0.4410757
## Mix1_AACTCTTCACAGCCCA Mix1 14496 3380 0.02384398 A549_TGFB1_3d A549 TGFB1 3d Singlet 0.0162727
## Mix1_AAGCCGCAGGAATCGC Mix1 30190 4554 0.03075295 A549_TGFB1_3d A549 TGFB1 3d Singlet 1.4221480
## Mix1_ACACTGAGTAACGCGA Mix1 21772 3886 0.05087156 A549_TGFB1_3d A549 TGFB1 3d Singlet -0.4427886
## Mix1_ACACTGATCAACGCTA Mix1 18431 3724 0.03013713 A549_TGFB1_3d A549 TGFB1 3d Singlet 0.4270298
## Mix1_ACAGCTAAGTAGTGCG Mix1 15720 3439 0.04594268 A549_TGFB1_7d A549 TGFB1 7d Singlet -0.1178486
## G2M.Score Phase Mix SCT_snn_res.0.8 SCT_snn_res.0.1 RNA_snn_res.0.1 seurat_clusters RNA_snn_res.0.05
## Mix1_AAAGCAACACTTCGAA -1.3621855 S Mix1 9 0 0 0 0
## Mix1_AACTCTTCACAGCCCA 0.6234093 G2M Mix1 9 0 0 0 0
## Mix1_AAGCCGCAGGAATCGC -1.6454059 S Mix1 9 0 0 0 0
## Mix1_ACACTGAGTAACGCGA -1.6124782 G1 Mix1 9 0 0 0 0
## Mix1_ACACTGATCAACGCTA -1.0752030 S Mix1 9 0 0 0 0
## Mix1_ACAGCTAAGTAGTGCG -0.8602084 G1 Mix1 9 0 0 0 0
## Cluster RNA_snn_res.0.5 Pseudotime ident Mscore_PC1 Mscore_PC2
## Mix1_AAAGCAACACTTCGAA 0 0 0.6281110 0 0.6175720 -0.08637753
## Mix1_AACTCTTCACAGCCCA 0 0 0.7151993 0 1.8668715 -0.73485632
## Mix1_AAGCCGCAGGAATCGC 0 0 0.6609553 0 2.0539906 0.87514286
## Mix1_ACACTGAGTAACGCGA 0 0 0.6928316 0 0.2055709 0.02578799
## Mix1_ACACTGATCAACGCTA 0 0 0.6511502 0 0.1691568 0.02682536
## Mix1_ACAGCTAAGTAGTGCG 0 0 0.7630827 0 0.9380215 0.59768646
df <- EMscore_result$A549_TGFB1@meta.data
plot1 <- Execute_E_M_plot(
df,
E_colname = "Escore",
M_colname = "Mscore",
celltype_colname = "Time",
colors = c("#F87189", "#CE9031", "#A48CF5", "#97A430", "#39A7D0", "#E57D5F",
"#84C7B9", "#E1AF64", "#C26CCF", "#B0BF43", "#57C3E8", "#F29D9E", "#92AAE6")
)
plot1
df <- Mscore_result$A549_TGFB1@meta.data
plot2 <- Execute_M_dimension_plot(
df,
M1_colname = "Mscore_PC1",
M2_colname = "Mscore_PC2",
celltype_colname = "Time",
colors = c("#F87189", "#CE9031", "#A48CF5", "#97A430", "#39A7D0", "#E57D5F",
"#84C7B9", "#E1AF64", "#C26CCF", "#B0BF43", "#57C3E8", "#F29D9E", "#92AAE6")
)
plot2
### Combined Plot
combined_plot <- Arrange_plots(
plots_list = list(plot1, plot2),
ncol_per_row = 2,
subtitles = c("E vs M", "M1 vs M2"),
fig_title = "Cook_et_al"
)
print(combined_plot)
df <- result$A549_TGFB1@meta.data
cor_test <- cor.test(df$Senescence_Score, df$Stemness_Score, method = "pearson")
R_val <- round(cor_test$estimate, 2)
p_val <- format(cor_test$p.value, scientific = TRUE, digits = 2)
n_clust <- length(unique(df$Time))
palette_colors <- colorRampPalette(RColorBrewer::brewer.pal(8, "Set2"))(n_clust)
ggplot(df, aes(x = Senescence_Score, y = Stemness_Score, color = Time)) +
geom_point(size = 2.5, alpha = 0.8) +
geom_smooth(method = "lm", se = FALSE, size = 1) +
scale_color_manual(values = palette_colors) +
annotate("text",
x = min(df$Senescence_Score),
y = max(df$Stemness_Score),
label = paste0("R = ", R_val, ", p < ", p_val),
hjust = 0, size = 5) +
theme_bw() +
theme(
panel.grid = element_blank(),
panel.border = element_rect(
colour = "black",
fill = NA,
size = 1
)) + theme(
text = element_text(colour = "black")
) + theme(
axis.title = element_text(size = 14),
axis.text = element_text(size = 14),
legend.title = element_text(size = 13),
legend.text = element_text(size = 11),
plot.title = element_text(size = 12, face = "bold")
)
# 5.25 3.84
In this section, we integrate stemness, senescence, and EMT scores at the single-cell level to systematically explore their relationships. By merging the computed scores for each cell, we can visualize how stemness and senescence individually correlate with the epithelial (E) and mesenchymal (M) components of EMT.
Specifically, we:
1.Merge metadata from stemness/senescence computations and EMT score calculations to obtain a single dataset containing all relevant scores for each cell.
2.Visualize relationships using scatter plots, where each plot shows one pairing:
Stemness vs. E-score
Stemness vs. M-score
Senescence vs. E-score
Senescence vs. M-score
# Extract metadata
df1 <- result$A549_TGFB1@meta.data
df2 <- EMscore_result$A549_TGFB1@meta.data
# Add cell names for merging
df1$cell <- rownames(df1)
df2$cell <- rownames(df2)
# Merge metadata
df <- df1 %>%
select(cell, Stemness_Score, Senescence_Score, Time) %>%
left_join(df2 %>% select(cell,
Escore,
Mscore), by = "cell")
# Automatically generate color palette for Time groups
n_groups <- length(unique(df$Time))
palette_colors <- colorRampPalette(brewer.pal(8, "Set2"))(n_groups)
# Define combinations to plot
x_vars <- c("Stemness_Score", "Senescence_Score")
y_vars <- c("Escore", "Mscore")
# Loop through all combinations
for (x_var in x_vars) {
for (y_var in y_vars) {
# Pearson correlation
cor_test <- cor.test(df[[x_var]], df[[y_var]])
R_val <- round(cor_test$estimate, 2)
p_val <- format(cor_test$p.value, scientific = TRUE, digits = 2)
# Plot
p <- ggplot(df, aes_string(x = x_var, y = y_var, color = "Time")) +
geom_point(size = 2.5, alpha = 0.8) +
geom_smooth(method = "lm", se = FALSE, size = 1) +
scale_color_manual(values = palette_colors) +
annotate("text",
x = min(df[[x_var]]),
y = max(df[[y_var]]),
label = paste0("R = ", R_val, ", p < ", p_val),
hjust = 0,
size = 5) +
labs(
x = gsub("_", " ", x_var),
y = gsub("_", " ", y_var),
title = paste(gsub("_", " ", y_var), "vs", gsub("_", " ", x_var))
) +
theme_bw() +
theme(
panel.grid = element_blank(),
panel.border = element_rect(
colour = "black",
fill = NA,
size = 1
)) + theme(
text = element_text(colour = "black")
) + theme(
axis.title = element_text(size = 14),
axis.text = element_text(size = 14),
legend.title = element_text(size = 13),
legend.text = element_text(size = 11),
plot.title = element_text(size = 12, face = "bold")
)
print(p)
}
}
sessionInfo()
## R Under development (unstable) (2025-11-25 r89063)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.3 LTS
##
## Matrix products: default
## BLAS: /usr/lib/R/lib/libRblas.so
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0 LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C 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 LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: America/Chicago
## tzcode source: system (glibc)
##
## attached base packages:
## [1] splines stats4 grid stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] EMTscore_0.99.0 devtools_2.4.6 usethis_3.2.1 SeuratWrappers_0.4.0
## [5] orthogene_1.17.0 reticulate_1.44.1 SeuratDisk_0.0.0.9021 ExperimentHub_3.1.0
## [9] AnnotationHub_4.1.0 BiocFileCache_3.1.0 dbplyr_2.5.1 Cairo_1.7-0
## [13] hrbrthemes_0.9.2 RColorBrewer_1.1-3 ggalluvial_0.12.5 mclust_6.1.2
## [17] GSA_1.03.3 Seurat_5.3.1 SeuratObject_5.2.0 sp_2.2-0
## [21] slingshot_2.19.0 TrajectoryUtils_1.19.0 SingleCellExperiment_1.33.0 SummarizedExperiment_1.41.0
## [25] GenomicRanges_1.63.0 Seqinfo_1.1.0 IRanges_2.45.0 S4Vectors_0.49.0
## [29] MatrixGenerics_1.23.0 matrixStats_1.5.0 princurve_2.1.6 monocle_2.39.0
## [33] DDRTree_0.1.5 irlba_2.3.5.1 VGAM_1.1-13 Biobase_2.71.0
## [37] BiocGenerics_0.57.0 generics_0.1.4 Matrix_1.7-4 DoubletFinder_2.0.6
## [41] AUCell_1.33.0 ComplexHeatmap_2.27.0 ggthemes_5.1.0 paletteer_1.6.0
## [45] circlize_0.4.16 pheatmap_1.0.13 ggpubr_0.6.2 curl_7.0.0
## [49] gridExtra_2.3 dplyr_1.1.4 ggtext_0.1.2 ggplot2_4.0.1
## [53] nsprcomp_0.5.1-2
##
## loaded via a namespace (and not attached):
## [1] igraph_2.2.1 graph_1.89.0 ica_1.0-3 plotly_4.11.0
## [5] Formula_1.2-5 rematch2_2.1.2 maps_3.4.3 BiocBaseUtils_1.13.0
## [9] tidyselect_1.2.1 bit_4.6.0 doParallel_1.0.17 clue_0.3-66
## [13] lattice_0.22-7 rjson_0.2.23 blob_1.2.4 stringr_1.6.0
## [17] S4Arrays_1.11.0 parallel_4.6.0 png_0.1-8 ggplotify_0.1.3
## [21] cli_3.6.5 askpass_1.2.1 openssl_2.3.4 goftest_1.2-3
## [25] textshaping_1.0.4 grr_0.9.5 purrr_1.2.0 uwot_0.2.4
## [29] mime_0.13 evaluate_1.0.5 tidytree_0.4.6 stringi_1.8.7
## [33] backports_1.5.0 desc_1.4.3 XML_3.99-0.20 httpuv_1.6.16
## [37] AnnotationDbi_1.73.0 magrittr_2.0.4 rappdirs_0.3.3 sctransform_0.4.2
## [41] sessioninfo_1.2.3 DBI_1.2.3 HDF5Array_1.39.0 jquerylib_0.1.4
## [45] withr_3.0.2 systemfonts_1.3.1 rprojroot_2.1.1 lmtest_0.9-40
## [49] GSEABase_1.73.0 brio_1.1.5 BiocManager_1.30.27 htmlwidgets_1.6.4
## [53] fs_1.6.6 ggrepel_0.9.6 labeling_0.4.3 EMTscoreData_0.99.9
## [57] SparseArray_1.11.4 extrafont_0.20 h5mread_1.3.1 annotate_1.89.0
## [61] zoo_1.8-14 XVector_0.51.0 knitr_1.50 foreach_1.5.2
## [65] patchwork_1.3.2 data.table_1.17.8 ggtree_4.1.1 rhdf5_2.55.11
## [69] R.oo_1.27.1 ggiraph_0.9.2 RSpectra_0.16-2 extrafontdb_1.1
## [73] gridGraphics_0.5-1 fastDummies_1.7.5 commonmark_2.0.0 ellipsis_0.3.2
## [77] lazyeval_0.2.2 yaml_2.3.10 survival_3.8-3 SpatialExperiment_1.21.0
## [81] scattermore_1.2 BiocVersion_3.23.1 crayon_1.5.3 RcppAnnoy_0.0.22
## [85] tidyr_1.3.1 progressr_0.18.0 later_1.4.4 ggridges_0.5.7
## [89] codetools_0.2-20 GlobalOptions_0.1.2 HSMMSingleCell_1.31.0 KEGGREST_1.51.1
## [93] Rtsne_0.17 shape_1.4.6.1 fastICA_1.2-7 limma_3.67.0
## [97] gdtools_0.4.4 filelock_1.0.3 pkgconfig_2.0.3 xml2_1.5.0
## [101] spatstat.univar_3.1-5 aplot_0.2.9 spatstat.sparse_3.1-0 ape_5.8-1
## [105] viridisLite_0.4.2 xtable_1.8-4 litedown_0.8 car_3.1-3
## [109] plyr_1.8.9 httr_1.4.7 tools_4.6.0 globals_0.18.0
## [113] sys_3.4.3 pkgbuild_1.4.8 broom_1.0.10 nlme_3.1-168
## [117] hdf5r_1.3.12 digest_0.6.39 dir.expiry_1.19.0 farver_2.1.2
## [121] reshape2_1.4.5 yulab.utils_0.2.3 viridis_0.6.5 glue_1.8.0
## [125] cachem_1.1.0 polyclip_1.10-7 Biostrings_2.79.2 parallelly_1.45.1
## [129] pkgload_1.4.1 statmod_1.5.1 RcppHNSW_0.6.0 ragg_1.5.0
## [133] ScaledMatrix_1.19.0 fontBitstreamVera_0.1.1 carData_3.0-5 pbapply_1.7-4
## [137] httr2_1.2.1 fields_17.1 spam_2.11-1 utf8_1.2.6
## [141] basilisk_1.23.0 ggsignif_0.6.4 shiny_1.11.1 GSVA_2.5.9
## [145] R.utils_2.13.0 rhdf5filters_1.23.1 RCurl_1.98-1.17 memoise_2.0.1
## [149] rmarkdown_2.30 scales_1.4.0 R.methodsS3_1.8.2 future_1.68.0
## [153] RANN_2.6.2 fontLiberation_0.1.0 spatstat.data_3.1-9 rstudioapi_0.17.1
## [157] cluster_2.1.8.1 spatstat.utils_3.2-0 fitdistrplus_1.2-4 cowplot_1.2.0
## [161] colorspace_2.1-2 rlang_1.1.6 DelayedMatrixStats_1.33.0 sparseMatrixStats_1.23.0
## [165] dotCall64_1.2 homologene_1.4.68.19.3.27 mgcv_1.9-4 xfun_0.54
## [169] remotes_2.5.0 iterators_1.0.14 abind_1.4-8 tibble_3.3.0
## [173] treeio_1.35.0 Rhdf5lib_1.33.0 bitops_1.0-9 ps_1.9.1
## [177] promises_1.5.0 RSQLite_2.4.4 leidenbase_0.1.35 DelayedArray_0.37.0
## [181] compiler_4.6.0 beachmat_2.27.0 memuse_4.2-3 listenv_0.10.0
## [185] Rcpp_1.1.0 Rttf2pt1_1.3.14 fontquiver_0.2.1 roxygen2_7.3.3
## [189] BiocSingular_1.27.1 tensor_1.5.1 MASS_7.3-65 BiocParallel_1.45.0
## [193] gridtext_0.1.5 babelgene_22.9 spatstat.random_3.4-3 R6_2.6.1
## [197] fastmap_1.2.0 rstatix_0.7.3 ROCR_1.0-11 rsvd_1.0.5
## [201] gtable_0.3.6 KernSmooth_2.23-26 miniUI_0.1.2 deldir_2.0-4
## [205] htmltools_0.5.8.1 gitcreds_0.1.2 bit64_4.6.0-1 spatstat.explore_3.6-0
## [209] lifecycle_1.0.4 S7_0.2.1 processx_3.8.6 callr_3.7.6
## [213] sass_0.4.10 vctrs_0.6.5 testthat_3.3.1 isoband_0.2.7
## [217] slam_0.1-55 spatstat.geom_3.6-1 ggfun_0.2.0 future.apply_1.20.0
## [221] gprofiler2_0.2.4 bslib_0.9.0 pillar_1.11.1 magick_2.9.0
## [225] otel_0.2.0 combinat_0.0-8 jsonlite_2.0.0 markdown_2.0
## [229] GetoptLong_1.0.5