如何手动将视口比例固定的视口放入其父视口,以免浪费空间,如ggplot一样?

akr*_*ica 5 plot r ggplot2 r-grid

我有一个视口,该视口必须具有固定的宽高比,因为它的原始坐标系中的x和y单位之间必须具有相等的距离。

我想将此视口装配到父视口中,以便将其最大程度地缩放,但保持其宽高比。

使用网格单元“ snpc”,尽管我无法达到最大程度,但我仍然可以保持宽高比。请参阅下面的代码,该代码以四种不同的设备纵横比打印出到目前为止已归档的内容。

绘制四种不同的输出设备宽度

当设备的宽度较小时,感兴趣的视口(灰色并带有网格的视口)会填充可用的最大区域,但如果设备的宽度变得太大而导致设备的高度成为视口大小的限制因素,则该方法将失败。视口无法覆盖整个可能的高度。我希望感兴趣的视口在最右边的图中覆盖整个设备的高度。

编辑:我发现ggplot可以做到这一点,并更新了我的示例来显示这一点。请注意ggplot如何触摸最右边图像中的设备上下边界以及最左边图像中的左右边界,为什么我自己制作的解决方案即使在有空格的情况下也不会触摸最右边图像中的设备上下边界。但是,我不能使用ggplot,因为我想包括一个仅使用网格构建的自定义图形,但该图形依赖于本机x和y坐标系上的相等距离​​。

ggplot以四种不同的输出设备宽度输出

# -- Helper functions ------------------------------------------------------

# Draw something (inside fun) for different paper sizes
forDifferentSizes <- function(names, width, height, fun, ...){
  cyc <- function(x, along) rep_len(x, length(along))
  mapply( names, cyc(width, names), cyc(height, names)
        , FUN = function(n, w, h){
            png(paste0(n,'.png'), width = w, height = h, ...)
            on.exit(dev.off())
            fun(n, w, h)
        })
}

# -- Own attempt -----------------------------------------------------------
library(grid)

# Coordinate system
x <- c(1,6)
y <- c(1,4)
range <- c(diff(x), diff(y))
dims <- range / max(range)

annot <- function(name){
  grid.rect(gp = gpar(fill = NA))
  grid.text( name,unit(1, 'npc'),unit(0,'npc'), just = c(1,0))
}

forDifferentSizes( paste0('X',letters[1:4]), seq(100, 500, length.out = 4), 250
  , fun = function(...){
  grid.newpage()

  pushViewport(
    viewport( width  = unit( dims[1], 'snpc')
              , height = unit( dims[2], 'snpc')
              , xscale = x
              , yscale = y
    )
  )
  annot('vp2')
  grid.grill(v = x[1]:x[2], h = y[1]:y[2], default.units = 'native')
})

# --- ggplot2 can do it -----------------------------------------------------

library(ggplot2)
data("mtcars")

forDifferentSizes(paste0('G',letters[1:4]), seq(100, 500, length.out = 4), 250
  , pointsize = 8
  , fun = function(...){
  p <- ggplot(mtcars) + aes(x = drat, y = mpg) + geom_point() + 
    theme(aspect.ratio = dims[2]/dims[1])
  print(p)
})

# --- Make the output images for post (imagemagick required) ---------------
system('convert G*.png -bordercolor black -border 1x1 +append G.png')
system('convert X*.png -bordercolor black -border 1x1 +append X.png')
Run Code Online (Sandbox Code Playgroud)

小智 5

ggplot2使用具有空单位和respect参数的网格布局来实施纵横比。这是一个例子

library(grid)

ar <- (1+sqrt(5))/2
gl <- grid.layout(1,1,widths=unit(1,"null"), height=unit(1/ar,"null"), respect = TRUE)
grid.newpage()
grid.rect(vp=vpTree(viewport(layout = gl), 
                    vpList(viewport(layout.pos.row = 1, layout.pos.col = 1))))
Run Code Online (Sandbox Code Playgroud)