I have this data frame in R called df :
df
# A tibble: 5 × 7
var n `Very \n Dissatisfied` Dissatisfied Neutral Satisfied `Very \n Satisfied`
<chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 A 106 18.9 14.5 23.0 22.0 21.7
2 B 106 19.2 16.0 25.5 18.9 20.4
3 C 87 22.2 25.3 15.7 17.2 19.5
4 D 102 19.0 19.0 21.2 22.9 18.0
5 E 99 22.2 20.5 20.9 17.5 18.9
from this data frame I have create two plots, one likert plot and one bar plot :
df_long <- df %>%
select(-n)%>%
pivot_longer(!var, names_to = "Likert", values_to = "Percentage")
# Likert plot
likert_plot <- ggplot(df_long, aes(x = var, y = Percentage, fill = Likert)) +
geom_col(position = position_likert(reverse = FALSE)) +
geom_text(
aes(
label = label_percent_abs(hide_below = .01, accuracy = 1)(Percentage),
color = after_scale(hex_bw(.data$fill))
),
position = position_likert(vjust = 0.5, reverse = FALSE),
size = 3.5
) +
scale_y_continuous(labels = scales::percent) +
labs(
title = "Likert Responses by Category",
x = "Category",
y = "Percentage",
fill = "Likert Scale"
) +
coord_flip()+
theme_minimal()+scale_fill_manual(values = custom_colors) +
labs(x = NULL, y = NULL, fill = NULL)
# Horizontal bar plot
bar_plot <- ggplot(df, aes(x = n, y = var)) +
geom_bar(stat = "identity", fill = "lightgrey") +
geom_label(
aes(
label = label_number_abs(hide_below = .05, accuracy = 2)(n)
),
size = 3.5,
position = position_stack(vjust = 0.5),
hjust = 1,
fill = NA,
label.size = 0,
color = "black"
) +
scale_y_discrete(labels = \(x) gsub("\\..*$", "", x)) +
scale_x_continuous(
labels = label_percent_abs(),
expand = c(0, .15)
) +
theme_light() +
theme(
legend.position = "bottom",
panel.grid.major.y = element_blank(),
axis.text.x = element_blank() # Hides x-axis numbers
) +
labs(x = NULL, y = NULL, fill = NULL)
# Print plots
(likert_plot) +(bar_plot)+
plot_layout(
width = c(4,1)
) &
theme(legend.position = "bottom")
that look like this :
I want :
How can I achieve these in R ?
Data
dput(df)
structure(list(var = c("A", "B", "C", "D", "E"), n = c(106L,
106L, 87L, 102L, 99L), `Very
Dissatisfied` = c(18.8679245283019,
19.1823899371069, 22.2222222222222, 18.9542483660131, 22.2222222222222
), Dissatisfied = c(14.4654088050314, 16.0377358490566, 25.2873563218391,
18.9542483660131, 20.5387205387205), Neutral = c(22.9559748427673,
25.4716981132075, 15.7088122605364, 21.2418300653595, 20.8754208754209
), Satisfied = c(22.0125786163522, 18.8679245283019, 17.2413793103448,
22.8758169934641, 17.5084175084175), `Very
Satisfied` = c(21.6981132075472,
20.440251572327, 19.5402298850575, 17.9738562091503, 18.8552188552189
)), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame"
))
To achieve your desired result set the scale=
parameter in label_percent_abs
to 1 to avoid that the proportions are multiplied by the default 100. To have bold labels use fontface="bold"
in geom_text
. Finally, to get the labels you can use a separate dataframe where you compute the totals (similar to what I have done in answers on your former questions), then use a second geom_text/label
:
df <- data.frame(
var = c("A", "B", "C", "D", "E"),
n = c(106, 106, 87, 102, 99),
`Very \n Dissatisfied` = c(18.9, 19.2, 22.2, 19.0, 22.2),
Dissatisfied = c(14.5, 16.0, 25.3, 19.0, 20.5),
Neutral = c(23.0, 25.5, 15.7, 21.2, 20.9),
Satisfied = c(22.0, 18.9, 17.2, 22.9, 17.5),
`Very \n Satisfied` = c(21.7, 20.4, 19.5, 18.0, 18.9),
check.names = FALSE
)
library(tidyverse)
library(ggstats)
library(patchwork)
levels <- names(df)[-c(1:2)]
df_long <- df %>%
select(-n) %>%
pivot_longer(!var, names_to = "Likert", values_to = "Percentage") |>
mutate(Likert = factor(Likert, levels))
custom_colors <- c(
"#D91828", "#D98989", "#71B1D9", "#71F26D", "#17A621"
)
names(custom_colors) <- levels
df_tot <- df_long |>
summarise(
prop_lower = sum(Percentage[Likert %in% levels[1:2]]),
prop_higher = sum(Percentage[Likert %in% levels[4:5]]),
.by = var
) |>
pivot_longer(-var,
names_prefix = "prop_",
values_to = "Percentage",
names_to = "where"
)
# Likert plot
likert_plot <- ggplot(df_long, aes(x = Percentage, y = var, fill = Likert)) +
geom_col(position = position_likert(reverse = FALSE)) +
geom_text(
aes(
label = label_percent_abs(hide_below = .01, accuracy = 1, scale = 1)(Percentage),
color = after_scale(hex_bw(fill))
),
position = position_likert(vjust = 0.5, reverse = FALSE),
size = 3.5,
fontface = "bold"
) +
geom_label(
data = df_tot,
aes(
label = label_percent_abs(hide_below = .01, accuracy = 1, scale = 1)(Percentage),
x = ifelse(where == "lower", -.6, .6),
fill = NULL
),
size = 3.5,
fontface = "bold",
label.size = 0,
show.legend = FALSE
) +
scale_x_continuous(
labels = label_percent_abs()
) +
labs(
title = "Likert Responses by Category",
x = "Category",
y = "Percentage",
fill = "Likert Scale"
) +
theme_minimal() +
scale_fill_manual(values = custom_colors) +
labs(x = NULL, y = NULL, fill = NULL) +
coord_cartesian(clip = "off")
# Horizontal bar plot
bar_plot <- ggplot(df, aes(x = n, y = var)) +
geom_bar(stat = "identity", fill = "lightgrey") +
geom_label(
aes(
label = label_number_abs(hide_below = .05, accuracy = 2)(n)
),
size = 3.5,
position = position_stack(vjust = 0.5),
hjust = 1,
fill = NA,
label.size = 0,
color = "black"
) +
scale_y_discrete(labels = \(x) gsub("\\..*$", "", x)) +
scale_x_continuous(
labels = label_percent_abs(),
expand = c(0, .15)
) +
theme_light() +
theme(
legend.position = "bottom",
panel.grid.major.y = element_blank(),
axis.text.x = element_blank() # Hides x-axis numbers
) +
labs(x = NULL, y = NULL, fill = NULL)
# Print plots
(likert_plot) + (bar_plot) +
plot_layout(
width = c(4, 1)
) &
theme(legend.position = "bottom")