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

如何使用ggplot2或patchwork对齐折线图与柱状图的X轴?

折线图与柱状图X轴偏移的解决方法(ggplot2+patchwork)

问题说明

使用ggplot2绘制的折线图(带带状区域)与柱状图通过patchwork拼接后,X轴出现轻微偏移,核心原因是:

  • 折线图的X轴为连续型(基于数值型的Site变量)
  • 柱状图因stat_summary(geom="bar")默认将X轴处理为离散型,加上两个图的X轴刻度断点设置不一致,导致坐标系统错位

具体解决方法

方法1:统一X轴属性与刻度(最稳妥)

强制两个图的X轴都为连续型,且使用完全一致的范围和刻度断点,消除偏移根源:

library(ggplot2)
library(patchwork)

data<-data.frame(
  Gains=c(NA,18.26,27.7,13.09,-8.36,1.73,5.57,17.1,-31.31,5.43,38.97,18.81,6.12,1.85,NA,16.28,21.18,3.44,-0.14,-3.87,10.57,11.942,-2.12,-0.07,33.34,13.66,14.14,30.66,NA,17.7,24.286,14.638,-7.986,0.622,9.265,3.216,-30.509,4.714,37.78,17.842,11.606,12.188),
  Site=c(67,66,61,60,58,57,55,52,48,44,42,39,33,24.5,67,66,61,60,58,57,55,52,48,44,42,39,33,24.5,67,66,61,60,58,57,55,52,48,44,42,39,33,24.5),
  Discharge=c(0,18.26,52.16,65.25,56.89,58.62,64.4,81.5,50.19,55.62,94.59,129.37,146.87,154.17,0,16.28,43.09,46.53,46.39,42.52,53.3,65.242,39.46,39.39,72.73,98.21,112.35,143.01,0,17.7,49.266,63.904,55.918,57.67,67.155,78.255,47.746,52.46,90.24,125.092,141.84,162.68)
)

# 提取Site的全局范围,确保两个图X轴范围一致
x_range <- range(data$Site, na.rm = TRUE)

# 绘制折线图(统一X轴刻度)
a<-ggplot(data, aes(x=Site, y=Discharge))+
  stat_summary(geom = "ribbon", fun.min = min, fun.max = max, alpha = 0.25) +
  stat_summary(geom = "linerange", fun.min = min, fun.max = max, alpha = 0.3) +  
  stat_summary(geom = "line", fun = mean, size=1.2) +
  geom_point(aes(y = Discharge)) +
  annotate("rect", xmin = 60, xmax = 57, ymin = -Inf, ymax = Inf, alpha = .08)+
  annotate("rect", xmin = 52, xmax = 44, ymin = -Inf, ymax = Inf, alpha = .08)+
  scale_y_continuous(n.breaks=10)+
  scale_x_reverse(breaks=seq(20,80,5), limits = x_range)+
  xlab("River Mile")+
  ylab("Discharge (cfs)")+
  theme(plot.margin = margin(5,10,5,10))

# 绘制柱状图(指定group=1确保X轴为连续型,统一刻度)
b<-ggplot(data, aes(x=Site, y=Gains))+
  stat_summary(geom = "bar", fun = mean, aes(group=1))+
  annotate("rect", xmin = 60, xmax = 57, ymin = -Inf, ymax = Inf, alpha = .08)+
  annotate("rect", xmin = 52, xmax = 44, ymin = -Inf, ymax = Inf, alpha = .08)+
  scale_x_reverse(breaks=seq(20,80,5), limits = x_range)+
  scale_y_continuous(breaks=seq(-30,50,10))+
  ylab("Gain and Loss (cfs)")+
  xlab("River Mile")+
  theme(plot.margin = margin(5,10,5,10))

# 拼接并强制水平对齐
pwrk <- b / a
pwrk + plot_layout(heights = c(1,2)) + plot_annotation(align = "h")

方法2:利用patchwork的对齐参数快速修复

若不想手动统一刻度,可直接使用patchwork的align="h"参数强制水平对齐,但需先确保柱状图的X轴为连续型(添加group=1):

# 仅修改柱状图和拼接部分
b<-ggplot(data, aes(x=Site, y=Gains))+
  stat_summary(geom = "bar", fun = mean, aes(group=1))+ # 关键:指定group=1
  annotate("rect", xmin = 60, xmax = 57, ymin = -Inf, ymax = Inf, alpha = .08)+
  annotate("rect", xmin = 52, xmax = 44, ymin = -Inf, ymax = Inf, alpha = .08)+
  scale_x_reverse(breaks=seq(20,80,5))+
  scale_y_continuous(breaks=seq(-30,50,10))+
  ylab("Gain and Loss (cfs)")+
  xlab("River Mile")+
  theme(plot.margin = margin(5,10,5,10))

# 拼接时添加align参数
pwrk <- b / a
pwrk + plot_layout(heights = c(1,2), align = "h")

方法3:改用分面绘图(共享X轴)

将数据转为长格式,使用facet_wrap实现共享X轴,从根源避免对齐问题:

library(ggplot2)
library(tidyr)

# 转换为长格式数据
data_long <- data %>%
  pivot_longer(cols = c(Discharge, Gains), names_to = "Metric", values_to = "Value")

ggplot(data_long, aes(x=Site, y=Value))+
  # 折线图相关元素
  geom_line(data = subset(data_long, Metric=="Discharge"), stat="summary", fun=mean, size=1.2)+
  geom_point(data = subset(data_long, Metric=="Discharge"))+
  stat_summary(data = subset(data_long, Metric=="Discharge"), geom = "ribbon", fun.min = min, fun.max = max, alpha = 0.25)+
  stat_summary(data = subset(data_long, Metric=="Discharge"), geom = "linerange", fun.min = min, fun.max = max, alpha = 0.3)+
  # 柱状图相关元素
  stat_summary(data = subset(data_long, Metric=="Gains"), geom = "bar", fun = mean, aes(group=1))+
  # 添加标注矩形
  annotate("rect", xmin = 60, xmax = 57, ymin = -Inf, ymax = Inf, alpha = .08)+
  annotate("rect", xmin = 52, xmax = 44, ymin = -Inf, ymax = Inf, alpha = .08)+
  # 分面设置,共享X轴,Y轴自由缩放
  facet_wrap(~Metric, scales = "free_y", ncol=1, strip.position = "left")+
  scale_x_reverse(breaks=seq(20,80,5))+
  xlab("River Mile")+
  theme(strip.placement = "outside")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 05:40:22