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

R语言多面板绘图:显示完整旋转X轴标签并减少空白

解决多面板绘图中旋转X轴标签被截断的问题

问题描述

我参考了Stack Overflow上《Avoid wasting space when placing multiple aligned plots onto one page》的方案,设置了如下par参数:

par(mfrow = c(5, 2),     # 5行2列布局
    oma = c(2, 2, 0, 0), # 外侧底部和左侧留2行文本空间
    mar = c(1,6,2,1),    # 刻度处留1行文本空间,用于分隔子图
    mgp = c(2, 1, 0),    # 轴标签距离轴2行,刻度标签距离轴1行
    xpd = NA)            # 允许内容延伸到外侧边距(及以外)

生成的多面板绘图效果接近预期,但底部子图的旋转X轴标签被截断。我需要让标签完整显示且保持旋转状态。尝试在绘制最后2个子图前执行par(mar = c(1,6,2,1)+1),但这会改变绘图尺寸,而非单纯显示标签。

可使用以下示例数据测试:

set.seed(42)
catA <- factor(c("m100", "m500", "m1000", "m2000", "m3000", "m5000"))
catB <- factor(20:28)
samples <- 100
rsample <- function(v) v[ceiling(runif(samples, max=length(v)))]
Tab <- data.frame(catA = rsample(catA),
                  catB = rsample(catB),
                  valA = rnorm(samples, 150, 8),
                  valB = pmin(1,pmax(0,rnorm(samples, 0.5, 0.3))))
op <- par(mfrow = c(2,2),
          oma = c(5,4,0,0) + 0.1,
          mar = c(0,0,1,1) + 0.1)
for (i in 0:3) {
  x <- Tab[[1 + i %% 2]]
  plot(x, Tab[[3 + i %/% 2]], axes = FALSE)
  axis(side = 1,
       at=1:nlevels(x),
       labels = if (i %/% 2 == 1) levels(x) else FALSE)
  axis(side = 2, labels = (i %% 2 == 0))
  box(which = "plot", bty = "l")
}
title(xlab = "Some Categories",
      ylab = "Some Values",
      outer = TRUE, line = 3)
par(op)

解决方案

方法1:为底部子图单独调整底部边距

核心思路是仅给底部子图增加底部边距,保持其他边距和绘图区域尺寸一致,避免整体布局变形:

set.seed(42)
catA <- factor(c("m100", "m500", "m1000", "m2000", "m3000", "m5000"))
catB <- factor(20:28)
samples <- 100
rsample <- function(v) v[ceiling(runif(samples, max=length(v)))]
Tab <- data.frame(catA = rsample(catA),
                  catB = rsample(catB),
                  valA = rnorm(samples, 150, 8),
                  valB = pmin(1,pmax(0,rnorm(samples, 0.5, 0.3))))

op <- par(mfrow = c(2,2),
          oma = c(2,4,0,0) + 0.1, # 减少外侧底部边距,由子图自身留出空间
          mar = c(0,0,1,1) + 0.1)

for (i in 0:3) {
  x <- Tab[[1 + i %% 2]]
  # 仅底部子图调整底部边距
  if (i %/% 2 == 1) {
    par(mar = c(3, 0, 1, 1) + 0.1) 
  } else {
    par(mar = c(0, 0, 1, 1) + 0.1)
  }
  plot(x, Tab[[3 + i %/% 2]], axes = FALSE)
  axis(side = 1,
       at=1:nlevels(x),
       labels = if (i %/% 2 == 1) levels(x) else FALSE,
       las = 2) # 旋转标签90度
  axis(side = 2, labels = (i %% 2 == 0))
  box(which = "plot", bty = "l")
}
title(xlab = "Some Categories",
      ylab = "Some Values",
      outer = TRUE, line = 1) # 适配新边距调整外侧标题位置
par(op)

方法2:用mtext手动添加旋转标签

如果不想调整子图边距,可通过mtext将标签绘制到外侧边距区域,避免截断:

set.seed(42)
catA <- factor(c("m100", "m500", "m1000", "m2000", "m3000", "m5000"))
catB <- factor(20:28)
samples <- 100
rsample <- function(v) v[ceiling(runif(samples, max=length(v)))]
Tab <- data.frame(catA = rsample(catA),
                  catB = rsample(catB),
                  valA = rnorm(samples, 150, 8),
                  valB = pmin(1,pmax(0,rnorm(samples, 0.5, 0.3))))

op <- par(mfrow = c(2,2),
          oma = c(4,4,0,0) + 0.1, # 为手动标签预留外侧底部空间
          mar = c(0,0,1,1) + 0.1)

for (i in 0:3) {
  x <- Tab[[1 + i %% 2]]
  plot(x, Tab[[3 + i %/% 2]], axes = FALSE)
  # 仅绘制刻度,用mtext添加旋转标签
  if (i %/% 2 == 1) {
    axis(side = 1, at=1:nlevels(x), labels = FALSE)
    mtext(levels(x), side = 1, at=1:nlevels(x), las=2, line=1.5, cex=0.8)
  } else {
    axis(side = 1, at=1:nlevels(x), labels = FALSE)
  }
  axis(side = 2, labels = (i %% 2 == 0))
  box(which = "plot", bty = "l")
}
title(xlab = "Some Categories",
      ylab = "Some Values",
      outer = TRUE, line = 2)
par(op)

方法3:结合mgp优化标签位置

通过mgp让刻度标签更靠近轴,配合最小化的底部边距,在不浪费空间的前提下显示完整标签:

set.seed(42)
catA <- factor(c("m100", "m500", "m1000", "m2000", "m3000", "m5000"))
catB <- factor(20:28)
samples <- 100
rsample <- function(v) v[ceiling(runif(samples, max=length(v)))]
Tab <- data.frame(catA = rsample(catA),
                  catB = rsample(catB),
                  valA = rnorm(samples, 150, 8),
                  valB = pmin(1,pmax(0,rnorm(samples, 0.5, 0.3))))

op <- par(mfrow = c(2,2),
          oma = c(2,4,0,0) + 0.1,
          mar = c(2,0,1,1) + 0.1, # 仅留2行底部边距
          mgp = c(1.5, 0.5, 0)) # 让刻度标签更贴近轴

for (i in 0:3) {
  x <- Tab[[1 + i %% 2]]
  plot(x, Tab[[3 + i %/% 2]], axes = FALSE)
  axis(side = 1,
       at=1:nlevels(x),
       labels = if (i %/% 2 == 1) levels(x) else FALSE,
       las=2) # 旋转标签
  axis(side = 2, labels = (i %% 2 == 0))
  box(which = "plot", bty = "l")
}
title(xlab = "Some Categories",
      ylab = "Some Values",
      outer = TRUE, line = 1)
par(op)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 22:45:40