Ускорьте рендеринг большой тепловой карты из ggplot в R - PullRequest
0 голосов
/ 19 октября 2018

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

Пример кода:

# Load packages (tidyverse)
library(tidyverse)

# Create dataframe
df <- expand.grid(x = seq(1,100000), y = seq(1,100000))

# add variable: performance
set.seed(123)
df$z <- rnorm(nrow(df))

ggplot(data = df, aes(x = x, y = y)) +
  geom_raster(aes(fill = z)) 

Хотя я сохраняю график как векторизованное изображение (.pdf; это не так уж и много), при открытии pdf загружается очень медленно.Я ожидаю, что каждая отдельная точка во фрейме данных отображается при открытии файла.

Я читал другие посты (например, Исследование данных в R: быстро отображать тепловую карту большой матрицы? ), которые используют image() для визуализации матриц, однако я хотел бы использовать ggplot дляизменить изображение.

Вопрос: Как ускорить рендеринг этого сюжета?Есть ли способ (помимо понижения разрешения графика) при сохранении векторизации изображения ускорить этот процесс?Можно ли уменьшить векторизацию ggplot?

Ответы [ 2 ]

0 голосов
/ 24 февраля 2019

Первое, что я попробовал, было stat_summary_2d, чтобы получить средний биннинг, но он казался медленным и также создал некоторые артефакты на правом и верхнем краях:

library(tidyverse)
df <- expand.grid(x = seq(1,1000), y = seq(1,1000))
set.seed(123)
df$z <- rnorm(nrow(df))
print(object.size(df), units = "Mb")
#15.4 Mb

ggplot(data = df, aes(x = x, y = y, z = z)) +
  stat_summary_2d(bins = c(100,100)) +  #10x downsample, in this case
  scale_x_continuous(breaks = 100*0:10) +
  labs(title = "stat_summary_2d, 1000x1000 downsampled to 100x100")  

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

enter image description here

Оттуда стало медленнее, когда я попробовал большую сетку, которую вы запрашиваете.

(Кстати, возможно, стоит пояснить, что файл векторной графикикак PDF, в отличие от растровой графики, можно изменить размер без потери разрешения, однако в этом случае выходной файл будет растровым файлом с разрешением 10 000 мегапикселей, далеко за пределы человеческого восприятия, то есть экспортируетсяв векторный формат, где каждый «пиксель» становится очень маленьким прямоугольником в PDF. Такое использование векторного формата может быть полезно для некоторых необычных случаев, таких какесли вам когда-нибудь понадобится взорвать вашу тепловую карту без потери разрешения на гигантской поверхности, например на футбольном поле.Но похоже, что в этом случае это может быть неправильный инструмент для работы, так как вы помещаете в векторный файл кучи данных, которые не будут заметны.)

То, что работало эффективнее, - это делатьусреднение с dplyr до ggplot.При этом я мог бы взять массив 10k x 10k и уменьшить его до 100x перед отправкой в ​​ggplot.Это обязательно уменьшает разрешение, но я не понимаю ценности в этом случае использования сохранения разрешения сверх человеческих способностей воспринимать его.

Вот некоторый код, чтобы выполнить группировку самостоятельно и затем построить уменьшенную версию:

# Using 10k x 10k array, 1527.1 Mb when initialized
downsample <- 100
df2 <- df %>%
  group_by(x = downsample * round(x / downsample),
           y = downsample * round(y / downsample)) %>%
  summarise(z = mean(z))

ggplot(df2, aes(x = x, y = y)) +
  geom_raster(aes(fill = z)) +
  scale_x_continuous(breaks = 1000*0:10) +
  labs(title = "10,000x10,000 downsampled to 100x100")

enter image description here

0 голосов
/ 23 февраля 2019

Ваш воспроизводимый пример показывает только шум, поэтому трудно понять, какой тип вывода вы хотите.

Один из способов - следовать предложению @ dww и использовать geom_hex, чтобы показатьагрегированные данные.

Другой способ, когда вы спрашиваете: «Можно ли уменьшить частоту дискретизации векторизованного ggplot?», это использовать dplyr::sample_frac или dplyr::sample_n в аргументе данных вашего geom_raster.Я должен взять образец меньшего размера, чем в вашем примере, или я не могу построить df.

library(tidyverse)

# Create dataframe
df <- expand.grid(x = seq(1,1000), y = seq(1,1000))

# add variable: performance
set.seed(123)
df$z <- rnorm(nrow(df))

ggplot(data = df, aes(x = x, y = y)) +
  geom_raster(aes(fill = z), . %>% sample_frac(0.1)) 

Если вы хотите начать с объекта ggplot высокого разрешения, вы можете сделать для того же эффекта:

gg <- ggplot(data = df, aes(x = x, y = y)) +
  geom_raster(aes(fill = z)) 

gg$data <-  sample_frac(gg$data,0.1)
gg

...