GExPipe: An Integrated Pipeline for Gene Expression Analysis

Introduction

GExPipe is a Shiny application for bulk RNA-seq and microarray analysis. This vignette walks through the guided 16-step interface end to end. Step 1 has four analysis types: RNA-seq only, microarray only, Merged (Both) (per-study normalize, common genes, one joint batch and limma DE), and Parallel DE, then merge (separate pipelines through DE, then RNA-seq intersect microarray at Step 7). Each RNA-seq and microarray box accepts one or more GSE IDs in the same run. Later steps cover WGCNA, DEG ∩ modules, PPI, machine learning, and a clinical summary report. For mixed microarray studies (Arraystar, Affymetrix, Agilent, custom probe IDs), the download step automatically runs STEP 2b to map probes to HGNC gene symbols so overlap and later merge use symbols — see Gene ID mapping below.

Vignette outline

Section Purpose
How the Shiny app is organised Pipeline overview figure
Installation Bioconductor and GitHub install
Run latest code for analysis Avoid stale installs; use main / pkgload
Launch the Shiny application Start the app (runGExPipe() + shiny::runApp())
Step-by-step Shiny walkthrough Actions and screenshots for all 16 steps
Gene ID mapping Probe / accession → symbol conversion (STEP 2b)
Programmatic example Optional scripting with bundled CSV data
Troubleshooting Common install and runtime issues

The package builds on GEOquery for data retrieval, limma, DESeq2, and edgeR for differential expression, WGCNA for co-expression networks, and clusterProfiler for functional enrichment.

How the Shiny app is organised

The sidebar lists 16 sequential steps grouped into four phases. Each step unlocks only after the previous one succeeds. The welcome screen explains the four analysis types; click Start Analyzing to open Step 1. Step 7 (RNA-seq ∩ microarray) is used only for Parallel DE.

Phase Steps What you do
Data preparation 1 – 5 Download GEO data (per GSE) → Normalize each study → QC & visualization → Select groups → Batch correction
Gene discovery 6 – 9 Differential expression → Parallel overlap (Step 7) → WGCNA → DEG ∩ modules
Candidate refinement 10 – 13 PPI network → ML feature selection → Validation → ROC
Clinical translation 14 – 16 Nomogram → GSEA → Summary PDF report
GExPipe 16-step pipeline. Each box corresponds to one sidebar tab in the Shiny app. Step 7 is Parallel DE only.

GExPipe 16-step pipeline. Each box corresponds to one sidebar tab in the Shiny app. Step 7 is Parallel DE only.

Installation

Follow the Bioconductor installation instructions and the official install guide to ensure your R version matches a supported Bioconductor release (e.g. Bioconductor 3.24 for R 4.6).

From GitHub (available before Bioconductor release)

Until the package is on Bioconductor, install from GitHub. Requires R ≥ 4.6.0 (see DESCRIPTION).

One line — install, update and open the app. Start a fresh R session (RStudio: Ctrl+Shift+F10) and run:

source("https://raw.githubusercontent.com/safarafique/GExPipe/main/install_gexpipe.R")

Each time it runs, the script installs or updates GExPipe from the latest GitHub main together with all CRAN and Bioconductor dependencies (missing or out-of-date ones only), retries any that fail, checks that the package loads, and then opens the app. If everything is already up to date it opens the app straight away. The first install takes 15–30 min.

If this line stops with Error in summary.connection(connection) : invalid connection, R could not download the script: your network blocks or drops raw.githubusercontent.com. Use the Manual install below instead; it downloads from GitHub by a different address.

Manual install (same result, step by step):

options(timeout = 3600)

if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")
options(repos = BiocManager::repositories())

if (!requireNamespace("remotes", quietly = TRUE))
    install.packages("remotes")
remotes::install_github(
  "safarafique/GExPipe",
  ref = "main",
  INSTALL_opts = "--no-staged-install"
)

# Optional packages for the extra ML / plotting features
BiocManager::install(
  c("Boruta", "car", "cicerone", "corrplot", "dcurves",
    "kernlab", "mixOmics", "SHAPforxgboost"),
  ask = FALSE, update = FALSE
)

Quick start without installing: see Run latest code for analysis (recommended for mixed microarray merges).

The annotation packages used for mixed microarray merges (org.Hs.eg.db, biomaRt) are regular dependencies and are installed automatically with GExPipe.

Install in a fresh R session (RStudio: Ctrl+Shift+F10) so no package is in use while it is updated; on Windows a package that is already loaded cannot be replaced.

Run latest code for analysis

If you installed from GitHub some time ago, reinstall or launch from the latest main branch so Parallel DE, multi-GSE download, probe-ID mapping (STEP 2b), and other fixes are included:

if (!requireNamespace("shiny", quietly = TRUE)) install.packages("shiny")
if (!requireNamespace("pkgload", quietly = TRUE)) install.packages("pkgload")
options(timeout = 600)  # the GitHub download can exceed R's 60 s default
shiny::runGitHub(
  "safarafique/GExPipe",
  ref = "main",
  subdir = "inst/shinyapp",
  destdir = tempfile()
)
# Local clone
setwd("path/to/GExPipe")
pkgload::load_all(".")
app <- GExPipe::runGExPipe(launch.browser = FALSE)
shiny::runApp(app)
options(repos = BiocManager::repositories())
remotes::install_github(
  "safarafique/GExPipe",
  ref = "main",
  force = TRUE,
  INSTALL_opts = "--no-staged-install"
)
app <- GExPipe::runGExPipe(launch.browser = FALSE)
shiny::runApp(app)

Launch the Shiny application

Bioconductor Shiny apps return an app object from the package; users start the server with shiny::runApp() (Bioconductor Shiny guide). If you need probe-ID conversion on mixed platforms, prefer Run latest code for analysis over a months-old install.

app <- GExPipe::runGExPipe()
shiny::runApp(app)

The browser opens at the welcome screen. Click Start Analyzing to begin Step 1 - Download Data.

options(gexpipe.auto_install = TRUE)  # GitHub installs only
app <- GExPipe::runGExPipe()
shiny::runApp(app)

Run in Google Colab (optional)

For users without a local R installation, run the app in Google Colab (Runtime → Change runtime type → R). Use a tunnel (e.g. ngrok) to expose port 3838, then install and start the app with host = "0.0.0.0". See the GitHub README for full Colab cells.

Step-by-step Shiny walkthrough

The sections below mirror the sidebar tabs. For each step, read the goal, apply the settings under What to do, run the primary action button, and confirm the success check before continuing.

Phase 1 — Data preparation

The sidebar tabs for this phase are 1. Download Data, 2. Normalize Data, 3. QC & Visualization, 4. Select Groups, and 5. Batch Correction. Any valid GEO accessions work; each box accepts one or more GSE IDs, comma-separated.

Example datasets

The walkthrough uses these public GEO series. They are also the examples shown under the GSE ID boxes in Step 1.

Platform Example GSE IDs (Step 1 box) Role
RNA-seq GSE144119, GSE100026 Training (RNA-seq box)
Microarray GSE268456, GSE47927 Training (microarray box)
RNA-seq GSE162462 External validation (Step 12)
Microarray GSE13159 External validation (Step 12)

The four analysis types

Choose one under Select Analysis Platform in Step 1. The table shows which box to fill for each type, using the example IDs above.

Analysis type RNA-seq box Microarray box DE method (Step 6) What happens
1. RNA-seq only GSE144119, GSE100026 — DESeq2, edgeR, limma-voom (raw counts) or limma (TMM log-CPM) RNA-seq studies normalized, batch-corrected and analysed together.
2. Microarray only — GSE268456, GSE47927 limma Microarray studies normalized (quantile / RMA / log2), batch-corrected and analysed with limma.
3. Merged (Both) GSE144119, GSE100026 GSE268456, GSE47927 limma Each study normalized on its own scale, common genes kept, global quantile on, one joint batch correction and one limma DE on all samples.
4. Parallel DE, then merge GSE144119, GSE100026 GSE268456, GSE47927 RNA-seq: DESeq2 / edgeR / limma-voom / limma; microarray: limma Two separate pipelines (each platform keeps its own genes, normalization, batch correction and DE); Step 7 keeps DEGs found on both platforms with the same direction.

For a single-study run, choose Single dataset (1 GSE) with RNA-seq only or microarray only (e.g. just GSE144119 or just GSE268456); Step 5 batch correction is then skipped.

Step 1 — Download Data

Sidebar: 1. Download Data

Goal: Download GEO series, map row IDs to gene symbols, and keep per-GSE matrices. Merged (Both) intersects genes after Step 2 normalization. Parallel DE keeps each platform’s genes until Step 7.

What to do:

  1. Optionally enter a Disease / Condition label (used in reports and saved workspace names).
  2. Under Select Analysis Platform, choose one of four types:
    • RNA-seq — counts; DESeq2 / edgeR / voom or limma on TMM.
    • Microarray — platform normalization + limma.
    • Merged (Both) — per-study normalize, common genes, one joint batch, one limma DE (original merged workflow).
    • Parallel DE, then merge — two separate pipelines through DE (RNA-seq engine + microarray limma). Step 7 keeps same-direction overlap. Step 8 is one WGCNA on one processed platform matrix.
  3. Datasets: RNA-seq-only and microarray-only can use Single dataset (1 GSE) (skips Step 5) or Multiple datasets. Merged and Parallel always keep every GSE typed in each box (several RNA-seq studies and several microarray studies in one run).
  4. Select the DE method for Step 6 (this also controls Step 2):
    • limma — microarray, merged, or normalized log-expression.
    • limma-voom, DESeq2, or edgeR — RNA-seq integer counts.
    • Parallel: RNA-seq method on the left; microarray is always limma.
  5. Enter comma-separated GSE IDs. RNA-seq and microarray each have their own box, e.g. GSE144119, GSE100026 in RNA-seq Datasets and GSE268456, GSE47927 in Microarray Datasets (see the four analysis types for which boxes each type uses).
  6. Click Start Processing and read the Download log.
  7. Click Next: Normalize Data.

A GEO series measured on several platforms (e.g. GSE18123: GPL570 and GPL6244) is stored on GEO as one matrix file per platform; GExPipe downloads all of them and keeps the platform with the most samples.

For multiple microarray platforms, install org.Hs.eg.db and biomaRt (see Installation) so STEP 2b converts probe IDs to HGNC symbols so overlap and later merge use gene symbols.

Success check: Download log lists samples per GSE; STEP 2b runs when needed; row names are symbols (TP53, BRCA1, …). Merged reports common genes; Parallel keeps each platform’s full gene list until Step 7.

Step 1: Select one of four analysis types, DE method, and GSE IDs (several per box).

Step 1: Select one of four analysis types, DE method, and GSE IDs (several per box).

Step 2 — Normalize Data

Sidebar: 2. Normalize Data

Goal: Normalize each GSE on its native scale. Merged then keeps the common genes (and, by default, applies one global quantile so RNA-seq and microarray share one scale); Parallel keeps each platform separate. Step 5 removes the remaining between-study batch.

What to do:

Count-based DE (DESeq2 / edgeR / limma-voom from Step 1): the panel shows Normalization Auto-Handled — continue to Next: QC & Visualization. Each RNA-seq GSE is TMM-normalized (Merged intersects common genes; Parallel does not). DESeq2/edgeR/voom still use raw counts.

limma path (microarray or merged):

  1. Choose Auto or Manual under Normalization Strategy.
  2. Microarray: Quantile or RMA per GSE; RNA-seq: TMM + log2-CPM per GSE.
  3. Merged only: Apply global quantile is on by default so the RNA-seq and microarray studies share one scale for the single limma DE. Parallel never applies it (each platform is normalized on its own).
  4. Click Apply Normalization. Merged intersects common genes here; Parallel keeps two separate matrices (no global quantile).
  5. Scroll to Normalization Quality Assessment (panels a and b below):
    • Overall density and Q–Q plot (panel a).
    • Median/range alignment and distribution overlap (panel b).
  6. Optional: under Download Before / After Normalization Data, download a ZIP with the input matrices (before), the normalized matrices (after, per dataset and per platform or combined), per-sample and per-dataset check tables and a README; or the check table alone as CSV. After a correct normalization Likely_log_scale is TRUE and Median_SD_across_samples falls towards 0.
  7. Click Next: QC & Visualization.

Success check: Within each dataset, sample medians align. Mixed-platform blocks remaining after Step 2 are expected; Step 5 removes study/platform batch. Parallel shows two columns (RNA-seq left, microarray right).

Step 2a: Overall density and Q-Q plots after normalization.

Step 2a: Overall density and Q-Q plots after normalization.

Step 2b: Median/range alignment and distribution overlap.

Step 2b: Median/range alignment and distribution overlap.

Step 3 — QC & Visualization

Sidebar: 3. QC & Visualization

Goal: Check gene overlap, inspect expression per platform after Step 2, and detect outlier samples within each GSE. Parallel DE does not require a gene intersection here.

What to do:

  1. Review Venn and UpSet plots (figure below, panel a). In Parallel mode RNA-seq (left, blue) and microarray (right, orange) have separate boxes; two datasets with identical gene sets are shown as one circle marked “100% overlap”.
  2. Open Quality Control Plots — Boxplot and Density tabs on raw expression (panel b).
  3. In Sample Outlier Detection, click Run Outlier Detection (panel c). PCA (Mahalanobis distance) and sample connectivity are computed on the normalized matrix — the combined matrix in Merged mode, each platform separately in Parallel mode (at least 5 samples per platform). The plots and outlier tables appear after the run; each table has a CSV download.
  4. Exclude flagged samples if needed; keep ≥ 3 samples per group after Step 4.
  5. Review Data Summary (datasets, samples, genes).
  6. Proceed to Step 4 (Select Groups).

Success check: Overlap and QC plots look reasonable; outliers reviewed.

Step 3a: Venn and UpSet gene overlap.

Step 3a: Venn and UpSet gene overlap.

Step 3b: Expression boxplot.

Step 3b: Expression boxplot.

Step 3c: PCA and connectivity outlier detection.

Step 3c: PCA and connectivity outlier detection.

Step 4 — Select Groups

Sidebar: 4. Select Groups

Goal: Assign each sample to Normal, Disease, or Exclude.

What to do:

  1. Browse Phenodata Browser for each GSE.
  2. Under Select Phenotype Columns (panel a), pick the condition column per dataset (e.g. characteristics_ch1, or title when treatment is only in sample titles).
  3. Click Extract Groups from Selected Columns.
  4. Categorize Groups — map labels to reference (Normal) or comparison (Disease), or None.
  5. Click Apply Groups.
  6. In Group Summary (panel b), optionally rename groups (e.g. Control / Treated); click Update, or leave as Normal / Disease and continue.
  7. Confirm sample counts, then click Next: Batch Correction.

Success check: Group Summary counts match your study design.

Step 4a: Select phenotype column per GSE.

Step 4a: Select phenotype column per GSE.

Step 4b: Group Summary after Apply Categorization.

Step 4b: Group Summary after Apply Categorization.

Step 5 — Batch Correction

Sidebar: 5. Batch Correction

Goal: Remove technical variation between datasets while keeping biological Normal vs Disease signal.

What to do:

  1. Read Dataset × Condition confounding — if dataset and condition are confounded, use limma or SVA instead of ComBat.
  2. Review Gene variance distribution.
  3. Set Variance percentile cutoff (panel a, default 25%).
  4. Choose Batch correction method (panel a, default ComBat-ref): ComBat-ref, SVA, limma, ComBat, Quantile + limma, or Hybrid.
  5. Click Apply Batch Correction.
  6. Compare before vs after PCA by dataset (panel b), plus PCA by condition, hierarchical clustering, and PVCA on the same panel.
  7. Check Batch effect check (before vs after) in the download box. For each corrected matrix it reports the % of top-PC variance explained by batch (dataset) and by condition, PC1 batch R², silhouette by batch and the % of genes with a significant batch effect, with a verdict (OK below 10% batch variance; warning above 25%; over-correction warning if the condition signal collapses). Download the check table (CSV) or a ZIP with matched before/after matrices, sample metadata and a README.
  8. Click Next: Differential Expression.

Note: With only one GSE loaded in Step 1, there is no between-study batch to remove, so cross-study correction is skipped by default - but a single dataset can still carry a technical batch effect from sample processing (extraction date, sequencing lane, processing day). Step 5 shows a diagnostic panel for this case: pick a candidate technical covariate from that GSE’s own phenodata, compare PCA colored by the covariate versus by Condition, and either confirm there is no batch effect or apply limma::removeBatchEffect() using that covariate before continuing.

Success check: After-correction PCA (panel b) shows datasets intermingled, and the batch-effect check reports a falling batch share with the condition signal kept.

Step 5a: Variance filtering and batch correction method.

Step 5a: Variance filtering and batch correction method.

Step 5b: PCA by dataset before and after batch correction.

Step 5b: PCA by dataset before and after batch correction.

Phase 2 — Gene discovery

Step 6 — Differential Expression Analysis

Sidebar: 6. Differential Expression Analysis

Goal: Identify genes differing between Normal and Disease.

What to do:

  1. Confirm the DE method banner matches your Step 1 choice (limma, limma-voom, DESeq2, or edgeR).
  2. Set DE Parameters (panel a):
    • LogFC cutoff (default 0.5; e.g. 1.0 for 2-fold change).
    • Adj. P-value (default 0.05, Benjamini–Hochberg FDR).
    • Heatmap Genes (number of top DEGs for the heatmap, default 50).
  3. Click Run DE Analysis.
  4. Read Statistical model and Pipeline verification — design formula, filterByExpr gene counts, samples used, and batch-in-model note.
  5. Review results (panel b):
    • Volcano plot (up / down / not significant).
    • Top DEGs table and heatmap below.
  6. Optionally download Analysis report (TXT).
  7. Click Next: WGCNA Analysis (RNA-seq only, microarray only, or Merged) or Next: RNA-seq ∩ microarray (Parallel DE).

Parallel DE runs two engines with one click (RNA-seq on the left, microarray limma on the right). Merged (Both) still uses one joint limma on the combined matrix.

Success check: Volcano shows expected direction; DEG count is plausible for your contrast; pipeline verification lists the correct method and samples.

Step 6a: DE parameters, statistical model, and pipeline verification.

Step 6a: DE parameters, statistical model, and pipeline verification.

Step 6b: Volcano plot and top DEG table.

Step 6b: Volcano plot and top DEG table.

Step 7 — RNA-seq ∩ microarray (Parallel DE only)

Sidebar: 7. RNA-seq ∩ microarray

Goal: Keep genes that are significant on both platforms with the same fold-change direction. This is the first merge after Parallel DE. RNA-seq only, microarray only, and Merged (Both) skip this tab.

What to do:

  1. Confirm both Step 6 DE tables exist (RNA-seq left, microarray right).
  2. Click Apply to store the same-direction overlap (Consensus DEGs).
  3. Review the Venn: Common is the two-circle overlap; Consensus is the list stored for Step 9.
  4. Click Next: WGCNA Analysis.

Success check: Consensus gene count is greater than 0 and matches the same-direction overlap, not the union of all DEGs.

Step 8 — WGCNA Network Analysis

Sidebar: 8. WGCNA Analysis

Goal: Find co-expression modules associated with disease and extract hub genes from significant modules.

What to do:

The WGCNA tab has internal sub-steps; complete them in order:

  1. Data Preparation & QC (panel a):
    • Choose All genes or Top variable genes (e.g. 5000).
    • Set Min samples per gene fraction (default 0.5).
    • Click Prepare Data.
    • Check the sample dendrogram; exclude outliers or click No outliers — proceed to Step 2 (within this tab).
  2. Pick Soft Threshold Power (panel b):
    • Click Calculate Power; choose power where scale-free R² ≥ 0.80.
  3. Network Construction & Module Detection (panel c):
    • Set minimum module size and merge cut height.
    • Click Build Network; inspect the module dendrogram and module colours.
  4. Module–trait relationships (panel c):
    • Click Calculate Correlations & GS/MM; review the heatmap of module–condition correlations.
  5. Identify significant modules (panel d):
    • Click Identify Significant Modules; note hub genes (GS/MM filters).
    • Optionally run GS vs MM plots for all modules.
  6. Click Next: Common Genes (DEG & WGCNA) (Step 9).

Success check: Soft-threshold R² ≥ 0.80; at least one module correlates with Disease; hub genes are listed for significant modules.

Step 8a: WGCNA data preparation and gene selection.

Step 8a: WGCNA data preparation and gene selection.

Step 8b: Soft-threshold power selection.

Step 8b: Soft-threshold power selection.

Step 8c: Module dendrogram and module-trait heatmap.

Step 8c: Module dendrogram and module-trait heatmap.

Step 8d: Significant modules and hub gene summary.

Step 8d: Significant modules and hub gene summary.

Step 9 — Common Genes (DEG & WGCNA) & Enrichment

Sidebar: 9. Common Genes (DEG & WGCNA)

Goal: Intersect DEGs (Step 6, or Step 7 consensus in Parallel) with genes in significant WGCNA modules (Step 8), then run GO/KEGG enrichment on the overlap.

What to do:

  1. Click Compute Common Genes (panel a).
  2. Review the summary counts and Venn diagram: DEG ∩ WGCNA.
  3. Download the common-gene table (CSV) if needed.
  4. Click Run GO Enrichment (panel b) on the common genes — dot plots for BP, MF, and CC.
  5. Click Run KEGG Enrichment (panel c) — bar plot and chord diagram.
  6. Choose next path at the bottom of the tab:
    • Path 1: PPI Interaction → then ML, or
    • Path 2: Direct to Machine Learning.

Requirements: Step 6 DE (and Step 7 if Parallel) plus WGCNA Identify Significant Modules must be complete.

Success check: Venn overlap > 0; GO/KEGG plots show interpretable terms.

Step 9a: Common genes Venn diagram (DEG intersect WGCNA).

Step 9a: Common genes Venn diagram (DEG intersect WGCNA).

Step 9b: GO enrichment of common genes.

Step 9b: GO enrichment of common genes.

Step 9c: KEGG enrichment of common genes.

Step 9c: KEGG enrichment of common genes.

Phase 3 — Candidate refinement

Step 10 — PPI Interaction

Sidebar: 10. PPI Interaction

Goal: Map common genes onto a STRING protein–protein interaction network and identify hub proteins.

What to do:

  1. Set STRING score threshold (default 400; 150–900).
  2. Click Run PPI Analysis (panel a).
  3. Review Interactive vs non-interactive gene counts and table.
  4. Choose genes for network view: Hub genes only, Top N by degree, or Select genes manually; click Run.
  5. Inspect PPI network layouts (panel b) and the hub score and consensus hub tables. Hub Scores (CSV) saves PPI_Hub_Gene_Scores.csv (all nodes, six centrality measures); Consensus Hubs (CSV) saves Consensus_Hub_Genes.csv (genes in ≥ 3 methods, which methods, and their scores).
  6. Click Extract Data for ML (required before Step 11).
  7. Click Next: Machine Learning Process.

Requirements: Step 9 common genes computed.

Success check: Network builds with mapped edges; hub genes listed; ML extract succeeds.

Step 10a: Run PPI and interactive vs non-interactive gene table.

Step 10a: Run PPI and interactive vs non-interactive gene table.

Step 10b: PPI network graph and hub gene metrics.

Step 10b: PPI network graph and hub gene metrics.

Step 11 — Machine Learning Process

Sidebar: 11. Machine Learning Process

Goal: Rank genes by predictive importance using multiple ML algorithms and find genes selected by ≥ 2 methods.

What to do:

  1. Confirm Extract Data for ML was run on the PPI tab (Step 10).
  2. Under Run ML Analysis (panel a), select one or more methods: LASSO, Elastic Net, Ridge, Random Forest, SVM-RFE, Boruta, sPLS-DA, XGBoost+SHAP.
  3. Set Top N per method where shown.
  4. Click Run ML Analysis.
  5. Review Venn diagram (selected methods) and the common ML genes table (panel b) — genes in ≥ 2 methods form the candidate panel.
  6. Inspect per-method importance plots (RF, Elastic Net, etc.).
  7. Click Continue to Validation Setup.

Note: If glmnet fails after install, restart R and relaunch the app.

Success check: At least one common ML gene; Venn overlap across methods is non-empty.

Step 11a: Select ML methods and run analysis.

Step 11a: Select ML methods and run analysis.

Step 11b: Method overlap Venn diagram and common ML genes.

Step 11b: Method overlap Venn diagram and common ML genes.

Step 12 — Validation

Sidebar: 12. Validation Setup

Goal: Test generalization on an external GEO cohort or an internal 70/30 train–test split. Target accuracy ≥ 70%.

What to do:

  1. Choose Validation Strategy (panel a):
    • External Validation — download an independent GSE, categorize groups, and run DE on the validation cohort.
    • Internal Validation — use a 70/30 stratified split of your current data (no extra download).
  2. External path only:
    • Enter validation GSE IDs (e.g. GSE162462 for RNA-seq or GSE13159 for microarray), select Platform Type and DE Method (limma, or DESeq2/edgeR when the platform is RNA-seq with raw counts).
    • Click Download - this normalizes the validation data with the same per-dataset method used in Step 2 (quantile for microarray, TMM for RNA-seq) and applies the same gene ID -> symbol conversion as Step 1, so validation gene identifiers and counts match the training pipeline for the same GSE.
    • Browse phenodata and select the group column.
    • A Batch Correction panel appears next: with 2+ validation datasets it runs the same auto-selected ComBat-ref/limma correction as Step 5; with a single dataset it offers the same optional technical-covariate correction described in Step 5.
    • Categorize labels as Normal / Disease, set LogFC cutoff and Adj. P-value for this validation-set DE (defaults 0.5 / 0.05, independent of Step 6’s thresholds), and click Run Validation DE
      • this uses the same DE engines (gexpipe_run_count_de / gexpipe_run_limma_on_subset) as Step 6, including a Dataset covariate when 2+ validation datasets are combined.
  3. Review validation status and DE results (panel b).
  4. Click Continue to ROC Curve Analysis.

Requirements: Step 11 ML analysis complete with at least one common ML gene.

Success check: External mode shows downloaded samples and validation DE results; internal mode confirms the 70/30 split is ready for ROC and nomogram.

Step 12a: Validation mode and external validation settings.

Step 12a: Validation mode and external validation settings.

Step 12b: External validation DE results.

Step 12b: External validation DE results.

Step 13 — ROC Analysis

Sidebar: 13. ROC Curve Analysis

Goal: Per-gene AUC with 95% CI (pROC). Retain genes with AUC ≥ 0.80 in training and validation.

What to do:

  1. Review AUC Summary — Training Data (panel a): table and bar plot for common ML genes with AUC ≥ 0.80.
  2. Inspect ROC Curves — Training Data and per-gene expression boxplots.
  3. If external validation was run in Step 12, compare training vs validation AUC in the summary and external ROC panels (panel b).
  4. Review Multi-variable ROC (combined biomarker panel vs best single gene).
  5. Under Select Final Biomarker Genes, choose genes to carry forward to nomogram and GSEA (defaults to all common ML genes if none selected).
  6. Click Continue to Diagnostic Nomogram, Continue to GSEA Analysis, or View Results Summary.

Requirements: Step 11 common ML genes; Step 12 validation mode selected.

Success check: At least one gene with training AUC ≥ 0.80; validation AUC reported when external data are loaded.

Step 13a: Training ROC curves and AUC summary.

Step 13a: Training ROC curves and AUC summary.

Step 13b: Training vs validation AUC comparison.

Step 13b: Training vs validation AUC comparison.

Phase 4 — Clinical translation

The sidebar tabs for this phase are 14. Diagnostic Nomogram Model, 15. GSEA Analysis, and 16. Results Summary.

Step 14 — Nomogram

Sidebar: 14. Diagnostic Nomogram Model

Goal: Build a points-based clinical score (rms::lrm()), calibration curve, and decision curve analysis.

What to do:

  1. Confirm the validation mode banner (external or internal 70/30 split).
  2. Click Run Nomogram Analysis.
  3. Review outputs in order:
    • Panel A: nomogram (points scale).
    • Panel B: training and validation ROC curves.
    • Panel C: calibration curves.
    • Panel D: decision curve analysis (DCA).
    • Panel E: clinical impact curves.
  4. Inspect Model Diagnostics (VIF, coefficients) and Performance Comparison (training vs validation).
  5. Click Continue to GSEA Analysis or View Results Summary.

Requirements: Batch correction (Step 5), group metadata, and common ML genes from Step 11 (or common DEG ∩ WGCNA genes from Step 9).

Success check: Nomogram renders; training AUC is reasonable; validation metrics match your chosen validation strategy.

Step 14: Nomogram, calibration, and decision curves.

Step 14: Nomogram, calibration, and decision curves.

Step 15 — GSEA

Sidebar: 15. GSEA Analysis (Signature Genes)

Goal: Pathway-level enrichment (GO, KEGG, MSigDB Hallmark/C2/C5) stratified by final gene expression.

What to do:

  1. Select one or more Gene Set Collection(s) (Hallmark, GO BP/MF, KEGG, Reactome, etc.).
  2. Optionally enter Custom target genes; leave blank to use common ML genes (or genes selected in Step 13).
  3. Click Run GSEA.
  4. For each target gene, review the enrichment plot and pathway list in the per-gene panels below.
  5. Click Continue to Results Summary.

Requirements: Batch-corrected expression and common ML genes from Step 11 (or Step 9 overlap).

Success check: GSEA completes for each target gene; enrichment plots and pathway tables are interpretable.

Step 15: GSEA enrichment plots per signature gene.

Step 15: GSEA enrichment plots per signature gene.

Step 16 — Summary Report

Sidebar: 16. Results Summary

Goal: Review a plain-text overview of the whole pipeline and its key result counts, in order.

What to do:

  1. Read the Pipeline summary narrative at the top - one paragraph covering genes/samples processed, normalization, batch correction, DE (significant/up/down genes), WGCNA modules, common genes, GO/KEGG/PPI counts, ML overlap, nomogram AUCs, and GSEA.
  2. Scroll through the step cards below it for the same information broken out per step (normalization, batch correction, DE, WGCNA, common genes, GO/KEGG, PPI, ML, nomogram, GSEA, and input/pipeline size).

This tab is text and tables only - it does not duplicate plots or offer JPG/PDF downloads. For figures, use the download buttons on each step’s own tab (e.g. Step 6 for the volcano plot, Step 9 for the PPI network).

Success check: The narrative and step cards reflect your completed steps’ actual numbers (e.g. DEG count matches Step 6, module count matches Step 7).

Step 16: Results summary overview.

Step 16: Results summary overview.

Gene ID mapping (mixed studies)

When you merge multiple GEO microarray series, row names are often probe IDs, Ensembl IDs, or GenBank accessions — not HGNC symbols. GExPipe detects the format per GSE and converts to symbols in STEP 2b before computing the gene intersection.

library(GExPipe)

detect_fmt <- getFromNamespace("detect_gene_id_format", "GExPipe")
need_conv <- getFromNamespace("gexpipe_ids_need_symbol_conversion", "GExPipe")

examples <- list(
  "HGNC symbols"              = c("TP53", "BRCA1", "EGFR"),
  "Arraystar / custom probes" = c("(+)E1A_r60_1", "ASHGV40000001"),
  "Affymetrix Ensembl probes" = c("ENSG00000000003_at", "ENSG00000000005_at"),
  "GenBank accessions"        = c("AB000409", "AB000463", "AB000781")
)

id_table <- data.frame(
  Example = names(examples),
  Detected_format = vapply(examples, detect_fmt, character(1)),
  Needs_symbol_conversion = vapply(examples, need_conv, logical(1)),
  check.names = FALSE
)
knitr::kable(id_table, caption = "How GExPipe classifies common GEO row ID types.")
How GExPipe classifies common GEO row ID types.
Example Detected_format Needs_symbol_conversion
HGNC symbols HGNC symbols Gene symbol (HGNC) FALSE
Arraystar / custom probes Arraystar / custom probes Microarray probe-like ID TRUE
Affymetrix Ensembl probes Affymetrix Ensembl probes Ensembl ID TRUE
GenBank accessions GenBank accessions GenBank/EMBL accession TRUE

Arraystar GPL21827 (e.g. GSE188653) has no gene-symbol column on GEO; GExPipe crosswalks V4 probe IDs to GPL26963 annotation (ORF / accession → symbol). Control probes such as (+)E1A_r60_* are dropped. Ensure org.Hs.eg.db and biomaRt are installed for full conversion.

Example platforms in a four-study microarray merge:

GSE GPL Row ID style
GSE188653 GPL21827 Arraystar V4 probes (+)E1A_r60_*, ASHGV…
GSE207304 GPL26963 Arraystar V5 probes ASHG19AP…V5
GSE211729 GPL30033 Affymetrix Ensembl ENSG*_at
GSE92252 GPL16025 GenBank accessions AB000409

Demonstration with two small matrices (symbols only — no network):

genes <- c("TP53", "BRCA1", "EGFR", "MYC", "GAPDH", "ACTB")
set.seed(11)
m1 <- matrix(abs(rnorm(length(genes) * 4)), nrow = length(genes),
             dimnames = list(genes, paste0("GSE1_S", 1:4)))
m2 <- matrix(abs(rnorm(length(genes) * 4)), nrow = length(genes),
             dimnames = list(genes, paste0("GSE2_S", 1:4)))

overlap_out <- gexp_download_normalize_ids_for_overlap(
  micro_expr_list = list(GSE1 = m1, GSE2 = m2),
  rna_counts_list = list()
)
fin <- gexp_download_finalize_common_genes(
  micro_expr_list = overlap_out$micro_expr_list,
  rna_counts_list = overlap_out$rna_counts_list,
  all_genes_list  = overlap_out$all_genes_list
)
cat(
  overlap_out$log_text,
  "\nCommon genes after merge:", length(fin$common_genes), "\n"
)
#> 
#> STEP 2b: Normalize IDs to gene symbols for overlap...
#> 
#> Gene symbols extracted per GSE (format detected + sample):
#>  GSE1: 6 genes; format: Gene symbol (HGNC); sample: 'TP53', 'BRCA1', 'EGFR', 'MYC', 'GAPDH', 'ACTB'
#>  GSE2: 6 genes; format: Gene symbol (HGNC); sample: 'TP53', 'BRCA1', 'EGFR', 'MYC', 'GAPDH', 'ACTB'
#>  
#> Common genes after merge: 6

Programmatic example (bundled data)

The Shiny app is the recommended interface. The functions below let you script normalization and QC plots using the example data bundled with the package.

Load package and example data

library(ggplot2)

expr_tab <- read.csv(
  system.file("extdata", "vignette_expression.csv", package = "GExPipe"),
  check.names = FALSE, stringsAsFactors = FALSE
)
meta_tab <- read.csv(
  system.file("extdata", "vignette_sample_metadata.csv", package = "GExPipe"),
  check.names = FALSE, stringsAsFactors = FALSE
)

expr <- as.matrix(expr_tab[, -1L, drop = FALSE])
storage.mode(expr) <- "numeric"
rownames(expr) <- expr_tab[[1L]]

rownames(meta_tab) <- meta_tab$SampleID
meta_tab <- meta_tab[colnames(expr), , drop = FALSE]

dim(expr)
#> [1] 120  12
head(meta_tab)
#>     SampleID Dataset Condition
#> S01      S01      D1    Normal
#> S02      S02      D1    Normal
#> S03      S03      D1   Disease
#> S04      S04      D1   Disease
#> S05      S05      D1   Disease
#> S06      S06      D1   Disease

Normalize and intersect datasets

gexp_normalize_and_intersect() normalizes each dataset, intersects genes, and returns a combined matrix.

if (!"Dataset" %in% colnames(meta_tab))
    meta_tab$Dataset <- "D1"

datasets <- unique(meta_tab$Dataset)
micro_expr_list <- setNames(
    lapply(datasets, function(ds) {
        ids <- rownames(meta_tab)[meta_tab$Dataset == ds]
        expr[, ids, drop = FALSE]
    }),
    datasets
)

norm_res <- gexp_normalize_and_intersect(
    micro_expr_list    = micro_expr_list,
    rna_counts_list    = list(),
    micro_norm_method  = "quantile",
    rnaseq_norm_method = "TMM",
    de_method          = "limma"
)

cat("Combined matrix :", paste(dim(norm_res$combined_expr), collapse = " x "), "\n")
#> Combined matrix : 120 x 12
cat("Common genes    :", length(norm_res$common_genes), "\n")
#> Common genes    : 120

Principal component analysis

expr_pca <- norm_res$combined_expr
keep     <- apply(expr_pca, 1L, var, na.rm = TRUE) > 1e-8
pca      <- prcomp(t(expr_pca[keep, ]), center = TRUE, scale. = TRUE)

pca_df <- data.frame(
    PC1     = pca$x[, 1L],
    PC2     = pca$x[, 2L],
    Dataset = meta_tab[rownames(pca$x), "Dataset"],
    stringsAsFactors = FALSE
)
var_pct <- round(summary(pca)$importance[2L, 1L:2L] * 100, 1)

ggplot(pca_df, aes(PC1, PC2, colour = Dataset)) +
    geom_point(size = 3) +
    theme_minimal() +
    labs(
        title    = "PCA - bundled example data",
        subtitle = "After quantile normalization and gene intersection",
        x        = paste0("PC1 (", var_pct[1L], "% variance)"),
        y        = paste0("PC2 (", var_pct[2L], "% variance)")
    )

Expression heatmap

top_var <- head(
    order(apply(norm_res$combined_expr, 1L, var, na.rm = TRUE),
          decreasing = TRUE),
    min(30L, nrow(norm_res$combined_expr))
)

if (length(top_var) > 1L) {
    pheatmap::pheatmap(
        norm_res$combined_expr[top_var, , drop = FALSE],
        scale         = "row",
        show_rownames = length(top_var) <= 30L,
        main          = "Top 30 most variable genes - bundled example data"
    )
}

Troubleshooting

Problem Solution
0 common genes after download Use latest code. Check STEP 2b in the log. Install org.Hs.eg.db and biomaRt. For Arraystar (GSE188653), allow GPL26963 to download once (cached under micro_data/).
IDs still probe-like in log Restart R; use Run latest code — an old install skips STEP 2b fixes.
Download log says Code source: installed You are not on the GitHub clone; use runGitHub(..., ref = "main") or pkgload::load_all().
Locked DLL files (Windows) Restart R (Ctrl+Shift+F10) before installing or launching.
failed to lock directory ... Try removing ... 00LOCK An earlier install was interrupted. Restart R, run the windows-fix chunk below (it removes the leftover 00LOCK folder) and install again.
Error in summary.connection(connection) : invalid connection (when running source(...)) R could not download the one-line installer: the network blocks or drops raw.githubusercontent.com. Check with readLines("https://raw.githubusercontent.com/safarafique/GExPipe/main/DESCRIPTION", n = 3); if that fails too, use the Manual install (remotes::install_github()), which downloads from GitHub by a different address.
“Rtools is required to build R packages” (RStudio warning) Usually safe to ignore: GExPipe has no compiled code and its dependencies install as ready-made Windows binaries. If R asks “Do you want to install from sources the packages which need compilation?”, answer no (or install Rtools).
createTcpServer: address already in use GExPipe is already running in another R session (open that browser tab, or stop it). runGExPipe() otherwise moves to the next free port; start it with shiny::runApp(app) without a fixed port.
Missing C++ compiler Install Rtools (Windows).
glmnet / ML step skipped Restart R after install; ensure glmnet ≥ 4.x or 5.x loads (packageVersion("glmnet")).
Dependencies not installed / “there is no package called” Restart R and run the one-line installer — it installs CRAN + Bioconductor dependencies, updates outdated ones and retries failures.
Version conflicts (e.g. namespace 'S4Vectors' ... is already loaded, but >= ... is required) Restart R (nothing loaded) and run the one-line installer; it updates the outdated packages in GExPipe’s dependency tree.
Corrupt lazy-load database Reinstall with INSTALL_opts = "--no-staged-install".
“No genes remain in microarray / RNA-seq after per-dataset normalization” The message names each GSE, its gene count and example IDs. A GSE with 0 genes is usually in the wrong platform box or its probe IDs could not be mapped (re-run Step 1 with internet); datasets sharing no IDs usually means one still has probe / Ensembl IDs.
Old version opens after reinstalling Check packageVersion("GExPipe") and the version in the download log. Restart R before launching; if an older copy is installed in a second library (see .libPaths()), reinstall the built package into that library too.
Corporate proxy Sys.setenv(https_proxy = "http://proxy:port") before installing.
options(timeout = 600)
unlink(
    list.files(.libPaths()[1], pattern = "^00LOCK", full.names = TRUE),
    recursive = TRUE, force = TRUE
)
if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")
options(repos = BiocManager::repositories())
if (!requireNamespace("remotes", quietly = TRUE))
    install.packages("remotes")
remotes::install_github(
  "safarafique/GExPipe",
  ref = "main",
  INSTALL_opts = "--no-staged-install"
)

Session Information

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] ggplot2_4.0.3    GExPipe_0.99.114 BiocStyle_2.41.0
#> 
#> loaded via a namespace (and not attached):
#>  [1] KEGGREST_1.53.6      gtable_0.3.6         xfun_0.61           
#>  [4] bslib_0.12.0         htmlwidgets_1.6.4    lattice_0.23-1      
#>  [7] Biobase_2.73.2       vctrs_0.7.3          tools_4.6.1         
#> [10] generics_0.1.4       stats4_4.6.1         tibble_3.3.1        
#> [13] AnnotationDbi_1.75.2 RSQLite_3.53.3       blob_1.3.0          
#> [16] pkgconfig_2.0.3      BiocBaseUtils_1.15.1 pheatmap_1.0.13     
#> [19] RColorBrewer_1.1-3   S7_0.2.2             S4Vectors_0.51.10   
#> [22] VennDiagram_1.8.2    lifecycle_1.0.5      compiler_4.6.1      
#> [25] farver_2.1.2         Biostrings_2.81.9    statmod_1.5.2       
#> [28] Seqinfo_1.3.2        httpuv_1.6.17        htmltools_0.5.9     
#> [31] sys_3.4.3            buildtools_1.0.0     sass_0.4.10         
#> [34] yaml_2.3.12          later_1.4.8          pillar_1.11.1       
#> [37] crayon_1.5.3         jquerylib_0.1.4      DT_0.34.0           
#> [40] cachem_1.1.0         limma_3.99.1         org.Hs.eg.db_3.23.1 
#> [43] mime_0.13            locfit_1.5-9.12      tidyselect_1.2.1    
#> [46] digest_0.6.39        dplyr_1.2.1          labeling_0.4.3      
#> [49] maketools_1.3.2      fastmap_1.2.0        grid_4.6.1          
#> [52] cli_3.6.6            magrittr_2.0.5       edgeR_4.99.6        
#> [55] withr_3.0.3          promises_1.5.0       scales_1.4.0        
#> [58] bit64_4.8.6          rmarkdown_2.32       lambda.r_1.2.4      
#> [61] XVector_0.53.0       httr_1.4.9           bit_4.6.0           
#> [64] otel_0.2.0           futile.logger_1.4.9  png_0.1-9           
#> [67] shiny_1.14.0         memoise_2.0.1        evaluate_1.0.5      
#> [70] knitr_1.52           IRanges_2.47.5       rlang_1.3.0         
#> [73] futile.options_1.0.1 Rcpp_1.1.2           xtable_1.8-8        
#> [76] glue_1.8.1           DBI_1.3.0            BiocManager_1.30.27 
#> [79] formatR_1.14         BiocGenerics_0.59.12 shinydashboard_0.7.3
#> [82] jsonlite_2.0.0       R6_2.6.1