# Volcano plot maker for differential expression

> Paste gene, log2 fold change and p-value to make a labelled volcano plot. Benjamini–Hochberg FDR, up/down counts, SVG and PNG export, CSV of hits.

URL: https://www.labcanvas.com/tools/volcano-plot-maker

Paste a differential-expression table (gene, log2 fold change, p-value, and the adjusted p-value if you have it) from DESeq2, edgeR, limma, proteomics or any t-tests. Set the fold-change and p or FDR thresholds, and the tool draws a volcano plot of log2 fold change against −log10 p, colours up-regulated, down-regulated and non-significant genes, labels the top genes and counts the hits. If you only have raw p-values it computes Benjamini–Hochberg adjusted p-values. Download the plot as SVG or 300 dpi PNG and the significant genes as CSV.

## Quick answer

- **What it does:** Draws a volcano plot (log2 fold change vs −log10 p) from a pasted gene table, adjusts p-values by Benjamini–Hochberg if needed, colours and counts up- and down-regulated genes and labels the top hits.
- **Formula:** Up: log2FC ≥ t and p_adj < α; down: log2FC ≤ −t and p_adj < α; BH p_adj(i) = min over j ≥ i of p₍ⱼ₎ · m / j (p sorted ascending, m tests); y = −log10 p.
- **Example:** In the built-in table of 1,000 genes, FDR < 0.05 and |log2FC| ≥ 1 give 25 up and 16 down; the top gene has p = 3.42 × 10⁻¹² and p_adj = 3.42 × 10⁻¹² × 1000 / 1 = 3.42 × 10⁻⁹.

Free, in the browser, no account needed. Updated 2026-10-19.

## Features

- Paste from Excel, R or CSV: DESeq2 (log2FoldChange, pvalue, padj), edgeR (logFC, PValue, FDR) and limma (logFC, P.Value, adj.P.Val) headers recognised
- Benjamini–Hochberg adjusted p-values computed when the table has only raw p-values
- Thresholds on |log2 fold change| and on raw p or FDR, with dashed threshold lines
- Up, down and not-significant colours (colour-blind-safe defaults, changeable)
- Top N genes labelled (smallest p first), nudged so labels do not overlap
- Counts of up- and down-regulated genes on the plot and in the results
- Publication-ready SVG and 300 dpi PNG; CSV of significant genes with direction
- Runs in your browser: your gene list is not uploaded

## How to use it

1. **Paste the results table**: Copy the gene, log2 fold change and p-value columns (and padj / FDR if present) with their header row from Excel or R.
2. **Set the thresholds**: Choose the fold-change cut-off (1 = 2-fold) and the significance level, on the adjusted p-value (FDR, recommended) or the raw p-value.
3. **Label and export**: Choose how many top genes to label, adjust colours and title, then download the plot as SVG or PNG and the significant genes as CSV.

## At a glance

| | |
| --- | --- |
| Input | Gene, log2 fold change, p-value and optionally adjusted p (DESeq2, edgeR, limma headers recognised) |
| Axes | \(x = \log_2\) fold change, \(y = -\log_{10}\) p-value |
| Significance | \(\lvert\log_2\mathrm{FC}\rvert \ge \text{threshold}\) and adjusted p (FDR) or raw p below \(\alpha\) |
| Adjustment | Benjamini–Hochberg (1995), the same as R’s p.adjust("BH") and DESeq2’s padj |
| Labels | Top N genes by p-value, de-overlapped |
| Export | SVG and 300 dpi PNG plot; CSV of significant genes |

## How it works

A volcano plot shows every gene (or protein, metabolite) at \(x = \log_2\) fold change and \(y = -\log_{10}\) p-value, so large, reliable changes sit at the top left (down) and top right (up) and look like the plume of a volcano (Li 2012). A log₂ fold change of 1 is a 2-fold change; 0.585 is 1.5-fold. On the y axis, \(p = 0.05\) is at 1.30, \(p = 0.001\) at 3 and \(p = 10^{-10}\) at 10.

**Classification.** A gene is *up* if \(\log_2\mathrm{FC} \ge t\) and its p-value is below \(\alpha\), *down* if \(\log_2\mathrm{FC} \le -t\) and \(p \lt \alpha\), and *not significant* otherwise. You choose whether \(\alpha\) applies to the adjusted p-value (the false discovery rate, the standard for genome-wide data) or the raw p-value. The y axis always shows the raw p-value, as in DESeq2 and EnhancedVolcano; with FDR the horizontal line is drawn at the largest raw p whose adjusted p passes, so the line still separates significant from not.

**Benjamini–Hochberg adjustment.** With \(m\) p-values sorted from smallest to largest, \(p_{(1)} \le \dots \le p_{(m)}\), the adjusted value of the \(i\)-th is \(p_\mathrm{adj}(i) = \min_{j \ge i}\, (p_{(j)} \cdot m / j)\), capped at 1. Calling every gene with \(p_\mathrm{adj} \lt \alpha\) keeps the expected proportion of false discoveries among the hits at or below \(\alpha\) (Benjamini and Hochberg 1995). This is R’s `p.adjust(method = "BH")` and the `padj` column of DESeq2. If your table already has an adjusted column (padj, FDR, q-value, adj.P.Val), the tool uses it.

**By hand.** Five p-values 0.005, 0.01, 0.03, 0.04, 0.5 (\(m = 5\)): the raw products \(p \cdot m / \text{rank}\) are 0.025, 0.025, 0.05, 0.05, 0.5; taking the running minimum from the largest down leaves them unchanged, so at \(\mathrm{FDR} \lt 0.05\) only the first two are significant, although four have \(p \lt 0.05\).

p-values reported as 0 (below the precision of the software) are drawn at the smallest non-zero p in the data divided by 10, so they stay on the plot.

Sources: Benjamini Y, Hochberg Y. Controlling the false discovery rate: a practical and powerful approach to multiple testing. *J R Stat Soc B* 1995;57:289–300, [doi:10.1111/j.2517-6161.1995.tb02031.x](https://doi.org/10.1111/j.2517-6161.1995.tb02031.x). Li W. Volcano plots in analyzing differential expressions with mRNA microarrays. *J Bioinform Comput Biol* 2012;10:1231003, [doi:10.1142/S0219720012310038](https://doi.org/10.1142/S0219720012310038).

## Worked example: 1,000 genes with raw p-values

The built-in table is synthetic: 1,000 genes with a log₂ fold change and a raw p-value, of which 40 were simulated as changed (24 up, including hypoxia-response genes such as *VEGFA* and *CA9*, and 16 down, proliferation genes such as *MKI67*). There is no adjusted column, so the tool computes Benjamini–Hochberg adjusted p-values.

- **Adjustment.** The smallest p-value, *DDIT4* (log₂FC 2.21, \(p = 3.42 \times 10^{-12}\)), has rank 1, so \(p_\mathrm{adj} = 3.42 \times 10^{-12} \times 1000 / 1\) \(= 3.42 \times 10^{-9}\). *VEGFA* (log₂FC 3.06, \(p = 2.48 \times 10^{-10}\)) ranks 5th: \(2.48 \times 10^{-10} \times 1000 / 5 = 4.96 \times 10^{-8}\).
- **Thresholds.** With \(\mathrm{FDR} \lt 0.05\) and \(\lvert\log_2\mathrm{FC}\rvert \ge 1\) (2-fold), the plot shows **25 up and 16 down**. 103 genes pass \(\mathrm{FDR} \lt 0.05\) on their own; the largest raw p among them is 0.00469, which is where the horizontal line is drawn (\(-\log_{10} 0.00469 = 2.33\)). 230 genes have a raw \(p \lt 0.05\), which shows why the fold-change cut-off and the adjustment matter.
- **One false positive.** Of the 25 up genes, 24 are the simulated changes and one (GENE0386, log₂FC 1.01, \(p = 0.00061\)) is a null gene that crossed both lines by chance: 1 of 41 calls, within the 5% false discovery rate.
- **Looser threshold.** At 1.5-fold (\(\lvert\log_2\mathrm{FC}\rvert \ge 0.585\)) the counts rise to 35 up and 27 down; at \(\mathrm{FDR} \lt 0.01\) and 2-fold they fall to 24 up and 15 down.

| Fold change | \(\log_2\mathrm{FC}\) | p-value | \(-\log_{10} p\) |
| --- | --- | --- | --- |
| 1.5× up / down | ±0.585 | 0.05 | 1.30 |
| 2× up / down | ±1 | 0.01 | 2 |
| 4× up / down | ±2 | 0.001 | 3 |
| 8× up / down | ±3 | \(10^{-6}\) | 6 |

| Software | Fold change | p-value | Adjusted p |
| --- | --- | --- | --- |
| DESeq2 | log2FoldChange | pvalue | padj |
| edgeR | logFC | PValue | FDR |
| limma | logFC | P.Value | adj.P.Val |

## Questions

### How do I make a volcano plot from my data?

Paste the gene, log2 fold change and p-value columns (with headers) into the box, set the fold-change and FDR thresholds, and the plot appears. Download it as SVG or a 300 dpi PNG; the significant genes download as CSV.

### How do I make a volcano plot in Excel?

Excel can do it as a scatter chart of log2FC against =-LOG10(p), with colours set by hand for each group of points. This tool does the same from a pasted Excel range, adds the FDR adjustment, labels and counts, and exports a figure.

### Should I use the p-value or the adjusted p-value (FDR)?

Use the adjusted p-value for genome-wide data: with 20,000 genes, about 1,000 would have p < 0.05 by chance alone. The y axis still shows the raw p-value, as in DESeq2 and EnhancedVolcano; only the colouring follows the FDR.

### What log2 fold change cut-off should I use?

A log2 fold change of 1 (2-fold) is the most common; 0.585 (1.5-fold) is also used, especially for proteomics. The cut-off is a convention, so state it in the figure legend together with the FDR threshold.

### How is the Benjamini–Hochberg FDR calculated?

Sort the m p-values from smallest to largest, multiply each by m and divide by its rank, then go up the list from the bottom keeping the running minimum, and cap at 1. A gene with an adjusted p below 0.05 is significant at 5% FDR.

### What does −log10 p mean on the y axis?

It turns small p-values into large numbers: \(p = 0.05\) is 1.3, \(p = 0.01\) is 2 and \(p = 10^{-8}\) is 8. The higher a point, the stronger the evidence that the gene changed.

### Why do some genes have p = 0?

DESeq2, edgeR and R report p-values below about \(10^{-308}\) as 0. The tool draws them at the smallest non-zero p in the table divided by 10 and says how many there are.

### Can I use it for proteomics or metabolomics?

Yes. Any table of features with a log2 fold change and a p-value works: proteins, metabolites, lipids or phosphosites.
