使用给定的宽高比保存绘图

时间:2013-05-07 15:24:55

标签: r ggplot2 gtable

我正在使用非常棒的库ggplot2。我想出了如何使用coord_fixed设置绘图的纵横比。现在,我想将绘图保存为具有指定宽度(例如10 cm)的PDF,并计算所需的高度。我没弄明白如何实现这一目标。这甚至可能吗?

5 个答案:

答案 0 :(得分:11)

您可以使用网格函数来计算ggplot grob的完整大小,但至少有( edit:)两个警告:

  • 将打开一个额外的设备窗口,进行单位转换

  • 默认情况下,绘图面板大小为0,因为它意味着根据它所在的设备(视口)即时计算,而不是相反。

话虽如此,以下函数试图打开一个完全适合ggplot的设备,

library(ggplot2)
library(grid)

sizeit <- function(p, panel.size = 2, default.ar=1){

  gb <- ggplot_build(p)
  # first check if theme sets an aspect ratio
  ar <- gb$plot$coordinates$ratio

  # second possibility: aspect ratio is set by the coordinates, which results in 
  # the use of 'null' units for the gtable layout. let's find out
  g <- ggplot_gtable(gb)
  nullw <- sapply(g$widths, attr, "unit")
  nullh <- sapply(g$heights, attr, "unit")

  # ugly hack to extract the aspect ratio from these weird units
  if(any(nullw == "null"))
    ar <- unlist(g$widths[nullw == "null"]) / unlist(g$heights[nullh == "null"])

  if(is.null(ar)) # if the aspect ratio wasn't specified by the plot
       ar <- default.ar

  # ensure that panel.size is always the larger dimension
  if(ar <= 1 ) panel.size <- panel.size / ar

  g$fullwidth <- convertWidth(sum(g$widths), "in", valueOnly=TRUE) + 
    panel.size
  g$fullheight <- convertHeight(sum(g$heights), "in", valueOnly=TRUE) + 
    panel.size / ar

  class(g) <- c("sizedgrob", class(g))
  g
}


print.sizedgrob <- function(x){
  # note: dev.new doesn't seem to respect those parameters
  # when called from Rstudio; in this case it 
  # may be replaced by x11 or quartz or ...
  dev.new(width=x$fullwidth, height=x$fullheight)
  grid.draw(x)
}


p1 <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point() + coord_fixed() +
  theme(plot.background = element_rect(colour = "red"))

p2 <- p1 + aes(x = mpg, y = wt)

# need for an explicit dummy device open, otherwise it's a bit off
# for no apparent reason that I can understand
dev.new() 

sizeit(p1, 0.1)

enter image description here

sizeit(p2, 2)

enter image description here

答案 1 :(得分:3)

根据巴普蒂斯特的答案,我删除了他的代码以返回地理位置建议的纵横比。这对我来说更方便,因为我想要一个固定的宽度或高度,并通过一个现有的包装函数传递所有内容,该函数也为我的pdf添加了字体。

哦,如果你使用了facet,你需要手动考虑它们。按行划分并乘以列。不确定是否有更好的方法.....

ggGetAr <- function(p, default.ar=-1){

    gb <- ggplot_build(p)
    # first check if theme sets an aspect ratio
    ar <- gb$plot$coordinates$ratio

    # second possibility: aspect ratio is set by the coordinates, which results in 
    # the use of 'null' units for the gtable layout. let's find out
    g <- ggplot_gtable(gb)
    nullw <- sapply(g$widths, attr, "unit")
    nullh <- sapply(g$heights, attr, "unit")

    # ugly hack to extract the aspect ratio from these weird units
    if(any(nullw == "null"))
        ar <- unlist(g$widths[nullw == "null"]) / unlist(g$heights[nullh == "null"])

    if(is.null(ar)) # if the aspect ratio wasn't specified by the plot
        ar <- default.ar

    ar[1]
}

答案 2 :(得分:2)

不确定,但是这就是你想要的东西吗?

ggplot(data.frame(x = seq(10), y = seq(10)), aes(x = x, y = y)) +
    geom_point() +
    coord_equal() +
    theme(aspect.ratio = 1)

这对我来说很好看:

ggsave("test.pdf", width = 4, height = 4)

空白太多,但图形本身的宽高比为1:

ggsave("test2.pdf", width = 4)

消息: 在图像中保存4 x 6.93

答案 3 :(得分:0)

如果您使用ggsave,则只需指定图形设备的宽度和高度即可。如果指定绘图本身的纵横比,则在图形设备中具有此粗略比例(大致)也是很好的。保存heightwidthpdf的单位是英寸:

ggplot(...) # make a plot here
ggsave("plot.pdf", width = 10)

现在你只需要将10厘米变成英寸。此外,如果您未指定height,则ggplot(...) # make plot width = 10 height = (9/16) * width ggsave("plot.pdf", width = width, height = height) 不会强制为某个宽高比。如果您想要16:9的宽高比,您可以根据宽度轻松计算高度:

coord_fixed()

如果你真的想要,可以将它包装在一个函数中。


编辑:关键是要同步绘图的宽高比(通过library(ggplot2) ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point() + coord_fixed() ggsave("plt.png", width = 7, height = 7) )和图形设备的宽高比。例如

ggsave

enter image description here 导致很多白色空间。虽然以下ggsave("plt.png", width = 2, height = 7) 调用的宽高比更合适,但没有这么大的空白区域(对于大图片而言,无法设置最大尺寸:):

{{1}}

enter image description here

答案 4 :(得分:0)

更简单的解决方案是使用默认边距保存绘图,并使用ImageMagick修剪生成的png。

require(ggplot2)
require(dplyr)

ggplot(iris, aes(Sepal.Length, Sepal.Width)) + geom_point() + coord_fixed(0.3)
ggsave("untrimmed.png")


system("convert untrimmed.png -trim -bordercolor white -border 20  reframed.png")

当然,根据使用的输出设备,修剪会有所不同。例如。如果是pdf,您可以使用pdfcrop所述的here