25

我正在使用非常棒的库 ggplot2。我想出了如何使用coord_fixed. 现在,我想将绘图保存为具有指定宽度(例如 10 厘米)的 PDF,并计算所需的高度。我不知道如何实现这一目标。这甚至可能吗?

4

5 回答 5

15

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

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

  • 默认情况下,绘图面板大小将为 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)

在此处输入图像描述

sizeit(p2, 2)

在此处输入图像描述

于 2013-05-08T13:29:22.187 回答
5

根据巴蒂斯特的回答,我剥离了他的代码以返回地球理论所建议的纵横比。这对我来说更方便,因为我要么想要一个固定的宽度或高度,而且还通过一个现有的包装函数传递所有内容,该函数也将字体添加到我的 pdf 中。

哦,如果您使用构面,则需要手动考虑它们。除以行并乘以列。不知道有没有更好的方法......

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]
}
于 2015-07-17T14:19:57.913 回答
2

If you use ggsave you can simply specify the width and height of the graphics device. If you specify the aspect ratio of the plot itself, it is also good to have this aspect ratio (roughly) in your graphics device. The unit of height and width when saving pdf is inches:

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

Now you only have to transform the 10 cm into inches. In addition, height is not forced to a certain aspect ratio if you do not specify it. If you want a 16:9 aspect ratio, you can easily calculate the height based on the width:

ggplot(...) # make plot
width = 10
height = (9/16) * width
ggsave("plot.pdf", width = width, height = height)

You could wrap this in a function if you really want to.


edit: The crux is to synchronize the aspect ratio of the plot (through coord_fixed()) and the aspect ratio of the graphics device. For example

library(ggplot2)
ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point() + coord_fixed()
ggsave("plt.png", width = 7, height = 7)

enter image description here leads to a lot of white space. While the following ggsave call, which has a much better fit in aspect ratio, does not have this amount of white space (sorry for the large picture, could not set the maximum size :)):

ggsave("plt.png", width = 2, height = 7)

enter image description here

于 2013-05-07T15:36:13.117 回答
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

于 2013-05-08T12:28:02.133 回答
1

更简单的解决方案是使用默认边距保存绘图并使用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

于 2015-10-07T09:39:06.353 回答