GSEAlens derives its name from Lens, symbolizing how this package acts as a magnifying glass to help researchers deeply explore key pathways in GSEA enrichment analysis.
GSEAlens provides a web-based interactive platform for displaying pathway introductions and descriptions, integrating AI-assisted pathway enrichment result export functionality. By encapsulating workflows and standardizing input formats, this R package simplifies the process of viewing and exploring GSEA enrichment analysis results.
GSEAlens is designed to plug into standard Bioconductor RNA-seq and functional enrichment workflows as a post-DEG exploration layer:
Upstream (input preparation): GSEAlens accepts
fitted model objects from limma (the
MArrayLM object returned by limma::eBayes(),
based on the edgeR +
limma-voom pipeline) or DESeqDataSet objects from DESeq2.
The expression matrix and sample metadata can be passed as SummarizedExperiment
objects, ensuring interoperability with the core Bioconductor data
containers.
Enrichment computation: Under the hood, GSEAlens
wraps clusterProfiler
(GSEA() function) and uses gene set collections from msigdbr. The
statistical framework therefore inherits the methodology of fgsea via
clusterProfiler.
Parallelization: GSEAlens uses future
(future::multisession) for multi-contrast parallel
computation. The user’s original future::plan() and
future.globals.maxSize option are saved before the parallel
run and restored on exit via on.exit(), so the global state
is never polluted. We anecdotally observed
future::multisession to be noticeably faster than BiocParallel
(SnowParam / PSOCK serialization) on Windows for this
package’s typical workload, which serializes large globals (the full DE
table plus the gene set dictionary and metadata dictionary). This is an
informal observation from development, not a formal benchmark; users are
free to re-run the analysis with BiocParallel if it better
suits their environment.
Visualization: Plotting builds on enrichplot, ComplexHeatmap, ggplot2, patchwork, and visNetwork, producing figures compatible with downstream publication pipelines.
Downstream: The “Generate R Code” feature in the Shiny application emits self-contained scripts that can be embedded in rmarkdown / Quarto reports or integrated into multi-step pipelines.
A typical end-to-end Bioconductor workflow is therefore:
RNA-seq counts
|
+--[edgeR + limma-voom]--> MArrayLM fit --+
| |
+--[DESeq2]--------------> DESeqDataSet --+
|
v
[setup_gsea_env]
|
v
[batch_calc_gsea]
|
v
Shiny app exploration
|
v
Reproducible R code export
This makes GSEAlens a natural complement to existing Bioconductor enrichment packages: where clusterProfiler, GSVA, gprofiler2, or ReactomePA focus on computing enrichment, GSEAlens focuses on interactive interpretation of the resulting pathway lists.
This section demonstrates a complete GSEAlens workflow using the
airway
dataset. Because GSEAlens does not perform DEG analysis
itself, we assume the input objects (fit,
dds_se, dds) have been prepared according to
standard limma /
DESeq2
workflows.
For detailed input preparation steps (limma-voom fitting, DESeq2
object construction, gene filtering), please see the supplementary
vignette vignette("GSEAlens-preprocessing").
For reproducibility in this main vignette, the three input objects
(fit, dds_se, dds) are prepared
following the preprocessing vignette. Because re-running
DESeq2::DESeq() and the limma-voom pipeline on every build
would make the vignette slow, we ship pre-computed
versions of those objects in inst/extdata/; the script that
regenerates them lives in
inst/scripts/make_preprocessed_inputs.R and follows the
preprocessing vignette exactly.
Note on the shipped dds_se: to stay
below the Bioconductor 5 MB extdata limit, the
preprocessed_dds_se.rds shipped here is a slimmed
DESeqDataSet produced by slim_dds_se() inside
make_preprocessed_inputs.R. The slimmed copy drops the
mu / H / cooks assay layers
(DESeq() fitting intermediates) and flattens rowRanges from
GRangesList to GRanges (one representative
range per gene). DESeq2::results() and every GSEAlens entry
point return bit-identical output on the slimmed vs. the full object. To
rebuild the full, untrimmed DESeqDataSet for teaching
DESeq2 itself, see the preprocessing vignette.
data(preprocessed_limma, package = "GSEAlens")
preproc_limma <- preprocessed_limma
fit <- preproc_limma$fit
gsea_limma_voom_data <- preproc_limma$gsea_limma_voom_data
data(preprocessed_dds_se, package = "GSEAlens")
dds_se <- preprocessed_dds_se
data(preprocessed_dds, package = "GSEAlens")
dds <- preprocessed_ddsTo prepare these objects from your own data, follow the supplementary preprocessing vignette:
Use the build_gsea_pathways function to construct a
pathway object for GSEA enrichment analysis. The real call downloads
multiple MSigDB collections and is slow on the Bioconductor build
machine, so it is shown commented out; instead we load a pre-computed
lightweight pathway object (Hallmark + KEGG_LEGACY, 236 pathways, see
inst/scripts/make_gsea_pathwaysets_toy.R for regeneration
instructions).
# Real call (slow on the Bioconductor build machine):
# gsea_pathwaysets <- build_gsea_pathways(
# species = "HS", auto_select = c("H", "C2:CP:REACTOME", "C5:GO:BP")
# )
# For the vignette we load a pre-computed lightweight pathway object instead:
data(gsea_pathwaysets_toy, package = "GSEAlens")
gsea_pathwaysets <- gsea_pathwaysets_toyThrough the setup_gsea_env function, assemble a
GSEAEnv object for computational analysis. Different
workflows use the same function with different data inputs. For the
limma-voom workflow, since the fit object does not contain
the original gene read counts, the filtered DGEList used to
generate the fit object must be additionally provided (here
gsea_limma_voom_data). The three supported backends are
assembled below.
# limma-voom workflow (needs the DGEList because fit alone lacks raw counts)
gseadata_limmavoom <- setup_gsea_env(fit = fit, pathway_obj = gsea_pathwaysets, expr_data = gsea_limma_voom_data)
# DESeq2 SummarizedExperiment workflow
gseadata_se <- setup_gsea_env(fit = dds_se, pathway_obj = gsea_pathwaysets)
# DESeq2 Count matrix workflow
gseadata_dds <- setup_gsea_env(fit = dds, pathway_obj = gsea_pathwaysets)All objects are processed using the batch_calc_gsea
function with no differences.
Parallel computing note: Adjust the workers option based
on your computer’s performance to set the number of cores for
computation. More contrasts recommend higher core settings for better
computational efficiency.
# Write vignette outputs to a temporary directory to avoid polluting the
# Bioconductor build machine's working directory.
out_dir <- tempdir()
# limma-voom workflow
gsea_res_limmavoom <- batch_calc_gsea(gseadata_limmavoom,
custom_series_name = "limmavoom_data",
output_dir = out_dir,
workers = 2,
force = TRUE)
# DESeq2 SummarizedExperiment workflow
gsea_res_se <- batch_calc_gsea(gseadata_se,
custom_series_name = "dds_se_data",
output_dir = out_dir,
workers = 2,
force = TRUE)
# DESeq2 Count matrix workflow
gsea_res_dds <- batch_calc_gsea(gseadata_dds,
custom_series_name = "dds_data",
output_dir = out_dir,
workers = 2,
force = TRUE)After running batch_calc_gsea, an RDS file (the “GSEA
Capsule”) is generated in the output directory. You can either read it
directly with readRDS or use
import_gsea_capsule, which automatically organizes related
files into the working directory of your .Rmd /
.R script and performs data inspection.
GSEAlens provides an interactive Shiny application for visual
exploration of GSEA results. The app is launched by passing a
GseaRes object (returned by batch_calc_gsea or
loaded via import_gsea_capsule) to
launch_gsea_app.
Launch the Shiny app by passing a GseaRes object
(returned by batch_calc_gsea or loaded via
import_gsea_capsule) to launch_gsea_app.
Optionally pass an addition_data data frame (or path to
.csv / .rds file) to merge pathway annotations
into the main table; if NULL, the app auto-detects
addition_data_gsealens.rds or
addition_data_gsealens.csv in the working directory.
The app uses a sidebar + main panel layout with
6 tabs. The sidebar (Data Preprocessing
module) provides global controls; the main panel hosts the six feature
tabs.
The default landing tab, combining two sub-modules:
Master Table (DT::datatable):
interactive table of all enriched pathways with sortable columns (NES,
pvalue, p.adjust, setSize) and checkbox selection. Selected rows are
pushed to other tabs.
Combined Pathway Plotting: aggregates multiple
selected pathways into a single composite figure (uses
patchwork under the hood). The export modal includes a
WYSIWYG Live Preview, PDF/PNG/SVG/TIFF output, and a “Copy R Code”
button via generate_combined_plot_code().
Click any pathway row to open the Pathway Detail Modal, which shows the full description, leading-edge genes, and an option to add the pathway to the plot queue.
Source: R/09_shiny_mod_table.R,
R/11_shiny_mod_modal.R,
R/12_shiny_mod_multi_plot.R.
Four synchronized panels:
Top-left: pathway selector (linked to Main Workspace selection)
Top-right: gene ranking table (ranked by
|stat|)
Bottom-left: volcano plot for the selected contrast
Bottom-right: expression boxplot for the selected gene
Selections are bidirectionally synchronized – clicking a gene in the table highlights it in the volcano; clicking a point in the volcano scrolls the table.
Source: R/10_shiny_mod_quadrant.R.
Network visualization of pathway-to-pathway relationships, where nodes are pathways and edges represent shared genes (Jaccard similarity). Two selection modes:
Single mode: explore one pathway and its neighbors
Batch mode: select multiple pathways from Main Workspace and visualize their interconnections Two sub-panels are provided under this tab:
DotPlot panel: horizontal dot plot where the X
axis is NES, dot color encodes significance (-log10(FDR) /
-log10(P-value) / |NES|, dot size encodes
gene-set magnitude. A data-driven size scale (no fixed limits, no
transform) is used so that dot sizes faithfully reflect the underlying
gene-set magnitude range. This mirrors the
ggplot2::scale_size_continuous(range=c(3,8)) convention
used by enrichplot::dotplot, where size limits are derived
from the data rather than imposed as a fixed domain.
Network panel: graph layout (Fruchterman-Reingold / Kamada-Kawai / Circle) with two user-selectable edge-width encodings:
Weight-based (default, emapplot
convention): edge width is linearly proportional to the Jaccard value,
faithfully reflecting the underlying similarity magnitude. Recommended
for publication.
Rank-based: edge width is assigned by Jaccard rank,
guaranteeing uniform visual spacing between edges regardless of absolute
weight. Useful for dense networks with low weight variance. Node size
reflects |NES|; node color reflects enrichment direction
(red = up in left group, blue = up in right group).
Export Center (both panels): clicking “Export Publication Plot” opens a
modal with width / height / DPI / format (PDF, PNG, SVG, TIFF)
controls and two actions: download a static
ggplot2-rendered image via ggsave (no external
dependencies such as kaleido/orca), or copy a fully reproducible R
script (generate_dotplot_code() /
generate_network_code()) to the clipboard. The static
figures are byte-for-byte identical to what the copied code would
produce.
Source: R/13_shiny_mod_pathway_relation.R, helper
R/utils_hubgene.R, code generators in
R/15_code_generator.R.
Identifies and visualizes hub genes (highly connected genes across
multiple enriched pathways) using a visNetwork interactive
plot. Adjustable parameters:
Physics simulation: toggle on/off, adjust force-directed parameters
Pathway node size encoding: three user-selectable modes
By gene-set size (setSize, default):
matches the enrichplot::cnetplot convention; pathway node
size is proportional to the number of genes in the set (sqrt-scaled).
Recommended for biological interpretation.
By significance (-log10(FDR)): emphasizes
the most statistically trustworthy pathways.
Fixed size: constant node size controlled by the slider
(legacy behavior). The slider value always acts as the
base size; the chosen encoding scales around it within
[0.6x, 1.4x] to keep visNetwork’s force-directed layout
stable (size variance beyond ~2.3x causes visible layout jitter).
Gene-node size is unaffected (always
base + degree * 3).
Network statistics: summary panel showing node count, edge count, density
Export Center: same modal pattern as Tab 3. The static reproduction uses
generate_hubgene_code() and renders pathway nodes as
diamonds and gene nodes as circles in a bipartite layout via
igraph + ggplot2 (no ggraph
dependency). The current size-encoding mode is preserved in the
generated script.
Source: R/16_shiny_mod_hubgene_vis.R, code generator in
R/15_code_generator.R.
Generates a structured prompt for an external LLM (e.g. GPT-4, Claude) to interpret the selected pathways. Supports custom templates so users can enforce a particular output format (e.g. “produce a 3-paragraph biological interpretation citing leading-edge genes”). The generated prompt can be copied to clipboard.
Source: R/17_shiny_mod_AI.R.
Note: This tab only generates prompts; it does not call external APIs directly. The author explicitly designed this to keep API keys and network calls under user control.
Aggregates enrichment running-score curves for multiple selected
pathways into a single composite canvas. The image export modal includes
a WYSIWYG Live Preview, PDF/PNG/SVG/TIFF output, adjustable canvas
margins, and a “Copy R Code” button that generates a self-contained R
script via generate_joint_canvas_code() for reproduction
outside the Shiny environment.
Source: R/14_shiny_mod_joint_canvas.R, code generator
R/15_code_generator.R.
A practical interpretation guide:
| Visualization | What to look for | Biological meaning |
|---|---|---|
| NES (Normalized Enrichment Score) | Sign and magnitude | Positive NES -> pathway up-regulated in the right-hand group of the contrast |
| p.adjust | < 0.05 threshold | Statistical significance after BH correction |
| Volcano (Tab 2) | Symmetry / asymmetry | Balanced volcano suggests global shift; skewed suggests targeted regulation |
| Pathway network (Tab 3) | Cluster structure | Tightly connected clusters indicate co-regulated biological modules |
| HubGene (Tab 4) | High-degree genes | Hub genes are candidate biomarkers or regulatory nodes |
| Joint Canvas (Tab 6) | Curve overlap | Overlapping running-score curves suggest coordinated regulation |
Tabs 1 (Combined Pathway Plotting), 2, 3, 4, and 6 include a “Copy R Code” button integrated directly into each module’s image export modal, producing a self-contained R script reproducing the current visualization. This is the recommended way to generate publication-quality figures: iteratively refine the plot in the Shiny app, then export the code for final customization.
The GseaEnv object returned by the
setup_gsea_env function contains the following
components:
| Component | Description |
|---|---|
backend_info |
Backend type information (limma-voom or DESeq2) |
contrast_registry |
Contrast registry containing all pairwise comparison information |
de_store |
Differential expression analysis results storage |
expr_bundle |
Expression data bundle (raw counts, normalized matrix, sample metadata) |
geneset |
Geneset information (TERM2GENE, metadata dictionary, species) |
The GseaRes object returned by the
batch_calc_gsea function contains the following
components:
| Component | Description |
|---|---|
metadata |
Computation metadata (runtime, cores used, parameter settings) |
backend_info |
Backend type information |
contrast_registry |
Contrast registry |
de_store |
Differential expression analysis results storage |
expr_bundle |
Expression data bundle |
geneset_info |
Geneset information |
results |
GSEA results list, one entry per contrast |
The GseaTask object returned by the
extract_gsea_task function is used for single-contrast
analysis:
| Component | Description |
|---|---|
gsea_res |
GSEA result object |
meta |
Metadata (contrast information, geneset name, expression data) |
## R version 4.6.1 (2026-06-24)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 26.04 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] stats4 stats graphics grDevices utils datasets methods
## [8] base
##
## other attached packages:
## [1] GSEAlens_0.99.35 DESeq2_1.53.2
## [3] edgeR_4.11.6 limma_3.69.4
## [5] airway_1.33.2 SummarizedExperiment_1.43.0
## [7] Biobase_2.73.2 GenomicRanges_1.65.1
## [9] Seqinfo_1.3.0 IRanges_2.47.2
## [11] S4Vectors_0.51.6 BiocGenerics_0.59.12
## [13] generics_0.1.4 MatrixGenerics_1.25.0
## [15] matrixStats_1.5.0 BiocStyle_2.41.0
##
## loaded via a namespace (and not attached):
## [1] later_1.4.8 splines_4.6.1 ggplotify_0.1.3
## [4] tibble_3.3.1 polyclip_1.10-7 enrichit_0.2.1
## [7] lifecycle_1.0.5 httr2_1.3.0 doParallel_1.0.17
## [10] globals_0.19.1 processx_3.9.0 lattice_0.23-1
## [13] MASS_7.3-66 magrittr_2.0.5 plotly_4.12.1
## [16] sass_0.4.10 rmarkdown_2.31 jquerylib_0.1.4
## [19] yaml_2.3.12 httpuv_1.6.17 otel_0.2.0
## [22] ggtangle_0.1.2 DBI_1.3.0 buildtools_1.0.0
## [25] RColorBrewer_1.1-3 abind_1.4-8 purrr_1.2.2
## [28] msigdbr_26.1.0 yulab.utils_0.2.4 tweenr_2.0.3
## [31] rappdirs_0.3.4 aisdk_1.4.12 gdtools_0.5.1
## [34] circlize_0.4.18 enrichplot_1.33.0 ggrepel_0.9.8
## [37] listenv_1.0.0 tidytree_0.4.8 maketools_1.3.2
## [40] parallelly_1.48.0 codetools_0.2-20 DelayedArray_0.39.5
## [43] DOSE_4.7.2 DT_0.34.0 ggforce_0.5.0
## [46] tidyselect_1.2.1 shape_1.4.6.1 aplot_0.3.1
## [49] farver_2.1.2 jsonlite_2.0.0 GetoptLong_1.1.1
## [52] progressr_1.0.0 iterators_1.0.14 systemfonts_1.3.2
## [55] foreach_1.5.2 tools_4.6.1 ggnewscale_0.5.2
## [58] treeio_1.37.0 Rcpp_1.1.2 glue_1.8.1
## [61] SparseArray_1.13.2 BiocBaseUtils_1.15.1 xfun_0.60
## [64] qvalue_2.45.0 dplyr_1.2.1 withr_3.0.3
## [67] BiocManager_1.30.27 fastmap_1.2.0 shinyjs_2.1.1
## [70] callr_3.8.0 digest_0.6.39 mime_0.13
## [73] R6_2.6.1 gridGraphics_0.5-1 colorspace_2.1-3
## [76] GO.db_3.23.1 RSQLite_3.53.3 tidyr_1.3.2
## [79] fontLiberation_0.1.0 data.table_1.18.4 httr_1.4.8
## [82] htmlwidgets_1.6.4 S4Arrays_1.13.0 scatterpie_0.2.6
## [85] pkgconfig_2.0.3 gtable_0.3.6 blob_1.3.0
## [88] ComplexHeatmap_2.29.0 S7_0.2.2 XVector_0.53.0
## [91] sys_3.4.3 clusterProfiler_4.21.1 htmltools_0.5.9
## [94] fontBitstreamVera_0.1.1 clue_0.3-68 scales_1.4.0
## [97] png_0.1-9 ggfun_0.2.1 knitr_1.51
## [100] reshape2_1.4.5 rjson_0.2.23 visNetwork_2.1.4
## [103] nlme_3.1-170 curl_7.1.0 cachem_1.1.0
## [106] GlobalOptions_0.1.4 stringr_1.6.0 shinycssloaders_1.1.0
## [109] parallel_4.6.1 AnnotationDbi_1.75.2 pillar_1.11.1
## [112] grid_4.6.1 vctrs_0.7.3 promises_1.5.0
## [115] tidydr_0.0.6 xtable_1.8-8 cluster_2.1.8.3
## [118] evaluate_1.0.5 cli_3.6.6 locfit_1.5-9.12
## [121] compiler_4.6.1 rlang_1.3.0 crayon_1.5.3
## [124] future.apply_1.20.2 ps_1.9.3 plyr_1.8.9
## [127] fs_2.1.0 ggiraph_0.9.6 stringi_1.8.9
## [130] viridisLite_0.4.3 BiocParallel_1.47.0 assertthat_0.2.1
## [133] babelgene_22.9 Biostrings_2.81.6 lazyeval_0.2.3
## [136] GOSemSim_2.39.2 fontquiver_0.2.1 Matrix_1.7-6
## [139] patchwork_1.3.2 bit64_4.8.2 future_1.75.0
## [142] ggplot2_4.0.3 KEGGREST_1.53.6 statmod_1.5.2
## [145] shiny_1.14.0 clipr_0.8.1 igraph_2.3.3
## [148] memoise_2.0.1 bslib_0.12.0 ggtree_4.3.0
## [151] bit_4.6.0 ape_5.8-1 gson_0.2.1