Выравнивание по левому краю ggplot при сохранении при использовании фиксированного соотношения сторон - PullRequest
2 голосов
/ 14 апреля 2020

Я создаю собственную тему ggplot для стандартизации внешнего вида графиков, которые я создаю. Цель более сложная, чем этот минимальный пример, поэтому я ищу общее решение. У меня есть несколько ключевых целей:

  • Я хочу, чтобы все графики экспортировались с одинаковым размером (3000 пикселей в ширину, 1500 пикселей в высоту).
  • Я хочу контролировать соотношение сторон Сам сюжет панели.
  • Я хочу использовать textGrobs для включения чисел.
  • Я хочу, чтобы изображение было выровнено по левому краю

Проблема, с которой я сталкиваюсь, заключается в том, что при объединении этих двух ограничений сохраняемое изображение центрирует график ggplot в окне , что имеет смысл по умолчанию, но выглядит плохо в этом случае.

Я надеюсь, что есть общее решение для выравнивания по левому краю панели ggplot при экспорте. В идеале, это также будет работать аналогично для граненых графов.

Кажется, что-то должно быть возможно с использованием одной или нескольких комбинаций пакетов gridExtra, gtable, cowplot и egg, но после экспериментов в течение нескольких часов я Я в растерянности. Кто-нибудь знает, как я могу это сделать? Мой код включен ниже.

Это изображение, которое получается. Как видите, заголовок выровнен по левому краю внизу, но сам ggplot центрирован по горизонтали. Я также хочу выровнять график ggplot по левому краю.

Вывод графика: https://i.stack.imgur.com/5EM2c.png

library(ggplot2)

# Generate dummy data
x <- paste0("var", seq(1,10))
y <- LETTERS[1:10]
data <- expand.grid(X=x, Y=y)
data$Z <- runif(100, -2, 2)

# Generate heatmap with fixed aspect ratio
p1 <- ggplot(data, aes(X, Y, fill= Z)) + 
    geom_tile() +
    labs(title = 'A Heatmap Graph') +
    theme(aspect.ratio = 1)


# A text grob for the footer
figure_number_grob <- grid::textGrob('Figure 10',
                                     x = 0.004,
                                     hjust = 0,
                                     gp = grid::gpar(fontsize = 10,
                                                     col = '#01A184'))

plot_grid <- ggpubr::ggarrange(p1,
                               figure_number_grob,
                               ncol = 1,
                               nrow = 2,
                               heights = c(1,
                                           0.05))

# save it
png(filename = '~/test.png', width = 3000, height = 1500, res = 300, type = 'cairo')
print(plot_grid)
dev.off()

1 Ответ

0 голосов
/ 17 апреля 2020

Мне удалось найти решение для этого, которое работает для моих нужд, хотя это выглядит немного хакерским.

Вот основная идея:

  • Создание графика без с фиксированным соотношением сторон.
  • Разделить легенду из сюжета как его собственный компонент
  • Использовать GridExtrarangeGrob для комбинирования графика, разделителя, легенды и другого разделителя по горизонтали
  • Установить ширину график до некоторой доли np c (нормальные родительские координаты), в данном случае 0,5. Это означает, что график займет 50% горизонтального пространства выходного файла.
    • Обратите внимание, что это не то же самое, что установка фиксированного соотношения сторон для графика. Если вы знаете размер выходного файла, это близко к тому же, но размер текста и заголовков осей будет влиять на выходное соотношение сторон для самой панели, поэтому, пока он приближается, это не идеально, если вам нужно действительно фиксированное соотношение сторон
  • Установите ширину проставок на оставшуюся часть np c (в данном случае снова 0,5) минус ширина легенды для горизонтального центрирования легенды в оставшемся пространстве.

Вот мой код:

library(ggplot2)

# Generate dummy data
x <- paste0("var", seq(1,10))
y <- LETTERS[1:10]
data <- expand.grid(X=x, Y=y)
data$Z <- runif(100, -2, 2)

# Generate heatmap WITHOUT fixed aspect ratio. I address this below
p1 <- ggplot(data, aes(X, Y, fill= Z)) + 
    geom_tile() +
    labs(title = 'A Heatmap Graph')

# Extract the legend from our plot
legend = gtable::gtable_filter(ggplotGrob(p1), "guide-box")


plot_output <- gridExtra::arrangeGrob(
    p1 + theme(legend.position="none"),                           # Remove legend from base plot
    grid::rectGrob(gp=grid::gpar(col=NA)),                        # Add a spacer
    legend,                                                       # Add the legend back
    grid::rectGrob(gp=grid::gpar(col=NA)),                        # Add a spacer
    nrow=1,                                                       # Format plots in 1 row
    widths=grid::unit.c(unit(0.5, "npc"),                         # Plot takes up half of width
                        (unit(0.5, "npc") - legend$width) * 0.5,  # Spacer width
                        legend$width,                             # Legend width
                        (unit(0.5, "npc") - legend$width) * 0.5)) # Spacer width

# A text grob for the footer
figure_number_grob <- grid::textGrob('Figure 10',
                                     x = 0.004,
                                     hjust = 0,
                                     gp = grid::gpar(fontsize = 10,
                                                     col = '#01A184'))

plot_grid <- ggpubr::ggarrange(plot_output,
                               figure_number_grob,
                               ncol = 1,
                               nrow = 2,
                               heights = c(1,
                                           0.05))

# save it
png(filename = '~/test.png', width = 3000, height = 1500, res = 300, type = 'cairo')
print(plot_grid)
dev.off()

А вот и выходное изображение: https://i.stack.imgur.com/rgzFy.png

...