# GSEAlens: An Interactive Exploration Platform for Gene Set Enrichment Analysis

# Package Introduction

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.

## Integration with Bioconductor Workflows

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.

## Installation

GSEAlens is available on Bioconductor. Install the stable release with:

    if (!requireNamespace("BiocManager", quietly = TRUE))
        install.packages("BiocManager")
    BiocManager::install("GSEAlens")

The development version can be installed from GitHub:

    if (!requireNamespace("pak", quietly = TRUE))
        install.packages("pak")
    pak::pkg_install("DDL095/GSEAlens")

# Quick Start

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")`.

    library(GSEAlens)
    library(airway)

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_dds

To prepare these objects from your own data, follow the supplementary preprocessing vignette:

    vignette("GSEAlens-preprocessing")

## GSEAlens Processing

### Creating GSEA Pathway Object

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_toy

### Assembling Computation Object

Through 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)

### Running Processing

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)

### Interactive Analysis and Viewing

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.

    gsea_res <- import_gsea_capsule("/path/to/your/files/")
    # Or read the RDS directly:
    # gsea_res <- readRDS("/path/of/your/file/")

## Interactive Exploration with the Shiny Application

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`.

### Launching the 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.

    # Basic launch
    launch_gsea_app(gsea_res)
    # With explicit pathway annotations:
    # launch_gsea_app(gsea_res, addition_data = "pathway_annotations.csv")

### Application Layout

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.

#### Sidebar – Data Preprocessing

Provides global controls visible across all tabs:

- Contrast selection: choose which pairwise comparison to explore

- Gene set subgroup filtering: subset pathways by collection (e.g. H, C2, C5)

- DEG marker selection: highlight genes of interest

- Group display order: customize factor ordering for plots

- Expression metrics: switch between CPM / logCPM / VST / FPKM

Source: `R/08_shiny_mod_data_prep.R`.

#### Tab 1 – Main Workspace

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`.

#### Tab 2 – Holographic Quadruple Linkage

Four synchronized panels:

1. Top-left: pathway selector (linked to Main Workspace selection)

2. Top-right: gene ranking table (ranked by `|stat|`)

3. Bottom-left: volcano plot for the selected contrast

4. 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`.

#### Tab 3 – Pathway Relationship Exploration

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`.

#### Tab 4 – HubGene Network

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`.

#### Tab 5 – AI Interpretation

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.

#### Tab 6 – Joint GSEA Canvas

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`.

### Interpreting Outputs

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

### Reproducible Code Export

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.

# Package Intermediate Object Descriptions

## GseaEnv Object

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)

## GseaRes Object

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

## GseaTask Object

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)

# Session Info

    sessionInfo()

    ## 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

# References