Written and maintained by CASRAI Editorial Board
Last updated
A heatmap in R colours the cells of a matrix by value, so patterns across many rows and columns show at a glance. You can draw one with three routes: the base heatmap() function in the stats package, pheatmap() from the pheatmap package, or geom_tile() in ggplot2. The choice matters less than three settings that change what the colours mean: scaling, clustering and, for correlation heatmaps, how cor() treats missing values.
What a heatmap is used for in research
Researchers use heatmaps to show a table of numbers as colour: expression levels across samples, a correlation matrix among variables, or counts across categories. Clustered heatmaps add dendrograms so similar rows and columns sit together. For the wider figure rules that apply once the plot is made, see designing effective scientific figures and scientific figure rules for journal submission.
Install or access (official sources only)
The base heatmap() function belongs to the stats package, which is part of a standard R installation, so nothing needs installing. The other two routes use CRAN packages:
install.packages("pheatmap")
install.packages("ggplot2")
If you are new to the R environment itself, how to use RStudio covers the interface.
Step-by-step: how to make a heatmap in R
The examples use mtcars, a data set that ships with R, so they run without any file.
Step 1. Base R: heatmap()
- Convert the data to a numeric matrix:
x <- as.matrix(mtcars). - Draw it:
heatmap(x, scale = "column").
The scale argument accepts "row", "column" or "none". Its default is "row" when symm is false and "none" otherwise. Scaling affects only the colour scale, not the underlying data. In the mtcars example the columns are different measurements on different units, which is why column scaling is chosen.
By default heatmap() reorders rows and columns using hierarchical clustering (distfun = dist, hclustfun = hclust) and draws the dendrograms. Setting Rowv = NA suppresses the row dendrogram and reordering, which keeps your rows in their original order.
Step 2. pheatmap()
- Load the package:
library(pheatmap). - Draw it:
pheatmap(as.matrix(mtcars), scale = "column").
pheatmap() is documented as a function to draw clustered heatmaps. Its defaults are scale = "none", cluster_rows = TRUE, cluster_cols = TRUE, clustering_distance_rows and clustering_distance_cols of "euclidean", and clustering_method = "complete" (any method hclust accepts). Set display_numbers = TRUE to print values in the cells (default FALSE), and pass a data frame to annotation_col to add column annotations matched by row names.
Step 3. ggplot2: geom_tile()
- Reshape the matrix to long format:
df <- as.data.frame(as.table(as.matrix(mtcars))). This gives columnsVar1,Var2andFreq. - Plot:
ggplot(df, aes(Var2, Var1)) + geom_tile(aes(fill = Freq)).
geom_tile() uses the centre of each tile and its size. geom_raster() is documented as a high-performance special case for when all tiles are the same size. Because geom_tile() does no clustering, order the rows and columns yourself if you need clusters.
How to make a correlation heatmap in R
A correlation heatmap colours the output of cor(). The signature is cor(x, y = NULL, use = "everything", method = c("pearson", "kendall", "spearman")).
- Compute the matrix:
r <- cor(mtcars). Addmethod = "spearman"for rank correlation. - Base R:
heatmap(r, symm = TRUE). For a square symmetric matrix,symm = TRUEis the documented setting, and it also makes the default scaling"none". - pheatmap:
pheatmap(r, display_numbers = TRUE). The defaultscale = "none"already leaves correlations unscaled. - ggplot2:
rdf <- as.data.frame(as.table(r))thenggplot(rdf, aes(Var1, Var2, fill = Freq)) + geom_tile().
Do not row-scale a correlation matrix. With the base default (scale = "row" when symm is false) the colours no longer show the correlation coefficients themselves, which is an easy silent mistake.
Output and how to read it
- Colour encodes the value after any scaling. With
scale = "row"or"column"it shows position relative to that row or column, not the raw number. - Dendrograms show the hierarchical clustering. Rows or columns that join low in the tree are more similar under the chosen distance and linkage (
distandhclustdefaults in base R; euclidean and complete in pheatmap). - Row and column order follows the clustering unless you switched it off, so two heatmaps of the same data can look different if the clustering settings differ.
In a Methods section, report the correlation method, the use setting, any scaling, and the distance and linkage used for clustering. Those four choices are what a reader needs to reproduce the figure.
Troubleshooting
The correlation heatmap has blank cells or NA
The default is use = "everything", so a correlation is NA whenever a contributing observation is NA. Other documented options are "all.obs" (an error if any NA), "complete.obs", "na.or.complete" and "pairwise.complete.obs". Note that the pairwise option can return a matrix that is not positive semi-definite and may still contain NA.
The colours do not match the numbers
Check scale. Base heatmap() defaults to "row" for non-symmetric input; pheatmap defaults to "none".
The rows moved
Clustering reorders them. In base R set Rowv = NA; in pheatmap set cluster_rows = FALSE.
The ggplot2 tiles have gaps or uneven sizes
With geom_tile() each tile has its own centre and size. Use geom_raster() only when all tiles are the same size.
Alternatives in R (comparison table)
| Approach | Package | Clusters by default | Default scaling |
|---|---|---|---|
heatmap() |
stats (base R) | Yes, with dendrograms (dist, hclust) |
"row" unless symm = TRUE |
pheatmap() |
pheatmap | Yes (euclidean, complete) | "none" |
geom_tile() / geom_raster() |
ggplot2 | No; you order the data | None; you transform the data |
For other common figure types in R, see histograms in R, scatterplots in R and box plots in R.
FAQ
How do I make a heatmap in R?
Convert your data to a numeric matrix and call heatmap(x) from base R, or pheatmap(x) after loading the pheatmap package. For a ggplot2 version, reshape to long format and use geom_tile(aes(fill = value)).
How do I make a correlation heatmap in R?
Compute r <- cor(data), then pass it to heatmap(r, symm = TRUE) or pheatmap(r). Decide the use argument first if your data has missing values.
Should I scale the data before plotting?
Scale when variables are on different units and you want to compare patterns, not raw size. Do not scale a correlation matrix.
Sources (official documentation, checked 2026-10-29)
- R documentation, stats package: heatmap
- R documentation, stats package: cor
- pheatmap reference (CRAN manual page): pheatmap: Pretty Heatmaps
- ggplot2 reference: geom_tile and geom_raster








