如何在R的geom_col图表中实现指定填充的堆叠柱状图?
问题描述
我尝试用以下代码创建柱状图,要求每个物种对应Best frequency和High frequency两列堆叠显示,但无法让fill仅填充较小的变量,反而按较大变量生成了着色效果。使用的包包括ggplot2、ggthemes和forcats。
当前代码:
ggplot(data = penta_calcs, mapping = aes(x = Best_frequency_of_hearing_kHz + High_frequency_of_hearing_limit_kHz, y = fct_reorder(Species, Clade), fill = High_frequency_of_hearing_limit_kHz)) + geom_col() + labs(title = "Best frequency of hearing in non-avian dinosaurs", x = "Hearing frequency (kHz)", y = " ") + scale_color_colorblind()
当前结果:所有柱子整体按High_frequency_of_hearing_limit_kHz的数值着色,没有区分出两个堆叠部分,且x轴是两列数值的总和,不符合堆叠柱状图的结构。
期望效果:每个物种对应的柱子由Best frequency(基础部分)和High frequency(堆叠在上方的部分)组成,仅为较小的那个变量(或指定的High frequency部分)填充颜色,整体呈现类似单侧堆叠的效果,x轴显示实际的频率范围。
解决方案
你现在的问题出在两点:一是数据格式不对,堆叠柱状图需要长格式数据(每个变量单独占一行),而不是直接在x轴把两个数值加起来;二是fill映射错了——你应该把它绑定到变量类别(是Best还是High频率),而不是数值本身。
按下面的步骤改就行:
- 先把宽格式的原始数据转成长格式,区分开Best和High两种频率类型
- 调整ggplot的映射关系,让x对应频率值,y对应物种,fill对应频率类型
- 可选:设置只有你想要的那个变量(比如较小的频率)上色,另一个用白色/背景色
修改后的代码示例:
library(tidyverse) library(ggthemes) library(forcats) # 把宽格式转成长格式,方便堆叠 penta_long <- penta_calcs %>% # 保留需要的列 select(Species, Clade, Best_frequency_of_hearing_kHz, High_frequency_of_hearing_limit_kHz) %>% pivot_longer( cols = -c(Species, Clade), # 除了物种和分支列,其他列转成类型 names_to = "Frequency_type", # 新列存频率类型 values_to = "Frequency_kHz" # 新列存频率数值 ) %>% # 固定顺序,让Best频率在柱子下方,High在上方 mutate(Frequency_type = fct_relevel(Frequency_type, "Best_frequency_of_hearing_kHz")) # 画堆叠图,只给High频率上色 ggplot(penta_long, aes(x = Frequency_kHz, y = fct_reorder(Species, Clade), fill = Frequency_type)) + geom_col(position = "stack") + # 自定义颜色:Best用白色,High用色盲友好色 scale_fill_manual( values = c( "Best_frequency_of_hearing_kHz" = "white", "High_frequency_of_hearing_limit_kHz" = scale_color_colorblind()$palette[1] ), labels = c("最佳听觉频率", "听觉上限频率") # 给图例改中文标签 ) + labs( title = "非鸟类恐龙的听觉频率分布", x = "听觉频率 (kHz)", y = "", fill = "频率类型" ) + theme_minimal()
如果想要严格实现“仅填充较小变量”的效果(不管是Best还是High,只要数值小就上色),可以先给每个物种标记出较小的频率类型,再对应上色:
# 先给每个物种标记哪个频率更小 penta_calcs <- penta_calcs %>% mutate( Smaller_freq = ifelse( Best_frequency_of_hearing_kHz < High_frequency_of_hearing_limit_kHz, "Best_frequency_of_hearing_kHz", "High_frequency_of_hearing_limit_kHz" ) ) # 转长格式并添加填充标记 penta_long <- penta_calcs %>% pivot_longer( cols = c(Best_frequency_of_hearing_kHz, High_frequency_of_hearing_limit_kHz), names_to = "Frequency_type", values_to = "Frequency_kHz" ) %>% mutate(Fill_flag = ifelse(Frequency_type == Smaller_freq, "需要填充", "不填充")) # 绘图,只给较小的频率上色 ggplot(penta_long, aes(x = Frequency_kHz, y = fct_reorder(Species, Clade), fill = Fill_flag)) + geom_col(position = "stack") + scale_fill_manual( values = c("需要填充" = scale_color_colorblind()$palette[1], "不填充" = "white") ) + labs( title = "非鸟类恐龙的听觉频率分布", x = "听觉频率 (kHz)", y = "" ) + theme(legend.position = "none") # 不需要图例就隐藏
内容的提问来源于stack exchange,提问作者Adam_M
相关产品推荐
相关产品推荐

