I am trying to create circular bar plots where each bar is colored according to its group. I would like to display the contribution of each group as a percentage on the bars, while keeping the group labels separate from the percentage values for better clarity. Could anyone suggest how to achieve this in a clear and visually appealing way? I tried below codes and arrived at circular barplots.
# Set a number of 'empty bar' to add at the end of each group
empty_bar=3
to_add = data.frame( matrix(NA, empty_bar*nlevels(data$group), ncol(data)) )
colnames(to_add) = colnames(data)
to_add$group=rep(levels(data$group), each=empty_bar)
data=rbind(data, to_add)
data=data %>% arrange(group)
data$id=seq(1, nrow(data))
# Get the name and the y position of each label
label_data=data
number_of_bar=nrow(label_data)
angle= 90 - 360 * (label_data$id-0.5) /number_of_bar # I substract 0.5 because the letter must have the angle of the center of the bars. Not extreme right(1) or extreme left (0)
label_data$hjust<-ifelse( angle < -90, 1, 0)
label_data$angle<-ifelse(angle < -90, angle+180, angle)
# prepare a data frame for base lines
base_data=data %>%
group_by(group) %>%
summarize(start=min(id), end=max(id) - empty_bar) %>%
rowwise() %>%
mutate(title=mean(c(start, end)))
# prepare a data frame for grid (scales)
grid_data = base_data
grid_data$end = grid_data$end[ c( nrow(grid_data), 1:nrow(grid_data)-1)] + 1
grid_data$start = grid_data$start - 1
grid_data=grid_data[-1,]
# Exclude all "Mister" from label_data
label_data <- label_data %>% filter(!grepl("^Mister", individual))
# Make the plot
p = ggplot(data, aes(x=as.factor(id), y=value, fill=group)) + # Note that id is a factor. If x is numeric, there is some space between the first bar
geom_bar(aes(x=as.factor(id), y=value, fill=group), stat="identity", alpha=0.5) +
# Add a val=100/75/50/25 lines. I do it at the beginning to make sure barplots are OVER it.
geom_segment(data=grid_data, aes(x = end, y = 80, xend = start, yend = 80), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
geom_segment(data=grid_data, aes(x = end, y = 60, xend = start, yend = 60), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
geom_segment(data=grid_data, aes(x = end, y = 40, xend = start, yend = 40), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
geom_segment(data=grid_data, aes(x = end, y = 20, xend = start, yend = 20), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
# Add text showing the value of each 100/75/50/25 lines
annotate("text", x = rep(max(data$id),4), y = c(20, 40, 60, 80), label = c("-4", "-2", "0", "3") , color="black", size=3 , angle=0, fontface="bold", hjust=1) +
geom_bar(aes(x=as.factor(id), y=value, fill=group), stat="identity", alpha=0.5) +
ylim(-100,120) +
theme_minimal() +
theme(
legend.position = "none",
axis.text = element_blank(),
axis.title = element_blank(),
panel.grid = element_blank(),
plot.margin = unit(rep(-1,4), "cm")
) +
coord_polar() +
geom_text(data=label_data, aes(x=id, y=value+10, label=individual, hjust=hjust), color="black", fontface="bold",alpha=0.6, size=2.5, angle= label_data$angle, inherit.aes = FALSE ) +
# Add base line information
geom_segment(data=base_data, aes(x = start, y = -5, xend = end, yend = -5), colour = "black", alpha=0.8, size=0.6 , inherit.aes = FALSE ) +
geom_text(data=base_data, aes(x = title, y = -18, label=group), hjust=c(0,1,1,1,0,0,1), colour = "black", alpha=0.8, size=4, fontface="bold", inherit.aes = FALSE)
p
but my expected result is something as follows:
data for reproducibility:
data = structure(list(individual = c("Mister9", "Mister3", "Mister5",
"Mister1", "Mister6", "Mister7", "Mister8", "Mister4", "Mister10",
"Mister11", "Mister2", "Mister20", "Mister26", "Mister30", "Mister14",
"Mister19", "Mister18", "Mister16", "Mister27", "Mister12", "Mister23",
"Mister24", "Mister17", "Mister25", "Mister15", "Mister29", "Mister13",
"Mister21", "Mister22", "Mister28", "Mister31", "Mister32", "Mister47",
"Mister48", "Mister45", "Mister49", "Mister46", "Mister42", "Mister41",
"Mister35", "Mister37", "Mister43", "Mister33", "Mister34", "Mister40",
"Mister39", "Mister44", "Mister38", "Mister36", "Mister179",
"Mister165", "Mister166", "Mister174", "Mister155", "Mister139",
"Mister120", "Mister152", "Mister140", "Mister119", "Mister178",
"Mister173", "Mister177", "Mister160", "Mister172", "Mister168",
"Mister150", "Mister175", "Mister176", "Mister153", "Mister156",
"Mister134", "Mister161", "Mister154", "Mister164", "Mister169",
"Mister181", "Mister157", "Mister167", "Mister65", "Mister183",
"Mister147", "Mister170", "Mister135", "Mister158", "Mister145",
"Mister87", "Mister171", "Mister163", "Mister182", "Mister127",
"Mister61", "Mister128", "Mister129", "Mister118", "Mister144",
"Mister136", "Mister149", "Mister121", "Mister112", "Mister85",
"Mister137", "Mister180", "Mister151", "Mister138", "Mister148",
"Mister146", "Mister91", "Mister126", "Mister117", "Mister96",
"Mister97", "Mister95", "Mister113", "Mister92", "Mister99",
"Mister81", "Mister98", "Mister115", "Mister107", "Mister86",
"Mister125", "Mister110", "Mister84", "Mister89", "Mister133",
"Mister111", "Mister109", "Mister100", "Mister123", "Mister124",
"Mister88", "Mister94", "Mister108", "Mister116", "Mister90",
"Mister53", "Mister114", "Mister162", "Mister102", "Mister101",
"Mister64", "Mister143", "Mister68", "Mister93", "Mister67",
"Mister106", "Mister79", "Mister122", "Mister63", "Mister159",
"Mister78", "Mister103", "Mister62", "Mister51", "Mister60",
"Mister132", "Mister83", "Mister142", "Mister54", "Mister141",
"Mister56", "Mister130", "Mister52", "Mister131", "Mister66",
"Mister59", "Mister50", "Mister69", "Mister82", "Mister104",
"Mister55", "Mister105", "Mister74", "Mister73", "Mister76",
"Mister58", "Mister71", "Mister57", "Mister80", "Mister75", "Mister70",
"Mister72", "Mister77", "Mister184", "Mister185", "Mister191",
"Mister196", "Mister192", "Mister195", "Mister188", "Mister193",
"Mister187", "Mister189", "Mister186", "Mister194", "Mister190",
"Mister201", "Mister204", "Mister206", "Mister200", "Mister207",
"Mister208", "Mister198", "Mister199", "Mister203", "Mister197",
"Mister202", "Mister205", "Mister226", "Mister227", "Mister225",
"Mister229", "Mister219", "Mister218", "Mister220", "Mister228",
"Mister222", "Mister221", "Mister223", "Mister224", "Mister212",
"Mister213", "Mister215", "Mister217", "Mister211", "Mister230",
"Mister216", "Mister210", "Mister214", "Mister209"), group = c("A",
"A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "B", "B", "B",
"B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B",
"B", "B", "B", "B", "B", "C", "C", "C", "C", "C", "C", "C", "C",
"C", "C", "C", "C", "C", "C", "C", "C", "C", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "G",
"G", "G", "G", "G", "G", "G", "G", "G", "G", "G", "G", "G", "G",
"G", "G", "G", "G", "G", "G", "G", "G"), value = c(11.02911835,
4.704593761, 6.084237329, 7.210865307, 8.923452205, 10.97381326,
11.1340509, 14.20915859, 15.43248876, 18.31250393, 32.66343939,
15.43951498, 10.07896574, 5.842966, 6.742587654, 8.212683412,
8.884210644, 9.148645253, 9.220297077, 9.27063146, 9.382737778,
9.82520696, 11.34338043, 11.38390891, 12.98406544, 13.41780906,
20.71406412, 25.73528387, 25.76179696, 37.58409529, 39.1098185,
48.89609316, 18.17295966, 13.75527894, 13.66649766, 13.39137151,
13.05892791, 12.40772362, 12.21544586, 11.75496099, 10.39396666,
9.969703691, 9.708871989, 9.396143117, 8.674631169, 7.160201387,
6.869214145, 5.681204595, 5.508248872, 50.30170058, 26.53058006,
25.19603349, 22.95011296, 22.04357295, 20.80706089, 20.5080487,
20.40577626, 19.83179136, 19.34357996, 19.01510487, 18.50699957,
18.34253534, 18.19692252, 16.86829523, 16.5163713, 15.73216674,
15.66448277, 15.55217427, 13.91257473, 13.77744015, 13.76266752,
13.62696906, 13.52299989, 13.52052077, 13.49820108, 13.236779,
13.20177911, 12.76645405, 12.73606233, 12.70818073, 12.6929635,
12.36679029, 11.97300121, 11.9212063, 11.65588905, 11.61932016,
11.22252378, 10.78121331, 10.72231904, 10.49386514, 10.22051336,
10.20964479, 9.898505446, 9.862853549, 9.846386933, 9.404480788,
9.23736005, 8.92331421, 8.872586528, 8.668959306, 8.438496055,
8.321278052, 7.964428845, 7.854361277, 7.775950751, 7.101006599,
7.006092397, 6.671911803, 3.985297226, 4.682410586, 5.234034919,
5.274506855, 5.346801683, 5.46789583, 5.567505728, 5.57424037,
5.580555239, 5.652623005, 5.655154315, 5.81032488, 5.823886434,
5.834908952, 5.954677792, 5.988301493, 6.02962921, 6.080394992,
6.096620978, 6.148764325, 6.198841563, 6.21040773, 6.265290454,
6.329712605, 6.546152866, 6.638816564, 6.7108602, 6.773907848,
6.776519092, 7.109253987, 7.18136414, 7.314088953, 7.414507805,
7.453068558, 7.63445725, 7.784076636, 7.814523066, 7.970740755,
8.10098952, 8.402040125, 8.522893414, 8.572263214, 8.977074377,
9.184918646, 9.200741549, 9.50786689, 9.689064249, 9.723051779,
9.731553669, 9.752344506, 9.774093203, 10.02276925, 10.42839353,
10.43899025, 10.90445102, 11.06879188, 11.18958947, 11.237825,
11.44280574, 11.79221849, 11.97775325, 11.98579794, 12.89577317,
13.09019857, 13.84253541, 14.34257592, 16.19968262, 16.23191164,
16.45547868, 17.75826902, 18.6551079, 19.82079501, 20.44794895,
22.76322419, 28.41580997, 8.725372959, 12.20014461, 15.38935919,
26.63274737, 28.67366257, 32.22364195, 37.29689097, 41.89528827,
43.30171877, 53.59388158, 57.8091483, 59.15980241, 76.08966091,
62.92937225, 50.15206365, 14.90668236, 12.20001927, 10.46149594,
9.59848128, 8.959906549, 8.447058043, 6.928790267, 0.357389166,
1.8283806, 13.49008525, 71.64450694, 28.11151216, 15.70417498,
15.64111399, 12.85747587, 12.58371838, 10.16885842, 8.889503684,
4.714868371, 5.114968965, 5.809477452, 7.654519326, 8.567689096,
19.21173213, 23.43383162, 28.10549842, 43.69929885, 44.29908174,
48.48705434, 60.56687775, 74.14460712, 89.66578052)), class = "data.frame", row.names = c(NA,
-230L))
I think I would convert your axis to numeric rather than discrete, then just precalculate the position of your bars, incorporating the gap. I also find adding text to polar plots is often easier with the geomtextpath package.
library(tidyverse)
data %>%
mutate(individual = seq(nrow(.)),
xpos = individual + as.numeric(factor(group)) * 10) %>%
ggplot(aes(xpos, value, fill = group)) +
geom_hline(yintercept = seq(0, 90, 10), color = "gray90", linewidth = 0.2) +
geom_col() +
annotate("line", x = c(11, 311), y = c(0, 0), linetype = 0) +
geom_segment(data = . %>%
group_by(group) %>%
summarize(xend = last(xpos), xpos = first(xpos), value = -10),
aes(xend = xend, yend = -10), linewidth = 1, color = "gray50") +
geomtextpath::geom_textpath(data = . %>%
group_by(group) %>%
summarize(xpos = mean(xpos),
label = scales::percent(
sum(value)/sum(data$value), .1)) %>%
mutate(value = -15),
aes(label = label)) +
geomtextpath::geom_textpath(data = . %>%
group_by(group) %>%
summarize(xpos = mean(xpos)) %>%
mutate(value = -30), color = "gray50",
aes(label = group), size = 6, fontface = 2) +
scale_y_continuous(limits = c(-90, 90)) +
scale_fill_manual(values = RColorBrewer::brewer.pal(7, name = "Set1"),
guide = "none") +
coord_polar(start = 0.1) +
theme_void()