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

ggplot中如何将标准差适配至第二Y轴?

适配第二Y轴的标准差柱状图解决方案

问题描述

我正在制作多组带有标准差的柱状图,已成功添加第二Y轴,但希望标准差数据能够适配该第二Y轴,而非仅对Y轴刻度进行调整。目前我仅将主Y轴数值除以100,得到的效果如图所示,期望实现类似Excel示例中的效果。

原始代码

df_bar <- as.data.frame(
rbind(
c('g1', 0.945131015,      1.083188828,                 1.040164338,                  
  1.115716593,                 0.947886795),
c('g2', 1.393211286,      1.264193745,                 1.463434395,                  
  1.298126006,                 1.112718796),
 c('g3', 1.509976099,      1.450923745,                 1.455102201,                  
       1.280102338,                 1.462689245),
     c('g4', 1.591697668,      1.326292649,                 1.767207296,                  
    1.623619341,                 2.528108183),
     c('g5', 2.625114848,      2.164050167,                 2.092843287,                  
   2.301950359,                 2.352736806)
 )
  ) 

colnames(df_bar)<-c('interval', 'lvl3.Mellem.Høj',    'lvl1.Lav',     'TOM',          
        ',lvl4.Høj',                 'lvl2.Lav.Mellem')

df_bar <- melt(df_bar, id.vars = "interval",
           variable.name = "name", 
           value.name = "value")

df_line <- as.data.frame(
rbind(
c('g1', 0.0212972,    0.0164494,                0.0188898,                 0.01888982,                  
0.03035883),
c('g2', 0.0195600,    0.0163811,                 0.0188747,                0.01887467,                
0.03548092),
c('g3', 0.0192249,    0.0161914,               0.02215852,                0.02267605,                  
0.03426538),
c('g4', 0.0187961,    0.0180842,               0.01962371,                0.02103450,                  
0.03902890),
c('g5', 0.0209987,    0.0164596,               0.01838280,                0.02282300,                  
0.03516818)
)
) 

colnames(df_line)<-c('interval', 'lvl3.Mellem.Høj',   'lvl1.Lav',     'TOM',          
         ',lvl4.Høj',                 'lvl2.Lav.Mellem')

df_line <- melt(df_line, id.vars = "interval",
            variable.name = "name", 
            value.name = "sd")

df <- inner_join(df_bar,df_line, by=c("interval", "name"))

df %>%
  mutate(value = as.numeric(value)) %>%
  mutate(sd = as.numeric(sd)) %>%
  mutate(interval = as.factor(interval)) %>%
 mutate(name = as.factor(name)) %>%
  ggplot() +
geom_bar(aes(x = interval, y = value, fill = interval), stat = "identity") + 
geom_line(aes(x = interval, y = sd, group = 1), 
color = "black", size = .75) +
scale_y_continuous("Value", sec.axis = sec_axis(~ . /100, name = "sd")) +
facet_grid(~name, scales = "free") +
theme_bw() + theme(legend.position = "none") +
xlab("Interval") + ylab("Value") +
labs(caption = "Black line indicates standard deviation.")

解决方案

核心问题是你仅调整了第二Y轴的刻度显示,但标准差数据的实际数值未映射到第二Y轴尺度。正确做法是将标准差数据按比例放大以匹配主Y轴范围,同时让第二Y轴刻度对应实际标准差。

修改后的代码:

df_bar <- as.data.frame(
rbind(
c('g1', 0.945131015,      1.083188828,                 1.040164338,                  
  1.115716593,                 0.947886795),
c('g2', 1.393211286,      1.264193745,                 1.463434395,                  
  1.298126006,                 1.112718796),
 c('g3', 1.509976099,      1.450923745,                 1.455102201,                  
       1.280102338,                 1.462689245),
     c('g4', 1.591697668,      1.326292649,                 1.767207296,                  
    1.623619341,                 2.528108183),
     c('g5', 2.625114848,      2.164050167,                 2.092843287,                  
   2.301950359,                 2.352736806)
 )
  ) 

colnames(df_bar)<-c('interval', 'lvl3.Mellem.Høj',    'lvl1.Lav',     'TOM',          
        ',lvl4.Høj',                 'lvl2.Lav.Mellem')

df_bar <- melt(df_bar, id.vars = "interval",
           variable.name = "name", 
           value.name = "value")

df_line <- as.data.frame(
rbind(
c('g1', 0.0212972,    0.0164494,                0.0188898,                 0.01888982,                  
0.03035883),
c('g2', 0.0195600,    0.0163811,                 0.0188747,                0.01887467,                
0.03548092),
c('g3', 0.0192249,    0.0161914,               0.02215852,                0.02267605,                  
0.03426538),
c('g4', 0.0187961,    0.0180842,               0.01962371,                0.02103450,                  
0.03902890),
c('g5', 0.0209987,    0.0164596,               0.01838280,                0.02282300,                  
0.03516818)
)
) 

colnames(df_line)<-c('interval', 'lvl3.Mellem.Høj',   'lvl1.Lav',     'TOM',          
         ',lvl4.Høj',                 'lvl2.Lav.Mellem')

df_line <- melt(df_line, id.vars = "interval",
            variable.name = "name", 
            value.name = "sd")

df <- inner_join(df_bar,df_line, by=c("interval", "name"))

df %>%
  mutate(value = as.numeric(value)) %>%
  mutate(sd = as.numeric(sd)) %>%
  mutate(interval = as.factor(interval)) %>%
 mutate(name = as.factor(name)) %>%
  ggplot() +
geom_bar(aes(x = interval, y = value, fill = interval), stat = "identity") + 
# 将sd乘以100,匹配主Y轴尺度
geom_line(aes(x = interval, y = sd * 100, group = 1), 
color = "black", size = .75) +
# 第二Y轴将主Y轴数值除以100,对应实际标准差
scale_y_continuous("Value", sec.axis = sec_axis(~ . / 100, name = "Standard Deviation")) +
facet_grid(~name, scales = "free") +
theme_bw() + theme(legend.position = "none") +
xlab("Interval") + ylab("Value") +
labs(caption = "Black line indicates standard deviation.")

说明

  • 将geom_line中的y = sd改为y = sd * 100,让标准差数据放大后适配主Y轴的高度范围。
  • sec_axis(~ . / 100)确保第二Y轴的刻度显示的是实际的标准差数值,和放大后的线条对应。
  • 这样修改后,标准差线条的高度会准确对应第二Y轴的刻度,实现类似Excel的双Y轴适配效果。

内容的提问来源于stack exchange,提问作者Mathias Nissen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 23:15:46