如果这对于讨论 R 中不同绘图机制的优点的旧线程是多余的,我深表歉意。但是,我认为可能值得展示具有三种主要绘图机制的“简单”多面板绘图的解决方案。 @thelatemail 关于使用lattice 或ggplot2 进行此类情节的建议是正确的,也许这个答案说明了原因。
尽管如此,尽管 base R 可能需要通过 par() 进行最大程度的调整,并且需要熟悉 library(help = "graphics") 中的功能,但我还是倾向于使用 base R 来生成出版质量数据。我在这个PDF 中发现了Sean Anderson 对基于R 的多面板绘图的精彩讨论。
首先,生成一些可重现的数据(总是一个好主意),由单个 data.frame 中的 18 组 20 个 x-y 对组成,具有合适的组标签和索引 uid。这些图将显示 x-y 数据并添加一条平滑线。
set.seed(1234)
x <- seq(0, 9, length.out = 20)
y <- replicate(6, (x-5) + rnorm(x))
y <- c(y, replicate(6, 5*sin(x) + rnorm(x)))
y <- c(y, replicate(6, 5*atanh((9-x)/10) + rnorm(x)))
a <- gl(3, 120, labels = c("A","B","C")) # these factors are handy
b <- gl(6, 20, length = 360)
uid <- as.numeric(b:a)
df <- data.frame(x, y, a, b, uid)
rm(x, y, a, b, uid) # prevent use of variables outside of the data.frame
根据我的经验,R Studio 在绘图方面要求更高(控制)。我不确定这段代码在 R Studio 下的运行情况如何。发出警告后,将创建一个适当大小的绘图设备以启动。
dev.new(width = 6.5, height = 6.5)
首先,使用par(mfrow = c(6, 3) 和外边距参数 (oma) 的基本 R 解决方案。这也非典型地使用legend() 函数为每个面板添加标题。
par(mfrow = c(6, 3), mar = c(0,0,0,0), oma = c(6, 6, 2, 2))
ylim <- range(df$y) # to ensure uniformly sized plots
ncol <- 3 # number of columns to the plot
for(u in 1:18) {
sel <- df$uid == u
plot(y ~ x, df, subset = sel, ann = FALSE, axes = FALSE, ylim = ylim)
box() # adds a "frame" or "box" around each plot
xy <- loess.smooth(df$x[sel], df$y[sel], span = 1/3)
lines(xy)
if ((u - 1)%%ncol == 0) axis(2, las = 1)
if ((u - 1)%/%ncol == 5) axis(1)
leg.text <- paste(unique(df$a[sel]), unique(df$b[sel]), sep = ":")
legend("top", leg.text, bty = "n")
}
mtext("x", side = 1, outer = TRUE, line = 3)
mtext("y", side = 2, outer = TRUE, line = 3)
ggplot2 和 lattice 都将返回可以进一步细化的对象。此处显示了带有 lattice 的解决方案。
library(lattice)
o <- xyplot(y ~ x | b:a, df, as.table = TRUE, layout = c(3, 6))
o <- update(o, type = c("p", "smooth"), span = 1/3)
plot(o)
绘图机制之间的句法以及嵌入的美学原则不同。这在基本的ggplot2 解决方案中很明显。
library(ggplot2)
g <- ggplot(df, aes(x, y)) + geom_point() + facet_wrap(b:a ~ ., ncol = 3)
g <- g + geom_smooth()
plot(g)
选择使用哪种机制是个人的。我提到我经常喜欢基本图形来进行精细控制。为了准备要在监视器上显示的图,ggplot2 提供了屏幕友好的图像,几乎没有大惊小怪。对于反复探索多维数据,我发现lattice 是最有用的。这可以通过执行绘图代码(不加载库)所需的时间来说明。捕获每个system.time() 的输出并在此处显示(来自 Windows i7 机器)。
rbind(base = time1, lattice = time2, ggplot = time3)[, 1:3]
> user.self sys.self elapsed
> base 0.05 0.03 0.10
> lattice 0.23 0.03 0.28
> ggplot 1.27 0.05 1.38