将 fileInput 用于工作簿并 Sheet 与闪亮的 renderDataTable 一起上传

Using fileInput for Workbook and Sheet upload along with renderDataTable in shiny

我想将 fileInput 用于 WorkbookSheet 上传以及 renderDataTable 上传文件并执行分析并下载不同格式的输出。无法弄清楚如何实现这一点。我的最低工作示例如下:

library(tidyverse)
library(shiny)
library(shinydashboard)
library(DT)

ui <-
  dashboardPage(
    skin = "green",
    dashboardHeader(
      title      = "Test",
      titleWidth = 280
      ),
    dashboardSidebar(
      width = 280,
      sidebarMenu(
        menuItem(text = "File(s) Upload", tabName = "Files",     icon = icon("file-upload")),
        menuItem(text = "Output", tabName = "Out1",     icon = icon("file-upload"))
      )
    ),
    dashboardBody(
      tabItems(
        tabItem(
          tabName = "Files",
          fluidRow(
            column(
              width = 4,
              inputPanel(
                fileInput(inputId = "File1", label = "File", multiple = TRUE, accept = c(".xlsx")),
                selectInput(inputId = "Sheet1", label = "Select sheet", choices = NULL, selected = NULL)
                )
              )
              )
          ),
        tabItem(
                 tabName = "Out1",
                 fluidRow(column(width = 10, strong("Data")), align = "center"),
                 br(),
                 fluidRow(dataTableOutput("Data1"))
                 ) 
      )
    )
  )


server <- 
  function(input, output){
    
    thedata <- 
      reactive(
        iris %>% 
        filter(Species == "setosa")
        )
    
    output$Data1 <- 
      renderDataTable(
          thedata()
        , extensions = "Buttons"
        , options = list(
                     dom = "Bfrtip"
                   , buttons = c("copy", "csv", "excel", "pdf", "print")
                   )
      )
    }

runApp(
    list(ui = ui, server = server)
  , launch.browser = TRUE
  ) 

已编辑

想要 select Excel WorkbookSheet

前提是您的 excel 本地文件具有此结构(sheet 名称为 'Sheet1'):

structure(list(x = c(1, 2, 5), y = c(2, 9, 6)), class = "data.frame", row.names = c(NA, 
-3L))

假设您通过文件上传输入法上传它。那么你的代码应该如下:

library(tidyverse)
library(shiny)
library(shinydashboard)
library(DT)

ui <-
  dashboardPage(
    skin = "green",
    dashboardHeader(
      title      = "Test",
      titleWidth = 280
    ),
    dashboardSidebar(
      width = 280,
      sidebarMenu(
        menuItem(text = "File(s) Upload", tabName = "Files",     icon = icon("file-upload")),
        menuItem(text = "Output", tabName = "Out1",     icon = icon("file-upload"))
      )
    ),
    dashboardBody(
      tabItems(
        tabItem(
          tabName = "Files",
          fluidRow(
            column(
              width = 4,
              inputPanel(
                fileInput(inputId = "File1", label = "File", multiple = F, accept = c(".xlsx")),
                selectInput(inputId = "sheet_name", label = "Select sheet", choices = 'Sheet1', selected = 'Sheet1')
              )
            )
          )
        ),
        tabItem(
          tabName = "Out1",
          fluidRow(column(width = 10, strong("Data")), align = "center"),
          br(),
          fluidRow(DT::DTOutput("Data1"))
        ) 
      )
    )
  )


server <-  function(session, input, output){
    
    values <- reactiveValues(
      infile = NULL
    )
    
    thedata <- reactive({
      
      if(is.null(input$File1))
        return(NULL)
      
      values$infile <- input$File1
      df <- xlsx::read.xlsx(values$infile$datapath, encoding="UTF-8", sheetName = input$sheet_name)

      # do some calculations here, add additional column 'z'
      df <- df %>% mutate(z=x+y)
      df
    })
    
    output$Data1 <- DT::renderDT(server=FALSE,{
      # Load data
      data <- thedata()
      # Show data
      datatable(data, extensions = 'Buttons', 
                options = list(
                  dom = "Bfrtip", 
                  buttons = c("copy", "csv", "excel", "pdf", "print")
               ))
    })
    
    
}


shinyApp(ui, server)

这是一个解决方案,您可以选择任何 Excel 文件并动态更改要读取的 sheet。

将以下内容添加到您的服务器:

# Populate the drop down menu with the names of the different Excel Sheets, but
# only after a new file is supplied
observe({

  sheet_names <- readxl::excel_sheets(input$File1$datapath)

  shiny::updateSelectInput(
    inputId = "Sheet1",
    choices = sheet_names,
    selected = sheet_names[[1]] # Choose first sheet as default
  )
  
}) %>%
  bindEvent(input$File1)


# When the drop down meny is populated, read the selected sheet from the Excel
# file
thedata <- reactive({
  
  req(input$Sheet1)
  
  readxl::read_xlsx(input$File1$datapath, sheet = input$Sheet1)
  
})

其余代码可以保持不变。下面是一个完整的代表。

完整示例,基于您的代码

library(tidyverse)
library(shiny)
library(shinydashboard)
library(DT)

ui <-
  dashboardPage(
    skin = "green",
    dashboardHeader(
      title      = "Test",
      titleWidth = 280
    ),
    dashboardSidebar(
      width = 280,
      sidebarMenu(
        menuItem(text = "File(s) Upload", tabName = "Files",     icon = icon("file-upload")),
        menuItem(text = "Output", tabName = "Out1",     icon = icon("file-upload"))
      )
    ),
    dashboardBody(
      tabItems(
        tabItem(
          tabName = "Files",
          fluidRow(
            column(
              width = 4,
              inputPanel(
                fileInput(inputId = "File1", label = "File", multiple = TRUE, accept = c(".xlsx")),
                selectInput(inputId = "Sheet1", label = "Select sheet", choices = NULL, selected = NULL)
              )
            )
          )
        ),
        tabItem(
          tabName = "Out1",
          fluidRow(column(width = 10, strong("Data")), align = "center"),
          br(),
          fluidRow(dataTableOutput("Data1"))
        )
      )
    )
  )


server <- function(input, output){


  # Populate the drop down menu with the names of the different Excel Sheets, but
  # only after a new file is supplied
  observe({

    sheet_names <- readxl::excel_sheets(input$File1$datapath)

    shiny::updateSelectInput(
      inputId = "Sheet1",
      choices = sheet_names,
      selected = sheet_names[[1]]
    )

  }) %>%
    bindEvent(input$File1)


  # When the drop down meny is populated, read the selected sheet from the Excel
  # file
  thedata <- reactive({

    req(input$Sheet1)

    readxl::read_xlsx(input$File1$datapath, sheet = input$Sheet1)

  })


  output$Data1 <-
    renderDataTable(
      thedata()
      , extensions = "Buttons"
      , options = list(
        dom = "Bfrtip"
        , buttons = c("copy", "csv", "excel", "pdf", "print")
      )
    )
}

runApp(
  list(ui = ui, server = server)
  , launch.browser = TRUE
)

Note: I see that you have multiple = TRUE in fileInput(). If you want to supply multiple Excel files at the same time, you need to add some logic to handle which file to read the sheet names from, and which sheet names to use for which file. I would probably set multiple to FALSE.