writeData() to second sheet without overwriting first sheet - r

If i have an excel file called my_table.xlsx which has one sheet containing some data. Is there then a way to add a second sheet with some data without overwriting what's in sheet one?
For example this code will remove the data that already exists in sheet 1.
wb <- createWorkbook()
addWorksheet(wb, sheet = 1)
addWorksheet(wb, sheet = 2)
writeData(wb, 2, "test")
saveWorkbook(wb, file = "my_table.xlsx", overwrite =
TRUE)

Related

Use downloadHandler to edit an existing excel file based on uploaded data?

I am working on a shiny app where the user will upload an excel file, the data will be manipulated, and then a new excel file with this data is exported for the user to examine. I am having issues with the downloadHandler function. I used to create an entirely new excel file every time based on the uploaded data like this:
output$export <- downloadHandler(
filename = "answers.xlsx",
content = function(file){
write.xlsx(exportdata(), file)
})
})
This works fine.
Now I would like to edit an excel file that I will include when I publish the app and allow the user to download this edited version like this:
output$export <- downloadHandler(
filename = "answers.xlsx",
content = function(file){
wb <- loadWorkbook("6rep-charts.xlsx")
writeData(wb, sheet = "Species Match Results", correlInput())
writeData(wb, sheet = "BS1 Data", bs1Input())
writeData(wb, sheet = "BS2 Data", bs2Input())
saveWorkbook(wb, file)
})
However, this results in the error Warning: Error in write_file: Expecting a single string value: [type=character; extent=0]. [No stack trace available]. I am not sure what is going wrong as when I run the content section outside of the shiny app, it works just fine. The problem seems to be in the saveWorkbook command.
The reason I would like to edit an existing excel file rather than create a new one is that the template file I'm including in the app has charts already made that should change when the new data is written into the file. The users would like to be able to edit these charts themselves, rather than just see a picture of a graph. If anyone has a simpler way to accomplish this, that would be great! Thank you in advance for your help!
Reproducible example using this excel file:
library(shiny); library(readxl); library(xlsx)
ui <- shinyUI(fluidPage(
titlePanel("Old Faithful Geyser Data"),
fluidRow(
column(3,
downloadButton(outputId = "export",
label = "Export Results to Excel")
),
column(6,
dataTableOutput("data")
))))
server <- function(input, output) {
adata <- faithful[1:20,]
bdata <- faithful[21:50,]
cdata <- faithful[51:200,]
read_excel_allsheets <- function(filename, tibble = FALSE) {
sheets <- readxl::excel_sheets(filename)
x <- lapply(sheets, function(Y) {readxl::read_excel(filename, sheet = Y)})
if(!tibble) x <- lapply(x, as.data.frame)
names(x) <- sheets
x
}
output$data <- renderDataTable({
adata })
output$export <- downloadHandler(
filename = "answers.xlsx",
content = function(file){
wb <- loadWorkbook("./Data/template.xlsx")
writeData(wb, sheet = "Alpha", adata)
writeData(wb, sheet = "Beta", bdata)
writeData(wb, sheet = "Gamma", cdata)
saveWorkbook(wb, file="./Data/temp.xlsx", overwrite = T)
print("done")
Fin_WB<- read_excel_allsheets("./Data/temp.xlsx")
write.xlsx(Fin_WB, file)
} ) }
shinyApp(ui = ui, server = server)
Simpler solution (I am unable to leave comments due to too low reputation):
output$export <- downloadHandler(
filename = "answers.xlsx",
content = function(file){
wb <- loadWorkbook("./Data/template.xlsx")
writeData(wb, sheet = "Alpha", adata)
writeData(wb, sheet = "Beta", bdata)
writeData(wb, sheet = "Gamma", cdata)
saveWorkbook(wb, file="./Data/temp.xlsx", overwrite = T)
file.copy(from = "./Data/temp.xlsx", to = file)
})
No need for the function read_excel_allsheets.
The saveWorkbook function does not like to operate as a write function for the content function. Confusing yes, but we can still use it within the content function, just not as the final step. We have to use a classic write function such as write.xlsx to satisfy the content function which is expecting the file and file path to write to.
To get around this we create a temp file in the Data folder (this folder will be in the dir with server and ui, and will be published). The program reads in the template file (see special function below), modifies it, and then writes/overwrites the temp file. This temp file is then read in and assigned by read.xlsx and then written to by write.xlsx. This satisfies the content function and allows us to use a template for export.
read_excel_allsheets <- function(filename, tibble = FALSE) {
sheets <- readxl::excel_sheets(filename)
x <- lapply(sheets, function(X) readxl::read_excel(filename, sheet = X))
if(!tibble) x <- lapply(x, as.data.frame)
names(x) <- sheets
x
}
output$export <- downloadHandler(
filename = "answers.xlsx",
content = function(file){
wb <- loadWorkbook("./Data/template.xlsx")
writeData(wb, sheet = "Alpha", adata)
writeData(wb, sheet = "Beta", bdata)
writeData(wb, sheet = "Gamma", cdata)
saveWorkbook(wb, file="./Data/temp.xlsx", overwrite = T)
print("done")
Fin_WB<- read_excel_allsheets("./Data/temp.xlsx")
write.xlsx(Fin_WB, file)
})
}
In order to read in all the sheets, we cannot simply use read.xlsx as it wont look at all the sheets. Using a function created here by Jeromy Anglim, we can read in all the sheets from excel. This is the read_excel_allsheets function.

R: add sheet to an existing excel workbook

In my script, I need to create an excel workbook with many sheets, where the first 2 sheets are by default, read from another workbook and incorporated into the exported excel.
Im using the xlsx package to format the export excel. However, I could not find any function in the xlsx package, that could read a sheet from an excel, and add it to another one.
Here is my code to read the first excel:
template_wb <- loadWorkbook(file = 'template.xlsx')
sheets <- getSheets(wb)
sheet1 <- sheets[[1]]
sheet2 <- sheets[[2]]
In the second part of the code, i create another workbook, which contains multiple sheets, from which, sheet1 and sheet2, should be one of.
wb<-createWorkbook(type="xlsx")
as_sheet <- createSheet(wb, sheetName = "AS")
dc_sheet <- createSheet(wb, sheetName = "DC")
ro_sheet <- createSheet(wb, sheetName = "RO")
### add content to worksheets
# the suggested code should go there
### save workbook
saveWorkbook(wb, 'out.xlsx')
I would like to add the content of sheet1 to dc_sheet and the content of sheet2 to ro_sheet before adding more data into as_sheet and then saving the workbook.
How can I do this?
I'm pretty sure a simple assignment statement will do the trick:
template_wb <- loadWorkbook(file = 'template.xlsx')
sheets <- getSheets(template_wb)
sheet1 <- sheets[[1]]
sheet2 <- sheets[[2]]
wb<-createWorkbook(type="xlsx")
as_sheet <- createSheet(wb, sheetName = "AS")
dc_sheet <- createSheet(wb, sheetName = "DC")
ro_sheet <- createSheet(wb, sheetName = "RO")
dc_sheet<-sheet1
ro_sheet<-sheet2
# Your code here
saveWorkbook(wb, 'out.xlsx')
I tried it out and it worked fine
You can work with a copy, and save it as a new file.
wb <- loadWorkbook(file)
# Rename the sheets
wb$setSheetName(0L, "AS")
wb$setSheetName(1L, "DC")
# Delete the aditional sheets
sheets <- getSheets(wb)
lapply(names(sheets)[-(1:2)], function(x) removeSheet(wb, sheetName = x))
# Assign the sheets to the objects of R
sheets <- getSheets(wb)
as_sheet <- sheets[[1]]
dc_sheet <- sheets[[2]]
# Create the new sheet
ro_sheet <- createSheet(wb, sheetName = "RO")
# save workbook
saveWorkbook(wb, 'out.xlsx')

Edit existing named region with openxlsx

I have an existing workbook with some data and charts.
I'm using openxlsx to add recent data and would like to edit an existing named range to reflect this (the charts use this named region).
I tried using writeData and createNamedRegion to do that, but I receive the error message "Error in (...): Named region with name 'named_region' already exists!"
library(openxlsx)
filename <- 'test.xlsx'
wb <- createWorkbook()
addWorksheet(wb, sheetName = 'test')
writeData(wb, sheet='test', x=data.frame(a=1:3,b=2:4), startCol=1, startRow=1,
colNames=T, rowNames=F, name='named_region')
saveWorkbook(wb, file=filename, overwrite=TRUE)
wb <- loadWorkbook(file = filename)
writeData(wb, sheet='test', x = data.frame(a=4:5,b=5:6),
startRow=5, colNames=F, rowNames=FALSE, keepNA=FALSE) # ok
# not ok
# writeData(wb, sheet='test', x = data.frame(a=4:5,b=5:6),
# startRow=5, colNames=F, rowNames=FALSE, keepNA=FALSE, name='named_region')
# createNamedRegion(wb, sheet='test', cols=1, rows=2:6, name='named_region')
saveWorkbook(wb, file=filename, overwrite=TRUE)

How to retain number formats when inserting data into an xlsx workbook via openxlsx writeData()

I have a .xlsx file I'm using as a template. It's filled with colors, borders, number formats, etc. I simply want to populate this workbook with data from R.
I'm using the xlsx package which works great, except that it appears to overwrite the pre-existing cell formats. For example, let's start by generating a template workbook:
#--------------------------------------------------
# Create a workbook with styling
# (I'm not actually making my workbook via code. This is just to generate a reproducible example.)
library(xlsx)
## Create a new workbook
wb <- createWorkbook("Sample Workbook")
addWorksheet(wb, "Sample Worksheet")
writeData(wb, sheet = "Sample Worksheet", data.frame(Dates = as.Date(c("2017-1-1", "2018-1-1"))))
addStyle(wb, sheet = "Sample Worksheet", createStyle(numFmt="mm/dd/yy"), rows = 2:3, cols = 1, gridExpand = TRUE)
saveWorkbook(wb, "Sample Workbook.xlsx", overwrite = TRUE)
This should create a workbook, "Sample Workbook.xlsx" which looks like
Now let's make new values and insert them into our template:
#--------------------------------------------------
# Insert data and retain cell styles
newdates <- data.frame(Dates = as.Date(c("2019-1-1", "2020-1-1")))
wb <- loadWorkbook("Sample Workbook.xlsx")
writeData(wb, sheet = "Sample Worksheet", newdates)
saveWorkbook(wb, "Sample Workbook Modified.xlsx", overwrite = TRUE)
This inserts data, but notice it removes the date formats we set up above
How can I insert data and retain the formats in my template workbook?

How to increase memory size for downloadHandler in Shiny

When running Shiny, I get the message that "java.lang.OutOfMemoryError: Java heap space" when the download function is called. It works when the data file is smaller; but all of the tables combined should be less than 5,000 rows and 15 columns for the instance I'm looking at. Can someone help me make my downloadHandler functional with this kind of file size?
*# server.R*
library(XLConnect)
shinyServer(function(input, output, session) {
... (filtering operation on a data frame to create multiple sub tables)
output$downloadData <- downloadHandler(
filename = function() {paste(input$category,"_raw_token_data.xlsx")},
content = function(file){
fname <- paste(file,"xlsx",sep=".")
wb <- loadWorkbook(fname, create = TRUE)
createSheet(wb, name = "-terms")
createSheet(wb, name = "+terms")
createSheet(wb, name = "-tokens")
createSheet(wb, name = "+tokens")
createSheet(wb, name = "test_stats")
writeWorksheet(wb, raw()$filter_neg, sheet = "-terms")
writeWorksheet(wb, raw()$filter_kw, sheet = "+terms")
writeWorksheet(wb, df()$neg_raw, sheet = "-tokens")
writeWorksheet(wb, df()$rel_raw, sheet = "+tokens")
writeWorksheet(wb, df()$test_raw, sheet = "test_stats")
saveWorkbook(wb)
file.rename(fname,file)
}
) # closing for downloadHandler
}) # closing for shinyServer
Solution:
options(java.parameters = "-Xmx1g") # increase heap size to 1gb
library(RWeka)

Resources