0

I am trying to create a dynamic UI that has variable number of user inputs based on a user input and charts that uses that second level of user input.

A working example below:

library(shiny)


ui <- fluidPage(

titlePanel("Old Faithful Geyser Data"),
    numericInput(inputId = "Chartcount",
        label = "Enter number of charts",
        value = 5,
        min = 2,
        max = 8),
       uiOutput("distui")
    )


server <- function(input, output) {

c_count = reactive({input$Chartcount})
output$distui <- renderUI({
    lapply(seq(1:c_count()), function(x){ 
    chartId = (paste("Chart",x, sep = "="))
    sinput <- sliderInput(inputId = paste(x,"_bins"),
                    "Number of bins:",
                    min = 1,
                    max = 50,
                    value = 30)
    
    
    selectedbins = input[[paste(x,"_bins")]] # input$inputId does not work here as expression after $ can not be evaluated
    
    x    <- faithful[, 2]
    bins <- seq(min(x), max(x), length.out = 25 ) #I want to use selectedbins here for length.out

    distplot <- renderPlot(hist(x, breaks = bins, col = 'darkgray', border = 'white'))
    list(chartId, sinput,selectedbins, distplot)
    
    })
})

}

shinyApp(ui = ui, server = server)

I think there are at least a couple of problems with this.

  1. Selected number of bins resets as soon as they are selected

  2. I get an error when I try to use selectedbins in the chart for length.out

    bins <- seq(min(x), max(x), length.out = selectedbins ) # This throws an error Error: argument 'length.out' must be of length 1

1 Answer 1

2

The selected number of bins is resetting because it is inside of the same reactive expression, you should put it in a different reactive expression, otherwise the full expression is going to be executed every time you change the input and it is going to recreate all the inputs and plots.

The second problem is caused because you are trying to use the selectedbins input value before the slider is created, therefore the value is NULL (length 0), you can only get the value after the slider is created.

Below is your code modified to create the plots in a separated reactive expression as a nested expression, maybe not the best solution but it is in the same style that your program. Also, reusing the x variable is confusing, so I changed the first one by k.

library(shiny)

ui <- fluidPage(
  titlePanel("Old Faithful Geyser Data"),
  numericInput(inputId = "Chartcount",
               label = "Enter number of charts",
               value = 5,
               min = 2,
               max = 8),
  uiOutput("distui")
)

server <- function(input, output) {
  
  output$distui <- renderUI({
    lapply(seq(1:input$Chartcount), function(k){ 
      chartId = (paste("Chart", k, sep = "="))
      sinput <- sliderInput(inputId = paste(k, "bins_"),
                            "Number of bins:",
                            min = 1,
                            max = 50,
                            value = 30)
      x <- faithful[, 2]
     
      distplot <- tagList(
        renderUI({
          selectedbins = input[[paste(k, "bins_")]]
          bins <- seq(min(x), max(x), length.out = selectedbins )
          tagList(
            selectedbins,
            renderPlot(hist(x, breaks = bins, col = 'darkgray', border = 'white'))
          )
        })
      )
      
      list(chartId, sinput, distplot)
      
    })
  })
}

shinyApp(ui = ui, server = server)
Sign up to request clarification or add additional context in comments.

2 Comments

This solution works as I needed. I am new to shiny, so yes I believe its not the best way to do what I am doing. can you recommend a better way or some link where I can learn better ways?
Look at this for useful Shiny tips.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.