【问题标题】:dynamically list 'choices' for selectInput from a user selected column从用户选择的列中动态列出 selectInput 的“选择”
【发布时间】:2018-04-25 04:52:11
【问题描述】:

selectInput() 的列表选项是通过对值进行硬编码来完成的,如 ?selectInput 中的示例:

selectInput(inputID = "variable", label ="variable:",
                choices = c("Cylinders" = "cyl",
                  "Transmission" = "am",
                  "Gears" = "gear"))

但是,我希望我的 choices 列表是来自用户上传的文件 (csv) 的用户选择列的唯一值列表。我该怎么做?这是据我所知:

用户界面

    shinyUI(fluidPage(
          fluidRow(
                   fileInput('datafile', 'Choose CSV file',
                accept=c('text/csv', 'text/comma-separated-values,text/plain')),
                   uiOutput("selectcol10"),
                   uiOutput("pic")
    ))
)

服务器

    shinyServer(function(input, output) {

  filedata <- reactive({
    infile <- input$datafile
    if (is.null(infile)) {
      # User has not uploaded a file yet
      return(NULL)
    }
    temp<-read.csv(infile$datapath)
    #return
    temp[order(temp[, 1]),]
  })

  output$selectcol10 <- renderUI({
    df <-filedata()
    if (is.null(df)) return(NULL)

    items=names(df)
    names(items)=items
    selectInput("selectcol10", "Primary C",items) 
  })

  col10 <- reactive({
    (unique(filedata()$selectcol10))
  })

  output$pic <- renderUI({
    selectInput("pic", "Primary C values",col10())
  })
})

【问题讨论】:

    标签: r dynamic shiny shiny-reactivity


    【解决方案1】:

    对于动态 UI,您可以采用两种方式:updateXXXrenderUI。这是采用updateXXX 方法的解决方案。

    library(shiny)
    
    ui <- fluidPage(sidebarLayout(
      sidebarPanel(
        selectInput("dataset", "choose a dataset", c("mtcars", "iris")),
        selectInput("column", "select column", "placeholder1"),
        selectInput("level", "select level", "placeholder2")
      ),
      mainPanel(tableOutput("table"))
    ))
    
    server <- function(input, output, session){
      dataset <- reactive({
        get(input$dataset)
      })
    
      observe({
        updateSelectInput(session, "column", choices = names(dataset())) 
      })
    
      observeEvent(input$column, {
        column_levels <- as.character(sort(unique(
          dataset()[[input$column]]
        )))
        updateSelectInput(session, "level", choices = column_levels)
      })
    
      output$table <- renderTable({
        subset(dataset(), dataset()[[input$column]] == input$level)
      })
    }
    
    shinyApp(ui, server)
    

    server函数中有一行

    updateSelectInput(session, "level", choices = column_levels)
    

    更新第三个下拉菜单levelchoices 参数。要计算级别,您可以使用base::levels 函数,但是不适用于数字列。所以我用了

    as.character(sort(unique( . )))
    

    相反。 “占位符”将在启动后立即被替换。

    使用 fileInput 创建的数据框

    下面的代码显示了如何将此逻辑与fileInput 结合使用。我在ui 中添加了一个conitionalPanel 来隐藏下拉菜单,只要没有选择文件。见here

    library(shiny)
    
    # test data
    write.csv(reshape2::tips, "tips.csv", row.names = FALSE)
    write.csv(mtcars, "mtcars.csv")
    
    ui <- fluidPage(
      sidebarLayout(
        sidebarPanel(
          fileInput('datafile', 'Choose CSV file',
                    accept = c('text/csv', 'text/comma-separated-values,text/plain', '.csv')),
          conditionalPanel(
            # use a server side condition
            condition = "output.fileUploaded",
            # placeholders will be replaced from the server
            selectInput("pic", "Primay C", "placeholder 1"),
            selectInput("level", "select level", "placeholder 2")
          )
        ),
        mainPanel(
          h3("filtered data"),
          tableOutput("table")
        )
      )
    )
    
    server <- function(input, output, session){
      # create reactive version of the dataset (a data.frame object)
      filedata <- reactive({
        infile <- input$datafile
        if (is.null(infile))
          # User has not uploaded a file yet. Use NULL to prevent observeEvent from triggering
          return(NULL)
        temp <- read.csv(infile$datapath)
        temp[order(temp[, 1]),]
      })
    
      # inform conditionalPanel wheter dropdowns sohould be hidden
      output$fileUploaded <- reactive({
        return(!is.null(filedata()))
      })
      outputOptions(output, 'fileUploaded', suspendWhenHidden=FALSE)
    
      # update the selectInput elements according to the dataset
    
      ## update 'column' selector
      observeEvent(filedata(), {
        updateSelectInput(session, "pic", choices = names(filedata()))
      })
    
      ## update 'level' selector
      observeEvent(input$pic, {
        column_levels <- unique(filedata()[[input$pic]])
        updateSelectInput(session, "level", choices = column_levels,
                          label = paste("Choose level in", input$pic))
      }, ignoreInit = TRUE)
    
      # show table
      output$table <- renderTable({
        subset(filedata(), filedata()[[input$pic]] == input$level)
      }, bordered = TRUE)
    }
    
    shinyApp(ui, server)
    

    【讨论】:

    • 谢谢,但是我无法访问 UI 中的名称(choices_df),因为用户加载了文件;看到你的行 selectInput("column", "select column", names(choices_df))。请注意,我的 SERVER 从创建反应变量 filedata() 开始。
    • 我刚刚更新了答案以包含一个“反应性”数据集。
    • 查看我的答案以了解有效的方法。我必须加载数据集(csv 文件)才能执行操作,因此 selectInput("dataset", "choose a dataset", c("mtcars", "iris")) 对我不起作用。如果你能更新你的答案,我宁愿给你解决方案。
    • 您的解决方案似乎不错。下班后我再看看这个。希望我能够创建一个可以处理 CSV 文件的完整工作示例。
    【解决方案2】:

    这是有效的,感谢@GregordeCillia 引导我完成它:

    在我替换的服务器中

    col10 <- reactive({
        (unique(filedata()$selectcol10))
      })
    
      output$pic <- renderUI({
        selectInput("pic", "Primary C values",col10())
      })
    

      observe({
        valu <- unique(unlist(filedata()[input$selectcol10]))
        updateSelectInput(session, "level", choices = valu)
      })
    

    在我替换的 UI 中

    uiOutput("pic")
    

    selectInput("level", "select level", "placeholder")),
    

    【讨论】:

      猜你喜欢
      • 2019-01-19
      • 1970-01-01
      • 2014-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多