【问题标题】:Overlay multi-panel plot on single plot在单个图上叠加多面板图
【发布时间】:2015-09-10 14:48:33
【问题描述】:

我正在尝试将多面板图(使用 R 中的基本图形)覆盖在地图的单个面板图上。多面板图如下所示:

...我希望将其覆盖在地图上(使用 maps 包绘制)。

我的代码如下所示:

# Blank plot for map
plot(1, 1, type="n", xlab="", ylab="", axes=F,
     xlim=c(-39,-35.5),ylim=c(-55,-54))
# Plot map
map("worldHires", regions="Falkland Islands:South Georgia",col="#BFBFBF",
  fill=F, add=T, bg="#7F7F7F", lwd=0.05) 
# Start overplotting
par(new=T)
par(mfrow=c(2,3))
par(mar=c(0,0,0,0),oma=c(5,7,1,0))
hist(~yy$l.class[yy$strat=="SR"], breaks=classes, main="",xlab="",ylab="",
  col=cols[1], border=cols[1], probability=T, ylim=c(0,0.18),
  bg=rgb(1,1,1,0))

但是,一旦我绘制了第一个直方图,我就会得到以下信息:

如您所见,第一个直方图被绘制到多面板布局的最后一个面板中。当我尝试绘制更多直方图时,会打开一个新设备。

我认为这与我在绘制地图后的 par() 调用有关?有什么建议吗?

【问题讨论】:

    标签: r plot


    【解决方案1】:

    如果没有可重复的问题,我将展示一种方法 通用数据。您必须使其适应您的工作。

    使用par(mfrow=c(2,3))可以实现多图,虽然简单,但是限制性最强。其他选项包括layout(...)(我认为这不起作用)和par(fig=...)(这是我在这里使用的)。一个合理的起始参考是here

    我将从您的地图开始(注意:请在您的代码中包含所需的库):

    library(maps)
    library(mapdata)
    par(fig=c(0,1,0,1))                     # force full-device plot
    plot(1, 1, type="n", xlab="", ylab="", axes=F,
         xlim=c(-39,-35.5),ylim=c(-55,-54))
    map("worldHires", regions="Falkland Islands:South Georgia",col="#BFBFBF",
        fill=F, add=T, bg="#7F7F7F", lwd=0.05)
    

    接下来我将设置一个矩阵用于定义绘图区域,模仿您使用par(mfrow=c(2,3)) 定义的排列:

    xs <- seq(0, 1, len=4)
    ys <- seq(0, 1, len=3)
    m <- merge(cbind(head(xs, n=-1), tail(xs, n=-1)),
               cbind(head(ys, n=-1), tail(ys, n=-1)),
               by=NULL)
    ##        V1.x      V2.x V1.y V2.y
    ## 1 0.0000000 0.3333333  0.0  0.5
    ## 2 0.3333333 0.6666667  0.0  0.5
    ## 3 0.6666667 1.0000000  0.0  0.5
    ## 4 0.0000000 0.3333333  0.5  1.0
    ## 5 0.3333333 0.6666667  0.5  1.0
    ## 6 0.6666667 1.0000000  0.5  1.0
    

    par(fig=...) 采用左右 (x) 和底部和顶部 (y) 百分比。 m 的第一行表示下一个图将包括屏幕的水平 0 到 33% 和垂直 0 到 50%(即左下角)。第一个绘图调用并不严格需要par(fig=...) 调用,但我喜欢将它放在那里,以便在重做绘图时重置绘图布局。它应该省略 new=TRUE 或使用 new=FALSE 来明确(在这种情况下可以说是一件好事)。

    接下来,我将仅提供一些图表。这部分是我做的部分,但它显示了它是如何被使用的。 m 的编程定义及其在下面的使用不是完全必要的;您可以轻松地手动定义每个par(fig=...) 调用。无论如何,也不需要使用简单的 2x3 网格图,并且这种方法允许将直方图放置在地图上有意义的位置。 (这显然可以通过编程方式完成,但完全取决于您和您的数据。)

    columns <- c('mpg', 'hp', 'drat', 'wt', 'qsec')
    for (i in 1:5) {
         par(fig=unlist(m[i,]), new=TRUE)
         col <- names(mtcars)[i]
         hist(mtcars[[col]], col=1+i, main=col)
    }
    

    【讨论】:

    • 但请注意,使用par(fig=...) 几乎是你所能得到的体力劳动......如果管理不善,它很容易变得笨拙。 权力越大,责任越大 :-)
    • 你现在可能知道了,与par(mfrow=...)相反,这是从左到右和(不同地)从下到上填充的。这很容易补救,例如rev(ys)
    • 干得好。我想您可能会对我刚刚找到并作为替代答案发布的更直接的解决方案感兴趣。
    • 对于未来的读者:这个解决方案对于 OP 的需求来说有点强硬;鉴于所述布局要求的简单性,Josh 的解决方案更简单、更优雅。
    【解决方案2】:

    最直接的解决方案是手动设置par(mfg = c(1,1))。这告诉 R 将下一个(子)图放置到 mfrow 诱导布局的第一个槽中在当前页面上1

    因此,例如,您可以这样做:

    library(maps)
    library(mapdata)
    
    ## Set up the background map
    plot.new()
    par(fig = c(0,1,0,1))
    plot.window(xlim=c(-39,-35.5),ylim=c(-55,-54))
    map("worldHires", regions="Falkland Islands:South Georgia", col="#BFBFBF", add=TRUE)
    
    ## Set up a grid of subplots areas
    par(mfrow = c(2, 3), mfg = c(1, 1))          ## **Key is to set mfg=c(1,1)**
    
    ## Fill grid with subplots
    hist(mtcars[["mpg"]],  main="mpg",  col=2)
    hist(mtcars[["hp"]],   main="hp",   col=3)
    hist(mtcars[["cyl"]],  main="cyl",  col=4)
    plot.new()                                   ## Skip plotting into this cell
    hist(mtcars[["disp"]], main="dip",  col=5)
    hist(mtcars[["drat"]], main="drat", col=6)
    

    1 您需要明确设置par(mfg=...),因为对于m-by-n 布局,R 的默认行为是设置par(mfg=c(m,n));进行设置,以便下一个绘图将进入 下一页 上布局的第一个插槽 - 在这种情况下不是您想要的。

    【讨论】:

    • 哦,废话,太棒了!这在日常修补中也非常有用,而不仅仅是一次性的,从而减少了对我的 par(fig) 手动解决方案的需求。 (par(fig) 在需要非平凡布局时仍然有用。)
    • @r2evans -- 哈哈。很高兴你和我一样欣赏它。值得把它写下来!是的,我同意:par(fig=...) 等。提供最大的灵活性(首先是layout(),最后是par(mfcol=...)par(mfrow=...))。
    猜你喜欢
    • 1970-01-01
    • 2018-12-25
    • 2017-03-28
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多