Auditable gene mapping with SpaMTPdb and SpaMTPData

Reference ownership and reproducibility

SpaMTPdb provides RaMP annotation tables and a separate versioned HGNC gene reference. SpaMTPData supplies native experiment data and declared species. SpaMTP resolves identifiers, annotates row metadata and runs pathway analyses. Use SpaMTP >= 0.99.6, SpaMTPdb >= 0.99.4 and SpaMTPData >= 0.99.5 together.

library(SpaMTP)
SpaMTPdb::spaMTPdbGeneReference(metadata = TRUE)
##              resource  version     organism taxonomy_id                  title
## 1 hgnc_gene_reference 2026.7.7 Homo sapiens        9606 SpaMTPdb_HGNC_2026.7.7
##                          file_name
## 1 hgnc_complete_set_2026-07-07.tsv
##                                                                            location_prefix
## 1 https://storage.googleapis.com/public-download-files/hgnc/archive/archive/quarterly/tsv/
##                         rdata_path                                  source_url
## 1 hgnc_complete_set_2026-07-07.tsv https://www.genenames.org/download/archive/
##      bytes                              md5
## 1 16913890 cd41d33955722de9ac0e14a2557ef5fc
SpaMTPdb::spaMTPdbVersion()
## [1] "3.0.7"

The HGNC reference uses a fixed quarterly archive, with its own version and checksum. It does not change the existing RaMP 3.0.7 or experiment 1.1.0 files. HGNC mapping is for Homo sapiens; it does not convert mouse genes to human orthologues. Native experiments loaded by SpaMTPData carry their registry species in metadata(x)$SpaMTPData, including their nested experiments. Species checks therefore still apply after extracting RNA with altExp().

Build once, inspect before testing

The following examples run during vignette builds, using a bundled 240-location subset of the published human-brain dataset. The locations nearest the coordinate-wise median were selected without consulting expression or mapping results. All 339 measured RNA features and their paired MS features are retained; see help("vignetteData") for the recipe and source checksums. Pinned annotation references are downloaded if not already available locally or in a verified cache. Local files and verified caches can also be used with offline = TRUE.

database <- loadSpaMTPDatabase(
  c("source_df", "analyte", "analytehaspathway", "pathway"),
  version = "3.0.7"
)
reference <- SpaMTPdb::spaMTPdbGeneReference(
  version = "2026.7.7"
)
index <- buildGeneMappingIndex(database$source_df, gene_reference = reference)
mapping <- mapGeneIdentifiers(
  c("gene_symbol:AATK", "entrez:9625", "gene_symbol:BANK1"), index = index
)
mapping
##               input    gene_id symbol canonical_ramp_id
## 1  gene_symbol:AATK    HGNC:21   AATK  RAMP_G_000021175
## 2       entrez:9625    HGNC:21   AATK  RAMP_G_000021175
## 3 gene_symbol:BANK1 HGNC:18233  BANK1  RAMP_G_000031335
##                            ramp_ids status          method candidate_gene_ids
## 1 RAMP_G_000021175;RAMP_G_000030253 mapped approved_symbol            HGNC:21
## 2 RAMP_G_000021175;RAMP_G_000030253 mapped       entrez_id            HGNC:21
## 3                  RAMP_G_000031335 mapped approved_symbol         HGNC:18233
##   candidate_ramp_ids
## 1                   
## 2                   
## 3

The index records a fingerprint of the source table’s gene identifiers and common names. Pathway workflows reject a cached index built from different identity assignments, even if the RaMP ID set is unchanged. Rebuild older saved indices with buildGeneMappingIndex(); changing row order or duplicating identical source rows does not invalidate the fingerprint.

Symbols, previous symbols and aliases are resolved to an HGNC gene. An approved symbol takes priority over other genes’ aliases. Entrez, HGNC, UniProt and versioned Ensembl gene IDs are supported. A shared protein ID can be resolved by a compatible gene-specific ID in the same RaMP record. Conflicting specific IDs quarantine the record rather than joining different genes.

gene_id is the stable HGNC identity. ramp_ids lists its non-conflicting RaMP records, and canonical_ramp_id is one representative used to count the gene once. For example, AATK’s UniProt and Entrez records in RaMP 3.0.7 belong to one HGNC gene, so their pathway memberships are united before enrichment.

Inspect status, method, candidate_gene_ids and candidate_ramp_ids. The latter exposes raw RaMP candidates for direct IDs and crossreferences. A shared crossreference with unresolved or conflicting competitors remains ambiguous even when only one candidate has a known HGNC identity. not_in_ramp means HGNC recognizes the gene but no usable RaMP record was found; ambiguous and conflicting_ramp_records require review. mapped_ramp_only denotes a raw RaMP record whose HGNC identity was not resolved. A warning is not evidence that the gene has no biological function or pathway membership.

Annotate experiment features without altering expression

spe <- readRDS(system.file("extdata", "human_demo.rds", package = "SpaMTP"))
SingleCellExperiment::altExpNames(spe)
## [1] "SPT"
# Select the actual transcriptome altExp shown above. If identifiers live in
# a rowData column, set id_column; otherwise row names are used.
spe <- annotateGeneIdentifiers(
  spe, assay = "SPT", index = index, organism = "Homo sapiens"
)
## Warning: 10 gene input(s) unresolved; inspect mapping status and
## candidate_gene_ids.
rna <- SingleCellExperiment::altExp(spe, "SPT")
head(SummarizedExperiment::rowData(rna))
## DataFrame with 6 rows and 6 columns
##         spamtp_gene_id spamtp_gene_symbol spamtp_gene_canonical_ramp_id
##            <character>        <character>                   <character>
## AATK           HGNC:21               AATK              RAMP_G_000021175
## ABCA2          HGNC:32              ABCA2              RAMP_G_000012783
## ABCC3          HGNC:54              ABCC3              RAMP_G_000000236
## AIF1          HGNC:352               AIF1              RAMP_G_000014049
## AKAP12        HGNC:370             AKAP12              RAMP_G_000009757
## ALOX5AP       HGNC:436            ALOX5AP              RAMP_G_000008688
##           spamtp_gene_ramp_ids spamtp_gene_status spamtp_gene_method
##                    <character>        <character>        <character>
## AATK    RAMP_G_000021175;RAM..             mapped    approved_symbol
## ABCA2         RAMP_G_000012783             mapped    approved_symbol
## ABCC3         RAMP_G_000000236             mapped    approved_symbol
## AIF1          RAMP_G_000014049             mapped    approved_symbol
## AKAP12        RAMP_G_000009757             mapped    approved_symbol
## ALOX5AP       RAMP_G_000008688             mapped    approved_symbol
table(SummarizedExperiment::rowData(rna)$spamtp_gene_status)
## 
## conflicting_ramp_records                   mapped              not_in_ramp 
##                        2                      329                        8
unresolved <- SummarizedExperiment::rowData(rna)$spamtp_gene_status != "mapped"
SummarizedExperiment::rowData(rna)[unresolved,
  c("spamtp_gene_symbol", "spamtp_gene_status", "spamtp_gene_ramp_ids")]
## DataFrame with 10 rows and 3 columns
##          spamtp_gene_symbol     spamtp_gene_status spamtp_gene_ramp_ids
##                 <character>            <character>          <character>
## BRINP3               BRINP3            not_in_ramp                     
## C1orf162           C1orf162            not_in_ramp                     
## C1orf194            CFAP276            not_in_ramp                     
## C9orf24              SPMIP6            not_in_ramp                     
## FBXO36               FBXO36            not_in_ramp                     
## HEPN1                 HEPN1            not_in_ramp                     
## HLA-DQA1           HLA-DQA1 conflicting_ramp_rec..                     
## SULT1A3             SULT1A3 conflicting_ramp_rec..                     
## TMIGD3               TMIGD3            not_in_ramp                     
## TRBC2                 TRBC2            not_in_ramp
stopifnot(ncol(rna) == ncol(spe), nrow(rna) == 339L)

Mapping columns remain aligned with original features. Counts, feature names, coordinates and paired modalities are preserved. If multiple expression rows map to the same gene, annotation records that fact without summing expression. Resolve those features before differential analysis. Regional pathway and network workflows reject different differential statistics for the same gene within a cluster rather than selecting an arbitrary row.

For these pinned inputs, 329 genes map and 10 produce an intentional unresolved identifier warning: two have conflicting RaMP records and eight are absent from RaMP. Their original expression remains in the object, but they are excluded from pathway testing. The table above exposes those exclusions rather than silently treating the entire 339-gene panel as mapped.

Use the whole measured panel as the universe

For a runnable foreground, we declare the measured genes AATK and BANK1 as genes of interest. This is an illustrative, predeclared query, not a list of statistically significant genes inferred from this single section.

genes_of_interest <- c("AATK", "BANK1")
measured_panel_genes <- rownames(rna)
stopifnot(all(genes_of_interest %in% measured_panel_genes))
result <- fishersPathwayAnalysis(
  Analyte = list(genes = genes_of_interest),
  universe = list(genes = measured_panel_genes),
  database = database, gene_index = index,
  min_path_size = 5, pval_cutoff = NULL
)
## Warning: universe$genes: 10 unmapped value(s) excluded; see attr(result,
## 'enrichment')$unmapped.
## Testing 1004 pathways; foreground = 2, universe = 329.
head(attr(result, "enrichment")$gene_mapping$inputs)
##    input    gene_id symbol canonical_ramp_id                          ramp_ids
## 1   AATK    HGNC:21   AATK  RAMP_G_000021175 RAMP_G_000021175;RAMP_G_000030253
## 2  BANK1 HGNC:18233  BANK1  RAMP_G_000031335                  RAMP_G_000031335
## 3  ABCA2    HGNC:32  ABCA2  RAMP_G_000012783                  RAMP_G_000012783
## 4  ABCC3    HGNC:54  ABCC3  RAMP_G_000000236                  RAMP_G_000000236
## 5   AIF1   HGNC:352   AIF1  RAMP_G_000014049                  RAMP_G_000014049
## 6 AKAP12   HGNC:370 AKAP12  RAMP_G_000009757                  RAMP_G_000009757
##   status          method candidate_gene_ids candidate_ramp_ids
## 1 mapped approved_symbol            HGNC:21                   
## 2 mapped approved_symbol         HGNC:18233                   
## 3 mapped approved_symbol            HGNC:32                   
## 4 mapped approved_symbol            HGNC:54                   
## 5 mapped approved_symbol           HGNC:352                   
## 6 mapped approved_symbol           HGNC:370
head(result)
##                                                                                                                                  pathway_name
## 1                                                                                            Aberrant B Cell Signaling in Autoimmune Diseases
## 2                                                                                                    Pathomechanisms of LN outside the kidney
## 3 Identification of key genes and pathway related to chemoresistance of small cell lung cancer through an integrative bioinformatics analysis
## 4                                                                                                                 GWAS of fibrosing disorders
## 5        ZIKV infection downregulates host mRNA expression in the placenta, including genes associated with cellular function and development
## 6                                         Pervasive translational regulation of the cell signalling circuitry underlies mammalian development
##       pathway_id  type pathwayCategory      p_val fdr      ratio
## 1 PMC9654300__F2 pfocr            <NA> 0.03020980   1 0.20000000
## 2 PMC3752952__F1 pfocr            <NA> 0.03020980   1 0.20000000
## 3 PMC9577795__F4 pfocr            <NA> 0.03020980   1 0.20000000
## 4 PMC7698326__F1 pfocr            <NA> 0.03619616   1 0.16666667
## 5 PMC9104602__F5 pfocr            <NA> 0.04216399   1 0.14285714
## 6 PMC5316868__F2 pfocr            <NA> 0.06584995   1 0.09090909
##   analytes_in_pathways total_in_pathways    pathwayRampId
## 1                    1                 5 RAMP_P_000082114
## 2                    1                 5 RAMP_P_000100894
## 3                    1                 5 RAMP_P_000103072
## 4                    1                 6 RAMP_P_000094730
## 5                    1                 7 RAMP_P_000077931
## 6                    1                11 RAMP_P_000087198
##   foreground_analytes_number background_analytes_number database_size
## 1                          2                        329            21
## 2                          2                        329            32
## 3                          2                        329           130
## 4                          2                        329            54
## 5                          2                        329            74
## 6                          2                        329            85
##   database_raw_size measured_size coverage_fraction used_size
## 1                21             5        0.23809524         5
## 2                33             5        0.15625000         5
## 3               130             5        0.03846154         5
## 4                54             6        0.11111111         6
## 5                75             7        0.09459459         7
## 6                85            11        0.12941176        11
##   excluded_conflict_count
## 1                       0
## 2                       1
## 3                       0
## 4                       0
## 5                       1
## 6                       0

Foreground and universe use the same complete identity index. All RaMP records of a resolved gene contribute to its union of pathway memberships, but the gene counts once in K, M, U and overlap. The universe is fixed before size filtering; zero-overlap eligible pathways remain in the BH family. pval_cutoff filters FDR after correction. Missing identifiers are excluded with an explicit audit; do not set U to the raw panel length to hide mapping failures.

Official SpaMTPdb workflows harmonize human genes automatically. A custom bundle can provide gene_reference, or an index can be supplied explicitly. Custom bundles without a reference retain RaMP-only behavior without a network request. gene_mapping = "ramp" explicitly reproduces historical mapping or uses a separately curated species-specific database; it is not an orthology conversion switch. Previously saved gene-ID mappings and p-values may change after identity reconciliation even though Fisher arithmetic is unchanged.

Use the same gene_index in findRegionalPathways() and pathwayNetworkPlots() to keep annotation identity and provenance consistent.

One membership index for enrichment, expression and plots

buildPathwayIndex() joins the gene identity index to RaMP memberships once. A pathway’s database_size counts unique identities after reconciliation and conflict exclusion; database_raw_size counts original RaMP records. measured_size and coverage_fraction describe the selected assay or measured universe. used_size and used_members record what actually contributes to a score or test. In regional analysis these can be smaller than the measured set because of the requested ranking filters. A pathway score is an expression summary, not evidence that the whole pathway is activated.

This small example runs offline. Its fictional gene has two RaMP records with complementary pathway memberships; both contribute while the gene counts once.

reference_example <- data.frame(
  hgnc_id = c("HGNC:1", "HGNC:2", "HGNC:3"),
  symbol = c("GENEA", "GENEB", "GENEC"), entrez_id = c("101", "102", "103"),
  uniprot_ids = c("U1", "U2", "U3")
)
database_example <- list(
  source_df = data.frame(rampId = paste0("RAMP_G_", c(1, 2, 3, 4)),
    sourceId = c("entrez:101", "uniprot:U1", "entrez:102", "entrez:103")),
  analytehaspathway = data.frame(rampId = paste0("RAMP_G_", c(1, 3, 2, 4)),
    pathwayRampId = c("P1", "P1", "P2", "P2")),
  pathway = data.frame(pathwayRampId = c("P1", "P2"), pathwayName = c("First", "Second")),
  gene_reference = reference_example
)
pathway_index_example <- buildPathwayIndex(database_example)
example <- SpaMTPData::spaMTPExampleData()
E_example <- matrix(seq_len(36), 3, dimnames = list(c("GENEA", "GENEB", "GENEC"), colnames(example)))
SingleCellExperiment::altExp(example, "transcriptome") <-
  SingleCellExperiment::SingleCellExperiment(assays = list(logcounts = log1p(E_example)))
example <- createPathwayAssay(example, analyte_type = "genes", assay = "transcriptome",
  slot = "logcounts", new_assay = "gene_ids", pathway_index = pathway_index_example)
example <- createPathwayObject(example, assay = "gene_ids", new.assay = "gene_scores",
  pathway_index = pathway_index_example)
SummarizedExperiment::rowData(SingleCellExperiment::altExp(example, "gene_scores"))[
  , c("pathwayRampId", "database_size", "measured_size", "coverage_fraction", "used_members")]
## DataFrame with 2 rows and 5 columns
##    pathwayRampId database_size measured_size coverage_fraction
##      <character>     <integer>     <integer>         <numeric>
## P1            P1             2             2                 1
## P2            P2             2             2                 1
##         used_members
##               <AsIs>
## P1 RAMP_G_1,RAMP_G_3
## P2 RAMP_G_1,RAMP_G_4

For the real human subset loaded above, use the full measured RNA panel and the same index for every entry point. This chunk runs during package builds on all 339 RNA features and 240 retained observations. The end-to-end guide also uses these data for descriptive regional rankings. Neither example treats locations as biological replicates.

pathway_index <- buildPathwayIndex(database = database, gene_index = index)
spe <- createPathwayAssay(spe, analyte_type = "genes", assay = "SPT",
  slot = "counts", new_assay = "gene_ids", pathway_index = pathway_index)
## Warning: 10 gene input(s) unresolved; inspect mapping status and
## candidate_gene_ids.
spe <- createPathwayObject(spe, assay = "gene_ids", new.assay = "gene_pathways",
  pathway_index = pathway_index, min_path_size = 5, max_path_size = 500)
pathways <- SingleCellExperiment::altExp(spe, "gene_pathways")
coverage <- S4Vectors::metadata(pathways)$pathway_mapping$coverage
head(coverage[, c("pathwayRampId", "database_size", "database_raw_size",
             "measured_size", "coverage_fraction", "excluded_conflict_count")])
##      pathwayRampId database_size database_raw_size measured_size
## 1 RAMP_P_000000001             0                 0             0
## 2 RAMP_P_000000002            18                18             1
## 3 RAMP_P_000000003            33                33             1
## 4 RAMP_P_000000004            15                15             1
## 5 RAMP_P_000000005            28                29             1
## 6 RAMP_P_000000006             9                 9             1
##   coverage_fraction excluded_conflict_count
## 1                NA                       0
## 2        0.05555556                       0
## 3        0.03030303                       0
## 4        0.06666667                       0
## 5        0.03571429                       1
## 6        0.11111111                       0
head(coverage$used_members)
## [[1]]
## character(0)
## 
## [[2]]
## [1] "RAMP_G_000000001"
## 
## [[3]]
## [1] "RAMP_G_000000001"
## 
## [[4]]
## [1] "RAMP_G_000000001"
## 
## [[5]]
## [1] "RAMP_G_000000001"
## 
## [[6]]
## [1] "RAMP_G_000000001"
head(coverage$excluded_conflict_records)
## [[1]]
## character(0)
## 
## [[2]]
## character(0)
## 
## [[3]]
## character(0)
## 
## [[4]]
## character(0)
## 
## [[5]]
## [1] "RAMP_G_000000095"
## 
## [[6]]
## character(0)
selected <- head(coverage$pathwayRampId[coverage$eligible], 2)
plots <- plotPathwaysSpatially(selected, spe, assay = "SPT", slot = "counts",
  pathway_index = pathway_index)
## Warning: 10 gene input(s) unresolved; inspect mapping status and
## candidate_gene_ids.
attr(plots, "pathway_coverage")
##        pathwayRampId sourceId type pathwayCategory
## 115 RAMP_P_000000115 map00500 kegg            kegg
## 173 RAMP_P_000000173 map00010 kegg            kegg
##                       pathwayName database_size database_raw_size measured_size
## 115 Starch and sucrose metabolism           102               105             8
## 173  Glycolysis / Gluconeogenesis           262               280             6
##     coverage_fraction used_size eligible database_members measured_members
## 115        0.07843137         8     TRUE     RAMP_G_0....     RAMP_G_0....
## 173        0.02290076         6     TRUE     RAMP_G_0....     RAMP_G_0....
##     used_members foreground_members excluded_conflict_records
## 115 RAMP_G_0....                                 RAMP_G_0....
## 173 RAMP_G_0....                                             
##     excluded_conflict_count
## 115                       2
## 173                       0
for (plot in plots) print(plot)

stopifnot(ncol(pathways) == ncol(spe), length(plots) == 2L)

The original assays, feature names, coordinates and paired modalities are preserved. A derived gene assay keeps its selected layer name: logcounts do not become counts. Different expression rows mapping to one gene error by default; choose duplicate_genes = "mean" or "sum" only after considering the measurement scale (summing log-expression is generally inappropriate). Identical repeated rows are deduplicated. Named pathway plots accept exact pathwayRampId values; ambiguous display names error instead of choosing the first match. Gene and pathway reference fingerprints are retained in outputs.

Fisher’s complete coverage table is attr(result, "pathway_coverage"); its per-row size columns also appear in the result. Pathway score objects put coverage in rowData and the complete audit in metadata. Named plots return coverage attributes and the exact plotted score vector. Unmeasured and conflict-only pathways stay in the complete audit even when no score is drawn.

sessionInfo()
## 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] SpaMTP_0.99.11   BiocStyle_2.41.0
## 
## loaded via a namespace (and not attached):
##   [1] splines_4.6.1               later_1.4.8                
##   [3] filelock_1.0.3              tibble_3.3.1               
##   [5] lifecycle_1.0.5             httr2_1.3.0                
##   [7] sf_1.1-3                    edgeR_4.99.7               
##   [9] globals_0.20.0              lattice_0.23-1             
##  [11] crosstalk_1.2.2             magrittr_2.0.5             
##  [13] SpaMTPdb_0.99.4             limma_3.99.2               
##  [15] plotly_4.12.1               sass_0.4.10                
##  [17] rmarkdown_2.32              jquerylib_0.1.4            
##  [19] yaml_2.3.12                 metapod_1.21.0             
##  [21] httpuv_1.6.17               otel_0.2.0                 
##  [23] cowplot_1.2.0               DBI_1.3.0                  
##  [25] buildtools_1.0.0            RColorBrewer_1.1-3         
##  [27] abind_1.4-8                 GenomicRanges_1.65.4       
##  [29] purrr_1.2.2                 BiocGenerics_0.59.12       
##  [31] rappdirs_0.3.4              SpaMTPData_0.99.5          
##  [33] IRanges_2.47.5              S4Vectors_0.51.10          
##  [35] ggrepel_0.9.8               irlba_2.4.1                
##  [37] listenv_1.1.0               maketools_1.3.2            
##  [39] pheatmap_1.0.13             units_1.0-1                
##  [41] RSpectra_0.16-2             matter_2.15.0              
##  [43] dqrng_0.4.1                 parallelly_1.48.0          
##  [45] codetools_0.2-20            DelayedArray_0.39.8        
##  [47] scuttle_1.23.2              tidyselect_1.2.1           
##  [49] farver_2.1.2                ScaledMatrix_1.21.0        
##  [51] viridis_0.6.5               matrixStats_1.5.0          
##  [53] stats4_4.6.1                BiocFileCache_3.3.0        
##  [55] Seqinfo_1.3.2               jsonlite_2.0.0             
##  [57] CardinalIO_1.11.0           BiocNeighbors_2.7.3        
##  [59] e1071_1.7-17                scater_1.41.2              
##  [61] tools_4.6.1                 Rcpp_1.1.2                 
##  [63] glue_1.8.1                  gridExtra_2.3.1            
##  [65] SparseArray_1.13.4          BiocBaseUtils_1.15.1       
##  [67] xfun_0.61                   MatrixGenerics_1.25.0      
##  [69] dplyr_1.2.1                 withr_3.0.3                
##  [71] BiocManager_1.30.27         fastmap_1.2.0              
##  [73] bluster_1.23.1              digest_0.6.39              
##  [75] rsvd_1.0.5                  R6_2.6.1                   
##  [77] mime_0.13                   RSQLite_3.53.3             
##  [79] tidyr_1.3.2                 generics_0.1.4             
##  [81] data.table_1.18.6.1         FNN_1.1.4.1                
##  [83] class_7.3-24                httr_1.4.9                 
##  [85] htmlwidgets_1.6.4           S4Arrays_1.13.2            
##  [87] ontologyIndex_2.12          pkgconfig_2.0.3            
##  [89] gtable_0.3.6                blob_1.3.0                 
##  [91] S7_0.2.2                    SingleCellExperiment_1.35.2
##  [93] XVector_0.53.0              sys_3.4.3                  
##  [95] htmltools_0.5.9             fgsea_1.39.2               
##  [97] ProtGenerics_1.45.0         scales_1.4.0               
##  [99] Biobase_2.73.2              png_0.1-9                  
## [101] SpatialExperiment_1.23.0    scran_1.41.1               
## [103] knitr_1.52                  rjson_0.2.23               
## [105] nlme_3.1-171                curl_8.0.0                 
## [107] proxy_0.4-29                cachem_1.1.0               
## [109] stringr_1.6.0               Cardinal_3.15.0            
## [111] BiocVersion_3.24.0          KernSmooth_2.23-27         
## [113] parallel_4.6.1              vipor_0.4.7                
## [115] AnnotationDbi_1.75.2        pillar_1.11.1              
## [117] grid_4.6.1                  vctrs_0.7.3                
## [119] promises_1.5.0              BiocSingular_1.29.2        
## [121] dbplyr_2.6.0                beachmat_2.29.3            
## [123] xtable_1.8-8                cluster_2.1.8.3            
## [125] beeswarm_0.4.0              evaluate_1.0.5             
## [127] magick_2.9.1                cli_3.6.6                  
## [129] locfit_1.5-9.12             compiler_4.6.1             
## [131] rlang_1.3.0                 crayon_1.5.3               
## [133] future.apply_1.20.2         labeling_0.4.3             
## [135] mclust_6.1.3                classInt_0.4-11            
## [137] ggbeeswarm_0.7.3            stringi_1.8.9              
## [139] viridisLite_0.4.3           BiocParallel_1.47.0        
## [141] Biostrings_2.81.9           Matrix_1.7-6               
## [143] ExperimentHub_3.3.2         bit64_4.8.6                
## [145] future_1.76.0               ggplot2_4.0.3              
## [147] KEGGREST_1.53.6             statmod_1.5.2              
## [149] shiny_1.14.0                SummarizedExperiment_1.43.0
## [151] AnnotationHub_4.3.2         igraph_2.3.4               
## [153] memoise_2.0.1               bslib_0.12.0               
## [155] fastmatch_1.1-8             bit_4.6.0