How to find and use selected options in selectInput (multiple = TRUE)

I'm trying to build an app that looks at biological data, and I created a dropdown menu that allows multiple options to be selected. Now I want to be able to see where those options are stored, and how to use them. I've pasted the code, and what I want to do with it. If someone could help, it would be greatly appreciated as I'm stuck and don't know how to continue:

  1. I want to select whatever genes from the “PCR Positive” drop down menu on page 2 (this works)

  2. After selecting the genes, I would like it to take all of that gene’s values from the table on page 1 (the table appears after uploading certain files, I've attached a photo of the table)

  3. Those values are saved/stored as a separate output, and can then be assessed whether they pass the conditions for the PCR Positive Control row on page 3 in the QC summary

  4. If all the samples pass, then “PASS” is displayed. If any of the samples fail, “FAIL” is displayed. The result is dependent on whether the Ct value is greater/lower than the selected “High Ct Cutoff” on page 2

  5. The failed samples are displayed in the “Failed PPC Samples” at the bottom of page 3, with the Sample ID being the string in the “SampleID” column of page 1’s table, the Gene Name being the name of the gene selected from page 2 (column name, PPC in this specific case), and Ct being the value for that gene in page 1’s table

Code:

library(tidyverse)
library(readxl)
library(shiny)
library(bslib)
library(data.table)

UI

ui <- fluidPage(

titlePanel("QPCR App"),
theme = bs_theme(version = 4, bootswatch = "journal"),

tabsetPanel(
id = "switch",

tabPanel("Import Data",
         
         fluidRow(
           column(width = 12,
                  sidebarPanel(
                    style = "height: 350px",
                    width = 16, 
                    
                    actionButton("instrButton", "Instructions", style = "background-color: black; color: white;"),
                    br(),
                    br(),
                    
                    fileInput("metaFile", strong("Upload metadata.xlsx File:"),
                              accept = c(".xlsx")),
                    
                    fileInput("dataFiles", strong("Upload .txt File(s):"),
                              accept = c(".txt"),
                              multiple = TRUE),
                  fluidRow(
                    column(width = 12, align = "right",
                    actionButton("page_12", "Proceed to Analysis Options")
                  )
                )
               ),
                  
           )
         ),
         
         mainPanel(
           DT::dataTableOutput("fullTable")
         )
),

tabPanel("Analysis Options",
         sidebarLayout(
           sidebarPanel(
             column(12,
                    selectInput("sfactors", label = strong("Select Factors"), 
                                choices = NULL, multiple = TRUE)
             ),
             
             
             column(12,
                    selectInput("sHK", label = strong("Select House Keeping Genes"), 
                                choices = NULL, multiple = TRUE),
                    actionButton("reset", "Reset")
             ),
             
             fluidRow(
               column(6,
                      selectInput("sGC", label = strong("Genomic Contamination"), 
                                  choices = NULL, multiple = TRUE)),
               
                 column(6,
                      selectInput("sPP", label = strong("PCR Positive"), 
                                    choices = NULL, multiple = TRUE)),
                    ),
               
               
              fluidRow(
                column(6,
                    selectInput("sRTC", label = strong("Reverse Transcriptase Control"), 
                                      choices = NULL, multiple = TRUE)),
                
                column(6,
                    selectInput("sNTC", label = strong("No Template Control"), 
                                        choices = NULL, multiple = TRUE)),
                     ),
             
             fluidRow(
               column(6, 
                      numericInput("lowCT", label = strong("Low CT Cutoff"), value = 1, min=1, max=15)),
               
               column(6, 
                      numericInput("highCT", label = strong("High CT Cutoff"), value = 25, min=25, max=40)),
             ),
             
             
             fluidRow(
             column (6, actionButton("page_21", "Return to Import Data"), align = "left"),
             column (6, actionButton("page_23", "Proceed to QC Report"), align = "right"),
             )
             
             ),
           
           mainPanel(),
         ), 
),

tabPanel("QC Report",
         
         h3("QC Summary"),
         mainPanel(tableOutput("RTable")),
         
         h3("QC Details"),
         
         h5("Failed PPC Samples"),
         mainPanel(tableOutput("FPPCTable")),
         
         h5("Failed RTC Samples"),
         mainPanel(tableOutput("RTCTable")),
         
         h5("Failed NTC Samples"),
         mainPanel(tableOutput("NTCTable")),
         
         h5("Failed GCC Samples"),
         mainPanel(tableOutput("GCCTable")),
         
         actionButton("page_32", "Return to Analysis Options")
)

)
)

SERVER

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

observeEvent(input$instrButton, {
showModal(modalDialog(
title = "Instructions",
p("Input 1: Upload a metadata.xlsx file with 3 columns (SampleID, Type, Control)"),
p("Input 2: Upload .txt files that match the name in metadata's SampleID column. Each .txt file has to contain 'Well Name' and 'Ct (dRn)' columns"),
easyClose = TRUE,
footer = tagList(
actionButton("instrCloseButton", "Close", style = "background-color: black; color: white;")),
size = "l",
))
observeEvent(input$instrCloseButton, {
removeModal()
})
})

switch_page <- function(tab_name) {
updateTabsetPanel(inputId = "switch", selected = tab_name)
}

observeEvent(input$page_12, {switch_page("Analysis Options")})
observeEvent(input$page_21, {switch_page("Import Data")})
observeEvent(input$page_23, {switch_page("QC Report")})
observeEvent(input$page_32, {switch_page("Analysis Options")})

LOAD DATA ----

Load metaData

metaData <- reactive({
req(input$metaFile)
read_excel(input$metaFile$datapath)
})

#load geneData
geneData <- reactive({
req(input$dataFiles)
rawList<-list()
for(i in 1:nrow(input$dataFiles)) {
lname<-gsub(".txt", "", input$dataFiles$name[i])
rawList[[lname]] <- read.table(file = input$dataFiles$datapath[i], header = TRUE, sep="\t", stringsAsFactors = FALSE, check.names=FALSE, na.strings = "No Ct")
rawList[[lname]] <- rawList[[lname]][c("Well Name","Ct (dRn)")]
colnames(rawList[[i]])[2] <-lname
}
combData<- reduce(rawList, left_join, by = 'Well Name')
})

Join metaData and geneData into one table

fullTable<-reactive({

# Move gene names into row names so that they become column names when we transform table
tempGeneData <- geneData()
rownames(tempGeneData)<-tempGeneData$'Well Name'
tempGeneData <- tempGeneData %>%
  dplyr::select(-'Well Name') %>%
  t() 

# Move "sample IDs" (which are currently the new row names) into a column called "SampleID"
tempGeneData <- data.frame(SampleID=rownames(tempGeneData), tempGeneData)

# join with metaData
fullData <- inner_join(metaData(), tempGeneData, by="SampleID")

})

OBSERVE EVENTS ----

observeEvent(metaData(), {
choices <- colnames(metaData())
updateSelectInput(inputId = "sfactors", choices = choices)
})

observeEvent(geneData(), {
choices <- geneData()$'Well Name'
updateSelectInput(inputId = "sHK", choices = choices)
})

observeEvent(input$reset, {
# Reset the selected options by setting choices to an empty set
updateSelectInput(inputId = "sHK", selected = character(0))
})

input_ids <- c("sGC", "sPP", "sRTC", "sNTC")
update_select_input <- function(input_id) {
observe({
choices <- c("None", geneData()$'Well Name')
updateSelectInput(session, input_id, choices = choices)
})
}

Apply the function for each input ID

lapply(input_ids, update_select_input)

RENDERED OBJECTS

output$fullTable<-DT::renderDataTable({
fullTable()
})

#Page 3 Tables

RTable with custom data

RTable <- reactive({
highCT <- input$highCT

tibble(
  "Control Type" = c("PCR Positive Control", 
                     "Reverse Transcription Control", 
                     "No Template Control", 
                     "Genomic Contamination Control"),
  
  "Purpose" = c("To test if your PCR reactions worked",
                "To test if your RT reactions worked", 
                "Checks for RNA Contamination",
                "Checks for DNA Contamination"),
  
  "Pass Criteria" = c("Ct < High Ct Cutoff",
                      "Ct < High Ct Cutoff",
                      "Ct > High Ct Cutoff or No Ct",
                      "Ct > High Ct Cutoff or No Ct"),
  
  "Result" = c("NA") #make QC Detail tables first, and just have the Result display everything (don't need to have it test things here)
)

})

Render empty table

output$RTable <- renderTable({
RTable()
})

detailTable <- reactive({
tibble(
"Sample ID" = c("NA"),
"Gene Name" = c("NA"),
"Ct" = c("NA"))
})

output$FPPCTable <- renderTable({
detailTable()
})

output$RTCTable <- renderTable({
detailTable()
})

output$NTCTable <- renderTable({
detailTable()
})

output$GCCTable <- renderTable({
detailTable()
})

}

Run the app

shinyApp(ui = ui, server = server)

Table 1 Image:

If you are asking how to access the user's selections, input$sHK will produce a vector of strings, one for each choice selected, or NULL if the user did not select any of the choices.

I don't have access to my computer now so I can't test what you said, but I tried previously putting input$... to do the tests and they didn't work. In this case, I want to focus on "sPP". The sPP dropdown menu consist of a list of gene options that match the column headings of table 1 (page 1) excluding "SampleID" and "Site". For example, if I select CYP3A7, CYP1A4, and PDK4 as my "sPP" options, how do I access them? After I access them, can I make specific tests for each one of the selected options?

I'm sorry if I'm not explaining this very well. I don't have too much experience with shiny. We can have a video call where I can share my screen if that works for you.

How you want to use the selections is still vague. The control will give you a vector that looks like c("CYP3A7", "CYP1A4", "PDK4"). If you want to use those to extract columns, you can use the selection vector as column names (for instance, via fullData[ , input$sPP] or fullData |> select(all_of(input$sPP)).

When I use the codes you provided, they both provide errors. The first one (fullData [ , input$sPP] shows: object "fullData" not found. The second shows this: no applicable method for 'select' applied to an object of class "c('reactiveExpr', 'reactive', 'function')". In both cases, the entire RTable is gone

Your code creates fullData inside a reactive block. I assumed (perhaps incorrectly) that was where you wanted to access columns selected by sPP. In any event, just replace fullData with the name of the dataframe or tibble containing the data you want to extract and put one of the lines I suggested wherever the extraction should occur (bearing in mind that the dataframe/tibble needs to exist and contain the relevant columns at that point in the code).

The same error occurs when I do that. I'm unsure if I'm doing what I'm intending to correctly. I want to extract the columns from fullTable, then run them through a few tests, and display the answer in the "Result" section of RTable.

I have not written the tests I want to do yet as I don't know how to write the code without the extracted columns saved as something. I want each column to be saved separately, so the test could be done to each one individually.

Try writing a minimal example that demonstrates the problem you are encountering -- just one multiple select input and one action button in the UI, and just code that loads fullTable and reacts to the button by extracting the desired columns. Assuming it triggers the error message, post that code here.

I apologize for the delay. I simplified the code as much as I could. It triggers the same error message. Here's the code (the options in sPP only appear if the metaFile and dataFiles are uploaded, but I can't attach those files here. I've uploaded photos instead):

library(tidyverse)
library(readxl)
library(shiny)
library(bslib)
library(data.table)

ui <- fluidPage(

titlePanel("QPCR App"),
theme = bs_theme(version = 4, bootswatch = "journal"),

tabPanel("Import Data",
         
         fluidRow(
           column(width = 12,
                  sidebarPanel(
                    style = "height: 350px",
                    width = 16, 
                    
                    fileInput("metaFile", strong("Upload metadata.xlsx File:"),
                              accept = c(".xlsx")),
                    
                    fileInput("dataFiles", strong("Upload .txt File(s):"),
                              accept = c(".txt"),
                              multiple = TRUE),
                  ),
                  
           )
         ),
         
         mainPanel(
           DT::dataTableOutput("fullTable")
         )
),

tabPanel("Analysis Options",
             fluidRow(
               column(12,
                      selectInput("sPP", label = strong("PCR Positive"), 
                                  choices = NULL, multiple = TRUE)),
             ),
         ), 

tabPanel("QC Report",
         
         h3("QC Summary"),
         mainPanel(tableOutput("RTable")),
         
         h3("QC Details"),
         
         h5("Failed PPC Samples"),
         mainPanel(tableOutput("FPPCTable")),

)

)

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

metaData <- reactive({
req(input$metaFile)
read_excel(input$metaFile$datapath)
})

geneData <- reactive({
req(input$dataFiles)
rawList<-list()
for(i in 1:nrow(input$dataFiles)) {
lname<-gsub(".txt", "", input$dataFiles$name[i])
rawList[[lname]] <- read.table(file = input$dataFiles$datapath[i], header = TRUE, sep="\t", stringsAsFactors = FALSE, check.names=FALSE, na.strings = "No Ct")
rawList[[lname]] <- rawList[[lname]][c("Well Name","Ct (dRn)")]
colnames(rawList[[i]])[2] <-lname
}
combData<- reduce(rawList, left_join, by = 'Well Name')
})

fullTable<-reactive({

tempGeneData <- geneData()
rownames(tempGeneData)<-tempGeneData$'Well Name'
tempGeneData <- tempGeneData %>%
  dplyr::select(-'Well Name') %>%
  t() 


tempGeneData <- data.frame(SampleID=rownames(tempGeneData), tempGeneData)

fullData <- inner_join(metaData(), tempGeneData, by="SampleID")

})

observeEvent(geneData(), {
choices <- c("None", geneData()$'Well Name')
updateSelectInput(inputId = "sPP", choices = choices)
})

output$fullTable<-DT::renderDataTable({
fullTable()
})

RTable <- reactive({
highCT <- input$highCT

tibble(
  "Control Type" = c("PCR Positive Control", 
                     "Reverse Transcription Control", 
                     "No Template Control", 
                     "Genomic Contamination Control"),
  
  "Purpose" = c("To test if your PCR reactions worked",
                "To test if your RT reactions worked", 
                "Checks for RNA Contamination",
                "Checks for DNA Contamination"),
  
  "Pass Criteria" = c("Ct < High Ct Cutoff",
                      "Ct < High Ct Cutoff",
                      "Ct > High Ct Cutoff or No Ct",
                      "Ct > High Ct Cutoff or No Ct"),
  
  "Result" = c(fullTable |> select(all_of(input$sPP)),
               "NA") 
)

})

output$RTable <- renderTable({
RTable()
})

detailTable <- reactive({
tibble(
"Sample ID" = c("NA"),
"Gene Name" = c("NA"),
"Ct" = c("NA"))

})

output$FPPCTable <- renderTable({
detailTable()
})

}

shinyApp(ui = ui, server = server)

metaFile:

It didn't let me attach more than one media type as I am a new user, so here's how one of the 26 dataFiles look like:

I truly believe I could explain my concerns better via a zoom/teams call, and I can share my screen which will allow you to see the entire code, and how changes occur when I upload the files (metaFile, dataFiles) from my side. I am in EST, and am quite flexible with dates/timings.

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.