3
votes

My Shiny App has multiple inputs that depend on the number of variables used. A simplified version, though not working, is below. I was able to get the UI to update based upon the numericInput using a function called Make.UI which I used to make uiOutput, but getting the inputs back into the server is beyond my Shiny skill set! Any suggestions would be greatly appreciated.

gwynn

library(shiny)
D = matrix(runif(400), nrow = 20)
colnames(D) = labs = sapply(1:20, function(i) {paste0("col",i)})

# Define UI for application that summarises data
ui <- fluidPage(

  # Application title
  titlePanel("Summaries"),

  # Select columns to get fed into summary 
  tabsetPanel(
    tabPanel("Matching Variables Info",
             sidebarPanel(

               numericInput("NoVars","No. of variables to summarize", 
                            value = 3, min = 2, max = dim(D)[2]),

               uiOutput("VarsInput")
             ),

             # Show summaries of columns choosen above
             mainPanel(
               verbatimTextOutput("dataInfo")
             )
    )
  )
)


# Define the server code
server <- function(input, output){

  Make.UI <- function(NoV){
    C = sapply(1:NoV, function(i){paste0("cols",i)})
    L = sapply(1:NoV, function(i){paste0("label",i)})

    output = tagList()

    for(i in seq_along(1:NoV)){
      output[[i]] = tagList()
      output[[i]][[1]] = selectInput(C[i], "Variable to summarize:", labs)
      output[[i]][[2]] = textInput(L[i], label = "Label for variable:", 
                                   value = "Label for variable Here")
    } ## for loop

    output
  } # closes Make.UI function

  K <- reactive({
    input$NoVars
  })

  output$VarsInput <- renderUI({
    Make.UI(K())
  })

  output$dataInfo <- renderPrint({
    C <- sapply(1:K(), function(i) {input[[paste0("cols",i)]]})
    ## the code in the line above doesn't work

    summary(D[, C()])
  })

}

# Return a Shiny app object
shinyApp(ui = ui, server = server)
1
Are you sure you can define Make.UI() outside your server function. It does not have the output variable available does it? You would have to use shiny module for that. Moreover, if you want to return mutliple inputs from a renderUI you should use a tagList(). To your final question on how to use the renderUI generated input, is simply by the id you assign them within the server. Should work as soon as you talk the remarks above into account.Tonio Liebrand
@BigDataScientist I've never used tagList() before. Do you know of any examples that are similar to this? I've used functions defined globally in Shiny before and not had any problems, but perhaps this is different.nzgwynn
Ah I see, your output is not the shiny output but you define it yourself, seems like I was a bit tired. Well then I would try to use output=tagList() instead. By the way the code is not completely reproducible, because u didnt provide what l.colsis. Therefore, I answer in a more generic way. Hope it helps anyway.Tonio Liebrand
@BigDataScientist OOOpps!! I've updated it now, l.cols = dim(D)[2]. I was thinking this morning that your suggestion seemed to be to put Make.UI into the server and then have output = tagList() instead of output = list() and then it would run. I'll try that later today and fingers crossed it works! If it doesn't I'll let you know.nzgwynn
@BigDataScientist I still get this error (argument "object" is missing, with no default) when trying to run the coding. No clue what's wrong. Any help would be really appreciated.nzgwynn

1 Answers

7
votes

Like I wrote in the first comment, I am unsure about the Make.UI()function. If you really want to keep it as a seperate function you should make it reactive. Or just use it as I did in the code below. Moreover, in output$dataInfo <- renderPrint({ C is not a reactive() function so you would need to remove brackets there.

library(shiny)
D = matrix(runif(400), nrow = 20)
colnames(D) = labs = sapply(1:20, function(i) {paste0("col",i)})

# Define UI for application that summarises data
ui <- fluidPage(

  # Application title
  titlePanel("Summaries"),

  # Select columns to get fed into summary 
  tabsetPanel(
    tabPanel("Matching Variables Info",
             sidebarPanel(

               numericInput("NoVars","No. of variables to summarize", 
                            value = 3, min = 2, max = dim(D)[2]),

               uiOutput("VarsInput")
             ),

             # Show summaries of columns choosen above
             mainPanel(
               verbatimTextOutput("dataInfo")
             )
    )
  )
)


# Define the server code
server <- function(input, output){

  K <- reactive({
    input$NoVars
  })

  output$VarsInput <- renderUI({
    NoV = K()
    C = sapply(1:NoV, function(i){paste0("cols",i)})
    L = sapply(1:NoV, function(i){paste0("label",i)})

    output = tagList()

    for(i in seq_along(1:NoV)){
      output[[i]] = tagList()
      output[[i]][[1]] = selectInput(C[i], "Variable to summarize:", labs)
      output[[i]][[2]] = textInput(L[i], label = "Label for variable:", 
                                   value = "Label for variable Here")
    } ## for loop

    output
  })

  output$dataInfo <- renderPrint({
    C <- sapply(1:K(), function(i) {input[[paste0("cols",i)]]})
    ## the code in the line above doesn't work

    summary(D[, C])
  })

}

# Return a Shiny app object
shinyApp(ui = ui, server = server)