minem
minem

Reputation: 3650

fastest way to create xlsx with plots R

I have list of data and list of plots which I want two write to xlsx file (each element to separate sheet). Example data:

require(ggplot2)
require(data.table)

n <- 10
N <- 100

dtList <- lapply(1:n, function(x) data.table(sample(1e6, N), 1:N))
names(dtList) <- 1:n
plots <- lapply(dtList, function(x) ggplot(x, aes(y = V1, x = V2)) + geom_line())

Currently I use openxlsx, but it is quite slow for multiple plots:

require(openxlsx)
wb <- createWorkbook()
modifyBaseFont(wb, fontSize = 10)

writeXlsx <- function(x, sName) {
  addWorksheet(wb, sName, gridLines = FALSE)
  writeData(wb, sName, x = x, xy = c(1, 1))
  print(plots[[sName]])
  insertPlot(wb, sName, width = 19, height = 9, dpi = 200, units = "cm",
             startRow = 2, startCol = 5)
}

system.time(
sapply(seq_along(dtList), function(x) {
  writeXlsx(dtList[[x]], names(dtList)[[x]])
})
) # ~ 17.00 sek

openXL(wb)

How could I increase speed of this? Is there a better package to accomplish this?

Upvotes: 4

Views: 1329

Answers (1)

minem
minem

Reputation: 3650

One options is to use simpler graphics. For example, changing plots to base graphics, like:

plots <- lapply(dtList, function(x) plot(x$V2, x$V1, type = 'l'))

reduces the xlsx creation time to ~0.72 seconds vs ~7.78 seconds (original code works now faster than before), that is around 10 times faster.

When ggplot graphics are needed, I modified insertPlot function to accept this type of object and save it to file without needing to print in R session (using ggsave):

insertggPlot <- function(wb, sheet, width = 6, height = 4, xy = NULL,
                        startRow = 1, startCol = 1, fileType = "png",
                        units = "in", dpi = 300, PLOT) {
  od <- getOption("OutDec")
  options(OutDec = ".")
  on.exit(expr = options(OutDec = od), add = TRUE)
  if (!"Workbook" %in% class(wb)) stop("First argument must be a Workbook.")
  if (!is.null(xy)) {
    startCol <- xy[[1]]
    startRow <- xy[[2]]
  }
  fileType <- tolower(fileType)
  units <- tolower(units)
  if (fileType == "jpg") fileType = "jpeg"
  if (!fileType %in% c("png", "jpeg", "tiff", "bmp")) 
    stop("Invalid file type.\nfileType must be one of: png, jpeg, tiff, bmp")
  if (!units %in% c("cm", "in", "px")) 
    stop("Invalid units.\nunits must be one of: cm, in, px")
  fileName <- tempfile(pattern = "figureImage",
                       fileext = paste0(".", fileType))
  ggsave(plot = PLOT, filename = fileName, width = width, height = height,
         units = units, dpi = dpi)
  insertImage(wb = wb, sheet = sheet, file = fileName, width = width, 
              height = height, startRow = startRow, startCol = startCol, 
              units = units, dpi = dpi)
}

Using this, reduces time to ~2 sek.

Upvotes: 2

Related Questions