The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
ggcorrplot draws a correlation matrix as a ggplot2 plot. Because the result is an ordinary ggplot object, you keep the full ggplot2 vocabulary: restyle it with a theme, add layers or annotations, and compose it with other plots using +.
This vignette walks through the package end to end: computing the inputs, choosing a glyph and layout, reordering by clustering, adding the coefficients, marking statistical significance, and restyling the result.
Every plot starts from a correlation matrix. The examples use the built-in mtcars data set.
data(mtcars)
corr <- round(cor(mtcars), 1)
corr[1:5, 1:5]
#> mpg cyl disp hp drat
#> mpg 1.0 -0.9 -0.8 -0.8 0.7
#> cyl -0.9 1.0 0.9 0.8 -0.7
#> disp -0.8 0.9 1.0 0.8 -0.7
#> hp -0.8 0.8 0.8 1.0 -0.4
#> drat 0.7 -0.7 -0.7 -0.4 1.0To mark significance later, you also need the matrix of correlation p-values. cor_pmat() computes it with stats::cor.test():
p.mat <- cor_pmat(mtcars)
p.mat[1:5, 1:5]
#> mpg cyl disp hp drat
#> mpg 0.000000e+00 6.112687e-10 9.380327e-10 1.787835e-07 1.776240e-05
#> cyl 6.112687e-10 0.000000e+00 1.802838e-12 3.477861e-09 8.244636e-06
#> disp 9.380327e-10 1.802838e-12 0.000000e+00 7.142679e-08 5.282022e-06
#> hp 1.787835e-07 3.477861e-09 7.142679e-08 0.000000e+00 9.988772e-03
#> drat 1.776240e-05 8.244636e-06 5.282022e-06 9.988772e-03 0.000000e+00ggcorrplot() never computes correlations itself — it takes a matrix you already have. That means it works equally well with a partial correlation matrix, a distance-derived similarity, or any other square matrix in [-1, 1] (and, with legend.limit = NULL, matrices outside that range such as a covariance matrix).
The default encodes each correlation as a colored square. method = "circle" encodes the value with the circle’s area instead, which reads well when you want the magnitude to pop out.
When method = "circle", circle.scale tunes the circle sizes for your output device.
Ordering the variables by hierarchical clustering brings correlated variables next to each other, so the block structure becomes visible. Set hc.order = TRUE; hc.method chooses the linkage (as in hclust()).
hc.rect then draws rectangles around the clusters obtained by cutting the tree into k groups — a quick way to highlight the blocks.
For a symmetric matrix the two triangles carry the same information, so you can show just one with type = "lower" or type = "upper".
ggcorrplot(corr, hc.order = TRUE, type = "lower", outline.color = "white")
ggcorrplot(corr, hc.order = TRUE, type = "upper", outline.color = "white")A mixed layout draws a different glyph in each triangle. Set lower.method and/or upper.method to "square", "circle", or "number"; the variable names are placed on the diagonal. A common choice is the coefficients as numbers on one side and circles on the other. Adding cell.grid = TRUE boxes every cell so the glyphs sit in a tidy grid:
ggcorrplot(corr,
lower.method = "number", upper.method = "circle",
cell.grid = TRUE, show.legend = FALSE
)With "number", the coefficient text is colored by its value on the fill ramp, darkened over a light background so the polarity still reads at a glance while a near-zero coefficient stays legible. Over a dark background the ramp is used as given, since its pale middle is then the readable end. The background is read from ggtheme, so pass a dark theme there rather than adding it afterwards with +.
lab = TRUE prints the correlation coefficient in each cell. lab_size, lab_col, and lab_fontface control its appearance.
Two options match common conventions for correlation tables:
leading.zero = FALSE drops the leading zero (.85 instead of 0.85).nsmall keeps a fixed number of decimals (e.g. nsmall = 2 shows 0.70).ggcorrplot(cor(mtcars[, 1:6]),
lab = TRUE, lab_size = 3.5,
leading.zero = FALSE, nsmall = 2,
type = "lower"
)Supplying p.mat lets the plot convey which correlations are significant at sig.level (default 0.05). There are three styles, chosen with insig. sig.level sets the cut-off used by the first two; the third labels each cell with stars at the conventional fixed thresholds instead.
insig = "pch" (default) crosses out the non-significant cells:
insig = "blank" hides them entirely:
insig = "stars" flips the emphasis: rather than crossing out the non-significant cells, it marks the significant ones with significance stars (***, **, * for p <= 0.001, 0.01, 0.05 – these thresholds are fixed and do not follow sig.level). With the default lab = FALSE this is a standalone significance map:
With lab = TRUE, the stars are appended to the coefficients instead (-0.85***), so one plot shows both the value and its significance:
colors sets the diverging gradient. A length-3 vector maps to low / mid / high; any longer vector (for example an 11-color palette) is spread evenly across the scale.
ggcorrplot(corr,
hc.order = TRUE, type = "lower", outline.color = "white",
colors = c("#6D9EC1", "white", "#E46726")
)ggtheme swaps the base ggplot2 theme, and tl.cex, tl.col, tl.srt style the variable-name labels. legend.limit controls the color-scale range — set it to NULL to use the data range, which is what you want for a covariance matrix.
ggcorrplot(corr,
hc.order = TRUE, type = "lower",
ggtheme = ggplot2::theme_minimal,
tl.col = "gray30", tl.srt = 90,
colors = c("#003C67", "white", "#8F2727")
)Because ggcorrplot() returns a ggplot object, you refine it with the usual ggplot2 grammar — titles, captions, and any additional layer:
library(ggplot2)
ggcorrplot(corr, hc.order = TRUE, type = "lower", outline.color = "white") +
labs(
title = "Correlations among mtcars variables",
caption = "Hierarchically clustered"
) +
theme(plot.title = element_text(face = "bold"))The fixed 1:1 aspect ratio comes from coord_fixed(). To let the cells fill the plotting area — useful with many long variable names — use coord.fixed = FALSE (or add your own + coord_*, since the last coordinate system wins).
Saving works the same as any ggplot:
cor_pmat()cor_pmat(x, ...) returns the symmetric matrix of p-values from stats::cor.test(), and passes ... through to it — so you can, for example, request a Spearman test:
The use argument controls how missing values are handled when deciding which cells are NA, mirroring stats::cor(): the default "pairwise.complete.obs" tests every pair with enough overlapping observations, while "everything" sets a pair to NA as soon as either variable has a missing value (so its NA pattern lines up with cor(x)).
sessionInfo()
#> R version 4.5.1 (2025-06-13)
#> Platform: aarch64-apple-darwin20
#> Running under: macOS Sequoia 15.6.1
#>
#> Matrix products: default
#> BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
#>
#> locale:
#> [1] C/fr_FR.UTF-8/fr_FR.UTF-8/C/fr_FR.UTF-8/fr_FR.UTF-8
#>
#> time zone: Europe/Paris
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] ggcorrplot_0.3.0 ggplot2_4.0.3
#>
#> loaded via a namespace (and not attached):
#> [1] gtable_0.3.6 jsonlite_2.0.0 dplyr_1.2.1 compiler_4.5.1
#> [5] tidyselect_1.2.1 Rcpp_1.1.1 stringr_1.6.0 jquerylib_0.1.4
#> [9] scales_1.4.0 yaml_2.3.12 fastmap_1.2.0 R6_2.6.1
#> [13] plyr_1.8.9 labeling_0.4.3 generics_0.1.4 knitr_1.51
#> [17] tibble_3.3.1 bslib_0.10.0 pillar_1.11.1 RColorBrewer_1.1-3
#> [21] rlang_1.2.0 cachem_1.1.0 stringi_1.8.7 xfun_0.57
#> [25] sass_0.4.10 S7_0.2.1 otel_0.2.0 cli_3.6.6
#> [29] withr_3.0.2 magrittr_2.0.4 digest_0.6.39 grid_4.5.1
#> [33] lifecycle_1.0.5 vctrs_0.7.2 evaluate_1.0.5 glue_1.8.0
#> [37] farver_2.1.2 reshape2_1.4.5 rmarkdown_2.31 tools_4.5.1
#> [41] pkgconfig_2.0.3 htmltools_0.5.9These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.