R Shiny - Excel文件无法以正确的格式下载

时间:2018-03-07 00:17:33

标签: r shiny

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

让我知道这是否有意义!

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

UI:

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)
}

  )
})

1 个答案:

答案 0 :(得分:1)

故障排除

第1期

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

  

错误:对象&#39; wb&#39;找不到

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

您在reactive expression内创建了wb,用于将数据存储在reacdata中。这意味着我们需要在reacdata()中致电saveWorkbook。请注意括号。

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)
    }
    
  4. 完整应用

    ## 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)