Goal
Replicating this circular bar plot:
Data
data <- data.frame(
labels = c("A","B","C","D","E","F","G","H"),
values = c(88, 61, 56, 77, 83, 63, 42, 60)
) %>%
mutate(
bar_color = case_when(
values < 62 ~ "#ff7d48",
values < 85 ~ "#76c5d0",
values >= 85 ~ "#4b7d84",
)
)
My Code
ggplot(data) +
geom_bar(
stat = "identity",
aes(
x = labels,
y = values,
fill = bar_color
),
size = 1,
color = "gray20",
width = 1,
alpha = 0.9
) +
coord_polar() +
scale_fill_identity() +
theme(
panel.grid.major.x = element_line(
linewidth = .8,
color = "grey30"
),
panel.grid.major.y = element_line(
linewidth = .8,
color = alpha("grey70", 0.5)
),
axis.title = element_blank(),
panel.background = element_blank(),
axis.line.x.top = element_line(
color = "grey20"
),
axis.ticks.y = element_blank(),
axis.text.y = element_blank()
)
Initial result based on my code:
Need help on:
grey30
. The axis.line.x.top
seems has no effect. Even after I remove coord_polar()
just to test, it also didnt show any grey line.axis.text.x = element_textbox(color = "black",fill = "white")
, it returns error: Error: The function textbox_grob() is not vectorized.
geom_label(aes(x = labels,y = 100,label = labels)
; the label just too centered regardless how I edit the y
argument. for example y = 150
still makes the label too centered but it expand the y axis
; I intentionally let x axis text to be there just to compare the position of geom_label
that i expectedpanel.grid.major.x
on top of panel.grid.major.y
. In return, now i just set the color of the second to alpha("grey70", 0.5)
You can 'automate' some of the plotting (e.g. calculate how many groups you have before plotting), but working out the breaks is complicated will require tweaking depending on your dataset (e.g. +1 or -1 accordingly):
library(tidyverse)
library(scales)
data <- data.frame(
labels = c("A","B","C","D","E","F","G","H"),
values = c(88, 61, 56, 77, 83, 63, 42, 60)
) %>%
mutate(
bar_color = case_when(
values < 62 ~ "#f2452e",
values < 85 ~ "#76c5d0",
values >= 85 ~ "#4b7d84",
)
)
n <- length(unique(data$labels))
max_val <- max(data$values)
breaks_ext <- extended_breaks()(data$values)
ggplot(data, aes(x = labels, y = values)) +
geom_bar(aes(fill = bar_color),
stat = "identity", linewidth = 1,
color = "gray20", width = 1,
alpha = 0.8) +
coord_polar(start = -(pi / n)) +
scale_fill_identity() +
theme(
panel.grid.major.y = element_line(
linewidth = .8,
color = c(rep(alpha("grey80", 0.5),
ifelse(max(breaks_ext) > max_val,
length(breaks_ext) - 2)), # change this manually to suit
"transparent")
),
axis.title = element_blank(),
panel.background = element_blank(),
axis.ticks.y = element_blank(),
axis.text = element_blank(),
) +
geom_hline(yintercept = max_val + (max_val * 0.1),
color = "grey90", linewidth = 3) +
geom_segment(aes(x = 1.5:(n + 0.5), y = 0,
yend = max_val + (max_val * 0.075)),
inherit.aes = FALSE, color = alpha("grey20", 0.5)) +
geom_hline(yintercept = max_val + (max_val * 0.07),
color = "grey20", linewidth = 1) +
geom_label(aes(label = labels, y = max_val + (max_val * 0.09)),
fill = "white", size = 6)
With 'new' data:
####
set.seed(1234)
data <- data.frame(
labels = c("A","B","C","D","E","F","G","H", "I", "J"),
values = sample(1:100, 10, replace = TRUE)
) %>%
mutate(
bar_color = case_when(
values < 62 ~ "#f2452e",
values < 85 ~ "#76c5d0",
values >= 85 ~ "#4b7d84",
)
)
n <- length(unique(data$labels))
max_val <- max(data$values)
breaks_ext <- extended_breaks()(data$values)
ggplot(data, aes(x = labels, y = values)) +
geom_bar(aes(fill = bar_color),
stat = "identity", linewidth = 1,
color = "gray20", width = 1,
alpha = 0.8) +
coord_polar(start = -(pi / n)) +
scale_fill_identity() +
theme(
panel.grid.major.y = element_line(
linewidth = .8,
color = c(rep(alpha("grey80", 0.5),
ifelse(max(breaks_ext) > max_val,
length(breaks_ext))), # change this manually to suit
"transparent")
),
axis.title = element_blank(),
panel.background = element_blank(),
axis.ticks.y = element_blank(),
axis.text = element_blank(),
) +
geom_hline(yintercept = max_val + (max_val * 0.1),
color = "grey90", linewidth = 3) +
geom_segment(aes(x = 1.5:(n + 0.5), y = 0,
yend = max_val + (max_val * 0.075)),
inherit.aes = FALSE, color = alpha("grey20", 0.5)) +
geom_hline(yintercept = max_val + (max_val * 0.07),
color = "grey20", linewidth = 1) +
geom_label(aes(label = labels, y = max_val + (max_val * 0.09)),
fill = "white", size = 6)
Created on 2024-12-16 with reprex v2.1.0
Here is one potential approach:
library(tidyverse)
data <- data.frame(
labels = c("A","B","C","D","E","F","G","H"),
values = c(88, 61, 56, 77, 83, 63, 42, 60)
) %>%
mutate(
bar_color = case_when(
values < 62 ~ "#f2452e",
values < 85 ~ "#76c5d0",
values >= 85 ~ "#4b7d84",
)
)
ggplot(data, aes(x = labels, y = values)) +
geom_bar(aes(fill = bar_color),
stat = "identity", size = 1,
color = "gray20", width = 1,
alpha = 0.8) +
coord_polar(start = -(pi / 8)) +
scale_fill_identity() +
theme(
panel.grid.major.y = element_line(
linewidth = .8,
color = c("transparent", alpha("grey80", 0.5))
),
axis.title = element_blank(),
panel.background = element_blank(),
axis.ticks.y = element_blank(),
axis.text = element_blank(),
) +
geom_hline(yintercept = 96.5,
color = "grey90", size = 3) +
scale_y_continuous(breaks = seq(0, 95, 5)) +
geom_segment(aes(x = 1.5:8.5, y = 0, yend = 95),
inherit.aes = FALSE, color = alpha("grey20", 0.5)) +
geom_hline(yintercept = 94,
color = "grey20", size = 1) +
geom_label(aes(label = labels, y = 96), fill = "white", size = 6)
#> Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
#> ℹ Please use `linewidth` instead.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
#> generated.
Created on 2024-12-13 with reprex v2.1.0