将“mar”图形参数传递给绘图函数

der*_*tom 4 plot r parameter-passing

mar我对在plot函数中指定图形参数不起作用这一事实感到困惑。下面将为您提供两个相同的图:

plot(1:10, 10:1, xlab = "x", ylab = "y", mar = c(10, 0, 0, 0))
plot(1:10, 10:1, xlab = "x", ylab = "y", mar = c(0, 0, 0, 0))
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试指定其他图形参数(例如col.lab下面的示例),它会按预期工作。下面给出了具有不同颜色标签的图:

plot(1:10, 10:1, xlab = "x", ylab = "y", col.lab = "red")
plot(1:10, 10:1, xlab = "x", ylab = "y", col.lab = "black")
Run Code Online (Sandbox Code Playgroud)

mar令人困惑的是,在函数外部指定图形参数效果很好,如下所示:

par.default <- par()
par(mar = c(10, 0, 0, 0))
plot(1:10, 10:1, xlab = "x", ylab = "y")
par(par.default)
Run Code Online (Sandbox Code Playgroud)

有没有办法解决这个(在我看来)意外的行为?

All*_*ron 6

There are three different types of graphical parameter used in R:

  • Normal (ptype 0 in the underlying C code).
  • Non-inline, (ptype 1, meaning it can be set by the user via par, but not inline via high-level functions).
  • Read-only. (ptype 2, which cannot be set by the user at all, but is fixed according to the graphics device).

mar is of the non-inline type. If you read the documentation for ?par, then the Details section lists all of the other graphical parameters that cannot be set in a call to high-level plotting functions, i.e. all of the non-inline parameters :

Several parameters can only be set by a call to par():

  • "ask",
  • "fig", "fin",
  • "lheight",
  • "mai", "mar", "mex", "mfcol", "mfrow", "mfg",
  • "new",
  • "oma", "omd", "omi",
  • "pin", "plt", "ps", "pty",
  • "usr",
  • "xlog", "ylog",
  • "ylbias"

The remaining parameters can also be set as arguments (often via ...) to high-level plot functions

These parameters are all handled by the C function Specify, whereas the ptype 0 parameters, which can be used in high level plotting functions, are handled by the C function Specify2.

It is clear that these assignations are not random, but a conscious design choice. I could easily tell a just-so story about why they were designed this way; for example, if I make a scatter plot then want to add lines, annotations, titles or legends to it, then I would have to use the same mar argument in my calls to lines, axis, legend etc to ensure the plot areas were matching, and this would feel like worse design than having to set mar in advance. "Why can't I just set this once before I plot and be done with it!?"

但这种设计背后的实际原因需要来自开发人员本身(或者甚至可能来自系统所基于的GRZpar库的开发人员)。

至于如何解决这个问题,除了定义一个新的高级绘图函数来设置mar, 绘图,然后重置旧的之外,几乎没有什么可做的mar

plot_with_mar <- function(mar = par('mar'), ...) {
  parmar <- par('mar')
  par(mar = mar)
  plot(...)
  par(mar = parmar, new = FALSE)
  invisible(NULL)
}
Run Code Online (Sandbox Code Playgroud)

这可以用作以下内容的替代plot

set.seed(1)

x <- 1:10
y <- rnorm(10)

plot_with_mar(x, y, mar = c(2, 2, 2, 2))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

plot_with_mar(x, y, mar = c(8, 8, 8, 8))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

如果这感觉有点笨拙,那么请考虑这实际上是 R 中所有内置高级绘图函数所做的事情。另外,如果您尝试在使用 绘图后添加线条或注释plot_with_mar,您很快就会发现尝试以这种方式做事是多么烦人。

创建于 2022 年 11 月 17 日,使用reprex v2.0.2