使用条件格式通过xlsx将数据框导出到Excel

时间:2023-01-14 16:33:25

I want to export data frames to Excel and highlight cells according to certain rules. I don't think this answer to a similar question is correct. I think it is possible, and I think I get close using the CellStyle functions of the xlsx package.

我想将数据框导出到Excel并根据特定规则突出显示单元格。我不认为对类似问题的答案是正确的。我认为这是可能的,我认为我接近使用xlsx包的CellStyle函数。

Below I outline what I've tried. Most of the ideas come from the package help files. I get all the way to the end and get an error when I try to apply the style I created to the cells that meet the criteria. I get the error: Error in .jcall(cell, "V", "setCellStyle", cellStyle$ref) : RcallMethod: invalid object parameter.

下面我概述了我尝试过的内容。大多数想法来自包帮助文件。当我尝试将我创建的样式应用于符合条件的单元格时,我会一路走到最后并收到错误。我收到错误:.jcall错误(单元格,“V”,“setCellStyle”,cellStyle $ ref):RcallMethod:无效的对象参数。

library(xlsx)
# create data 
  cols <- sample(c(1:5), 1) # number of columns to vary to mimic this unknown
  label <- rep(paste0("label ", seq(from=1, to=10)))
  mydata <- data.frame(label)
  for (i in 1:cols) {
    mydata[,i+1] <- sample(c(1:10), 10)
  }
# exporting data.frame to excel is easy with xlsx package
  sheetname <- "mysheet"
  write.xlsx(mydata, "mydata.xlsx", sheetName=sheetname)
  file <- "mydata.xlsx"
# but we want to highlight cells if value greater than or equal to 5
  wb <- loadWorkbook(file)              # load workbook
  fo <- Fill(backgroundColor="yellow")  # create fill object
  cs <- CellStyle(wb, fill=fo)          # create cell style
  sheets <- getSheets(wb)               # get all sheets
  sheet <- sheets[[sheetname]]          # get specific sheet
  rows <- getRows(sheet)                # get rows
  cells <- getCells(rows)               # get cells
  values <- lapply(cells, getCellValue) # extract the values
# find cells meeting conditional criteria 
  highlight <- "test"
  for (i in names(values)) {
    x <- as.numeric(values[i])
    if (x>=5 & !is.na(x)) {
      highlight <- c(highlight, i)
    }    
  }
  highlight <- highlight[-1]
# apply style to cells that meet criteria
  if (length(highlight)>0) {            # proceed if any cells meet criteria
    setCellStyle(cells[highlight], cs)  # DOES NOT WORK
  }
# save
  saveWorkbook(wb, file)

Update: I've also tried:

更新:我也尝试过:

if (length(highlight)>0) {                # proceed if any cells meet criteria
    for (h in 1:length(highlight)) {
      setCellStyle(cells[highlight[h]], cs)  # DOES NOT WORK
    }
  }

But I get the error: Error in .jcall(cell, "V", "setCellStyle", cellStyle$ref) : RcallMethod: cannot determine object class

但我收到错误:.jcall中的错误(单元格,“V”,“setCellStyle”,cellStyle $ ref):RcallMethod:无法确定对象类

2 个解决方案

#1


8  

Try this out. I changed a few things, including the a slight change to the call to Fill and limiting the cells included for consideration to those with numeric data. I used lapply to apply the conditional formatting.

试试吧。我更改了一些内容,包括对Fill调用的轻微更改,并将包含的单元格限制为考虑使用数字数据。我使用lapply来应用条件格式。

  cols <- sample(c(1:5), 1) # number of columns to vary to mimic this unknown
  label <- rep(paste0("label ", seq(from=1, to=10)))
  mydata <- data.frame(label)
  for (i in 1:cols) {
    mydata[,i+1] <- sample(c(1:10), 10)
  }
# exporting data.frame to excel is easy with xlsx package
  sheetname <- "mysheet"
  write.xlsx(mydata, "mydata.xlsx", sheetName=sheetname)
  file <- "mydata.xlsx"
# but we want to highlight cells if value greater than or equal to 5
  wb <- loadWorkbook(file)              # load workbook
  fo <- Fill(foregroundColor="yellow")  # create fill object
  cs <- CellStyle(wb, fill=fo)          # create cell style
  sheets <- getSheets(wb)               # get all sheets
  sheet <- sheets[[sheetname]]          # get specific sheet
  rows <- getRows(sheet, rowIndex=2:(nrow(mydata)+1)     # get rows
                                                         # 1st row is headers
  cells <- getCells(rows, colIndex = 3:(cols+3))       # get cells
# in the wb I import with loadWorkbook, numeric data starts in column 3
# and the first two columns are row number and label number

  values <- lapply(cells, getCellValue) # extract the values

# find cells meeting conditional criteria 
  highlight <- "test"
  for (i in names(values)) {
    x <- as.numeric(values[i])
    if (x>=5 & !is.na(x)) {
      highlight <- c(highlight, i)
    }    
  }
  highlight <- highlight[-1]

lapply(names(cells[highlight]),
       function(ii)setCellStyle(cells[[ii]],cs))

saveWorkbook(wb, file)

#2


3  

It has been a while since I used this feature. Yes it should be possible to save conditional formatting. My (old) code is given below. Hope it helps you.

我用这个功能已经有一段时间了。是的,应该可以保存条件格式。我的(旧)代码如下。希望它能帮到你。

file.name <- paste('loadings.',state$data,'.xls', sep = "")
wb <- loadWorkbook(file.name, create = TRUE)

createSheet(wb, name = 'loadings')
clearSheet(wb, sheet = 'loadings')

Variables <- rownames(df)
df.loadings <- cbind(Variables,df)
df.loadings[,'Communality'] <- NULL
writeWorksheet(wb,df.loadings[,-1], sheet = 'loadings', rownames = 'Variables', startRow = 1, startCol = 1)

max.loading <- createCellStyle(wb)
setFillPattern(max.loading, fill = XLC$"FILL.SOLID_FOREGROUND")
setFillForegroundColor(max.loading, color = XLC$"COLOR.SKY_BLUE")
maxVal <- apply(abs(df.loadings[,-1]),1,max)
maxValIndex <- which(abs(df.loadings[,-1]) == maxVal, arr.ind = TRUE)
setCellStyle(wb, sheet = "loadings", row = maxValIndex[,'row']+1, col = maxValIndex[,'col']+1, cellstyle = max.loading)

df.corr <- data.frame(cor(f.data))
df.corr <- cbind(Variables,df.corr)
createSheet(wb, name = 'correlations')
clearSheet(wb, sheet = 'correlations')
writeWorksheet(wb, df.corr, sheet = 'correlations', startRow = 1, startCol = 1)
corr <- createCellStyle(wb)
setFillPattern(corr, fill = XLC$"FILL.SOLID_FOREGROUND")
setFillForegroundColor(corr, color = XLC$"COLOR.SKY_BLUE")
corrIndex <- which(abs(df.corr[,-1]) > .3 & df.corr[,-1] != 1 , arr.ind = TRUE)
setCellStyle(wb, sheet = "correlations", row = corrIndex[,'row']+1, col = corrIndex[,'col']+1, cellstyle = corr)

saveWorkbook(wb)

if(.Platform$OS.type == "unix") {
    execute(paste("browseURL(\"",getwd(),'/',file.name,"\", browser = '/usr/bin/open')",sep=''))
} else {
    execute(paste("browseURL(\"",getwd(),'/',file.name,"\", browser = NULL)",sep=''))
}

#1


8  

Try this out. I changed a few things, including the a slight change to the call to Fill and limiting the cells included for consideration to those with numeric data. I used lapply to apply the conditional formatting.

试试吧。我更改了一些内容,包括对Fill调用的轻微更改,并将包含的单元格限制为考虑使用数字数据。我使用lapply来应用条件格式。

  cols <- sample(c(1:5), 1) # number of columns to vary to mimic this unknown
  label <- rep(paste0("label ", seq(from=1, to=10)))
  mydata <- data.frame(label)
  for (i in 1:cols) {
    mydata[,i+1] <- sample(c(1:10), 10)
  }
# exporting data.frame to excel is easy with xlsx package
  sheetname <- "mysheet"
  write.xlsx(mydata, "mydata.xlsx", sheetName=sheetname)
  file <- "mydata.xlsx"
# but we want to highlight cells if value greater than or equal to 5
  wb <- loadWorkbook(file)              # load workbook
  fo <- Fill(foregroundColor="yellow")  # create fill object
  cs <- CellStyle(wb, fill=fo)          # create cell style
  sheets <- getSheets(wb)               # get all sheets
  sheet <- sheets[[sheetname]]          # get specific sheet
  rows <- getRows(sheet, rowIndex=2:(nrow(mydata)+1)     # get rows
                                                         # 1st row is headers
  cells <- getCells(rows, colIndex = 3:(cols+3))       # get cells
# in the wb I import with loadWorkbook, numeric data starts in column 3
# and the first two columns are row number and label number

  values <- lapply(cells, getCellValue) # extract the values

# find cells meeting conditional criteria 
  highlight <- "test"
  for (i in names(values)) {
    x <- as.numeric(values[i])
    if (x>=5 & !is.na(x)) {
      highlight <- c(highlight, i)
    }    
  }
  highlight <- highlight[-1]

lapply(names(cells[highlight]),
       function(ii)setCellStyle(cells[[ii]],cs))

saveWorkbook(wb, file)

#2


3  

It has been a while since I used this feature. Yes it should be possible to save conditional formatting. My (old) code is given below. Hope it helps you.

我用这个功能已经有一段时间了。是的,应该可以保存条件格式。我的(旧)代码如下。希望它能帮到你。

file.name <- paste('loadings.',state$data,'.xls', sep = "")
wb <- loadWorkbook(file.name, create = TRUE)

createSheet(wb, name = 'loadings')
clearSheet(wb, sheet = 'loadings')

Variables <- rownames(df)
df.loadings <- cbind(Variables,df)
df.loadings[,'Communality'] <- NULL
writeWorksheet(wb,df.loadings[,-1], sheet = 'loadings', rownames = 'Variables', startRow = 1, startCol = 1)

max.loading <- createCellStyle(wb)
setFillPattern(max.loading, fill = XLC$"FILL.SOLID_FOREGROUND")
setFillForegroundColor(max.loading, color = XLC$"COLOR.SKY_BLUE")
maxVal <- apply(abs(df.loadings[,-1]),1,max)
maxValIndex <- which(abs(df.loadings[,-1]) == maxVal, arr.ind = TRUE)
setCellStyle(wb, sheet = "loadings", row = maxValIndex[,'row']+1, col = maxValIndex[,'col']+1, cellstyle = max.loading)

df.corr <- data.frame(cor(f.data))
df.corr <- cbind(Variables,df.corr)
createSheet(wb, name = 'correlations')
clearSheet(wb, sheet = 'correlations')
writeWorksheet(wb, df.corr, sheet = 'correlations', startRow = 1, startCol = 1)
corr <- createCellStyle(wb)
setFillPattern(corr, fill = XLC$"FILL.SOLID_FOREGROUND")
setFillForegroundColor(corr, color = XLC$"COLOR.SKY_BLUE")
corrIndex <- which(abs(df.corr[,-1]) > .3 & df.corr[,-1] != 1 , arr.ind = TRUE)
setCellStyle(wb, sheet = "correlations", row = corrIndex[,'row']+1, col = corrIndex[,'col']+1, cellstyle = corr)

saveWorkbook(wb)

if(.Platform$OS.type == "unix") {
    execute(paste("browseURL(\"",getwd(),'/',file.name,"\", browser = '/usr/bin/open')",sep=''))
} else {
    execute(paste("browseURL(\"",getwd(),'/',file.name,"\", browser = NULL)",sep=''))
}