--- title: "GExPipe: An Integrated Pipeline for Gene Expression Analysis" author: - name: Safa Rafique affiliation: University of the Punjab - name: Naeem Mahmood affiliation: University of the Punjab - name: Muhammad Farooq Sabar affiliation: University of the Punjab date: "`r Sys.Date()`" output: BiocStyle::html_document: toc: true toc_depth: 3 number_sections: true vignette: > %\VignetteIndexEntry{Introduction to GExPipe} %\VignetteEncoding{UTF-8} %\VignetteEngine{knitr::rmarkdown} editor_options: markdown: wrap: 72 --- ```{r setup, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", warning = FALSE, message = FALSE, fig.width = 7, fig.height = 5 ) ``` # Introduction `GExPipe` is a **Shiny application** for bulk RNA-seq and microarray analysis. This vignette walks through the guided 15-step interface end to end — download GEO data, run QC and normalization, correct batch effects, discover differentially expressed genes, build co-expression networks, refine candidates with PPI and machine learning, and export a clinical summary report — without manually wiring separate Bioconductor tools together. For mixed microarray studies (Arraystar, Affymetrix, Agilent, custom probe IDs), the download step automatically runs **STEP 2b** to map probes to HGNC gene symbols before merging — see [Gene ID mapping](#gene-id-mapping-mixed-studies) below. ## Vignette outline | Section | Purpose | |------------------------------------|------------------------------------| | [How the Shiny app is organised](#how-the-shiny-app-is-organised) | Pipeline overview figure | | [Installation](#installation) | Bioconductor and GitHub install | | [Run latest code for analysis](#run-latest-code) | Avoid stale installs; use `main` / `pkgload` | | [Launch the Shiny application](#launch-the-shiny-application) | Start the app (`runGExPipe()` + `shiny::runApp()`) | | [Step-by-step Shiny walkthrough](#step-by-step-shiny-walkthrough) | Actions and screenshots for all 15 steps | | [Gene ID mapping](#gene-id-mapping-mixed-studies) | Probe / accession → symbol conversion (STEP 2b) | | [Programmatic example](#programmatic-example-bundled-data) | Optional scripting with bundled CSV data | | [Troubleshooting](#troubleshooting) | Common install and runtime issues | The package builds on `r BiocStyle::Biocpkg("GEOquery")` for data retrieval, `r BiocStyle::Biocpkg("limma")`, `r BiocStyle::Biocpkg("DESeq2")`, and `r BiocStyle::Biocpkg("edgeR")` for differential expression, `r BiocStyle::Biocpkg("WGCNA")` for co-expression networks, and `r BiocStyle::Biocpkg("clusterProfiler")` for functional enrichment. ## How the Shiny app is organised {#how-the-shiny-app-is-organised} The sidebar lists **15 sequential steps** grouped into four phases. Each step unlocks only after the previous one succeeds. The welcome screen explains the workflow; click **Go to Analysis** to open Step 1. | Phase | Steps | What you do | |------------------------|------------------------|------------------------| | **Data preparation** | 1 – 5 | Download GEO data → QC & visualization → Normalize → Select groups → Batch correction | | **Gene discovery** | 6 – 8 | Differential expression → WGCNA → DEG ∩ hub genes | | **Candidate refinement** | 9 – 12 | PPI network → ML feature selection → Validation → ROC | | **Clinical translation** | 13 – 15 | Nomogram → GSEA → Summary PDF report | ```{r pipeline-overview, echo=FALSE, fig.cap="GExPipe 15-step pipeline. Each box corresponds to one sidebar tab in the Shiny app."} pipeline <- data.frame( step = 1:15, phase = rep( c("Data preparation", "Gene discovery", "Candidate refinement", "Clinical translation"), c(5, 3, 4, 3) ), label = c( "1 Download", "2 QC", "3 Normalize", "4 Groups", "5 Batch", "6 DE", "7 WGCNA", "8 Common genes", "9 PPI", "10 ML", "11 Validation", "12 ROC", "13 Nomogram", "14 GSEA", "15 Report" ), stringsAsFactors = FALSE ) phase_cols <- c( "Data preparation" = "#4E79A7", "Gene discovery" = "#59A14F", "Candidate refinement" = "#F28E2B", "Clinical translation" = "#E15759" ) pipeline$y <- rev(pipeline$step) ggplot2::ggplot(pipeline, ggplot2::aes(x = 1, y = y, fill = phase)) + ggplot2::geom_tile( ggplot2::aes(width = 0.92, height = 0.88), colour = "white", linewidth = 0.4 ) + ggplot2::geom_text( ggplot2::aes(label = label), colour = "white", size = 3.2, fontface = "bold" ) + ggplot2::scale_fill_manual(values = phase_cols, name = "Phase") + ggplot2::scale_x_continuous(limits = c(0.5, 1.5), expand = c(0, 0)) + ggplot2::scale_y_continuous(expand = c(0.02, 0.02)) + ggplot2::labs(x = NULL, y = NULL, title = "Shiny app workflow") + ggplot2::theme_void() + ggplot2::theme( legend.position = "bottom", plot.title = ggplot2::element_text(hjust = 0.5, face = "bold") ) ``` # Installation {#installation} Follow the [Bioconductor installation instructions](https://contributions.bioconductor.org/docs.html#installation) and the [official install guide](https://bioconductor.org/install/) to ensure your R version matches a supported Bioconductor release (e.g. Bioconductor 3.22 for R 4.6). ## From Bioconductor (recommended) Install `GExPipe` and all runtime dependencies with `BiocManager`: ```{r install-bioc, eval=FALSE} if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager") BiocManager::install("GExPipe", dependencies = TRUE) ``` Verify the installation: ```{r verify-bioc, eval=FALSE} library(GExPipe) packageVersion("GExPipe") ``` When installed from Bioconductor, dependencies are resolved at **install time**; `runGExPipe()` does not download packages at launch. ## From GitHub (available before Bioconductor release) Until the package is on Bioconductor, install from [GitHub](https://github.com/safarafique/GExPipe). Requires **R ≥ 4.5.0**. ```{r install-github, eval=FALSE} 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", dependencies = TRUE, INSTALL_opts = "--no-staged-install" ) ``` **Quick start without installing:** see [Run latest code for analysis](#run-latest-code) (recommended for mixed microarray merges). For **mixed microarray merges** (probe IDs across platforms), also install annotation helpers once: ```{r install-annot, eval=FALSE} if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager") BiocManager::install(c("org.Hs.eg.db", "biomaRt"), ask = FALSE, update = FALSE) ``` # Run latest code for analysis {#run-latest-code} If you installed from GitHub some time ago, reinstall or launch from the latest `main` branch so probe-ID mapping (STEP 2b) and other fixes are included: ```{r run-latest-github, eval=FALSE} if (!requireNamespace("shiny", quietly = TRUE)) install.packages("shiny") if (!requireNamespace("pkgload", quietly = TRUE)) install.packages("pkgload") shiny::runGitHub( "safarafique/GExPipe", ref = "main", subdir = "inst/shinyapp", destdir = tempfile() ) ``` ```{r run-latest-local, eval=FALSE} # Local clone setwd("path/to/GExPipe") pkgload::load_all(".") app <- GExPipe::runGExPipe(launch.browser = FALSE) shiny::runApp(app, port = 3838L) ``` ```{r run-latest-reinstall, eval=FALSE} remotes::install_github( "safarafique/GExPipe", ref = "main", force = TRUE, dependencies = TRUE, INSTALL_opts = "--no-staged-install" ) app <- GExPipe::runGExPipe(launch.browser = FALSE) shiny::runApp(app, port = 3838L) ``` # Launch the Shiny application {#launch-the-shiny-application} Bioconductor Shiny apps return an app object from the package; users start the server with `shiny::runApp()` ([Bioconductor Shiny guide](https://contributions.bioconductor.org/shiny.html#documentation)). If you need probe-ID conversion on mixed platforms, prefer [Run latest code for analysis](#run-latest-code) over a months-old install. ```{r launch, eval=FALSE} app <- GExPipe::runGExPipe() shiny::runApp(app, port = 3838L) ``` The browser opens at the **welcome screen**. Click **Go to Analysis** to begin **Step 1 - Download Data**. ```{r launch-github-auto, eval=FALSE} options(gexpipe.auto_install = TRUE) # GitHub installs only app <- GExPipe::runGExPipe() shiny::runApp(app, port = 3838L) ``` ## 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](https://github.com/safarafique/GExPipe) for full Colab cells. # Step-by-step Shiny walkthrough {#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. QC & Visualization**, **3. Normalize Data**, **4. Select Groups**, and **5. Batch Correction**. The walkthrough uses a two-study RNA-seq example (`GSE50760`, `GSE104836`); any valid GEO accessions work the same way. ### Step 1 — Download Data **Sidebar:** `1. Download Data` **Goal:** Download GEO series, map row IDs to gene symbols, and build a combined genes × samples matrix for downstream steps. **What to do:** 1. Optionally enter a **Disease / Condition** label (used in reports and saved workspace names). 2. Under **Select Analysis Platform**, choose **RNA-seq**, **Microarray**, or **Merged (Both)**. 3. Choose **Datasets** mode: - **Single dataset (1 GSE)** — Step 5 (batch correction) is skipped. - **Multiple datasets (comma-separated)** — batch correction is recommended in Step 5. 4. Select the **DE method for Step 6** (this also controls Step 3 behaviour): - **limma** — microarray, merged, or normalized log-expression. - **limma-voom**, **DESeq2**, or **edgeR** — RNA-seq integer counts. 5. Enter comma-separated **GSE IDs** (e.g. `GSE50760, GSE104836`). 6. Click **Start Processing** and read the **Download log**. 7. Click **Next: QC & Visualization**. For **multiple microarray platforms**, install `org.Hs.eg.db` and `biomaRt` (see [Installation](#installation)) so **STEP 2b** converts probe IDs to HGNC symbols before merging. **Success check:** Download log lists samples per GSE; **STEP 2b** runs when needed; row names are symbols (`TP53`, `BRCA1`, …); **Common genes** > 0. ```{r step01-screenshot, echo=FALSE, fig.cap="Step 1: Select platform, dataset mode, DE method, and GSE IDs.", out.width="100%"} knitr::include_graphics("images/step01_download.png") ``` ### Step 2 — QC & Visualization **Sidebar:** `2. QC & Visualization` **Goal:** Check gene overlap, inspect raw expression, and detect outlier samples **before** normalization. **What to do:** 1. Review **Venn** and **UpSet** plots (figure below, panel a). 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** (97.5% chi-squared threshold). - **Sample connectivity** (signed network; mean − 2×SD cutoff). 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 3. **Success check:** Overlap and QC plots look reasonable; outliers reviewed. ```{r step02a-screenshot, echo=FALSE, fig.cap="Step 2a: Venn and UpSet gene overlap.", out.width="100%"} knitr::include_graphics("images/step02a_qc.png") ``` ```{r step02b-screenshot, echo=FALSE, fig.cap="Step 2b: Raw expression boxplot.", out.width="100%"} knitr::include_graphics("images/step02b_qc.png") ``` ```{r step02c-screenshot, echo=FALSE, fig.cap="Step 2c: PCA and connectivity outlier detection.", out.width="100%"} knitr::include_graphics("images/step02c_qc.png") ``` ### Step 3 — Normalize Data **Sidebar:** `3. Normalize Data` **Goal:** Make expression values comparable across samples and datasets. **What to do:** **Count-based DE (DESeq2 / edgeR / limma-voom from Step 1):** the panel shows **Normalization Auto-Handled** — proceed with **Go to Step 4: Select Groups**. Background TMM + quantile still runs for WGCNA and heatmaps. **limma path (microarray or merged):** 1. Choose **Auto** or **Manual** under **Normalization Strategy**. 2. Microarray: **Quantile** or **RMA**; RNA-seq: **TMM + log2-CPM**. 3. Toggle **Apply global quantile normalization** if appropriate. 4. Click **Apply Normalization**. 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. Click **Next: Select Groups**. **Success check:** Q–Q points follow the diagonal; sample medians align. ```{r step03a-screenshot, echo=FALSE, fig.cap="Step 3a: Overall density and Q-Q plots after normalization.", out.width="100%"} knitr::include_graphics("images/step03a_normalize.png") ``` ```{r step03b-screenshot, echo=FALSE, fig.cap="Step 3b: Median/range alignment and distribution overlap.", out.width="100%"} knitr::include_graphics("images/step03b_normalize.png") ``` ### 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. ```{r step04a-screenshot, echo=FALSE, fig.cap="Step 4a: Select phenotype column per GSE.", out.width="100%"} knitr::include_graphics("images/step04a_groups.png") ``` ```{r step04b-screenshot, echo=FALSE, fig.cap="Step 4b: Group Summary after Apply Categorization.", out.width="100%"} knitr::include_graphics("images/step04b_groups.png") ``` ### 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. Click **Next: Differential Expression**. **Note:** Step 5 is skipped when only **one GSE** was loaded in Step 1. **Success check:** After-correction PCA (panel b) shows datasets intermingled. ```{r step05a-screenshot, echo=FALSE, fig.cap="Step 5a: Variance filtering and batch correction method.", out.width="100%"} knitr::include_graphics("images/step05a_batch.png") ``` ```{r step05b-screenshot, echo=FALSE, fig.cap="Step 5b: PCA by dataset before and after batch correction.", out.width="100%"} knitr::include_graphics("images/step05b_batch.png") ``` ## 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**. **Success check:** Volcano shows expected direction; DEG count is plausible for your contrast; pipeline verification lists the correct method and samples. ```{r step06a-screenshot, echo=FALSE, fig.cap="Step 6a: DE parameters, statistical model, and pipeline verification.", out.width="100%"} knitr::include_graphics("images/step06a_de.png") ``` ```{r step06b-screenshot, echo=FALSE, fig.cap="Step 6b: Volcano plot and top DEG table.", out.width="100%"} knitr::include_graphics("images/step06b_de.png") ``` ### Step 7 — WGCNA Network Analysis **Sidebar:** `7. 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)**. **Success check:** Soft-threshold R² ≥ 0.80; at least one module correlates with Disease; hub genes are listed for significant modules. ```{r step07a-screenshot, echo=FALSE, fig.cap="Step 7a: WGCNA data preparation and gene selection.", out.width="100%"} knitr::include_graphics("images/step07a_wgcna.png") ``` ```{r step07b-screenshot, echo=FALSE, fig.cap="Step 7b: Soft-threshold power selection.", out.width="100%"} knitr::include_graphics("images/step07b_wgcna.png") ``` ```{r step07c-screenshot, echo=FALSE, fig.cap="Step 7c: Module dendrogram and module-trait heatmap.", out.width="100%"} knitr::include_graphics("images/step07c_wgcna.png") ``` ```{r step07d-screenshot, echo=FALSE, fig.cap="Step 7d: Significant modules and hub gene summary.", out.width="100%"} knitr::include_graphics("images/step07d_wgcna.png") ``` ### Step 8 — Common Genes (DEG & WGCNA) & Enrichment **Sidebar:** `8. Common Genes (DEG & WGCNA)` **Goal:** Intersect DEGs (Step 6) with genes in significant WGCNA modules (Step 7), 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:** Steps 6 and 7 (including **Identify Significant Modules**) must be complete. **Success check:** Venn overlap > 0; GO/KEGG plots show interpretable terms. ```{r step08a-screenshot, echo=FALSE, fig.cap="Step 8a: Common genes Venn diagram (DEG intersect WGCNA).", out.width="100%"} knitr::include_graphics("images/step08a_common_genes.png") ``` ```{r step08b-screenshot, echo=FALSE, fig.cap="Step 8b: GO enrichment of common genes.", out.width="100%"} knitr::include_graphics("images/step08b_go.png") ``` ```{r step08c-screenshot, echo=FALSE, fig.cap="Step 8c: KEGG enrichment of common genes.", out.width="100%"} knitr::include_graphics("images/step08c_kegg.png") ``` ## Phase 3 — Candidate refinement ### Step 9 — PPI Interaction **Sidebar:** `9. 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 **consensus hub** table. 6. Click **Extract Data for ML** (required before Step 10). 7. Click **Next: Machine Learning Process**. **Requirements:** Step 8 common genes computed. **Success check:** Network builds with mapped edges; hub genes listed; ML extract succeeds. ```{r step09a-screenshot, echo=FALSE, fig.cap="Step 9a: Run PPI and interactive vs non-interactive gene table.", out.width="100%"} knitr::include_graphics("images/step09a_ppi.png") ``` ```{r step09b-screenshot, echo=FALSE, fig.cap="Step 9b: PPI network graph and hub gene metrics.", out.width="100%"} knitr::include_graphics("images/step09b_ppi.png") ``` ### Step 10 — Machine Learning Process **Sidebar:** `10. 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 9). 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. ```{r step10a-screenshot, echo=FALSE, fig.cap="Step 10a: Select ML methods and run analysis.", out.width="100%"} knitr::include_graphics("images/step10a_ml.png") ``` ```{r step10b-screenshot, echo=FALSE, fig.cap="Step 10b: Method overlap Venn diagram and common ML genes.", out.width="100%"} knitr::include_graphics("images/step10b_ml.png") ``` ### Step 11 — Validation **Sidebar:** `11. 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**, select **Platform Type** and **DE Method**. - Click **Download**, then browse phenodata and select the group column. - Categorize labels as Normal / Disease and click **Run Validation DE**. 3. Review validation status and DE results (panel b). 4. Click **Continue to ROC Curve Analysis**. **Requirements:** Step 10 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. ```{r step11a-screenshot, echo=FALSE, fig.cap="Step 11a: Validation mode and external validation settings.", out.width="100%"} knitr::include_graphics("images/step11a_validation.png") ``` ```{r step11b-screenshot, echo=FALSE, fig.cap="Step 11b: External validation DE results.", out.width="100%"} knitr::include_graphics("images/step11b_validation_external.png") ``` ### Step 12 — ROC Analysis **Sidebar:** `12. ROC Curve Analysis` **Goal:** Per-gene AUC with 95% CI (`r BiocStyle::CRANpkg("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 11, 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 10 common ML genes; Step 11 validation mode selected. **Success check:** At least one gene with training AUC ≥ 0.80; validation AUC reported when external data are loaded. ```{r step12a-screenshot, echo=FALSE, fig.cap="Step 12a: Training ROC curves and AUC summary.", out.width="100%"} knitr::include_graphics("images/step12a_roc.png") ``` ```{r step12b-screenshot, echo=FALSE, fig.cap="Step 12b: Training vs validation AUC comparison.", out.width="100%"} knitr::include_graphics("images/step12b_roc.png") ``` ## Phase 4 — Clinical translation The sidebar tabs for this phase are **13. Diagnostic Nomogram Model**, **14. GSEA Analysis**, and **Results Summary**. ### Step 13 — Nomogram **Sidebar:** `13. 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 10 (or common DEG ∩ WGCNA genes from Step 8). **Success check:** Nomogram renders; training AUC is reasonable; validation metrics match your chosen validation strategy. ```{r step13-screenshot, echo=FALSE, fig.cap="Step 13: Nomogram, calibration, and decision curves.", out.width="100%"} knitr::include_graphics("images/step13_nomogram.png") ``` ### Step 14 — GSEA **Sidebar:** `14. 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 12). 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 10 (or Step 8 overlap). **Success check:** GSEA completes for each target gene; enrichment plots and pathway tables are interpretable. ```{r step14-screenshot, echo=FALSE, fig.cap="Step 14: GSEA enrichment plots per signature gene.", out.width="100%"} knitr::include_graphics("images/step14_gsea.png") ``` ### Step 15 — Summary Report **Sidebar:** `Results Summary` **Goal:** Review the full pipeline narrative and key figures, then download exports where available. **What to do:** 1. Read the **Pipeline summary** narrative at the top. 2. Scroll through step cards for normalization, batch correction, DE, WGCNA, common genes, GO/KEGG, PPI, ML, ROC, nomogram, and GSEA — each with a short description and figure. 3. Use download buttons on individual plots (JPG/PDF) where you need figures for a manuscript or report. 4. Expand **Cite this analysis** for package and method references. **Success check:** Summary reflects your completed steps; key plots from earlier tabs appear in the ordered overview. ```{r step15-screenshot, echo=FALSE, fig.cap="Step 15: Results summary overview.", out.width="100%"} knitr::include_graphics("images/step15_summary.png") ``` # Gene ID mapping (mixed studies) {#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. ```{r id-formats} 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.") ``` **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): ```{r id-overlap-demo} 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" ) ``` # Programmatic example (bundled data) {#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 ```{r load-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) head(meta_tab) ``` ## Normalize and intersect datasets `gexp_normalize_and_intersect()` normalizes each dataset, intersects genes, and returns a combined matrix. ```{r normalize} 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") cat("Common genes :", length(norm_res$common_genes), "\n") ``` ## Principal component analysis ```{r pca-plot} 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 ```{r heatmap-plot} 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 {#troubleshooting} | Problem | Solution | |------------------------------------|------------------------------------| | **0 common genes after download** | Use [latest code](#run-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](#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. | | **Missing C++ compiler** | Install [Rtools](https://cran.r-project.org/bin/windows/Rtools/) (Windows). | | **glmnet / ML step skipped** | Restart R after install; ensure glmnet ≥ 4.x or 5.x loads (`packageVersion("glmnet")`). | | **Version conflicts** | `remotes::install_github("safarafique/GExPipe", ref = "main", force = TRUE, INSTALL_opts = "--no-staged-install")`. | | **Corrupt lazy-load database** | Reinstall with `INSTALL_opts = "--no-staged-install"`. | | **Corporate proxy** | `Sys.setenv(https_proxy = "http://proxy:port")` before installing. | ```{r windows-fix, eval=FALSE} options(download.file.method = "wininet") unlink( list.files(.libPaths()[1], pattern = "^00LOCK-", full.names = TRUE), recursive = TRUE, force = TRUE ) if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes") remotes::install_github( "safarafique/GExPipe", ref = "main", dependencies = TRUE, INSTALL_opts = "--no-staged-install" ) ``` # Session Information ```{r session-info} sessionInfo() ```