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

ggplot中对齐双Y轴与三Y轴图表并保持X轴长度一致

解决ggplot2中三Y轴与双Y轴图表的垂直对齐问题

我明白你遇到的问题——因为第三个Y轴的额外宽度占用,导致三Y轴图表和双Y轴图表的X轴长度不一致,红绿Y轴也没法垂直对齐。下面提供两种简单可行的解决方案,帮你实现精准对齐:

方法1:给双Y轴图表添加匹配的空白右侧面板

这个思路是让两个图表的整体结构保持一致:都由「主绘图面板 + 极窄右侧面板」组成,这样垂直拼接时主面板的X轴自然对齐。

library(ggplot2)
library(grid)
library(patchwork)

# 数据定义
data_1 <- data.frame(x = c(1,2,3,4), y1 = c(5,8,1,6), y2 = c(90,40,70,50), y3 = c(600,800,900,1000))
data_2 <- data.frame(x = c(1,2,3,4), y1 = c(9,4,2,1), y2 = c(45,70,20,10))

# 三Y轴图表构建(和你的原始代码一致)
plot_1a <- ggplot(data = data_1, aes(x = x)) + 
  geom_line(aes(y = y1, color = "y1")) + 
  scale_y_continuous(sec.axis = sec_axis(trans = ~ ./ 0.09, name = "y2")) + 
  geom_line(aes(y = y2 * 0.09, color = "y2")) + 
  geom_line(aes(y = y3 * 0.008, color = "y3")) + 
  scale_color_manual(values = c("y1" = "red", "y2" = "green", "y3" = "blue")) + 
  guides(colour = FALSE) + 
  theme(axis.text.y.left = element_text(color = "red"), 
        axis.ticks.y.left = element_line(color = "red"), 
        axis.line.y.left = element_line(color = "red"), 
        axis.title.y.left = element_text(color = "red"), 
        axis.text.y.right = element_text(color = "green"), 
        axis.ticks.y.right = element_line(color = "green"), 
        axis.line.y.right = element_line(color = "green"), 
        axis.title.y.right = element_text(color = "green"))

plot_1b <- ggplot(data = data_1, aes(x = x)) + 
  scale_y_continuous(sec.axis = sec_axis(trans = ~ . / 0.008, name = "y3")) + 
  labs(x = "", y = "") + 
  theme(axis.text.y.right = element_text(color = "blue"), 
        axis.ticks.y.right = element_line(color = "blue"), 
        axis.line.y.right = element_line(color = "blue"), 
        axis.title.y.right = element_text(color = "blue"),
        axis.text.y.left = element_blank(), 
        axis.line.y.left = element_blank(), 
        axis.ticks.y.left = element_blank(), 
        axis.line.x = element_blank(), 
        axis.text.x = element_blank(), 
        axis.ticks.x = element_blank(), 
        panel.background = element_blank(), 
        plot.margin = margin(1, 0, 1, 1, "mm"))

plot_1 <- plot_1a + plot_1b + plot_layout(ncol = 2, widths = c(1, 1e-3))

# 双Y轴图表构建:添加空白右侧面板匹配plot_1的宽度结构
plot_2_main <- ggplot(data = data_2, aes(x = x)) + 
  geom_line(aes(y = y1, color = "y1")) + 
  scale_y_continuous(sec.axis = sec_axis(trans = ~ ./ 0.09, name = "y2")) + 
  geom_line(aes(y = y2 * 0.09, color = "y2")) + 
  scale_color_manual(values = c("y1" = "red", "y2" = "green")) + 
  guides(colour = FALSE) + 
  theme(axis.text.y.left = element_text(color = "red"), 
        axis.ticks.y.left = element_line(color = "red"), 
        axis.line.y.left = element_line(color = "red"), 
        axis.title.y.left = element_text(color = "red"), 
        axis.text.y.right = element_text(color = "green"), 
        axis.ticks.y.right = element_line(color = "green"), 
        axis.line.y.right = element_line(color = "green"), 
        axis.title.y.right = element_text(color = "green"))

# 创建和plot_1b宽度一致的空白面板
plot_2_spacer <- ggplot() + 
  labs(x = "", y = "") + 
  theme_void() + 
  theme(plot.margin = margin(1, 0, 1, 1, "mm"))

# 组合双Y轴图表和空白面板
plot_2 <- plot_2_main + plot_2_spacer + plot_layout(ncol = 2, widths = c(1, 1e-3))

# 垂直拼接两个图表
plot_1 / plot_2

方法2:用gtable强制统一两个图表的面板宽度

如果你不想添加额外的空白面板,可以直接提取三Y轴图表的主面板宽度,强制双Y轴图表使用相同的宽度,这样也能实现对齐:

library(ggplot2)
library(grid)
library(patchwork)
library(gtable)

# 数据和图表构建部分和方法1一致,这里省略重复代码...

# 将图表转换为gtable对象
g1 <- ggplotGrob(plot_1)
g2 <- ggplotGrob(plot_2_main)

# 获取三Y轴图表主面板的宽度
panel_width <- g1$widths[g1$layout$name == "panel"][1]

# 强制双Y轴图表的主面板使用相同宽度
g2$widths[g2$layout$name == "panel"] <- panel_width

# 垂直拼接并绘制
grid.newpage()
grid.draw(rbind(g1, g2, size = "last"))

这两种方法都能让两个图表的X轴长度完全一致,红绿Y轴也能完美垂直对齐,你可以根据自己的偏好选择其中一种。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:18:59