You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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频率),而不是数值本身。

按下面的步骤改就行:

  1. 先把宽格式的原始数据转成长格式,区分开Best和High两种频率类型
  2. 调整ggplot的映射关系,让x对应频率值,y对应物种,fill对应频率类型
  3. 可选:设置只有你想要的那个变量(比如较小的频率)上色,另一个用白色/背景色

修改后的代码示例:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 13:30:57