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

如何在R语言中创建带双Y轴的分组箱线图

问题描述

我需要在R语言中创建一个双Y轴分组箱线图:X轴是因子变量,每个因子水平对应两个连续变量的箱线图(左右并排),同时两个连续变量使用不同刻度的Y轴。现在我改编了基础绘图的示例代码,但第二个变量的箱线图和散点图总是出现在第一个的下方,而不是旁边。

我的代码如下:

data <- data.frame(Factor1=factor(c("A", "B","A", "B","A", "B","A", "B", "A", "B","A",     "B","A", "B","A", "B", "A", "B","A", "B", "A", "B", "A", "B","A", "B", "A", "B","A", "B","A",     "B","A", "B", "A", "B")), Cont1=rnorm(36, mean=100, sd= 15), Cont2=rnorm(36, mean=0.35, sd=0.05))

par(mar=c(5, 4, 4, 6) + 0.5)

## Plot first continuous variable
# Boxplot
boxplot(Cont1 ~ Factor1, data = data, col="white", boxcol=2, xlim=c(0.5, 3.5 + length(unique(data$Factor1))),axes=FALSE, xlab="", ylab="")

# Points
stripchart(Cont1 ~ Factor1, data = data,method = "jitter",pch = 19,col = 2,vertical = TRUE,add = TRUE)

mtext("Cont1", side=2, line=2.5, col=2)
box()
axis(2, col=2, col.axis=2,las=1)  ## las=1 makes horizontal labels


## Allow a second plot on the same graph
par(new=TRUE)

## Plot the second continuous variable
# Boxplot
boxplot(Cont2 ~ Factor1, data = data, col="white", boxcol=3,xlim=c(0.5, 5.5), axes=FALSE, xlab="", ylab="") # with these limits the new boxplot and dotplot shows up below the previous ones, rather than next to them

# Points
stripchart(Cont2 ~ Factor1, data = data,method = "jitter", pch = 19, col = 3, vertical = TRUE, add = TRUE)
## a little farther out (line=4) to make room for labels
mtext("Cont2", side=4,col=3,line=4) 
axis(4, col=3,col.axis=3,las=1)

## Draw the factor axis
mtext("Factor1", side=1, col="black", line=2.5)  

希望得到代码改进方案或新的实现思路。


解决方案

方案一:修复基础绘图系统代码

问题核心是第二个箱线图的X轴位置未偏移,导致和第一个图重叠错位。通过手动指定两个变量箱线图的X位置(给第二个变量的X坐标加偏移量),就能实现并排效果。

改进后的完整代码:

data <- data.frame(Factor1=factor(c("A", "B","A", "B","A", "B","A", "B", "A", "B","A",     "B","A", "B","A", "B", "A", "B","A", "B", "A", "B", "A", "B","A", "B", "A", "B","A", "B","A",     "B","A", "B", "A", "B")), Cont1=rnorm(36, mean=100, sd= 15), Cont2=rnorm(36, mean=0.35, sd=0.05))

# 调整边距,为右侧Y轴预留空间
par(mar=c(5, 4, 4, 6) + 0.5)

# 定义偏移量,控制两个箱线图的间距
offset <- 0.3
factor_levels <- levels(data$Factor1)
n_factors <- length(factor_levels)

# --------------------- 绘制第一个变量(Cont1) ---------------------
# 明确指定箱线图的X位置:1,2,...n_factors
boxplot(Cont1 ~ Factor1, data = data, col="white", boxcol=2, 
        at = 1:n_factors,
        xlim = c(0.5, n_factors + 1),  # 扩展X轴范围,容纳偏移后的第二个箱线图
        axes=FALSE, xlab="", ylab="")

# 添加散点图,对应相同的X位置
stripchart(Cont1 ~ Factor1, data = data, method = "jitter", pch = 19, col = 2,
           vertical = TRUE, add = TRUE, at = 1:n_factors)

# 左侧Y轴配置
mtext("Cont1", side=2, line=2.5, col=2)
axis(2, col=2, col.axis=2, las=1)
box()

# --------------------- 绘制第二个变量(Cont2) ---------------------
par(new=TRUE)

# 第二个箱线图的X位置:1+offset, 2+offset,...n_factors+offset
boxplot(Cont2 ~ Factor1, data = data, col="white", boxcol=3,
        at = 1:n_factors + offset,
        xlim = c(0.5, n_factors + 1),  # 和第一个图保持一致的X范围
        ylim = range(data$Cont2),  # 锁定Y范围,避免自动缩放错位
        axes=FALSE, xlab="", ylab="")

# 添加散点图,对应偏移后的X位置
stripchart(Cont2 ~ Factor1, data = data, method = "jitter", pch = 19, col = 3,
           vertical = TRUE, add = TRUE, at = 1:n_factors + offset)

# 右侧Y轴配置
mtext("Cont2", side=4, col=3, line=4)
axis(4, col=3, col.axis=3, las=1)

# --------------------- 绘制X轴标签 ---------------------
# 将X轴刻度放在两个箱线图的中间位置
axis(1, at = 1:n_factors + offset/2, labels = factor_levels)
mtext("Factor1", side=1, col="black", line=2.5)

方案二:使用ggplot2实现(更简洁易维护)

基础绘图需要手动调整坐标,ggplot2通过数据重塑和内置的分组、双Y轴功能,可以更高效实现需求,且代码可读性更强。

步骤说明:

  1. 将宽格式数据转为长格式,方便分组绘图
  2. 计算两个变量的刻度转换系数,实现双Y轴的映射
  3. 绘制分组箱线图和抖动散点图,配置双Y轴样式

完整代码:

library(ggplot2)
library(tidyr)

# 将数据从宽格式转为长格式
data_long <- pivot_longer(data, cols = c(Cont1, Cont2), names_to = "Variable", values_to = "Value")

# 计算双Y轴的刻度转换系数(根据数据范围自动适配)
scale_factor <- diff(range(data$Cont1)) / diff(range(data$Cont2))
shift_value <- min(data$Cont1) - min(data$Cont2) * scale_factor

ggplot(data_long, aes(x = Factor1, y = Value, color = Variable)) +
  # 箱线图:设置分组偏移
  geom_boxplot(position = position_dodge(width = 0.8), fill = "white") +
  # 抖动散点图:和箱线图对齐分组
  geom_jitter(position = position_jitterdodge(jitter.width = 0.2, dodge.width = 0.8), size = 1) +
  # 配置双Y轴:左侧为Cont1刻度,右侧为转换后的Cont2原始刻度
  scale_y_continuous(
    name = "Cont1",
    sec.axis = sec_axis(~ (. - shift_value)/scale_factor, name = "Cont2")
  ) +
  # 设置变量对应颜色
  scale_color_manual(values = c("Cont1" = "red", "Cont2" = "green")) +
  # 调整主题样式
  theme_classic() +
  theme(
    axis.title.y = element_text(color = "red"),
    axis.title.y.right = element_text(color = "green"),
    axis.text.y = element_text(color = "red"),
    axis.text.y.right = element_text(color = "green")
  )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 10:44:50