Импортировать файл и добавить в ранее загруженный файл - PullRequest
1 голос
/ 25 мая 2019

Я пытаюсь сделать блестящее приложение, с помощью которого я могу загружать файлы 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))

1 Ответ

1 голос
/ 25 мая 2019

Ваше обновление df_all имеет недостатки по двум причинам:

  1. Когда вы ссылаетесь на df_all внутри реактивного блока, он берет внешнюю ссылку (вне реактивного блока), а затем присваивает ее df_all внутри блока, никогда не обновляя его снаружи. В некоторых контекстах это предполагает использование <<-, хотя я не одобряю это мышление, так как оно ведет к проблемному программированию (побочный эффект действительно следует избегать, если он не нужен). И ...
  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)
    })
}

Это должно работать при условии, что все таблицы имеют одинаковую структуру. Возможно, вы захотите быть немного более осторожным в привязке строк с помощью некоторых предварительных проверок и тому подобного (подтверждение имен в одном из присутствующих в другом и т. Д.).

Кстати: я использую isolate(...), чтобы повторный рендеринг таблицы не вызывал двойной запуск DT:renderDataTable. Это не означает, что рендеринг не может реагировать на то, что иначе вносит изменения в df_all, но не навязывается (циклически) реактивностью.

...