在R中基于条形图降序排序并左右拼接Likert图与条形图
问题解决:同步条形图与Likert图的类别排序
需求说明
现有R数据框df,已通过ggplot2、patchwork实现条形图与Likert图拼接,需完成以下调整:
- 左侧条形图按响应计数降序排列类别
- 右侧Likert图与条形图的类别排序完全对应
修改方案
核心思路是先从数据中提取按响应计数降序的类别顺序,再将该顺序同步应用到条形图和Likert图的y轴因子中,具体修改点如下:
1. 提前计算类别排序规则
先统计每个类别的总响应数,生成降序排列的类别顺序,后续所有可视化都基于这个顺序:
# 计算每个var的总响应数,得到降序排序的var列表 var_order <- df |> count(var) |> arrange(desc(n)) |> pull(var)
2. 调整条形图的排序
将条形图的var转换为按var_order排序的因子,确保条形图按计数降序排列:
bar_plot <- dat%>% select(var,n)%>% group_by(var)%>% summarise(count = sum(n))%>% # 将var转换为按count降序的因子 mutate(var = factor(var, levels = var_order)) %>% ggplot(., aes(y = var, x = count)) + geom_bar(stat = "identity", fill = "lightgrey")+labs(x="Response Count",y="")+ geom_text(aes(label = count),position = position_stack(vjust = .5)) + theme_bw()+ theme( axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank() )
3. 同步Likert图的排序
在处理dat数据时,不再用prop_lower排序,而是基于提前生成的var_order来创建y_sort因子,确保Likert图的类别顺序和条形图一致:
dat <- df |> mutate( across(-var, ~ factor(.x, likert_levels)) ) |> pivot_longer(-var, names_to = "group") |> count(var, value, group) |> complete(var, value, group, fill = list(n = 0)) |> mutate( prop = n / sum(n), prop_lower = sum(prop[value %in% c("Strongly disagree", "Disagree")]), prop_higher = sum(prop[value %in% c("Strongly agree", "Agree")]), .by = c(var, group) ) |> # 按提前定义的var_order排序,而不是prop_lower mutate(var = factor(var, levels = var_order)) |> arrange(group, var) |> mutate( y_sort = paste(var, group, sep = "."), y_sort = fct_inorder(y_sort) )
4. 适配top10筛选逻辑
由于var已转换为因子,筛选top10时直接基于计数即可,无需依赖prop_lower:
top10 <- df |> count(var) |> arrange(desc(n)) |> slice_max(n, n = 10) |> pull(var) dat <- dat |> filter(var %in% top10)
完整修改后代码
# Load necessary libraries library(tibble) library(tidyverse) library(ggplot2) library(ggpubr) library(ggstats) library(patchwork) # Define categories and Likert levels var_levels <- c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q") likert_levels <- c( "Strongly disagree", "Disagree", "Neither agree nor disagree", "Agree", "Strongly agree" ) # Set seed for reproducibility set.seed(42) # Create the dataframe with three Likert response columns df <- tibble( var = sample(var_levels, 50, replace = TRUE), # Random values from A to Q val1 = sample(likert_levels, 50, replace = TRUE) # Random values from Likert levels ) # 计算每个var的总响应数,得到降序排序的var列表 var_order <- df |> count(var) |> arrange(desc(n)) |> pull(var) # 筛选top10高响应的类别 top10 <- df |> count(var) |> arrange(desc(n)) |> slice_max(n, n = 10) |> pull(var) # 处理数据用于可视化 dat <- df |> mutate( across(-var, ~ factor(.x, likert_levels)) ) |> pivot_longer(-var, names_to = "group") |> count(var, value, group) |> complete(var, value, group, fill = list(n = 0)) |> mutate( prop = n / sum(n), prop_lower = sum(prop[value %in% c("Strongly disagree", "Disagree")]), prop_higher = sum(prop[value %in% c("Strongly agree", "Agree")]), .by = c(var, group) ) |> # 应用预定义的var排序 mutate(var = factor(var, levels = var_order)) |> filter(var %in% top10) |> arrange(group, var) |> mutate( y_sort = paste(var, group, sep = "."), y_sort = fct_inorder(y_sort) ) # 处理总计数据 dat_tot <- dat |> distinct(group, var, y_sort, prop_lower, prop_higher) |> pivot_longer(-c(group, var, y_sort), names_to = c(".value", "name"), names_sep = "_" ) |> mutate( hjust_tot = ifelse(name == "lower", 1, 0), x_tot = ifelse(name == "lower", -1, 1) ) # Bar plot bar_plot <- dat%>% select(var,n)%>% group_by(var)%>% summarise(count = sum(n))%>% mutate(var = factor(var, levels = var_order)) %>% ggplot(., aes(y = var, x = count)) + geom_bar(stat = "identity", fill = "lightgrey")+labs(x="Response Count",y="")+ geom_text(aes(label = count),position = position_stack(vjust = .5)) + theme_bw()+ theme( axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank() ) # Likert plot likert_plot <- ggplot(dat, aes(y = y_sort, x = prop, fill = value)) + geom_col(position = position_likert(reverse = FALSE)) + geom_text( aes( label = label_percent_abs(hide_below = .05, accuracy = 1)(prop), color = after_scale(hex_bw(.data$fill)) ), position = position_likert(vjust = 0.5, reverse = FALSE), size = 3.5 ) + geom_label( aes( x = x_tot, label = label_percent_abs(accuracy = 1)(prop), hjust = hjust_tot, fill = NULL ), data = dat_tot, size = 3.5, color = "black", fontface = "bold", label.size = 0, show.legend = FALSE ) + scale_y_discrete(labels = \(x) gsub("\\..*$", "", x)) + scale_x_continuous( labels = label_percent_abs(), expand = c(0, .15) ) + scale_fill_brewer(palette = "BrBG") + facet_wrap(~group, scales = "free_y", ncol = 1, strip.position = "right" ) + theme_light() + theme( legend.position = "bottom", panel.grid.major.y = element_blank() ) + labs(x = NULL, y = NULL, fill = NULL) # 拼接图形 bar_plot + likert_plot + plot_layout(guides = "collect") & theme(legend.position="bottom")
内容的提问来源于stack exchange,提问作者Homer Jay Simpson
相关产品推荐
相关产品推荐

