I have a default workbook with my company logo and formating already in place, in order to quickly generate workbooks to my clients, without having to reformat everything all the time.
I manage to do it for a single sheet. I would like to do it for as many sheets as I need, in a single workbook.
I do it, now, as follows
wb = loadWorkbook("O:/R/handle_wb.xlsx") # loads default workbook
sheets = getSheets(wb) # get pre-formatted sheet
# change styles
cs = CellStyle(wb) + ...
# add df of data to excel with the chosen styles
addDataFrame(data, sheets$Sheet1, startRow = 6, startColumn = 1,
colnamesStyle = cs, row.names = F)
Then, I would like to generate another sheet in the same wb, but using the preformatted sheet I already have, by writing a function like
add.sheet <- funtion(newdata, original.wb, default.wb){
wb = loadWorkbook(default.wb) # loads default workbook
sheets = getSheets(wb) # get pre-formatted sheet
ob = loadWorkbook(original.wb) # loads orginal workbook
# change styles
cs = CellStyle(wb) + ...
# add df of data to excel with the chosen styles
addDataFrame(newdata, sheets$Sheet1, startRow = 6, startColumn = 1, colnamesStyle = cs, row.names = F)
# create a new sheet in the original workbook to receive the newsheet created above
createSheet(ob, "sheet2")
she <- getSheets(ob)
she$sheet2 <- sheets$Sheet1 # designate to sheet2 the created default sheet
saveWorkbook(ob, original.wb)
}
The question is, how do I replace the blank sheet I created in the original workbook with the one in my default workbook, i.e., she$sheet2 <- sheets$Sheet1 ?
Related
I want to use openxlsx to change an individual cell in a workbook sheet and write it back out as the same .xlsx without losing the styling, validation, etc of the original .xlsx file. I stipulate openxlsx because it doesn't have a rJava dependency.
Here's a dummy workbook:
library(openxlsx)
## Make a dummy workbook to read in
write.xlsx(list(iris = iris, mtcars = mtcars), file = 'test.xlsx')
wb <- loadWorkbook('test.xlsx')
isS4(wb)
How can I change the value of cell [2,1] so that it essentially is identical to the original .xlsx file but with on cell altered?
I can of course read in the workbook but I don't know what good that does me.
m <- readWorkbook(wb)
m[2, 1] <- 20
m[1:5,]
writeData can help you with this.
test.fpath <- 'test.xlsx'
openxlsx::write.xlsx(list(iris = iris, mtcars = mtcars), file = test.fpath)
.wb <- openxlsx::loadWorkbook(test.fpath)
openxlsx::writeData(
wb = .wb,
sheet = 1,
x = 20,
xy = c(2,1)
)
openxlsx::saveWorkbook(
.wb,
test.fpath,
overwrite = TRUE
)
I am trying to use openxlsx::write.xlsx to write results into Excel spreadsheet in R.
if the file exists and a new sheet is to be added, I can use append=T. Instead of using if to check the file, are there any ways to automatically check?
if the file and sheet both exist and this sheet is to be updated, how should I do to overwrite the results? Thanks.
Here is an openxlsx answer. In order to demonstrate, we need some data.
## Create a simple test file
library(openxlsx)
hs <- createStyle(textDecoration = "Bold")
l <- list("IRIS" = iris, "MTCARS" = mtcars)
write.xlsx(l, file = "TestFile.xlsx", borders = "columns", headerStyle = hs)
Question 1
You can check whether or not the file exists with
## Check existence of file
file.exists("TestFile.xlsx")
You can check if the tab (sheet) exists within the workbook
## Check available sheets
getSheetNames("TestFile.xlsx")
Steps for question 2:
1. Read the file into a Workbook object.
2. Pull the data from the sheet you want to modify into a data.frame.
3. Modify the data.frame to taste
4. Save the data back into the Workbook
5. Save the Workbook out to disk
In order to have a simple example to work with, let's create a simple test file.
## Load existing file
wb = loadWorkbook("TestFile.xlsx")
## Pull all data from sheet 1
Data = read.xlsx(wb, sheet=1)
## Change a single element for demonstration
## ** Beware!! ** Because of the header,
## the 2,2 position in the data
## is row 3 column 2 in the spreadsheet
Data[2,2] = 1492
## Put the data back into the workbook
writeData(wb, sheet=1, Data)
## Save to disk
saveWorkbook(wb, "TestFile.xlsx", overwrite = TRUE)
You can open up the spreadsheet and check that the change has been made.
If you want to completely change the sheet (as in your comment),
you can just delete the old sheet and replace it with a new one
using the same name.
removeWorksheet(wb, "IRIS")
addWorksheet(wb, "IRIS")
NewData = data.frame(X1=1:4, X2= LETTERS[1:4], X3=9:6)
writeData(wb, "IRIS", NewData)
saveWorkbook(wb, "TestFile.xlsx", overwrite = TRUE)
You can check if sheet exists before and if so remove it, if not append it to existing file this command also will create file if it does not exist.
library(xlsx)
path <- "testing.xlsx"
sheet_name = "new_sheet"
data <-
data.frame(
B = c(1, 2, 3, 4)
)
if(sheet_name %in% names(getSheets(loadWorkbook(path)))){
wb <- loadWorkbook(path)
removeSheet(wb, sheetName = sheet_name)
saveWorkbook(wb, path)
}
write.xlsx(data, path, sheetName = sheet_name, append = TRUE)
I have an Excel workbook with two sheets. On the first sheet columns B and C have formulas (referring to the second, still empty, sheet) that are protected against editing. Now I imported this workbook through R, added my data to the second sheet and saved the workbook.
library(openxlsx)
wb <- loadWorkbook('Tables.xlsx')
writeData(wb, 'Sheet2', mydf)
saveWorkbook(wb, New_tables.xlsx')
However, after saving the workbook, columns B and C of sheet 1 are not protected anymore. Is there any specific function that I could add to protect (only) columns B and C from sheet 1 against editing?
Thanks!
There is a protectWorksheet function you can use.
You will need to createStyle to set locked = TRUE or FALSEthen you can control the columns and rows that you want to lock from editing.
For example:
library(openxlsx)
wb <- createWorkbook()
addWorksheet(wb, "NEW")
writeData(wb, "NEW", mtcars)
addStyle(wb, "NEW", rows = 1:nrow(mtcars), cols = 1, gridExpand = TRUE, style = createStyle(locked = FALSE))
protectWorksheet(wb, "NEW", protect = TRUE)
saveWorkbook(wb, "New_tables.xlsx", overwrite = TRUE)
This will lock first column up to the rows where data is populated and locks everywhere else.
How can one create an excel file using openxlsx where the number formatting includes both comma thousand separators and 2 decimal places? I have tried the code below, but no luck on the formatting.
# Create Customer Dataset
cust <- data.table(Customer = c("Sue", "Ben", "Jason", "Cody"), Sales =
c(5654.3456, 29384.4, 729, .4093))
# Start Workbook
wb <- createWorkbook()
# Set Sheet Name
sheet = "Customers Report"
# Initiate worksheet within workbook
addWorksheet(wb = wb, sheet = sheet)
# Add Formatting to Spreadsheet
addStyle(wb = wb, sheet = sheet, style = createStyle(numFmt = "NUMBER"), rows = 2:6, cols = 2)
addStyle(wb = wb, sheet = sheet, style = createStyle(numFmt = "COMMA"), rows = 2:6, cols = 2, stack = TRUE)
# Write Customer Dataset to Spreadsheet
writeData(wb = wb, sheet = sheet, x = cust, headerStyle =
createStyle(textDecoration = "bold"))
# Write Workbook to File
saveWorkbook(wb = wb, file = "~/Desktop/Customer_Report.xlsx", overwrite = TRUE)
You can set the default formatting for the 2 decimal cases prior to adding the thousands format.
wb = createWorkbook()
options("openxlsx.numFmt" = "0.00") # 2 decimal cases formating
styleT <- createStyle(numFmt = "#,##0.00") # create thousands format
addStyle(wb, sheetName, styleT,
rows = 'yourrows',cols = 'yourcols',
gridExpand = T, stack = T) # add thousands format to designated cols and rows
This will ensure that the thousands formatting happens on a value that already has only 2 decimal cases.
I found the answer as I was writing the question, but I figured I would go ahead and post it in the event that someone else has the same question down the road. I found this answer via github openxlsx issue #75. Please see the below code block:
# Add Formatting to Spreadsheet
addStyle(wb = wb, sheet = sheet, style = createStyle(numFmt = "#,##0.00"), rows = 2:6, cols = 2)
I have found that you use "0" when you want there to be a digit there no matter if it is 0 and that you use "#" to represent a placeholder for a potential digit. For example, if the number is .4093 as shown above, then it would be formatted to 0.41 and if the number is 29384.4 as shown above, then it would be formatted to 29,384.40.
I am trying to read value from a .xlsx file using openxlsx package in R. In simple words, I need to write a row of data, which then populates some output cell that has to be read back in R. I will share an example to better explain the problem.
Initial state of the .xlsx file:
I'm now trying to write new values to the cell : A2:A3 = c("c", 5). So ideally, I'm expecting A6 = 15
Below is the code used :
require(openxlsx)
path <- "C:/path_to_file/for_SO1.xlsx"
input_row <- c("c", 5)
# Load workbook; create if not existing
wb <- loadWorkbook(path)
# createSheet(wb, name = "1")
writeData(wb,
sheet = "Sheet1",
x = data.frame(input_row),
startCol=1,
startRow=1
)
data_IM <- read.xlsx(wb,
sheet = "Sheet1",
rows = c(5,6),
cols = c(1))
# Save workbook
saveWorkbook(wb, file = path, overwrite = TRUE)
#> data_IM
# output_row
#1 3
But I get the inital value(3). However, If i open the .xlsx file, I can see the 15 residing there:
What could be the reason for not able to read this cell? I tried saving it after writing to the file and again reading it but even that failed. openxlsx is the only option I have due to JAVA errors from XLConnect etc.
?read.xlsx
Formulae written using writeFormula to a Workbook object will not get
picked up by read.xlsx(). This is because only the formula is written
and left to be evaluated when the file is opened in Excel. Opening,
saving and closing the file with Excel will resolve this.
So the file needs to be opened in Excel and then saved, I can verify that this does work. However this may not be suitable for you.
XLConnect seems to have the desired functionality
# rjava can run out of memory sometimes, this can help.
options(java.parameters = "-Xmx1G")
library(XLConnect)
file_path = "test.xlsx"
input_row <- c("c", 5)
wb <- loadWorkbook(file_path, create=F)
writeWorksheet(wb, 1, startRow = 1, startCol = 1, data = data.frame(input_row))
setForceFormulaRecalculation(wb, 1, TRUE)
saveWorkbook(wb)
# checking
wb <- loadWorkbook(file_path, create=F)
readWorksheet(wb, 1)
The file https://cran.r-project.org/web/packages/openxlsx/openxlsx.pdf says
Workbook object will not get picked up by read.xlsx().
This is because only the formula is written and left to be evaluated when the file is opened in Excel.
Opening, saving and closing the file with Excel will resolve this.
So if you are using windows then
save following file vbs file to for example opensaveexcel.vbs
Set objExcel = CreateObject("Excel.Application")
Set objWorkbook = objExcel.Workbooks.Open("D:\Book2.xlsx")
objWorkbook.Save
objWorkbook.Close
objExcel.Quit
Set objExcel = Nothing
Set objWorkbook = Nothing
and then you can write R code as cell A4 has formula in Book1.xlsx as =A3*5
mywritexlsx(fname="d:/Book1.xlsx",data = 20,startCol = 1,startRow = 3)
system("cp d:\\Book1.xlsx d:\\Book2.xlsx")
system("cscript //nologo d:\\opensaveexcel.vbs")
tdt1=read.xlsx(xlsxFile = "d:/Book1.xlsx",sheet = "Sheet1",colNames = FALSE)
tdt2=read.xlsx(xlsxFile = "d:/Book2.xlsx",sheet = "Sheet1",colNames = FALSE)
Works for me by the way mywritexlsx is as
mywritexlsx<-function(fname="temp.xlsx",sheetname="Sheet1",data,
startCol = 1, startRow = 1, colNames = TRUE, rowNames = FALSE)
{
if(!file.exists(fname))
{
wb = openxlsx::createWorkbook()
sheet = openxlsx::addWorksheet(wb, sheetname)
}
else
{
wb <- openxlsx::loadWorkbook(file =fname)
if(!(sum(openxlsx::getSheetNames(fname)==sheetname)))
sheet = openxlsx::addWorksheet(wb, sheetname)
else
sheet=sheetname
}
openxlsx::writeData(wb,sheet,data,startCol = startCol, startRow = startRow,
colNames = colNames, rowNames = rowNames)
openxlsx::saveWorkbook(wb, fname,overwrite = TRUE)
}