导入文件并附加到 r shiny 中先前加载的文件

Import file and append to previously loaded file in r shiny

我正在尝试制作一个闪亮的应用程序,我可以使用它按顺序上传 excel 文件。每次我上传文件时,它都会添加到之前加载的文件中(假设它们具有相同的格式)。

我所做的是将 df_all 定义为空数据框。每次我点击上传并选择一个文件时,我都做了 bind_rows(df_all, df)。但它没有用。

谁能帮我弄清楚我做错了什么?我花了几个小时尝试所有不同的事情但没有成功。

# set working directory
setwd(my_working_directory)

ipak <- function(pkg){
    new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
    if (length(new.pkg)) 
        install.packages(new.pkg, dependencies = TRUE)
    sapply(pkg, require, character.only = TRUE)
}

packages <- c('devtools', 'readxl',
              'shiny', 'DT')
ipak(packages)

## ui
##---------------------------------------------------------------

ui <- fluidPage(
    fluidRow(
        column(9, h2('Import Excel'), align='center')    
    ),
    sidebarLayout(
        sidebarPanel(
            #----------------------Upload Files-----------------
            conditionalPanel(
                condition= " input.tabs == 'Upload_Files' ",

                fileInput('file', 'Choose Excel file',
                          accept = c(".xlsx")
                )
            )        
        ),        
        #------------------------------Main Panel------------------------    
        mainPanel(            
            tabsetPanel(
                id = 'tabs',               
                tabPanel('Upload_Files',
                         fluidRow (
                             column(12, DT::dataTableOutput('data.table1') ) 
                         ) 
                )
            )
        )
    )
)
##--------------------server-----------------------

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

    df_all = data.frame()

    output$data.table1 <- DT::renderDataTable({

        # input$file will be NULL initially.

        req(input$file)
        inFile <- input$file

        if(is.null(inFile)) {
            return(NULL)
        }

        df=read_excel(inFile$datapath)
        df_all = bind_rows(df_all, df)
        return(df_all)
    })
}
runApp(shinyApp(ui=ui, server=server))

您对 df_all 的更新存在缺陷,原因有二:

  1. 当您在反应块内引用 df_all 时,它需要 outer-reference (在反应块外)然后将其分配给块内的 df_all,从不更新一个外部。在某些情况下,这建议使用 <<-,但我不鼓励这种心态,因为它会导致有问题的编程(如果不必要,应该避免使用 side-effect)。还有...
  2. 你应该让外层 df_all 具有反应性。

相反,尝试

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

    df_all <- reactiveVal(NULL)

    output$data.table1 <- DT::renderDataTable({
        req(input$file)
        olddf <- isolate(df_all())
        if(is.null(input$file)) return(NULL)
        df <- readr::read_excel(input$file$datapath)
        df <- dplyr::bind_rows(olddf, df)
        isolate(df_all(df))
        return(df)
    })
}

假设所有 table 都是 similarly-structured,这应该可以工作。您可能希望通过一些 pre-checks 之类的方式在您的 row-binding 中更加谨慎(确认其中一个出现在另一个中的名称,等等)。

顺便说一句:我使用 isolate(...) 这样 re-rendering table 就不会 double-trigger DT:renderDataTable。这并不是说渲染不能响应 elsedf_all 的更改,但不能响应 self-imposed(循环)反应。