Сохранение графа с помощью ggsave после использования ggplot_build и ggplot_gtable

Я изменяю график, построенный с помощью ggplot, путем изменения данных, созданных ggplot_build (по той же причине, что и Включить пробел для отсутствующего уровня фактора, используемого в качестве заливки в geom_boxplot). Насколько я понимаю помощь, которую я нашел в этой теме, я должен был бы сохранить результат, применив ggplot_gtable и arrGrob до вызова ggsave в результатах (Сохранение графика grid.arrange() для файла).

Однако я получаю ошибку "график должен быть графиком ggplot2", также с помощью этого простого воспроизводимого примера:

require('ggplot2')
require('gridExtra')
df <- data.frame(f1=factor(rbinom(100, 1, 0.45), label=c("m","w")), 
                  f2=factor(rbinom(100, 1, 0.45), label=c("young","old")),
                  boxthis=rnorm(100))
g <- ggplot(aes(y = boxthis, x = f2, fill = f1), data = df) + geom_boxplot()
dd <- ggplot_build(g)

# Printing the graph works:
print(arrangeGrob(ggplot_gtable(dd)))

# Saving the graph doesn't:
ggsave('test.png',arrangeGrob(ggplot_gtable(dd)))

Может кто-нибудь объяснить, почему это не работает? Есть ли способ использовать ggsave после изменения данных с помощью ggplot_build()?

(Моя версия пакетов - gridExtra_0.9.1 и ggplot2_0.9.3.1)

Ответ 1

он не работает, потому что ggsave хочет объект класса ggplot, в то время как вы проходите grob. arrangeGrob будет иногда обманывать ggsave при притворстве наследования от ggplot, но только тогда, когда по крайней мере один из grobs принадлежит этому классу; здесь, однако, вы передаете только gtable.

Возможно, самым простым способом является клонирование ggsave и обход проверки класса,

ggsave <- ggplot2::ggsave; body(ggsave) <- body(ggplot2::ggsave)[-2]

Изменить: Dev-версия ggplot2 больше не требует этого взлома *, поскольку ggsave теперь работает с любым grob.

* PS: этот хак больше не работает, так как assemblyGrob теперь возвращает gtable, и его метод печати не нарисован на устройстве.

Ответ 2

Обход - это построить объект gtable с помощью grid.draw(), а затем использовать dev.copy() для переноса графика в файл.

Не забудьте также использовать dev.off() сразу после.