【问题标题】:generating graphs in one image在一张图像中生成图表
【发布时间】:2019-10-19 14:03:52
【问题描述】:

我在 R 中制作了大约 18 个图表,我希望它们在一张图像中呈现。我收到有关大小的错误消息。

过去我曾使用par(mfrow = c(2,2)) 和这样简单的东西在一次渲染中生成多个图形。

所以,在我正在做的事情中,我想要生成六乘以三的渲染。因此,它看起来像六行三列。我认为应该很简单,使用par(mfrow = c(6,3))

在 R 中,当我尝试做 par(mfrow = c(6,3)) 我得到 ​​p>

“plot.new() 中的错误:图形边距太大”。

我尝试通过使用 3 乘以 3 而不是 6 乘以 3 来解决这个问题。这将导致我想要的一半,但是我可以通过 MSpaint 将它们组合起来。有点麻烦,但它完成了产生最后 6 次 3 的工作。有没有更简单的方法可以做到这一点,允许在 R 中完成?

【问题讨论】:

  • 不出所料,这是因为您的“数字边距(太大)”。第一步可能是减少您的边距大小 - par(mar=c(1,1,1,1)) 或使您的设备尺寸更大以考虑额外的边距 - dev.new(width=16,height=10)。但诚然,在一个大数组中组合这样的图可能更适合基于网格的绘图方法,如 latticeggplot2
  • 我还建议使用ggplot2 进行分面。但是 6x3 的面最终可能看起来相当拥挤并且视觉上难以理解。提供示例数据和代码可能会有所帮助,以便我们判断可视化效果并提出建议。

标签: r plot graph


【解决方案1】:

如果这对于讨论 R 中不同绘图机制的优点的旧线程是多余的,我深表歉意。但是,我认为可能值得展示具有三种主要绘图机制的“简单”多面板绘图的解决方案。 @thelatemail 关于使用latticeggplot2 进行此类情节的建议是正确的,也许这个答案说明了原因。

尽管如此,尽管 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)


ggplot2lattice 都将返回可以进一步细化的对象。此处显示了带有 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  

【讨论】:

  • 真正彻底和有用的答案。
【解决方案2】:

我会推荐使用 ggplot2。这是tutorial

您可能想要使用grid.arrange()。我经常使用它并且效果很好。我上面提供的链接详细介绍了它的用法。

【讨论】:

    猜你喜欢
    • 2021-11-21
    • 2021-07-13
    • 2021-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多