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
)
Related
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 am trying to write formulas from an R dataframe to XLSX file. I want to reference data from one worksheet in another using cell references. One worksheet is suppposed to be a "database" and then the other sheet is supposed to have the "formula" which references data from the "database" sheet.
The R code:
require(openxlsx)
# create workbook ---------------------------------------------------------
wb <- createWorkbook()
# add worksheets ----------------------------------------------------------
addWorksheet(wb, "database")
addWorksheet(wb, "database space")
addWorksheet(wb, "reference")
# make database -----------------------------------------------------------
df1 <- data.frame(
a = 1,
b = 2,
formula_1 = "A2 + B2"
)
## change class to formula
class(df1$formula_1) <- c(class(df1$formula_1), "formula")
# prepare formula ---------------------------------------------------------
df2 <- data.frame(
formula_2 = "$database.A2",
formula_3 = "$'database space'.B2"
)
# change class to formula
class(df2$formula_2) <- c(class(df2$formula_2), "formula")
class(df2$formula_3) <- c(class(df2$formula_3), "formula")
# write to XLSX file ------------------------------------------------------
writeData(wb, sheet = "database", x = df1)
writeData(wb, sheet = "database space", x = df1)
writeData(wb, sheet = "reference", x = df2)
# open XLSX file ----------------------------------------------------------
openXL(wb)
The usual way of adding a formula works. In the openend XLSX file this is demonstrated in cell C3 of worksheet database and database space. But, when opening worksheet formula, my issue presents itself (see screenshot 1). Cells A2 and B2 both show #NAME? and not the value of the other worksheets.
However, when I add the cell reference manually, it works (see screenshot 2).
openxlsx version
> packageVersion("openxlsx")
[1] ‘4.0.17’
How can I solve this problem?
The problem here are the names that are passed to df2. The solution to the problem is to remove the $ and replace the . with a !.
Replacing df2 in the code above with the following works:
df2 <- data.frame(
formula_2 = "database!A2",
formula_3 = "'database space'!B2"
)
The character strings are now evaluated as formulas and correctly reference cells from other sheets. I found the solution by working through the XLConnect R package, where an example in the help file for setCellFormula-methods includes a formula as a reference to a separate sheet.
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)
}
I am creating a program that will generate a sample of a dataset for quality review. The actual data will be available on our intranet. This sample is output in an excel with a very specific user-friendly format. I am wanting to use XLconnect to add hyperlinks to the excel document based on the sample. I have been unable to find answers using several searches. I am hoping this is possible using XLconnect or similar package that will keep the format in excel. My code below adds just text, but not hyperlinks...
library(XLConnect)
Full_data_set = read.csv(paste(my.file.location, my.set, sep= "/"))
my.sample <- sample(Full_data_set$groupid, 50)
my.link <- paste("ourwebsite.org/group/" my.sample, sep = "")
wb <- loadWorkbook(filename = "my.file.location/Template2.xlsx",
create = TRUE)
writeWorksheet(wb, my.links, sheet= 1,
startRow=3, startCol=3,
header=FALSE)
saveWorkbook(wb)
You have to use
setCellFormula()
library("XLConnect")
df <- data.frame(
v1 = c("wiki", "google", "so"),
v2 = c("https://www.wikipedia.org/",
"https://www.google.com/",
"http://stackoverflow.com/"),
link = NA ,
stringsAsFactors = F)
# Load workbook (create if not existing)
wb <- loadWorkbook("hlink_example.xlsx", create = TRUE)
# Create a sheet
createSheet(wb, name = "Sheet1")
# Create a named region on sheet
createName(wb, name = "Sheet1", formula = "Sheet1!$A$1")
# Write data set to the above defined named region
writeNamedRegion(wb, df, name = "Sheet1")
# Create an excel column ref. for formula and links in data frame
excelCol <- letters[which(names(df) == "v2")]
# Construct the input range & formula
formula <- paste("HYPERLINK(",excelCol, 2:(nrow(df)+1),")", sep = "")
# Create the link column in data frame
df$link <- formula
# Set the cell formulas using index for rows/col
setCellFormula(wb, "Sheet1", 2:(nrow(df)+1), which(names(df) == "link"),
formula)
# Save workbook
saveWorkbook(wb)
I have an Excel workbook of which I want to edit/fill some particular cells using R, without changing any of the formatting.
So far I've tried XLConnect package and it seems it could do what I'm looking for, I just didn't find a way to do it.
My straightforward approach to the problem:
wb <- loadWorkbook("file1.xls")
data1 <- readWorksheet(wb, "Sheet1", header=TRUE)
## adding a value to a particular cell:
data1[11,12] <- 3.2
## rewriting old data:
writeWorksheet(wb, data1, "Sheet1")
saveWorkbook(wb, "new_file1.xls")
However, this way the new workbook loses all of the previous formatting (merged cells, formulas, etc).
Is there a way to change values in some of the cells without losing any of the formatting of the remaining sheet?
Here is an example using R to automate Excel.
library(RDCOMClient)
xlApp <- COMCreate("Excel.Application")
wb <- xlApp[["Workbooks"]]$Open("file.1.xls")
sheet <- wb$Worksheets("Sheet1")
# change the value of a single cell
cell <- sheet$Cells(11,12)
cell[["Value"]] <- 3.1
# change the value of a range
range <- sheet$Range("A1:F1")
range[["Value"]] <- paste("Col",1:6,sep="-")
wb$Save() # save the workbook
wb$SaveAS("new.file.xls") # save as a new workbook
xlApp$Quit() # close Excel
If you dont need to use formula, you have 2 possible solutions.
You can use the {xlsx} package :
library(xlsx)
xlsx::write.xlsx(x = head(iris),file = "source3.xlsx",sheetName = "A")
hop3 <- xlsx::loadWorkbook(file = "source3.xlsx")
sheets <- getSheets(hop3)
rows <- getRows(sheets$A,rowIndex = 2) # get all the rows
cc <- getCells(rows,colIndex = 3)
xlsx::setCellValue(cc[[1]],value = "54321")
hop3$setForceFormulaRecalculation(TRUE)
xlsx::saveWorkbook(hop3,file = "output3.xlsx")
You also can use {XLconnect}
library(XLConnect)
XLConnect::writeWorksheetToFile(file = "source2.xlsx",data = head(iris),sheet="A")
hop2 <- XLConnect::loadWorkbook(file = "source2.xlsx")
createName(hop2, name = "plop", formula = "A!C2")
writeNamedRegion(hop2, 12345, name = "plop", header = FALSE)
Regards
Using the XLC$STYLE_ACTION.NONE style action should add your data without changing any formatting:
data1 <- readWorksheetFromFile("file1.xls", "Sheet1")
## adding a value to a particular cell:
data1[11,12] <- 3.2
## rewriting old data:
writeWorksheetToFile("file1.xls", data1, "Sheet1", styleAction = XLC$STYLE_ACTION.NONE)
Thanks to Martin for the suggestion to look into this in the comments.