简体   繁体   中英

R Shiny: How to expand a reactive containing a list of data.frames with an uploaded data.frame?

I'm struggeling with this one for hours:

In my app a simple test dataset df gets loaded upon starting the app. The user then may add further datasets through a file upload before selecting from a dropdown menu (here selectInput ) the dataset he likes to continue working with.

What I'm failing to do:

After starting the app, the reactive df_list should only contain the initial dataset df and the dropdown menu should only hold the values c("", "df") . After adding a dataset through an upload (or else) df_list should be expanded (and the dropdown accordingly). So that I have a list containing all available datasets the user can select from.

But I only manage to create two scenarios: the dropdown menu contains df but I fail to expand the df_list after adding a dataset. Or the dropdown menu stays empty until I add a dataset, so the user has first to add a dataset before he can work with the test dataset.

My code example: I 'simulate' a file upload via an actionButton that creates the data.frame df_upload . Here follows the example without trying to expand df_list with the additional dataset df_upload .

library(shiny)

# df available from start
df <- data.frame(Var = 1:10)

ui <- fluidPage(
  selectInput("select", label = "Select data", choices = c("")),
  actionButton("upload", "Simulate Upload"),
  tableOutput("tabdata")
)

server <- function(input, output, session) {
  
  # reactive that lists all datasets
  df_list <- reactive({list(df = df)})
  
  # 'upload' of second df
  df_upload <- eventReactive(input$upload, {
    data.frame(Var = 11:20)
  })
  
  # observes if df_list() gets expanded to update choices
  observeEvent(df_list(), {
    updateSelectInput(session = session,
                      inputId = "select",
                      choices = c("", names(df_list())))
  })
  
  # output of selected dataset
  output$tabdata <- renderTable({
    req(df_list())
    df_list()[[input$select]]
  }) 

}

shinyApp(ui, server)

Here one of many things I tried (this adds df_upload succesfully, but fails to show df initially in the dropdown menu after starting the app):

library(shiny)

# df available from start
df <- data.frame(Var = 1:10)

ui <- fluidPage(
  selectInput("select", label = "Select data", choices = c("")),
  actionButton("upload", "Simulate Upload"),
  tableOutput("tabdata")
)

server <- function(input, output, session) {
  
  # reactive that lists all datasets
  df_list <- reactive({
    df_list <- list(df = df)
    
    # check if there is an uploaded df, and if yes add it to df_list
    # does not work, because it does not give me df_list only containing df 
    # in case no dataset was added yet.
    # is.null is not the proper way, because if df_upload does not exist yet,
    # it does not yield NULL. I also tried it unsuccessfully 
    # with exists("df_upload()")
    if (!is.null(df_upload())) {
      df_list[[2]] <- df_upload()
      names(df_list)[2] <- "df_upload"
    }
    return(df_list)
  })
  
  # 'upload' of second df
  df_upload <- eventReactive(input$upload, {
    data.frame(Var = 11:20)
  })

  # observes if df_list() gets expanded to update choices
  observeEvent(df_list(), {
    updateSelectInput(session = session,
                      inputId = "select",
                      choices = c("", names(df_list())))
  })
  
  # output of selected dataset
  output$tabdata <- renderTable({
    req(df_list())
    df_list()[[input$select]]
  })
  
}

shinyApp(ui, server)

A simple solution using reactiveValues based on @Limey's comment:

library(shiny)

# df available from start
df <- data.frame(Var = 1:10)

reactlog::reactlog_enable()

ui <- fluidPage(
  selectInput("select", label = "Select data", choices = c("df")),
  actionButton("upload", "Simulate Upload"),
  tableOutput("tabdata")
)

server <- function(input, output, session) {
  
  # empty reactiveValues rv to store all datasets in
  rv <- reactiveValues()
 
  # store the test df in rv
  rv$df <- df
  
  # 'upload' of second df and storing it in rv
   observeEvent(input$upload, {
     rv$df_upload <- data.frame(Var = 11:20)
  })
  
  # update selectInput choices 
  observe({
    updateSelectInput(session = session,
                      inputId = "select",
                      choices = names(rv),
                      selected = "df")
  })
  
  # output of selected dataset
  output$tabdata <- renderTable({
    rv[[input$select]]
  })

}

shinyApp(ui, server)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM