R语言50项调研排名数据ggplot2可视化优化咨询
排名数据可视化优化方案
原始问题背景
有一份调研排名数据,要求受访者对50个条目按1-5级优先级排序,原始数据示例:
Rank1 <- c("Item 1", "Item 3", "Item 6") Rank2 <- c("Item 6", "Item 9", "Item 10") Rank3 <- c("Item 45", "Item 6", "Item 10") Rank4 <- c("Item 12", "Item 32", "Item 34") Rank5 <- c("Item 22", "Item 5", "Item 21") df <- data.frame(Rank1, Rank2, Rank3, Rank4, Rank5)
数据转置后将条目映射为数值编码,结构如下(P1-P5为受访者):
P1 <- c(1, 3, 6, 3, 40) P2 <- c(6, 9, 10, 11, 30) P3 <- c(1, 3, 10, 11, 30) P4 <- c(1, 3, 10, 2, 5) P5 <- c(22, 5, 21, 11, 30) df <- data.frame(P1, P2, P3, P4, P5)
当前通过手动统计每行条目出现次数、计算占比后用ggplot2绘制堆叠柱形图,展示每个条目在1-5级排名中的相对占比,代码如下:
# 手动统计条目出现次数 df$item_1 <- rowSums(df == 1) df$item_2 <- rowSums(df == 2) df$item_3 <- rowSums(df == 3) df$item_4 <- rowSums(df == 5) df$item_5 <- rowSums(df == 6) df$item_6 <- rowSums(df == 9) df$item_7 <- rowSums(df == 10) df$item_8 <- rowSums(df == 40) df$item_9 <- rowSums(df == 11) df$item_10 <- rowSums(df == 30) df$item_11 <- rowSums(df == 22) df$item_12 <- rowSums(df == 21) # 生成计数子表 df_counts <- subset(df, select = 6:17) df_counts$counts <- Reduce(`+`, lapply(df_counts, `>`, 0)) # 计算相对占比 library(data.table) df_counts<-setDT(df_counts)[,.SD/counts] # 绘图 df_final_1<-reshape2::melt(df_counts) df_final_1$rowid<-1:5 library(ggplot2) ggplot(df_final_1, aes(x=variable, y=value)) + geom_bar(aes(y = value, x= rowid, fill=factor(variable)), data=df_final_1, stat="identity", width = 0.8) + labs(x="Ranking", y="Share")
当前遇到的问题:
- 50个条目绘制的堆叠柱形图非常杂乱,占比较小的条目几乎不可见,1级排名占比最高,2-4级的条目分布无法清晰展示,效果如下图:

优化建议
一、数据处理流程优化
首先替换手动统计条目的代码,用长表转换自动完成计数,适配任意数量的条目,避免手动编码出错:
library(tidyverse) # 直接将原始编码后的宽表转为长表,一步统计各排名下的条目占比 df_long <- df %>% mutate(rank = 1:nrow(.)) %>% pivot_longer(cols = -rank, names_to = "respondent", values_to = "item") %>% group_by(rank, item) %>% summarise(count = n(), .groups = "drop") %>% group_by(rank) %>% mutate(share = count/sum(count))
以上代码无需针对50个条目做任何修改,自动完成所有统计计算。
二、可视化优化
1. 精简分类减少干扰
先统计每个条目的总占比,将总占比低于2%(可根据实际情况调整阈值)的条目统一合并为「其他」类别,大幅减少图例数量,核心条目辨识度直接提升。
# 示例合并低占比条目 item_total <- df_long %>% group_by(item) %>% summarise(total_share = sum(share), .groups = "drop") %>% mutate(item_new = ifelse(total_share < 0.02, "其他", as.character(item))) df_long <- df_long %>% left_join(item_total, by = "item")
2. 更换更适配的图表类型
堆叠柱形图本身不适合展示超过10个分类的占比,推荐替换为以下类型:
- 热力图:X轴设为1-5级排名,Y轴设为条目,按条目总优先级得分排序Y轴,颜色深浅代表占比高低。不需要额外图例也能快速看出高优先级条目集中在哪个排名段,低优先级条目的分布也一目了然。
- 分面分组图:把50个条目按总占比分为高/中/低关注度3组,每组单独绘制小的堆叠柱形图,同组内条目数量少,不会出现堆叠过密的问题。
- 斜率图:如果重点关注不同排名层级的条目变化,用斜率图连接同一条目在不同排名的占比点,清晰展示变化趋势。
3. 解决低占比条目看不见的问题
如果需要保留所有条目且用静态堆叠柱形图,可做以下调整:
- 调整Y轴展示逻辑:1级排名单独做一个子图,Y轴范围0-1;2-5级排名做另一个子图,Y轴范围设为0到这几个等级的最大占比,不用强行和1级对齐,低占比的部分会自然放大。
- 仅为占比高于3%的部分添加数值标签,低占比部分不显示文字避免拥挤。
- 图例按条目总占比从高到低排序,和堆叠顺序保持一致,方便对应查找。
4. 改用交互图
如果是在线展示场景,直接用plotly包将静态图转为交互图,鼠标悬停就能看到对应块的条目名称、占比数值,不需要挤在静态图里放全部图例。
内容的提问来源于stack exchange,提问作者zepmaya
相关产品推荐
相关产品推荐

