【问题标题】:R Shiny - Excel file does not download in correct formatR Shiny - Excel 文件没有以正确的格式下载
【发布时间】:2018-03-07 10:30:28
【问题描述】:

我正在开发一个 Shiny 应用程序,该应用程序接受一个 Excel 文档,更改其结构和格式,并返回一个包含 10 个独特工作表的新 Excel 文档(基于美国地区)。我编写的代码在更改数据方面很好,但它不返回 Excel 文件。相反,它只是返回一个空白文件。如果有人知道如何回答这个问题,那就太棒了。这是我的代码,删节后只包含一些数据操作(这样更容易理解)。

让我知道这是否有意义!

GDrive 上的 Excel 文档链接:https://drive.google.com/file/d/1OHaYh0OcMDTbU5BhrL81EO7d5pgwfJju/view?usp=sharing

用户界面:

library(shiny)
library(xlsx)
library(dplyr)library(shinythemes)
shinyUI(fluidPage(theme = shinytheme("spacelab"),
titlePanel("Dataset Manipulation Example"),
tags$caption("Edited by S. Gouyet 2.21.2018"),

sidebarLayout(
      sidebarPanel(
            fileInput('file1', 'Insert File',
                            accept = c(".xlsx")
                  ),

            downloadButton("downloadData", "Download updated Excel document")

                )
                ,
                mainPanel(
                )

              )

)

)

服务器:

shinyServer(function(input, output) {

reacdata<-reactive({

inFile1 <- input$file1

if(is.null(inFile1))

  return(NULL)


df <- read_excel(inFile1$datapath)
df <- df %>% select(`SALES REGION`, `Price`)



Northeast1 <- df %>% filter(`SALES REGION` == "Northeast 1")

Northeast2 <- df %>% filter(`SALES REGION` == "Northeast 2")

CapMetro <-   df %>% filter(`SALES REGION` == "Cap-Metro")

Southern <-   df %>% filter(`SALES REGION` == "Southern")

Eastern <-    df %>% filter(`SALES REGION` == "Eastern")

GreatLakes <- df %>% filter(`SALES REGION` == "Great Lakes")

Western <-    df %>% filter(`SALES REGION` == "Western")

Pacific <-    df %>% filter(`SALES REGION` == "Pacific")

wb <- createWorkbook()

sheet  <- createSheet(wb, sheetName="addDataFrame1")
addDataFrame(df, sheet)

sheet  <- createSheet(wb, sheetName="Northeast1")
addDataFrame(Northeast1, sheet)

sheet <- createSheet(wb, sheetName = "Northeast 2")
addDataFrame(Northeast2, sheet)

sheet <- createSheet(wb, sheetName = "Cap-Metro")
addDataFrame(Northeast2, sheet)

sheet <- createSheet(wb, sheetName = "Southern")
addDataFrame(Southern, sheet)

sheet <- createSheet(wb, sheetName = "Eastern")
addDataFrame(Southern, sheet)

sheet <- createSheet(wb, sheetName = "Great Lakes")
addDataFrame(GreatLakes, sheet)

sheet <- createSheet(wb, sheetName = "Western")
addDataFrame(Western, sheet)

sheet <- createSheet(wb, sheetName = "Pacific")
addDataFrame(Pacific, sheet)

})

output$downloadData <- downloadHandler( 
filename ="test.xlsx",
content = function(file) {
  saveWorkbook(wb, file)
}

  )
})

【问题讨论】:

  • 你会添加一个示例数据集吗?一些选项见this answer
  • 抱歉,已经更新了。

标签: r shiny


【解决方案1】:

疑难解答

问题 1

当我运行您的应用并尝试下载 Excel 工作表时,我收到此错误:

错误:找不到对象“wb”

这意味着 R 找不到 wb,因此 saveWorkbook 没有要写入 Excel 工作表的对象。

您在将数据存储在reacdata 中的reactive expression 中创建wb。这意味着我们需要在saveWorkbook 中调用reacdata()。注意括号。

output$downloadData <- downloadHandler( 
    filename ="test.xlsx",
    content = function(file) {
      saveWorkbook(reacdata(), file)
    }
  )

问题 2

我们重新运行应用程序并尝试下载 Excel 工作表。但是,现在我们得到了这个错误:

错误:尝试应用非函数

然后我们可以在控制台中查看堆栈跟踪:

Warning: Error in saveWorkbook: attempt to apply non-function
Stack trace (innermost first):
    54: saveWorkbook
    53: download$func [#67]
     4: <Anonymous>
     3: do.call
     2: print.shiny.appobj
     1: <Promise>
Error : attempt to apply non-function

我们看到错误发生在saveWorkbook

我们在反应式表达式中返回的最后一个对象将存储在reacdata() 中。 reacdata 中的最后一行是 addDataFrame(Pacific, sheet)。但是,我们希望reacdata() 包含工作簿对象。所以,我们只需在reacdata 中添加一行,如下所示:

reacdata<-reactive({
  # data manipulation etc...
  wb
})

如果您使用这些更改运行您的应用程序,它将工作。但我们也可以进行一些改进。

改进

  1. 使用split 制作每个区域的数据帧列表。为了保持上传的数据框中不包含区域,我们将SALES REGION 设为一个因素。

    df$`SALES REGION` <- factor(df$`SALES REGION`, levels = c("Northeast 1",
                                                              "Northeast 2",
                                                              "Cap-Metro",
                                                              "Southern",
                                                              "Eastern",
                                                              "Great Lakes",
                                                              "Western", 
                                                              "Pacific"))
    df_list <- split(df, df$`SALES REGION`, drop = FALSE)
    
  2. 编写一个函数来添加命名的工作表。

    ## wb: workbook
    ## data_frame: data.frame to add to the new sheet
    ## sheet_name: name of the new sheet
    add_sheet <- function(wb, data_frame, sheet_name) {
      sheet <- createSheet(wb, sheetName = sheet_name)
      addDataFrame(data_frame, sheet)
    }
    
  3. 创建工作簿对象,然后添加工作表

    ## create workbook    
    wb <- createWorkbook()
    
    ## add sheets
    add_sheet(wb, df, "addDataFrame1")
    for(i in names(df_list)) {
        add_sheet(wb, df_list[[i]], i)
    }
    

完整应用

## write out data
example <- data.frame(structure(list(ID = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
                                 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26), `SALES REGION` = c("Northeast 1", 
                                                                                                             "Northeast 2", "Western", "Southern", "Pacific", "Northeast 1", 
                                                                                                             "Northeast 2", "Western", "Southern", "Pacific", "Northeast 1", 
                                                                                                             "Northeast 2", "Western", "Southern", "Pacific", "Northeast 1", 
                                                                                                             "Northeast 2", "Western", "Southern", "Pacific", "Northeast 1", 
                                                                                                             "Northeast 2", "Western", "Southern", "Pacific", "Great Lakes"
                                 ), Price = c(100, 106, 3201, 4236.66666666667, 5787.16666666667, 
                                              7337.66666666667, 8888.16666666667, 10438.6666666667, 11989.1666666667, 
                                              13539.6666666667, 15090.1666666667, 16640.6666666667, 18191.1666666667, 
                                              19741.6666666667, 21292.1666666667, 22842.6666666667, 24393.1666666667, 
                                              25943.6666666667, 27494.1666666667, 29044.6666666667, 30595.1666666667, 
                                              32145.6666666667, 33696.1666666667, 35246.6666666667, 36797.1666666667, 
                                              1031), Jobs = c(10, 900, 30, 321, 331, 337.3, 343.6, 349.9, 356.2, 
                                                              362.5, 368.8, 375.1, 381.4, 387.7, 394, 400.3, 406.6, 412.9, 
                                                              419.2, 425.499999999999, 431.799999999999, 438.099999999999, 
                                                              444.399999999999, 450.699999999999, 456.999999999999, 9312)), .Names = c("ID", 
                                                                                                                                       "SALES REGION", "Price", "Jobs"), row.names = c(NA, -26L), class = c("tbl_df", 
                                                                                                                                                                                                            "tbl", "data.frame")))
write.xlsx(example, "Example.xlsx")

## ui
library(shiny)
library(xlsx)
library(dplyr)
library(shinythemes)
ui <- fluidPage(theme = shinytheme("spacelab"),
                  titlePanel("Dataset Manipulation Example"),
                  tags$caption("Edited by S. Gouyet 2.21.2018"),

                  sidebarLayout(
                    sidebarPanel(
                      fileInput('file1', 'Insert File',
                                accept = c(".xlsx")
                      ),

                      downloadButton("downloadData", "Download updated Excel document")

                    )
                    ,
                    mainPanel(
                    )

                  )

)

## server
server <- function(input, output) {

  reacdata<-reactive({

    inFile1 <- input$file1

    if(is.null(inFile1))
      return(NULL)

    df <- read_excel(inFile1$datapath)
    df <- df %>% select(`SALES REGION`, `Price`)

    # create list with one dataframe per region
    df$`SALES REGION` <- factor(df$`SALES REGION`, levels = c("Northeast 1",
                                                              "Northeast 2",
                                                              "Cap-Metro",
                                                              "Southern",
                                                              "Eastern",
                                                              "Great Lakes",
                                                              "Western", 
                                                              "Pacific"))
    df_list <- split(df, df$`SALES REGION`, drop = FALSE)

    # write function to add named sheets
    ## wb: workbook
    ## data_frame: data.frame to add to the new sheet
    ## sheet_name: name of the new sheet
    add_sheet <- function(wb, data_frame, sheet_name) {
      sheet <- createSheet(wb, sheetName = sheet_name)
      addDataFrame(data_frame, sheet)
    }

    # make the workbook and add the first dataframe
    wb <- createWorkbook()
    add_sheet(wb, df, "addDataFrame1")

    # use a loop to add sheets
    for(i in names(df_list)) {
      add_sheet(wb, df_list[[i]], i)
    }

    # return the workbook object
    wb

  })

  output$downloadData <- downloadHandler( 
    filename ="test.xlsx",
    content = function(file) {
      saveWorkbook(reacdata(), file)
    }
  )
}

shinyApp(ui = ui, server = server)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-18
    • 2016-01-29
    • 2019-06-12
    • 1970-01-01
    • 2017-03-24
    • 1970-01-01
    • 2021-09-29
    相关资源
    最近更新 更多