Circular correlation “wheel” plots in native R.
circlecorR draws correlation wheel plots with variables arranged around a ring, grouped and colour-tiled by category, connected by curved links whose colour maps to the correlation coefficient using circlize.
A traditional correlation matrix is mostly redundant. A diagonal of self-correlations, two mirror-image triangles, and blocks of within-category correlations bury the between-category relationships we care about. The wheel, first seen in Gharibans et al. (2019), keeps only the relationships of interest. Hiding self- and within-category correlations also removes them from the multiple-comparison family, which improves statistical power (see vignette("circlecorR")).

Installation
Install the released version from CRAN:
install.packages("circlecorR")Or the development version from GitHub:
# install.packages("remotes")
remotes::install_github("kriz98/circlecorR", build_vignettes = TRUE)Dependencies (circlize and psych) install automatically with either command above.
Quick start — straight from your data
circlecorR is designed to work straight from a data frame, one row per subject, one column per variable, with no separate step to build correlation matrices yourself. Hand that data frame to corr_wheel() and it computes the correlations and p-values for you. The only other thing you supply is groups, which both selects the variables and orders them around the wheel (extra columns like IDs are ignored).
library(circlecorR)
# `gastro_symptoms` is a synthetic example dataset bundled with the package --
# swap it for your own data frame (one row per subject) to use your own data.
groups <- list(
Demographics = c("Age", "BMI"),
Metrics = c("Amplitude", "Fed-Fasted AR", "Frequency", "GA-RI"),
Symptoms = c("Nausea", "Early satiety", "Bloating",
"Upper GI pain", "Lower GI pain", "Heartburn"),
Scores = c("GCSI", "PAGI-SYM", "PAGI-QoL", "EQ-5D")
)
corr_wheel(
gastro_symptoms, # one row per subject -- use your own data here
groups = groups,
method = "pearson",
adjust = "hochberg",
sig_level = 0.05,
r_threshold = 0.3,
r_limits = c(-0.6, 0.6)
)Save to file
png("correlation_wheel.png", width = 2400, height = 2000, res = 300)
corr_wheel(gastro_symptoms, groups = groups, r_threshold = 0.3, r_limits = c(-0.6, 0.6))
dev.off()See vignette("circlecorR") for the full tour.
Flexibility
Everything the reference figure controls is a plain argument:
| What | Argument | Example |
|---|---|---|
| Category assignment & order | groups |
named list or variable = category vector |
| Colour scheme (category colours + link palette, together) | scheme |
"colorblind", "ocean", "vivid", "alimetry", or list(colors=, palette=)
|
| Category colours | colors |
c(Symptoms = "#55A868", Scores = "#C44E52") (overrides scheme per category) |
| Pretty variable labels | labels |
c("GA-RI" = "Rhythm index") |
| Significance cutoff | sig_level |
0.05 |
| Multiple-comparison adjustment | adjust |
"holm", "hochberg", "BH", "none"
|
| Minimum |r| shown | r_threshold |
0.3 |
| Hide within-category links | hide_within_group |
TRUE / FALSE
|
| Colour-scale range | r_limits |
c(-0.5, 0.5) |
| Link colour ramp | palette |
c("#2166AC", "white", "#B2182B") (overrides scheme’s) |
| Block size (thickness) | tile_height |
0.06 (thin) … 0.12 (thick) |
| Line size (width) | link_lwd |
1.6, 3
|
| Rotation / spacing |
start_degree, group_gap, node_gap
|
|
| Legend / colour bar |
legend, colorbar
|
Built-in schemes are listed with corr_wheel_schemes() and inspected/tweaked with corr_wheel_scheme(); see vignette("circlecorR") for examples.
corr_wheel() returns (invisibly) the ordered variables, resolved group and colour maps, the colour function, and the masked matrix actually plotted — handy for reproducibility or building a caption.
Example data
gastro_symptoms is a bundled synthetic dataset — fully simulated, not patient data — mimicking a gastric-symptom study, one row per subject. It’s loaded automatically with the package (LazyData: true), so it’s available directly as soon as you library(circlecorR) — no data() call needed. See ?gastro_symptoms for details, or use it as a template for your own data’s shape.
How masking & statistics work
A link between variables i and j is drawn only if all hold:
- they are in different categories (when
hide_within_group = TRUE), and never the same variable (self-correlations are always excluded); -
p_adjusted <= sig_level; and -
|r| >= r_threshold.
The correlations left after step 1 form the family of comparisons. The adjust correction is applied over only that family — so redundant self- and within-category correlations don’t inflate the count, and power improves. corr_wheel() returns n_tests (the family size) and the family-adjusted p-matrix for reporting.
References
The correlation wheel was introduced in:
Gharibans AA, Coleman TP, Mousa H, Kunkel DC. Spatial patterns from high-resolution electrogastrography correlate with severity of symptoms in patients with functional dyspepsia and gastroparesis. Clin Gastroenterol Hepatol. 2019 Dec;17(13):2668–77.
It has since been used in several other gastric physiology studies:
- Gharibans AA, Calder S, Varghese C, Waite S, Schamberg G, Daker C, et al. Gastric dysfunction in patients with chronic nausea and vomiting syndromes defined by a noninvasive gastric mapping device. Sci Transl Med. 2022 Sep 21;14(663):eabq3544.
- Wang TH-H, Varghese C, Calder S, Gharibans A, Schamberg G, Bartlett A, et al. Long-term evaluation of gastric electrophysiology, symptoms and quality of life after pancreaticoduodenectomy. HPB (Oxford). 2025 Dec;27(12):1535–42.
- Xu W, Wang T, Foong D, Schamberg G, Evennett N, Beban G, et al. Characterization of gastric dysfunction after fundoplication using body surface gastric mapping. J Gastrointest Surg. 2024 Mar;28(3):236–45.
- Xu W, Gharibans AA, Calder S, Schamberg G, Walters A, Jang J, et al. Defining and phenotyping gastric abnormalities in long-term type 1 diabetes using a novel body surface gastric mapping device. Gastro Hep Adv. 2023 Aug 18;2(8):1120–32.