{"id":27452189,"url":"https://github.com/epigen/dea_limma","last_synced_at":"2025-04-15T11:41:49.459Z","repository":{"id":65276660,"uuid":"524038188","full_name":"epigen/dea_limma","owner":"epigen","description":"A Snakemake workflow and MrBiomics module for performing and visualizing differential (expression) analyses (DEA) on NGS data powered by the R package limma.","archived":false,"fork":false,"pushed_at":"2025-03-06T10:50:21.000Z","size":151,"stargazers_count":26,"open_issues_count":4,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-12T11:23:54.995Z","etag":null,"topics":["atac-seq","bioinformatics","biomedical-data-science","chip-seq","differential-expression-analysis","limma","limma-trend","limma-voom","r","rna-seq","scrna-seq","snakemake","statistics","visualization","volcano-plot","workflow"],"latest_commit_sha":null,"homepage":"https://epigen.github.io/dea_limma/","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/epigen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-08-12T10:02:19.000Z","updated_at":"2025-04-09T07:05:03.000Z","dependencies_parsed_at":"2023-12-31T00:13:21.047Z","dependency_job_id":"e7bef300-771c-4811-ad8c-adb8c4a48483","html_url":"https://github.com/epigen/dea_limma","commit_stats":{"total_commits":60,"total_committers":3,"mean_commits":20.0,"dds":"0.23333333333333328","last_synced_commit":"baf6cdcd38fc6f2a41354c5a309f2cc00112adcc"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epigen%2Fdea_limma","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epigen%2Fdea_limma/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epigen%2Fdea_limma/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epigen%2Fdea_limma/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/epigen","download_url":"https://codeload.github.com/epigen/dea_limma/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249063491,"owners_count":21206916,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atac-seq","bioinformatics","biomedical-data-science","chip-seq","differential-expression-analysis","limma","limma-trend","limma-voom","r","rna-seq","scrna-seq","snakemake","statistics","visualization","volcano-plot","workflow"],"created_at":"2025-04-15T11:41:48.889Z","updated_at":"2025-04-15T11:41:49.421Z","avatar_url":"https://github.com/epigen.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![MrBiomics](https://img.shields.io/badge/MrBiomics-red)](https://github.com/epigen/MrBiomics/)\n[![DOI](https://zenodo.org/badge/524038188.svg)](https://zenodo.org/badge/latestdoi/524038188)\n[![](https://tokei.rs/b1/github/epigen/dea_limma?category=code)]() \n[![](https://tokei.rs/b1/github/epigen/dea_limma?category=files)]()\n[![GitHub license](https://img.shields.io/github/license/epigen/dea_limma)](https://github.com/epigen/dea_limma/blob/master/LICENSE)\n![GitHub Release](https://img.shields.io/github/v/release/epigen/dea_limma)\n[![Snakemake](https://img.shields.io/badge/Snakemake-\u003e=8.20.1-green)](https://snakemake.readthedocs.io/en/stable/)\n\n# Differential Analysis \u0026 Visualization Snakemake Workflow Using _limma_\nA [Snakemake 8](https://snakemake.readthedocs.io/en/stable/) workflow for performing and visualizing differential expression (or accessibility) analyses (DEA) of NGS data (eg RNA-seq, ATAC-seq, scRNA-seq,...) powered by the R package [_limma_](https://www.bioconductor.org/packages/release/bioc/html/limma.html).\n\n\u003e [!NOTE]  \n\u003e This workflow adheres to the module specifications of [MrBiomics](https://github.com/epigen/MrBiomics), an effort to augment research by modularizing (biomedical) data science. For more details, instructions, and modules check out the project's repository.\n\u003e\n\u003e ⭐️ **Star and share modules you find valuable** 📤 - help others discover them, and guide our focus for future work!\n\n\u003e [!IMPORTANT]  \n\u003e **If you use this workflow in a publication, please don't forget to give credit to the authors by citing it using this DOI [10.5281/zenodo.7808516](https://doi.org/10.5281/zenodo.7808516).**\n\n![Workflow Rulegraph](./workflow/dags/rulegraph.svg)\n\n# 🖋️ Authors\n- [Stephan Reichl](https://github.com/sreichl)\n- [Lukas Folkman](https://github.com/lukas-folkman)\n- [Christoph Bock](https://github.com/chrbock)\n\n\n# 💿 Software\nThis project wouldn't be possible without the following software and their dependencies:\n\n| Software       | Reference (DOI)                                   |\n| :------------: | :-----------------------------------------------: |\n| edgeR          | https://doi.org/10.1093/bioinformatics/btp616     |\n| EnhancedVolcano| https://doi.org/10.18129/B9.bioc.EnhancedVolcano  |\n| ggplot2        | https://ggplot2.tidyverse.org/                    |\n| patchwork      | https://CRAN.R-project.org/package=patchwork      |\n| pheatmap       | https://cran.r-project.org/package=pheatmap       |\n| _limma_        | https://doi.org/10.1093/nar/gkv007                |\n| Snakemake      | https://doi.org/10.12688/f1000research.29032.2    |\n\n# 🔬 Methods\nThis is a template for the Methods section of a scientific publication and is intended to serve as a starting point. Only retain paragraphs relevant to your analysis. References [ref] to the respective publications are curated in the software table above. Versions (ver) have to be read out from the respective conda environment specifications (`workflow/envs/*.yaml file`) or post-execution in the result directory (`dea_limma/envs/*.yaml`). Parameters that have to be adapted depending on the data or workflow configurations are denoted in squared brackets e.g., [X].\n\n__Differential Expression Analysis (DEA).__ DEA was performed on the quality-controlled filtered [raw/normalized] counts using the _limma_ (ver) [ref] workflow for fitting a linear model [formula] to identify features (genes/regions) that statistically significantly change with [comparisons] compared to the control group [reference levels] (intercept). Briefly, we determined normalization factors with edgeR::calcNormFactors (optional) using method [X], then applied voom (optional) to estimate the mean-variance relationship of the log-counts. We used blocking on (optional) variable [X] to account for repeated measurements, lmFit to fit the model to the data, and finally eBayes (optional) with the robust (and trend flag – optional for normalized data) flag to compute (moderated/ordinary) t-statistics. For each comparison we used topTable to extract feature-wise average expression, effect sizes (log2 fold change) and their statistical significance as adjusted p-values, determined using the Benjamini-Hochberg method. Furthermore, we calculated feature scores, for each feature in all comparisons, using the formula [score_formula] for downstream ranked enrichment analyses. Next, these results were filtered for relevant features based on the following criteria: statistical significance (adjusted p-value \u003c [X]), effect size (absolute log2 fold change \u003e [X]), and expression (average expression \u003e [X]). Finally, we performed hierarchical clustering on the effect sizes (log2 fold changes) of the union of all relevant features and comparison groups.\n\n__Visualization.__ The filtered result statistics, i.e., number of relevant features split by positive (up) and negative (down) effect sizes, were visualized with stacked bar plots using ggplot (ver) [ref].\nTo visually summarize results of all performed comparisons, the effect size (log2 fold change) values of all relevant features in at least one comparison were plotted in a hierarchically clustered heatmap using pheatmap (ver) [ref]. \nVolcano plots were generated for each comparison using EnhancedVolcano (ver) [ref] with adjusted p-value threshold of [pCutoff] and log2 fold change threshold of [FCcutoff] as visual cut-offs for the y- and x-axis, respectively.\nFinally, quality control plots of the fitted mean-variance relationship and raw p-values of the features were generated.\n\n**The analysis and visualizations described were performed using a publicly available Snakemake (ver) [ref] workflow (ver) [[10.5281/zenodo.7808516](https://doi.org/10.5281/zenodo.7808516)].**\n\n# 🚀 Features\nThe workflow performs the following steps that produce the outlined results:\n\n- Differential Expression Analysis (DEA) steps:\n  - (optional) calculation of normalization factors using __edgeR::calcNormFactors__.\n  - (optional) calculation of precision weights to model the mean-variance relationship in order to make linear models \"applicable\" to count data (weighted least squares) using __voom__.\n  - (optional) __block__ on a \"group\" factor in case you have repeated measurements (generalized least squares).\n      - example use-case: you have N donors and T timepoints for each donor and want to model donor specific information like age, but still want to account for the variable __donor__ ie ~\u0026nbsp;*timepoint*\u0026nbsp;+\u0026nbsp;*age*\u0026nbsp;+\u0026nbsp;*donor* is overdetermined hence the formula becomes ~\u0026nbsp;*timepoint*\u0026nbsp;+\u0026nbsp;*age* and you \"block\" on __donor__.\n  - fit linear models (ordinary least squares) with the design derived from the configured formula (expects \"normal\" data) using __lmFit__.\n      - the fitted model object is saved (lmfit_object.rds) for alternative downstream analyses or manual inspection e.g., contrasts (see instructions below in [Contrasts](#contrasts)).\n  - (optional) improve variance estimation using __eBayes__ with the robustness flag (`robust=TRUE`), which applies a robust empirical Bayes approach that downweights extreme variance estimates via winsorization, stabilizing hyperparameters across all genes (i.e., shrinking them toward a common value) and yielding moderated t-statistics and p-values that are more reliable in heterogeneous datasets.\n      - (optional) eBayes with __limma-trend__ (trend=TRUE)\n  - extract all statistics for variables of interest (=configured comparisons) using __topTable__ (eg coefficients/effect size, statistical significance,...).\n  - save a feature list per comparison group and direction of change (up/down) for downstream analyses (eg enrichment analysis) (TXT).\n    - (optional) annotated feature list with suffix \"_annot\" (TXT).\n  - (optional) save feature score tables (with two columns: \"feature\" and \"score\") per comparison group using score_formula for downstream analyses (eg ranked enrichment analysis) (CSV).\n    - (optional) annotated feature scores tables (with two columns: \"feature_name\" and \"score\") with suffix \"_annot\" (CSV).\n- DEA result statistics: total number of statistically significant features and split by positive (up) and negative (down) change (CSV).\n- DEA result filtering of features (eg genes) by \n  - statistical significance (\u003c= adjusted p-value: adj_pval)\n  - effect size (\u003e= absolute log 2 fold change: lfc)\n  - average expression (\u003e= ave_expr) in the data (to skip this filter use `-Inf`)\n- Visualizations\n  - filtered DEA result statistics ie number of features and direction (stacked bar plots)\n  - volanco plots per comparison with effect size on the x-axis and raw p-value(rawp)/adjusted p-value (adjp) on the y-axis\n      - highlighting features according to configured cut-offs for statistical significance (pCutoff) and effect size (FCcutoff)\n      - (optional) highlighting features according to configured feature lists\n  - hierarchically clustered heatmap of effect sizes (LFC) per comparison (features x comparisons) indicating statistical significance with a star '\\*'\n      - using all relevant features (FILTERED)\n      - (optional) using configured feature lists\n      - in case of more than 100 features the row labels and significance indicators (\\*) are removed\n      - in case of more than 50000 features no heatmap is generated\n  - diagnostic quality control plots\n      - (optional) voom mean-variance trend\n      - (optional) intermediate mean-variance trend, in case of blocking and vooming\n      - post-fitting mean-variance trend\n      - raw p-value distributions (to check for p-value inflation in relation to average expression)\n\n\u003e [!NOTE]  \n\u003e - Colons (\":\") in variable/group names (i.e., interactions) are replaced with double-underscores (\"\\_\\_\") downstream.\n\u003e - We do not support more complex contrast scenarios than are supported via topTable, but the fitted linear model is saved for downstream analyses (see instructions below in [Contrasts](#contrasts)).\n\n\n# 🛠️ Usage\nHere are some tips for the usage of this workflow:\n- _limma_ usage and best practices are not explained. For deatiled documentation, tutorials and insctructions see [Resources](#resources). To understand the implementation at hand see [limma.R](./workflow/scripts/limma.R).\n- Perform your first run(s) with loose filtering options/cut-offs and use the same for visualization to see if further filtering is even necessary or useful.\n- Test minimal complex configurations on a subset of your data.\n- Start with simple models and try to understand the results.\n\n# ⚖️ Contrasts\nCurrently, we do not support contrasts. If you have any idea how to implement contrasts, feel invited to reach out.\nIf you require contrasts to ask questions your model does not answer, just load the fitted model and perform the contrast manually (see examle in [_limma's_ User's Guide](https://www.bioconductor.org/packages/devel/bioc/vignettes/limma/inst/doc/usersguide.pdf) chapter 9.5):\n```R\n# load model and design\nfit \u003c- readRDS(file.path('{result_path}/dea_limma/{analysis}/lmfit_object.rds'))\ndesign \u003c- data.frame(fread(file.path(\"{result_path}/dea_limma/{analysis}/model_matrix.csv\"), header=TRUE), row.names=1)\n\n# define and create contrasts of interest\n# e.g., if you modeled \"~ 0 + group\", where group = {celltype}_{genotype}\n# you can find the genotype effect for cell types A, B, C using the following contrasts\ncontrasts_all \u003c- list(\n                ctA = \"groupCelltypeA_KO - groupCelltypeA_WT\",\n                ctB = \"groupCelltypeB_KO - groupCelltypeB_WT\",\n                ctC = \"groupCelltypeC_KO - groupCelltypeC_WT\"\n                )\ncontrast_matrix \u003c- makeContrasts(contrasts=contrasts_all, levels = design)\n\n# perform contrasts\nfit2 \u003c- contrasts.fit(fit, contrast_matrix)\n\n# estimate/correct variance with eBayes\nfit2 \u003c- eBayes(fit2, robust=TRUE)\n\n# extract results\ncontrast_result \u003c- data.frame()\n\nfor(coefx in colnames(coef(fit2))){\n    tmp_res \u003c- topTable(fit2, coef=coefx, number=nrow(fit2), sort.by=\"P\")\n    tmp_res$feature \u003c- rownames(tmp_res)\n    tmp_res \u003c- tmp_res[,c(ncol(tmp_res),1:(ncol(tmp_res)-1))]\n    rownames(tmp_res) \u003c- NULL\n    \n    # beautify group names by replacing them (the contrast formula) with the names of the comparison\n    tmp_res$group \u003c- names(contrasts_all)[contrasts_all == coefx]\n    \n    if(dim(contrast_result)[1]==0){\n        contrast_result \u003c- tmp_res\n    }else{\n        contrast_result \u003c- rbind(contrast_result, tmp_res)\n    }\n}\n\n# remove rows with adj.P.Val=NA\ncontrast_result \u003c- contrast_result[!is.na(contrast_result$adj.P.Val),]\n\n# save results\nfwrite(as.data.frame(contrast_result), file=file.path(\"path/to/contrast_results.csv\"), row.names=FALSE)\n\n# process and visualize results as you wish, feel free to reuse code from this module\n```\n\n# ⚙️ Configuration\nDetailed specifications can be found here [./config/README.md](./config/README.md)\n\n# 📖 Examples\n--- COMING SOON ---\n\n# 🔗 Links\n- [GitHub Repository](https://github.com/epigen/dea_limma/)\n- [GitHub Page](https://epigen.github.io/dea_limma/)\n- [Zenodo Repository](https://doi.org/10.5281/zenodo.7808516)\n- [Snakemake Workflow Catalog Entry](https://snakemake.github.io/snakemake-workflow-catalog?usage=epigen/dea_limma)\n\n# 📚 Resources\n- Recommended compatible [MrBiomics](https://github.com/epigen/MrBiomics) modules \n  - for upstream analyses:\n    - [ATAC-seq Processing](https://github.com/epigen/atacseq_pipeline) to quantify chromatin accessibility.\n    - [scRNA-seq Data Processing \u0026 Visualization](https://github.com/epigen/scrnaseq_processing_seurat) for processing (multimodal) single-cell transcriptome data.\n    - [\u003cins\u003eSp\u003c/ins\u003elit, F\u003cins\u003eilter\u003c/ins\u003e, Norma\u003cins\u003elize\u003c/ins\u003e and \u003cins\u003eIntegrate\u003c/ins\u003e Sequencing Data](https://github.com/epigen/spilterlize_integrate/) after count quantification.\n  - for downstream analyses:\n    - [Enrichment Analysis](https://github.com/epigen/enrichment_analysis) for biomedical interpretation of (differential) analysis results using prior knowledge.\n    - [Unsupervised Analysis](https://github.com/epigen/unsupervised_analysis) to understand and visualize similarities and variations between cells/samples, including dimensionality reduction and cluster analysis. Useful for all tabular data including single-cell and bulk sequencing data.\n    - [Genome Browser Track Visualization](https://github.com/epigen/genome_tracks/) for quality control and visual inspection/analysis of genomic regions/genes of interest or top hits.\n- [Bioconductor - _limma_](http://bioconductor.org/packages/release/bioc/html/limma.html) includes a 150 page [User's Guide](https://www.bioconductor.org/packages/devel/bioc/vignettes/limma/inst/doc/usersguide.pdf)\n- [R Manual on Model Formulae](https://stat.ethz.ch/R-manual/R-patched/library/stats/html/formula.html)\n- [Bioconductor - RNAseq123 - Workflow](https://bioconductor.org/packages/release/workflows/html/RNAseq123.html)\n- _limma_ workflow tutorial RNA-seq analysis is easy as 1-2-3 with _limma_, Glimma and edgeR\n    - [notebook](https://bioconductor.org/packages/release/workflows/vignettes/RNAseq123/inst/doc/limmaWorkflow.html)\n    - [paper](https://f1000research.com/articles/5-1408/v3)\n- A guide to creating design matrices for gene expression experiments\n    - [notebook](https://bioconductor.org/packages/release/workflows/vignettes/RNAseq123/inst/doc/designmatrices.html)\n    - [paper](https://f1000research.com/articles/9-1444/v1)\n- voom: precision weights unlock linear model analysis tools for RNA-seq read counts\n    - [paper](https://genomebiology.biomedcentral.com/articles/10.1186/gb-2014-15-2-r29)\n- scRNA-seq DEA benchmark paper featuring _limma_-voom and _limma_-trend as valid/best methods\n    - [paper: Bias, robustness and scalability in single-cell differential expression analysis](https://www.nature.com/articles/nmeth.4612)\n    - [code](https://github.com/csoneson/conquer_comparison)\n- scRNA-seq DEA benchmark featuring _limma_-voom and _limma_-trend emphasizing pseudo-bulking\n    - [paper: Confronting false discoveries in single-cell differential expression](https://www.nature.com/articles/s41467-021-25960-2)\n- alternative/complementary DEA method: Linear Mixed Models (LMM)\n    - [variancePartition](https://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-016-1323-z)\n    - [dream](https://academic.oup.com/bioinformatics/article/37/2/192/5878955)\n\n# 📑 Publications\nThe following publications successfully used this module for their analyses.\n- [FirstAuthors et al. (202X) Journal Name - Paper Title.](https://doi.org/10.XXX/XXXX)\n- ...\n\n# ⭐ Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=epigen/dea_limma\u0026type=Date)](https://star-history.com/#epigen/dea_limma\u0026Date)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepigen%2Fdea_limma","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fepigen%2Fdea_limma","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepigen%2Fdea_limma/lists"}