1

I am trying to create a shiny user interface with a dynamic reactive UI.

Essentially a user has to input the number of variants for an experiment (1-10).

For each variant the user is required to enter the variant name in a textbox and also a proportion 1 - 100 to allocate to each variant. The sum of proportions across all variants should add to 100.

e.g. User selects 5 variants. Then for each variant 1-5 the user should get dropdowns to select proportions.

  • Variant 1 proportion (1-100), user selects 40 say
  • Variant 2 proportion (1-60), user selects 10 say
  • Variant 3 proportion (1-50), user selects 35 say
  • Variant 4 proportion (1-15), user selects 10 say
  • Variant 5 proportion (5), user has no say in allocating this - the proportion is backed out as 100 - (v1 + v2 + v3 + v4) = 5

I have borrowed code from here to start this: Producing dynamic/multiple input boxes to collect data depending on user selection in Shiny R

ui.R

library(shiny)

shinyUI(pageWithSidebar (

  headerPanel( "Portfolio Returns"),

  sidebarPanel(
    numericInput("assets", label = "Enter Number of variants in Experiment", value="1"),
    uiOutput("variants")
  ),
  mainPanel()
))

Server.R

library(shiny)

shinyServer( function(input, output, session) {

  output$variants <- renderUI({
    numAssets <- as.integer(input$assets)

    lapply(1:numAssets, function(i) {
      list(tags$p(tags$u(h4(paste0("Variant ", i, ":")))),
           textInput(paste0("variant", i), label = "Variant Name", value = paste0("Variant ", i, " name..."))
           , numericInput(paste0("weight", i)
                          , label = "Proportion allocated (0 - 100)", value=0))
    })
  })
})

Could anyone please assist with the above?

1 Answer 1

3

I believe that the solution is to have the final numeric input mimic a numeric input, but actually just be a calculated output. Instead of creating as many numeric inputs as numAssets, create 1 less. Then create another output that looks like the rest, but whose value is calculated rather than entered. The code below does that, generally speaking, but does not do a good job of mimicking the appearance of the other numeric inputs. This code can also be pulled from github.

ui.R

library(shiny)
shinyUI(pageWithSidebar (
  headerPanel( "Portfolio Returns"),
  sidebarPanel(
    numericInput("assets", label = "Enter Number of variants in Experiment", value="3")
  ),
  mainPanel(
    uiOutput("variants"),
    uiOutput("lastVariant"))
))

server.R

library(shiny)
shinyServer( function(input, output, session) {
  output$variants <- renderUI({
    numAssets <- as.integer(input$assets)  
      lapply(1:(numAssets-1), function(i) {
        list(tags$p(tags$u(h4(paste0("Variant ", i, ":")))),
             textInput(paste0("variant", i), label = "Variant Name", value = paste0("Variant ", i, " name..."))
             , numericInput(paste0("weight", i)
                            , label = "Proportion allocated (0 - 100)", value=0)
        )
      }) #end of lapply
  }) # end of renderUI
  
  output$lastVariant <- renderUI({
    numAssets <- as.integer(input$assets)
    for (j in 1:(numAssets-1)){
      if(j==1){x=100}
      x = x - input[[paste0("weight",j)]]
    }
    tagList(
      tags$p(tags$u(h4(paste0("Variant ", numAssets, ":")))),
      textInput(paste0("variantFinal"), label = "Variant Name", value = paste0("Variant ", numAssets, " name...")), 
      tags$p(tags$b("Proportion allocated (0 - 100)")),
      helpText(paste0(x))
    ) #end of tagList
  }) #end of renderUI
}) #end of shinyServer
Sign up to request clarification or add additional context in comments.

4 Comments

Great answer! Marked as accepted. Two (hopefully) small follow up questions:
Paul is there a way to make the proportion selected a dropdown of 0-100 rather than as textInput?
Sure. instead of numericInput, use selectInput, and set the choices to c(0:100). Then you'll have to use as.as.integer on the returned value (since it will return characters). shiny.rstudio.com/reference/shiny/latest/selectInput.html shiny.rstudio.com/gallery/widget-gallery.html
Thanks again Paul - appreciate it.

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.