如何手动将具有固定长宽比的视口放入其父视窗,以免浪费空间,而不会像ggplot那样浪费空间? [英] How do I manually fit a viewport with a fixed aspect ratio into its parent such that no space is wasted like ggplot can do?

查看:85
本文介绍了如何手动将具有固定长宽比的视口放入其父视窗,以免浪费空间,而不会像ggplot那样浪费空间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a viewport which has to have a fixed aspect ratio as it has to have equal distance between x and y units in its native coordinate system.

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

I want to fit this viewport into a parent viewport such that it will scale to the largest extent possible, but maintains its aspect ratio.

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

Using the grid unit 'snpc', I was able to maintain the aspect ratio, though I could not reach the largest extent possible. See my code below, which prints out what I have archieved so far at four different device aspect ratios.

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

While the viewport of interest (gray and with grid) fills the maximal area available when the device has a small width, the approach fails if the device width becomes so large that the device height is the limiting factor for the viewport size. The viewport does not cover the whole possible height. I want the viewport of interest to cover the whole device height in the rightmost plot.

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

EDIT: I found out that ggplot can do this and have updated my example to show that. Note how ggplot touches the upper and lower device border in the rightmost image and the left and right border at the leftmost image, why my self-made solution does not touch the upper and lower device border in the rightmost image even if there would be space. I cannot use ggplot however, as I want to include a custom drawing built only with grid but which is dependent on equal distances on native x and y coordinate system.

# -- 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')

推荐答案

ggplot2使用具有空单位的网格布局和respect参数来强制执行宽高比.这是一个例子,

ggplot2 uses grid layouts with null units and the respect argument to enforce aspect ratios. Here's an example,

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))))

这篇关于如何手动将具有固定长宽比的视口放入其父视窗,以免浪费空间,而不会像ggplot那样浪费空间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆