Contents

1 Introduction

Geneset Ordinal Association Test Enrichment Analysis (GOATEA) provides a Shiny interface with interactive visualizations and utility functions for performing and exploring automated gene set enrichment analysis using the ‘goat’ package.

GOATEA is designed to support large-scale and user-friendly enrichment workflows across multiple gene lists and comparisons, with flexible plotting and output options. Visualizations pre-enrichment include interactive Volcano and UpSet (overlap) plots. Visualizations post-enrichment include interactive geneset split term dotplot, geneset hierarchical clustering treeplot, multi-genelist gene-effectsize heatmap, enrichment overview gene-geneset heatmap and bottom-up pathway-like STRING database of protein-protein-interactions network graph.

1.1 Why use goatea?

Some enrichment visualization packages are included in Bioconductor, for instance: enrichplot, vissE, CBNplot. goatea additionally provides interactive visualizations through an intuitive and customizable Shiny user interface and allows for multi-genelist comparisons. No bioinformatic expertise is needed. goatea includes commonly used visualizations and adds a novel enrichment overview heatmap and offers a bottom-up pathway-like protein-protein interaction graph with network statistics.

A number of enrichment analysis packages are already on Bioconductor: clusterProfiler, fgsea, DOSE and many more. In goatea, goat is implemented. goat is a novel method for efficient geneset enrichment analysis. It performs within seconds and results in more identified significant terms compared to other methods, see the reference. For researchers with coding expertise, goatea provides an automated analysis workflow for performing enrichment analysis with goat and obtaining overview tables and output figures to explore your data.

1.2 How goatea works

Genelists are often obtained from transcriptomic and/or proteomic experiments. These genelist tables have to contain a ‘gene’ column with NCBI Entrez gene identifiers, a ‘symbol’ column with gene aliases (optional: can be mapped from their gene IDs), and ‘effectsize’ and ‘pvalue’ columns with measurement outcomes for a performed comparison. User defined thresholds for effect size and p-values are used to define gene significance. To get a first look and understanding of your genelist data, a volcano plot is provided. For multi-genelist data a UpSet (overlap) plot can additionally be generated to visualize significant genes between comparisons.

Genesets can be obtained by downloading Gene Ontology organism specific genesets within goatea or from .gmt files, downloaded for instance from the Molecular Signatures Database. Genelist genes and genesets will be filtered and matched, then goat or an older version of gene set enrichment analysis can be performed. Extensive filtering options help you to explore only the terms and genes within your vision.

Post-enrichment visualizations help to identify genes and terms of interest or relevance for your experimental design. Identified and selected genes of interest are then used to specifically visualize your data by zooming in on specific biological or technical aspects.

The steps above can be automated, an example workflow is described in the rest of this vignette.

As intended for interactive and intuitive usage, run the goatea Shiny interface.

2 Running goatea: Shiny application

Simply install the package and its dependencies, then run the script below.

library(goatea)

## customizable coloring
css_colors <- list(
  main_bg = "#222222",
  darker_bg = "#111111",
  focus = "#32CD32", 
  hover = "#228B22",
  border = "#555555",
  text = "#FFFFFF"
)

## run the goatea Shiny application
shiny::shinyApp(
  ui = goatea:::goatea_ui,
  server = function(input, output, session) {
    goatea:::goatea_server(
      input, output, session, 
      css_colors = css_colors)
  }
)

3 Running goatea: automated analyses

3.1 Installation

goatea is available through Github, I intend for goatea to become available through Bioconductor.

## GOATEA installation requires the latest version of R and Rtools 
## Rtools is needed for package compilation, to download and install visit: 
# R: https://cran.r-project.org/mirrors.html
# Rtools: https://cran.r-project.org/bin/windows/Rtools/

# For the GOATEA development version use: 
if ( ! require("pak", quietly = TRUE)) install.packages('pak')
pak::pkg_install('mauritsunkel/goatea', dependencies = TRUE, upgrade = TRUE)

## When GOATEA is on Bioconductor use: 
# pak::pkg_install('goatea', dependencies = TRUE, upgrade = TRUE)

## goatea organism (taxid) genome wide annotation packages (org.Xx.eg.dg)
## goatea requires at least one of the following available organism packages:
# Human (9606)--------: org.Hs.eg.db
# Mouse (10090)-------: org.Mm.eg.db
# Fruit Fly (7227)----: org.Dm.eg.db
# Rhesus monkey (9544): org.Mmu.eg.db
# Rat (10116)---------: org.Rn.eg.db
# Worm (6239)---------: org.Ce.eg.db
# Chimpanzee (9598)---: org.Pt.eg.db
# Zebrafish (7955)----: org.Dr.eg.db
if ( ! require("pak", quietly = TRUE)) install.packages('pak')
pak::pkg_install(c(
  "org.Hs.eg.db", 
  "org.Mm.eg.db", 
  "org.Dm.eg.db", 
  "org.Mmu.eg.db", 
  "org.Rn.eg.db", 
  "org.Ce.eg.db", 
  "org.Pt.eg.db", 
  "org.Dr.eg.db"
))

## Optional: add gene descriptions to exported tables, install annotables:
# available only for: human, mouse, rat, worm, fruit fly, Rhesus Monkey
if ( ! require("pak", quietly = TRUE)) install.packages('pak')
pak::pkg_install('stephenturner/remotes')

3.2 Initialization

# load goatea package library
library(goatea)

Set parameter values used throughout goatea.

# set chosen organism taxid (for genome wide annotation package: org.Hs.eg.db)
taxid <- 9606 # Human (Homo Sapiens)

# set and create output folder
outdir <- tempdir()
dir.create(outdir, recursive = TRUE)
#> Warning in dir.create(outdir, recursive = TRUE):
#> 'C:\Users\Home\AppData\Local\Temp\Rtmpu26CvT' already exists

# set significance thresholds
p_value_threshold <- 0.05
absolute_effectsize_threshold <- 1

3.3 Loading genelists

Transcriptomic and/or proteomic experiments often end up in comparing groups through differential gene expression or something similar. There, lists of genes with measurement weights and statistical probability values are obtained. Genelists have to be in .csv/.tsv/.xlsx format. Genelist tables contain a ‘gene’ column with NCBI Entrez gene identifiers, a ‘symbol’ column with gene aliases (optional: can be mapped from their gene IDs), and ‘effectsize’ and ‘pvalue’ columns with measurement outcomes for a performed comparison. Here, goat manuscript example data will be used, and expected use through uploading your own file is shown.

# GOAT paper data: download to a specific folder, tempdir() by default
data <- goat::download_goat_manuscript_data(output_dir = outdir)
#> downloading https://github.com/ftwkoopmans/goat/raw/main/analyses/goat_manuscript_datasets.rda ...
#> downloaded data was stored at: C:\Users\Home\AppData\Local\Temp\Rtmpu26CvT/goat_manuscript_datasets.rda
# We select datasets from Colameo 2021 for our automated workflow.
# Thi is RNA-seq with matched mass-spectrometry data. 
# Rat data is mapped to HUman NCBI Entrez gene identifies with the goat package.
genelists <- list(
  rna = data$`Colameo 2021:RNA-seq:PMID34396684`,
  ms = data$`Colameo 2021:mass-spec:PMID34396684`
)
head(genelists[['rna']])
#> # A tibble: 6 × 10
#>   symbol log2fc effectsize    pvalue pvalue_adjust hgnc_id hgnc_symbol entrez_id
#>   <chr>   <dbl>      <dbl>     <dbl>         <dbl> <chr>   <chr>           <int>
#> 1 TP53I…   3.03       3.03 1.75e-106     2.50e-102 HGNC:1… TP53INP2        58476
#> 2 RAB13    3.12       3.12 9.13e- 87     2.39e- 83 HGNC:9… RAB13            5872
#> 3 B2M      2.85       2.85 1.00e- 86     2.39e- 83 HGNC:9… B2M               567
#> 4 METRN    2.55       2.55 4.12e- 86     8.43e- 83 HGNC:1… METRN           79006
#> 5 WASF3    2.70       2.70 1.37e- 79     2.19e- 76 HGNC:1… WASF3           10810
#> 6 NDRG2    2.81       2.81 7.30e- 79     1.04e- 75 HGNC:1… NDRG2           57447
#> # ℹ 2 more variables: gene <int>, signif <lgl>

To load your own data follow this alternative example.

# set the filepath to your own data files 
file <- system.file('extdata','example_genelist.csv', package = 'goatea')
# Check file formatting, see function documentation for additional parameters 
genelist <- goatea::read_validate_genelist(file = file)
#> Checking file format...
# genelists <- list(
  # csv = genelist
# )
head(genelist)
#> # A tibble: 6 × 5
#>   symbol   gene pvalue effectsize signif
#>   <chr>   <int>  <dbl>      <dbl> <lgl> 
#> 1 gene_45 11023 0.123         5   FALSE 
#> 2 gene_12 12763 0.435         5   FALSE 
#> 3 gene_34 16847 0.435         5   FALSE 
#> 4 gene_83 12069 0.0148       -4.9 TRUE  
#> 5 gene_14 17454 0.0151        4.8 TRUE  
#> 6 gene_96 12308 0.375         4.8 FALSE

3.4 Loading genesets

Genesets are terms of biological aspects associated with a set of genes. The Gene Ontology (GO) and Molecular Signatures databases (MSigDB) are commonly used repositories containing organism specific genesets. goat provides GO genesets for download, also to supply a .gmt file containing genesets downloaded from MSigDB for instance.

genesets <- goat::load_genesets_go_bioconductor(taxid = taxid)
#> 
#> load_genesets_go_bioconductor(): data version = org.Hs.eg.db - Homo sapiens - 2025-02-06

## optionally: save and load from .rda to speed up after downloading
# save(genesets, file = file.path(outdir, 'genesets.rda'))
# load(file.path(outdir, 'genesets.rda')) # loading .rda to variable: genesets

## alternatively: load via .gmt file (downloaded from e.g.: MSigDB)
# then use: goat::load_genesets_gmtfile()

head(genesets)
#> # A tibble: 6 × 7
#>   source source_version                       id    name  parent_id genes ngenes
#>   <chr>  <chr>                                <chr> <chr> <list<ch> <lis>  <int>
#> 1 GO_BP  org.Hs.eg.db - Homo sapiens - 2025-… GO:0… mito…       [1]  [30]     30
#> 2 GO_MF  org.Hs.eg.db - Homo sapiens - 2025-… GO:0… alph…       [1]   [3]      3
#> 3 GO_BP  org.Hs.eg.db - Homo sapiens - 2025-… GO:0… sing…       [1]  [14]     14
#> 4 GO_MF  org.Hs.eg.db - Homo sapiens - 2025-… GO:0… sing…       [1]  [11]     11
#> 5 GO_CC  org.Hs.eg.db - Homo sapiens - 2025-… GO:0… phos…       [2]   [4]      4
#> 6 GO_MF  org.Hs.eg.db - Homo sapiens - 2025-… GO:0… lact…       [1]   [1]      1

3.5 GOAT Enrichment Analysis

Gene significance is set per genelist by the user-defined thresholds. The genelist is then ordered by effect size. For this example, if there are more genes than the amount of precomputed nulldistributions goat uses for its enrichment testing the amount of genes is limited to that amount. If you do want to use all genes, set the method to ‘goat_bootstrap’.

Genelist genes and genesets will be filtered and matched, then goat or an older version of gene set enrichment analysis can be performed. Too small or too large genesets can be irrelevant or mess up testing statistics, leaving parameter values to defaults is a good starting point.

Geneset enrichment with goat is by default performed on ‘effectsize’. The user can also go for ‘pvalue’ or a specific direction by gene effectsize sign or absolute values. Besides the goat method, older methods are also implemented to enable easy comparison.

filtered_genesets_list <- list()
enrichment_results <- list()
for (name in names(genelists)) {
  genelist <- genelists[[name]]
  ## set signif column by given p-value- and effectsize significance thresholds
  genelist$signif <- genelist$pvalue <= p_value_threshold & 
                     abs(genelist$effectsize) >= absolute_effectsize_threshold
  # order genelist by effectsize 
  genelist <- genelist[order(abs(genelist$effectsize), decreasing = TRUE),]
  ## keep max n genes for regular goat method
  # optionally: remove this line and use goat_bootstrap method 
  if (nrow(genelist) > max(goat::goat_nulldistributions$N)) {
    genelist <- genelist[1:max(goat::goat_nulldistributions$N),]
  }
  # update genelist
  genelists[[name]] <- genelist
  
  ## filter genesets 
  filtered_genesets <- goat::filter_genesets(
    genesets = genesets,
    genelist = genelist,
    min_overlap = 10L,
    max_overlap = NA,
    max_overlap_fraction = 0.5,
    min_signif = NA,
    max_size = NA,
    dedupe = FALSE
  )
  filtered_genesets_list[[name]] <- filtered_genesets

  ## run enrichment 
  enrichment_results[[name]] <- goatea::run_geneset_enrichment(
    genesets = filtered_genesets,
    genelist = genelist,
    method = "goat",
    score_type = "effectsize",
    padj_method = "BH",
    padj_sources = TRUE,
    padj_cutoff = p_value_threshold,
    padj_min_signifgenes = 0L
  )
}
head(enrichment_results[[1]])
#> # A tibble: 6 × 17
#>   source source_version  id    name  parent_id ngenes_input ngenes ngenes_signif
#>   <chr>  <chr>           <chr> <chr> <list<ch>        <int>  <int>         <int>
#> 1 GO_CC  org.Hs.eg.db -… GO:0… cyto…       [2]          118     97            76
#> 2 GO_CC  org.Hs.eg.db -… GO:0… cyto…       [2]         5530   4335           687
#> 3 GO_BP  org.Hs.eg.db -… GO:0… cyto…       [1]          169    147            83
#> 4 GO_MF  org.Hs.eg.db -… GO:0… tran…       [1]         1320    394           105
#> 5 GO_MF  org.Hs.eg.db -… GO:0… stru…       [1]          175    144            78
#> 6 GO_MF  org.Hs.eg.db -… GO:0… sign…       [1]         1554    518           123
#> # ℹ 9 more variables: genes <list<int>>, genes_signif <list>, score_type <chr>,
#> #   pvalue <dbl>, zscore <dbl>, pvalue_adjust <dbl>, signif <lgl>,
#> #   score_oddsratio <dbl>, symbol <list>

3.6 Genes overview table

Here, the genelists are formatted into a gene-based overview table. If there are multiple genelists, for all genelists, each gene and their p-values, effect sizes, effect size percentages, gene set ratios and overlapping significant genes will be shown.

genes_overview <- goatea::run_genelists_overlap(genelists)
genes_overview <- goatea::calculate_geneSetRatio(
  enrichment_results, 
  genes_overview
)
head(genes_overview)
#> # A tibble: 6 × 11
#>     gene symbol   rna_efsi rna_pval ms_efsi ms_pval rna_perc ms_perc
#>    <int> <chr>       <dbl>    <dbl>   <dbl>   <dbl>    <dbl>   <dbl>
#> 1   3036 HAS1        -6.74 3.94e- 6      NA      NA    -99.1      NA
#> 2  80736 SLC44A4     -4.39 2.22e- 5      NA      NA    -95.2      NA
#> 3   4509 MT-ATP8      3.91 4.90e-37      NA      NA   1399.       NA
#> 4 284613 CYB561D1    -3.81 2.67e- 5      NA      NA    -92.9      NA
#> 5   5730 PTGDS       -3.62 9.69e- 3      NA      NA    -91.9      NA
#> 6   2830 GPR6        -3.41 2.85e- 6      NA      NA    -90.6      NA
#> # ℹ 3 more variables: genelist_overlap <chr>, rna_geneSetRatio <dbl>,
#> #   ms_geneSetRatio <dbl>

3.7 Enrichment searching and filtering

You can filter enrichment by querying the term names and by thresholding the numerical features. In this way you can explore relevant biological aspects and/or filter out technicalities. After filtering, use the filtered enrichment as input with the visualizations for zooming in on specific terms and their genes and interactions.

filtered_enrichment <- goatea::filter_enrichment(
  df = enrichment_results[[1]],
  terms_query = c("synapse", "synaptic"), 
  terms_antiquery = c("asymmetric"),
  min_ngenes = 100, 
  min_ngenes_signif = 10
)
head(filtered_enrichment$name)
#> [1] "synaptic membrane"                   
#> [2] "postsynaptic membrane"               
#> [3] "postsynaptic density"                
#> [4] "postsynaptic specialization membrane"
#> [5] "postsynaptic specialization"         
#> [6] "trans-synaptic signaling"

3.8 Gene selection

In the goatea app, the visualizations are used to select specific genes to pass to next visualizations in order to zoom in on specific terms or groups of genes. Here we simply take the significant genes of the first filtered enrichment to show some visualizations that use gene selections.

selected_genes <- filtered_enrichment$genes_signif[[1]]

4 Plotting

4.1 Genelist plotting

4.1.1 Volcano plot

A Volcano plot is commonly used to have a visual representation of the genelist. It shows an overview of genes as points with effectsize vs p-value and significance thresholds.

goatea::plot_EnhancedVolcano(
  genelist = genelists[[1]],
  effectsize_threshold = absolute_effectsize_threshold,
  pvalue_threshold = p_value_threshold,
  background_color = 'white',
  foreground_color = 'black'
)
#> Coordinate system already present. Adding new coordinate system, which will
#> replace the existing one.
#> Scale for x is already present.
#> Adding another scale for x, which will replace the existing scale.
#> Warning: ggrepel: 2228 unlabeled data points (too many overlaps). Consider
#> increasing max.overlaps

4.1.2 UpSet overlap plot

If multiple genelists are loaded, their overlap of significant genes is shown through an UpSet plot. These show the total number of genes in a genelist and the number of overlapping significant genes for each intersection.

if (length(genelists) > 2) {
  goatea::plot_genelists_overlap_upsetjs(
    genelists = genelists, 
    mode = 'distinct'
  )
}

4.2 Post-enrichment plotting

4.2.1 Tree plot

The tree plot shows a clustered hierarchical split between terms based on their term similarity. Similarity is based on semantics of the term. Terms are clustered together by semantics, meaning words that look or mean alike. A summary of the clustered semantics is given to the right of the vertical lines for each cluster.

# filter to keep a single geneset source
single_source_enrichment <- enrichment_results[[1]] %>% 
  dplyr::filter(source == enrichment_results[[1]]$source[1])
goatea::plot_termtree(
  single_source_enrichment, 
  Nterms = 20, 
  Nwords = 5, 
  Nclusters = 3
)

4.2.2 Term-split dotplot

The dotplot shows terms split by up- and down regulation. The regulation is defined by the sign of the effect sizes of the genes in the genelists. The gene ratio shows the percentage of genes of the term that were matched with the genes of the genelist.

# filter to keep a single geneset source
single_source_enrichment <- enrichment_results[[1]] %>% 
  dplyr::filter(source == enrichment_results[[1]]$source[1])
goatea::plot_splitdot(single_source_enrichment, topN = 20)

4.2.3 Gene-genelist heatmap

This heatmap shows the selected genes for each genelist to compare their effect sizes and p-values as a simple overview.

selected_symbols <- filtered_enrichment$symbol[[1]][
  filtered_enrichment$genes[[1]] %in% filtered_enrichment$genes_signif[[1]]
][1:15]
p <- goatea::plot_gene_effectsize_ComplexHeatmap(
  genes = selected_symbols, 
  genes_overview = genes_overview
)

4.2.4 Gene-term heatmap

This heatmap serves as an overview of the enrichment result, combined with all genelists information. Use the search functionality and pass the resulting filtered enrichment to zoom in on relevant biological aspects and focus on filtered aspects of the enrichment for exploration. In the goatea app this heatmap is also used to select genes/terms from identified aspects of interest.

p <- goatea::plot_ComplexHeatmap(
  enrichment_result = enrichment_results[[1]],
  genelist = genelists[[1]],
  n_cluster = 5,
  n_top_terms = 20,
  n_top_genes = 50,
  genelist_overlap = genes_overview
)
#> Following `at` are removed: NA, because no color was defined for them.
#> Following `at` are removed: NA, because no color was defined for them.
#> Following `at` are removed: NA, because no color was defined for them.

4.2.5 Protein-protein interaction network

Gene sets miss information of gene-gene interactions, this visualization can offer bottom-up relationships between genes to gain insight. The STRING database is used to obtain protein-protein interaction data by efficient streaming. For the selected genes of interest, an igraph network is built in the background in order to obtain network statistics. The igraph is passed to visNetwork for (in Shiny app) interactive visualization and exploration of the network.

I advise to regard this output as a basic and toy visualization, the goatea in Shiny app version contains node and edge hover information of all network statistics. Edges can be clicked to view their interaction scores and information on the STRING website. Nodes are clustered by STRING interaction scores. The nodes and edges can be colored by each statistical feature. Nodes can be filtered by each feature and made into a subnetwork for more detailed exploration.

# selecting 10 symbols of the searchad and significant first enriched term
selected_symbols <- filtered_enrichment$symbol[[1]][
  filtered_enrichment$genes[[1]] %in% filtered_enrichment$genes_signif[[1]]
][1:10]

## this will download the STRING database protein-protein interaction data 
## to your selected folder 
# downloading should only take a couple of seconds
# downlaod happens only if the files are not found in the specified folder
# if the download does not work, double check if the STRING database is online
ppi_data <- goatea::get_string_ppi(
  aliases = selected_symbols, 
  organism = taxid, 
  folder = file.path(outdir)
)
# creating igraph in order to do network statistics
ppi_graph <- goatea::get_ppigraph(ppi_data = ppi_data)
# converting igraph to visnetwork for (Shiny app) interactive visualization
vis_network <- goatea::get_visNetwork(
  ppigraph = ppi_graph, 
  genes_overview = genes_overview
)
#> Warning in min(genes_overview[[paste0(sample_name, "_efsi")]], na.rm = TRUE):
#> no non-missing arguments to min; returning Inf
#> Warning in max(genes_overview[[paste0(sample_name, "_efsi")]], na.rm = TRUE):
#> no non-missing arguments to max; returning -Inf
## showing a basic version of the visNetwork
## the goatea Shiny app version has full interactive capability 
visNetwork::visNetwork(
  vis_network$nodes, 
  vis_network$edges, 
  width = "100%", 
  height = "100%") %>% 
  visNetwork::visPhysics(stabilization = FALSE)

5 Information

A thank you for your time and effort in using goatea, I hope it may aid you in exploring your data!

5.1 Contact

goatea was developed by Maurits Unkel at the Erasmus Medical Center in the department of Psychiatry. Source code is available through GitHub: https://github.com/mauritsunkel/goatea Questions regarding goatea can be sent to:

5.2 License

goatea is licensed under Apache 2.0.

5.3 Issues and contributions

For issues and contributions, please find the goatea Github page: https://github.com/mauritsunkel/goatea/issues

5.4 GOAT reference

Koopmans, F. GOAT: efficient and robust identification of gene set enrichment. Commun Biol 7, 744 (2024). https://doi.org/10.1038/s42003-024-06454-5

5.5 Session info

sessionInfo()
#> R version 4.5.0 (2025-04-11 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 11 x64 (build 26100)
#> 
#> Matrix products: default
#>   LAPACK version 3.12.1
#> 
#> locale:
#> [1] LC_COLLATE=English_United States.utf8 
#> [2] LC_CTYPE=English_United States.utf8   
#> [3] LC_MONETARY=English_United States.utf8
#> [4] LC_NUMERIC=C                          
#> [5] LC_TIME=English_United States.utf8    
#> 
#> time zone: Europe/Amsterdam
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] goatea_0.99.5    dplyr_1.1.4      BiocStyle_2.37.0
#> 
#> loaded via a namespace (and not attached):
#>   [1] RColorBrewer_1.1-3               rstudioapi_0.17.1               
#>   [3] jsonlite_2.0.0                   shape_1.4.6.1                   
#>   [5] magrittr_2.0.3                   magick_2.8.6                    
#>   [7] shinyjqui_0.4.1                  ggtangle_0.0.6                  
#>   [9] farver_2.1.2                     rmarkdown_2.29                  
#>  [11] GlobalOptions_0.1.2              fs_1.6.6                        
#>  [13] vctrs_0.6.5                      memoise_2.0.1                   
#>  [15] ggtree_3.17.0                    tinytex_0.57                    
#>  [17] htmltools_0.5.8.1                gridGraphics_0.5-1              
#>  [19] sass_0.4.10                      bslib_0.9.0                     
#>  [21] htmlwidgets_1.6.4                fontawesome_0.5.3               
#>  [23] plyr_1.8.9                       plotly_4.10.4                   
#>  [25] cachem_1.1.0                     igraph_2.1.4                    
#>  [27] mime_0.13                        lifecycle_1.0.4                 
#>  [29] iterators_1.0.14                 pkgconfig_2.0.3                 
#>  [31] Matrix_1.7-3                     R6_2.6.1                        
#>  [33] InteractiveComplexHeatmap_1.17.0 fastmap_1.2.0                   
#>  [35] shiny_1.10.0                     clue_0.3-66                     
#>  [37] digest_0.6.37                    aplot_0.2.5                     
#>  [39] enrichplot_1.29.1                ggnewscale_0.5.1                
#>  [41] colorspace_2.1-1                 patchwork_1.3.0                 
#>  [43] AnnotationDbi_1.71.0             S4Vectors_0.47.0                
#>  [45] textshaping_1.0.1                RSQLite_2.3.11                  
#>  [47] org.Hs.eg.db_3.21.0              labeling_0.4.3                  
#>  [49] httr_1.4.7                       compiler_4.5.0                  
#>  [51] withr_3.0.2                      bit64_4.6.0-1                   
#>  [53] doParallel_1.0.17                BiocParallel_1.43.0             
#>  [55] DBI_1.2.3                        R.utils_2.13.0                  
#>  [57] rjson_0.2.23                     tools_4.5.0                     
#>  [59] ape_5.8-1                        zip_2.3.2                       
#>  [61] httpuv_1.6.16                    R.oo_1.27.1                     
#>  [63] glue_1.8.0                       nlme_3.1-168                    
#>  [65] GOSemSim_2.35.0                  promises_1.3.2                  
#>  [67] grid_4.5.0                       cluster_2.1.8.1                 
#>  [69] reshape2_1.4.4                   fgsea_1.35.0                    
#>  [71] generics_0.1.3                   gtable_0.3.6                    
#>  [73] R.methodsS3_1.8.2                tidyr_1.3.1                     
#>  [75] ggVennDiagram_1.5.2              data.table_1.17.0               
#>  [77] utf8_1.2.5                       xml2_1.3.8                      
#>  [79] XVector_0.49.0                   BiocGenerics_0.55.0             
#>  [81] ggrepel_0.9.6                    foreach_1.5.2                   
#>  [83] pillar_1.10.2                    stringr_1.5.1                   
#>  [85] yulab.utils_0.2.0                later_1.4.2                     
#>  [87] circlize_0.4.16                  splines_4.5.0                   
#>  [89] treeio_1.33.0                    lattice_0.22-7                  
#>  [91] bit_4.6.0                        tidyselect_1.2.1                
#>  [93] GO.db_3.21.0                     ComplexHeatmap_2.24.0           
#>  [95] Biostrings_2.77.0                knitr_1.50                      
#>  [97] bookdown_0.43                    IRanges_2.43.0                  
#>  [99] svglite_2.2.0                    shinydashboard_0.7.3            
#> [101] stats4_4.5.0                     xfun_0.52                       
#> [103] Biobase_2.69.0                   matrixStats_1.5.0               
#> [105] DT_0.33                          visNetwork_2.1.2                
#> [107] stringi_1.8.7                    UCSC.utils_1.5.0                
#> [109] lazyeval_0.2.2                   ggfun_0.1.8                     
#> [111] yaml_2.3.10                      kableExtra_1.4.0                
#> [113] evaluate_1.0.3                   codetools_0.2-20                
#> [115] tibble_3.2.1                     qvalue_2.41.0                   
#> [117] BiocManager_1.30.25              ggplotify_0.1.2                 
#> [119] cli_3.6.5                        arrow_19.0.1.1                  
#> [121] xtable_1.8-4                     systemfonts_1.2.3               
#> [123] jquerylib_0.1.4                  upsetjs_1.11.1                  
#> [125] EnhancedVolcano_1.27.0           Rcpp_1.0.14                     
#> [127] GenomeInfoDb_1.45.3              png_0.1-8                       
#> [129] parallel_4.5.0                   ggplot2_3.5.2                   
#> [131] assertthat_0.2.1                 blob_1.2.4                      
#> [133] DOSE_4.3.0                       goat_1.1.2                      
#> [135] viridisLite_0.4.2                tidytree_0.4.6                  
#> [137] scales_1.4.0                     openxlsx_4.2.8                  
#> [139] purrr_1.0.4                      crayon_1.5.3                    
#> [141] clisymbols_1.2.0                 GetoptLong_1.0.5                
#> [143] rlang_1.1.6                      cowplot_1.1.3                   
#> [145] fastmatch_1.1-6                  KEGGREST_1.49.0                 
#> [147] shinyjs_2.1.0