ggplot2堆叠百分比条形图中C组a1与a3值异常互换问题
堆叠百分比条形图分组堆叠顺序异常排查与解决
我需要将数据框可视化为堆叠百分比条形图,要求每个柱子的堆叠部分按降序排列。数据已转换为长格式,示例代码如下:
df<- data.frame(ID=c("A","B","C","D","E"), a1=c((0.452),(0.558),(0.554),(0.484),(0.661)), a2=c((0.326),(0.373),(0.465),(0.434),(0.499)), a3=c((0.450),(0.481),(0.613),(0.473),(0.504)), a4=c((0.561),(0.681),(0.633),(0.504),(0.723))) dflong<-df%>% pivot_longer(!ID, names_to="aa", values_to="prop") dflong$ID<-as.factor(dflong$ID)
转换后的数据结构:
# A tibble: 15 × 3 ID aa prop <fct> <chr> <dbl> 1 A a1 0.452 2 A a2 0.326 3 A a3 0.45 4 A a4 0.561 5 B a1 0.558 6 B a2 0.373 7 B a3 0.481 8 B a4 0.681 9 C a1 0.554 10 C a2 0.465 11 C a3 0.613 12 C a4 0.633 13 D a1 0.484 14 D a2 0.434 15 D a3 0.473
使用以下代码绘图后,发现C组的a1(55.4%)和a3(61.3%)堆叠顺序总是互换,尝试过将ID/aa转为因子、重排原始数据框、重启会话、更新RStudio及在GNU R中运行等方法均无效,无错误提示。
dflong %>% ggplot(aes(x=ID,y=prop, fill=reorder(aa,-prop))) + geom_col(position ="fill", data=dflong%>%filter(ID=="A")) + geom_col(position ="fill", data=dflong%>%filter(ID=="B")) + geom_col(position ="fill", data=dflong%>%filter(ID=="C")) + geom_col(position ="fill", data=dflong%>%filter(ID=="D")) + geom_col(position ="fill", data=dflong%>%filter(ID=="E")) + geom_text(aes(label=scales::percent(prop)), position=position_fill(vjust=.5), size=3, colour="black") + scale_y_continuous(labels = NULL, breaks = NULL)+ scale_fill_brewer(palette="GnBu", name="")+ coord_flip()+ theme_minimal()+ theme(legend.position = "bottom", legend.direction = "horizontal") + labs(caption="", x="", y="")
补充:使用多个独立geom_col是为了实现每个柱子单独按降序堆叠,参考相关方案。
问题原因
reorder(aa, -prop)是基于全局所有prop值对aa排序,而非每个ID分组内的局部排序,导致部分分组的堆叠顺序不符合预期。同时,多个geom_col的叠加并未覆盖全局的fill排序规则,反而容易出现层级混乱。
修复方案
先对数据按ID分组,在每个分组内将aa按prop降序排序,然后通过group参数控制堆叠顺序,无需拆分多个geom_col:
# 先对每个ID内的aa按prop降序排序 dflong_sorted <- dflong %>% group_by(ID) %>% arrange(desc(prop)) %>% mutate(aa_sorted = factor(aa, levels = unique(aa))) %>% ungroup() # 绘图 dflong_sorted %>% ggplot(aes(x = ID, y = prop, fill = aa, group = aa_sorted)) + geom_col(position = "fill") + geom_text(aes(label = scales::percent(prop)), position = position_fill(vjust = .5), size = 3, colour = "black") + scale_y_continuous(labels = NULL, breaks = NULL) + scale_fill_brewer(palette = "GnBu", name = "") + coord_flip() + theme_minimal() + theme(legend.position = "bottom", legend.direction = "horizontal") + labs(caption = "", x = "", y = "")
说明
group_by(ID) %>% arrange(desc(prop)) %>% mutate(aa_sorted = factor(aa, levels = unique(aa))):在每个ID分组内按prop降序排列,将aa转换为对应分组内排序后的因子,保证每个柱子的堆叠顺序是局部降序。- 使用
group = aa_sorted让ggplot按照每个分组内的排序规则堆叠,fill仍用原始aa保证图例一致性。
内容的提问来源于stack exchange,提问作者faaa96
相关产品推荐
相关产品推荐

