4

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?

minem
  • 3,640
  • 2
  • 15
  • 29
  • `XLConnect` does a lot. Maybe checkout that one. – JMT2080AD Dec 28 '17 at 16:58
  • I used `xlsx` and `r2excel` for this. I do not know which is faster but it would be worth checking these out. You need to have Java on your computer to make this work though. – Mike Oct 11 '18 at 18:07
  • `openxlsx` was the fastest of a few options measured here: https://www.mango-solutions.com/blog/r-the-excel-connection http://blog.eighty20.co.za//package%20exploration/2016/09/04/Mirror-Mirror/ https://stackoverflow.com/questions/44538199/fast-way-to-read-write-xlsx-files-into-from-r (last one was for reading in only) – Jon Spring Oct 13 '18 at 04:21
  • You might also consider the `rvg` and `officer` packages to write vector versions of the charts. I don't know if those will be faster to generate or not, but the charts will look sharper, be editable in excel, and the files will be smaller. – Jon Spring Oct 13 '18 at 05:02
  • Is it an option to install addidtional siftware, like BERT: https://bert-toolkit.com/r-graphics-in-excel ? – Wimpel Oct 15 '18 at 09:54
  • @Wimpel not relay, but what kind of advantage BERT would give? – minem Oct 15 '18 at 10:04
  • @minem: read the text in the link? – Wimpel Oct 15 '18 at 10:09
  • @Wimpel my question is related speed, because i need to crate a lot of separate plots. Whats the diference/advantage (if any) in this field? – minem Oct 15 '18 at 10:32

1 Answers1

2

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.

minem
  • 3,640
  • 2
  • 15
  • 29