i have a data frame in R called df that looks like this :
df
# A tibble: 90 × 3
# Groups: item [18]
item Response Percentage
<chr> <fct> <dbl>
1 A Very Dissatisfied 0
2 A Dissatisfied 0
3 A Average 33.3
4 A Satisfied 11.1
5 A Very Satisfied 55.6
6 B Very Dissatisfied 0
7 B Dissatisfied 0
8 B Average 44.4
9 B Satisfied 0
10 B Very Satisfied 55.6
# ℹ 80 more rows
# ℹ Use `print(n = ...)` to see more rows
the response column is Likert scale column with 5 levels. Plotting it with ggplot2
# Creating a mapping of responses to numeric values
response_mapping <- c("Very Dissatisfied" = 1,
"Dissatisfied" = 2,
"Average" = 3,
"Satisfied" = 4,
"Very Satisfied" = 5)
# Applying the mapping and calculate the sign
data_f_sum <- df %>%
ungroup() %>%
mutate(res.sgn = sign(response_mapping[as.character(Response)] - 3)) %>%
summarise(sum.prcnt = sum(Percentage),
.by = c(item, res.sgn))
likert_levels = c("Very Dissatisfied",
"Dissatisfied" ,
"Average" ,
"Satisfied",
"Very Satisfied")
df = df%>%
mutate(Response = factor(Response , levels = likert_levels))
ggplot(data = df,
aes(Percentage, item, fill = Response)) +
geom_col(position = position_likert()) +
scale_x_continuous(breaks = seq(-1, 1, 0.5),
labels = ggstats::label_percent_abs()) +
geom_label(data = data_f_sum,
aes(label = sprintf("%.1f", sum.prcnt), y = item, x = res.sgn * 0.5),
alpha = 0.3, inherit.aes = FALSE) +
scale_fill_brewer(type = "div", palette = "RdYlGn") +
theme_bw()
i receive the following plot (picture)
i want to solve some issues that i have here and i need some help:
I want to fix the average level in the middle and horizontically to start from 0%.
i want in the middle of each item in the average level to display the percentage of the average level. at the left of each item to display the percentage sum of the two lower levels (i.e very dissatisfied and satisfied) and at the right to display the percentage sum of the two upper levels (i.e satisfied and very satisfied) .Something like this :
Can someone help me solve these issues ?
data are here :
structure(list(item = c("A", "A", "A", "A", "A", "B", "B", "B",
"B", "B", "C", "C", "C", "C", "C", "D", "D", "D", "D", "D", "E",
"E", "E", "E", "E", "F", "F", "F", "F", "F", "G", "G", "G", "G",
"G", "H", "H", "H", "H", "H", "I", "I", "I", "I", "I", "J", "J",
"J", "J", "J", "K", "K", "K", "K", "K", "L", "L", "L", "L", "L",
"M", "M", "M", "M", "M", "N", "N", "N", "N", "N", "O", "O", "O",
"O", "O", "P", "P", "P", "P", "P", "Q", "Q", "Q", "Q", "Q", "R",
"R", "R", "R", "R"), Response = structure(c(4L, 2L, 1L, 3L, 5L,
4L, 2L, 1L, 3L, 5L, 4L, 2L, 1L, 3L, 5L, 4L, 2L, 1L, 3L, 5L, 4L,
2L, 1L, 3L, 5L, 4L, 2L, 1L, 3L, 5L, 4L, 2L, 1L, 3L, 5L, 4L, 2L,
1L, 3L, 5L, 4L, 2L, 1L, 3L, 5L, 4L, 2L, 1L, 3L, 5L, 4L, 2L, 1L,
3L, 5L, 4L, 2L, 1L, 3L, 5L, 4L, 2L, 1L, 3L, 5L, 4L, 2L, 1L, 3L,
5L, 4L, 2L, 1L, 3L, 5L, 4L, 2L, 1L, 3L, 5L, 4L, 2L, 1L, 3L, 5L,
4L, 2L, 1L, 3L, 5L), levels = c("Average", "Dissatisfied", "Satisfied",
"Very Dissatisfied", "Very Satisfied"), class = "factor"), Percentage = c(0,
0, 33.3, 11.1, 55.6, 0, 0, 44.4, 0, 55.6, 0, 0, 22.2, 33.3, 44.4,
0, 0, 33.3, 11.1, 55.6, 0, 22.2, 11.1, 11.1, 55.6, 0, 0, 44.4,
11.1, 44.4, 0, 0, 11.1, 33.3, 55.6, 0, 0, 33.3, 22.2, 44.4, 0,
0, 11.1, 33.3, 55.6, 0, 0, 22.2, 22.2, 55.6, 0, 0, 11.1, 11.1,
77.8, 0, 0, 11.1, 33.3, 55.6, 0, 0, 33.3, 0, 66.7, 0, 0, 33.3,
11.1, 55.6, 0, 11.1, 0, 33.3, 55.6, 0, 0, 22.2, 22.2, 55.6, 0,
22.2, 22.2, 11.1, 44.4, 0, 11.1, 22.2, 11.1, 55.6)), class = c("grouped_df",
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -90L), groups = structure(list(
item = c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R"), .rows = structure(list(
1:5, 6:10, 11:15, 16:20, 21:25, 26:30, 31:35, 36:40,
41:45, 46:50, 51:55, 56:60, 61:65, 66:70, 71:75, 76:80,
81:85, 86:90), ptype = integer(0), class = c("vctrs_list_of",
"vctrs_vctr", "list"))), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -18L), .drop = TRUE))
You can center the likert scale by hard-setting limits for the x axis, using coord_cartesian
, so that your plot actually goes from -100% to 100% instead of adjusting to the data ranges, and you can place the labels on the edges of the plot just by using -1 or 1 as your x value:
library(ggplot2)
library(ggstats)
ggplot(data = df,
aes(Percentage, item, fill = Response)) +
geom_col(position = position_likert()) +
scale_x_continuous(#breaks = seq(-1, 1, 0.5),
labels = ggstats::label_percent_abs()) +
geom_label(data = data_f_sum,
aes(label = sprintf("%.1f", sum.prcnt), y = item, x = res.sgn),
alpha = 0.3, inherit.aes = FALSE) +
coord_cartesian(xlim = c(-1, 1)) +
scale_fill_brewer(type = "div", palette = "RdYlGn") +
theme_bw()