Guardar el diagtwig con una relación de aspecto dada

Estoy trabajando con la biblioteca realmente impresionante ggplot2. Descubrí cómo establecer la relación de aspecto de un gráfico usando coord_fixed . Ahora, me gustaría guardar la ttwig en un PDF con un ancho especificado (por ejemplo, 10 cm) y calcular la altura requerida. No descubrí cómo lograr esto. ¿Esto es posible?

Puede usar funciones de cuadrícula para calcular el tamaño completo de ggplot grob, pero hay ( edite: al menos) dos advertencias:

  • se abrirá una ventana adicional para el dispositivo, para hacer la conversión de la unidad

  • el tamaño del panel de trazado será 0 por defecto, ya que está destinado a calcularse sobre la marcha según el dispositivo (puerto de visualización) en el que viva, no al revés.

Dicho esto, la siguiente función intenta abrir un dispositivo que se ajusta exactamente a 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

No estoy seguro, pero es algo como esto lo que buscas?

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

Esto me parece bien:

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

Demasiado espacio en blanco, pero el gráfico en sí tiene una relación de aspecto 1:

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

Mensaje: Guardar 4 x 6.93 en imagen

Basándome en la respuesta de Baptiste, quité su código para devolver la relación de aspecto como lo sugiere la geoteoría. Esto fue mucho más conveniente para mí, porque o quería una anchura o altura fija y también pasé todo a través de una función de envoltura existente que también agrega fonts a mi pdf.

Ah, y si usó facetas, debe tenerlas en cuenta de forma manual. Divida por filas y multiplique por columnas. No estoy seguro de si hay una mejor manera …..

 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] } 

Si usa ggsave , puede simplemente especificar el ancho y alto del dispositivo gráfico. Si especifica la relación de aspecto del gráfico en sí, también es bueno tener esta relación de aspecto (aproximadamente) en su dispositivo gráfico. La unidad de height y width al guardar pdf es pulgadas:

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

Ahora solo tienes que transformar los 10 cm en pulgadas. Además, la height no está forzada a una cierta relación de aspecto si no la especifica. Si desea una relación de aspecto de 16: 9, puede calcular fácilmente la altura en función del ancho:

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

Podría envolver esto en una función si realmente lo desea.


editar: La clave es sincronizar la relación de aspecto de la ttwig (a través de coord_fixed() ) y la relación de aspecto del dispositivo gráfico. Por ejemplo

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

enter image description here conduce a un montón de espacio en blanco. Mientras que la siguiente llamada ggsave , que tiene un ajuste mucho mejor en la relación de aspecto, no tiene esta cantidad de espacio en blanco (lo siento por la imagen grande, no se pudo establecer el tamaño máximo :)):

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

enter image description here

Una solución más simplista sería guardar la ttwig con los márgenes por defecto y recortar el png resultante con ImageMagick .

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

Por supuesto, el recorte variará según el dispositivo de salida utilizado. Por ejemplo, en el caso de pdf, puede usar pdfcrop como se describe aquí .