2013-05-07 4 views
17

Я работаю с действительно удивительной библиотекой ggplot2. Я понял, как установить соотношение сторон графика, используя coord_fixed. Теперь я хотел бы сохранить график в PDF с указанной шириной (например, 10 см) и позволить рассчитывать требуемую высоту. Я не понял, как это сделать. Возможно ли это?Сохранить участок с заданным соотношением сторон

ответ

10

Вы можете использовать функции сетки, чтобы вычислить полный размер 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) 

enter image description here

sizeit(p2, 2) 

enter image description here

+0

точный ответ на вопрос оставлен как упражнение для читателя (этот взлом сетки становится слишком уродливым, мне нужен перерыв) – baptiste

+0

Спасибо за ваш ответ, баптист. Похоже, что нет никакого правильного решения. – marsl

+0

Принял ваш ответ, поскольку я думаю, что нет лучшего решения. Спасибо всем. – marsl

0

Если вы используете ggsave, вы можете просто указать ширину и высоту графического устройства. Если вы укажете соотношение сторон самого сюжета, также хорошо иметь это соотношение сторон (примерно) в графическом устройстве. Единица height и width при сохранении pdf дюймы:

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

Теперь у вас есть только для преобразования 10 см в дюймы. Кроме того, height не привязан к определенному соотношению сторон, если вы его не укажете. Если вы хотите соотношение сторон 16: 9, вы можете легко рассчитать высоту на основе ширины:

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

Вы можете обернуть это в функции, если вы действительно хотите.


править: Суть состоит в синхронизации соотношение сторон участка (через coord_fixed()) и соотношение сторон графического устройства. Например

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

enter image description here приводит к большому количеству белого пространства. В то время как следующий ggsave вызов, который имеет гораздо лучше подходят в пропорции, не имеет такого количества белого пространства (простите за большую картину, не может установить максимальный размер :)):

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

enter image description here

+1

Я думал, что Пол, но это размер * устройства *, а не сюжет. Когда вы добавите в заголовок, метки осей и легенды и т. Д., Сама область построения графика может быть не квадратной, а с помощью 'coord_fixed()' самой области сюжета, а затем не заполняет свободное пространство. Я не знаю ничего хорошего, кроме как изменить размер окна построения до тех пор, пока 'ggsave()' не указывая ширину, получив изображение шириной 10 см. –

+0

Спасибо, Пол за ваш ответ. Гэвин, это точно так же, как вы указали в своем комментарии. Я думаю, что это довольно проблема, нужно обрезать каждый сюжет вручную. Подождем, если кто-нибудь придумает решение. – marsl

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 х 6,93 в изображении

+1

Спасибо за ваш ответ Деннис. К сожалению, это не подходит, поскольку 'ggsave' просто по умолчанию занимает размер текущего окна графика. – marsl

2

на основе I ответ Батист в разделил его код вниз, чтобы вернуть соотношение сторон, как предложено g eotheory. Это было намного удобнее для меня, потому что я либо хотел иметь фиксированную ширину или высоту, а также передавал все через существующую функцию обертки, которая также добавляет шрифты в мой 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] 
} 
0

Более упрощенное решение было бы сохранить участок с полямами по умолчанию и обрезать полученный с 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") 

Конечно, обрезка будет отличаться в зависимости от используемого устройства вывода. Например. в случае pdf вы можете использовать pdfcrop, как описано here.

Смежные вопросы