55

我想将四个图放在一个页面上。轴标签应仅打印在最边缘,即仅用于底部图表的x轴标签,仅用于左侧图表的y轴标签。这既适用于整个轴的名称,也适用于各个刻度线。我可以使用以下代码生成这些内容:

pdf(file = "ExampleOutput.pdf",
    width = 6.61,
    height = 6.61,
    pointsize = 10
    )
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))))
par(mfrow = c(2,2))
for (i in 0:3) {
  x <- Tab[[1 + i %% 2]]
  plot(x, Tab[[3 + i %/% 2]],
       xlab = if (i %/% 2 == 1) "Some Categories" else NULL,
       ylab = if (i %% 2 == 0) "Some Values" else NULL,
       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")
}
par(mfrow = c(1,1))
dev.off()

我会欢迎有关如何改进我的绘图命令的建议,也许可以避免手动耗尽左下角的轴和 L。但这只是一个补充。

此序列的结果如下所示:

电流输出

这里的问题是大量浪费的空白。我的印象是 R 为轴和刻度标签保留空间,即使它们没有被使用。由于浪费了空间,对于左下图,实际上只有每秒x刻度被标记,这在这里真的很糟糕。

我想生成一个没有那么多空白的类似情节。实际的地块应该是相同的大小,所以它们排列正确,但标签的空间应该只在外面。我想像这样的布局(在 GIMP 中创建的模型):

期望的输出

我怎样才能实现这样的布局?

4

4 回答 4

66

假设 y 和 x 轴标签适用于所有图,这里是对您显示的一般图的轻微修改。它使用外边距来包含轴标签,我们title()使用参数添加outer = TRUE。效果有点像ggplot2格子图中的标签。

这里的关键是:

op <- par(mfrow = c(2,2),
          oma = c(5,4,0,0) + 0.1,
          mar = c(0,0,1,1) + 0.1)

它设置绘图参数(调用之前的值存储在 中op)。我们在边 1 和边 2 上使用54线作为外边距,这是mar参数的常用数字。mar在顶部和右侧分别添加 1 行的绘图区域边距 ( ),以便在绘图之间留出一点空间。

轴标签在循环之后添加for()

title(xlab = "Some Categories",
      ylab = "Some Values",
      outer = TRUE, line = 3)

整个脚本是:

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)

产生

在此处输入图像描述

于 2012-11-05T21:58:43.290 回答
22

基于Gavin Simpson 的回答,我现在使用以下解决方案:

par(mfrow = c(2, 2),     # 2x2 layout
    oma = c(2, 2, 0, 0), # two rows of text at the outer left and bottom margin
    mar = c(1, 1, 0, 0), # space for one row of text at ticks and to separate plots
    mgp = c(2, 1, 0),    # axis label at 2 rows distance, tick labels at 1 row
    xpd = NA)            # allow content to protrude into outer margin (and beyond)

结果如下所示:

生成的图像

如您所见,这足以允许打印所有刻度标签。如果不是,那么根据Gavin 的评论,将cex.axis小于 1 的值添加到参数列表应该有助于减少那里的字体大小。

于 2012-11-06T20:46:00.623 回答
19

只需操纵您的参数,在par. 该参数mar控制单个绘图的边距大小。将您更改par为:

par(mfrow = c(2,2), mar=c(1, 4, 1, 1) + 0.1)#it goes c(bottom, left, top, right) 
于 2012-11-05T20:56:08.410 回答
2

您需要一个条件评估来分配par('mar')适合定位的值;这是检查“x-layout-position”的代码示例(在循环内):

    pdf(file = "ExampleOutput2.pdf",
    width = 6.61,
    height = 6.61,
    pointsize = 10
    )
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))))
par(mfrow = c(2,2), mar= c(3, 4, 1, 1) + 0.1)
for (i in 0:3) {
  x <- Tab[[1 + i %% 2]]
  plot(x, Tab[[3 + i %/% 2]], mar= if(i %/%2 == 0) {c(4, 4, 1, 1) + 0.1 
                                              }else{c(1, 1, 1, 1) + 0.1},
       xlab = if (i %/% 2 == 1) "Some Categories" else NULL,
       ylab = if (i %% 2 == 0) "Some Values" else NULL,
       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")
}
par(mfrow = c(1,1))
dev.off()

您将需要调整它以满足您的需要,因为它只处理两个边距条件并且您确实有 4 个单独的条件(下面的 2 个都需要更多的底部空间,右边的需要较少的左边空间,上面的两个(也有不同的要求)。如果您在全局范围内缩小“mar”值,它将切断您的 x 和 y 标签,正如您仅将此代码放入循环中时 xlab 值的丢失所示。

于 2012-11-05T21:38:08.457 回答