0

I want to create a dynamic UI in my shiny app where the column widths of various panels can be specified by the user. Is it possible to render the column width in the server and pass it to the UI as an output or does the width need to be hardcoded in the UI?

mosk915
  • 696
  • 1
  • 7
  • 16
  • Checkout `uiOutput()`. Very easily done with that function. – Adam Birenbaum Apr 25 '18 at 02:48
  • I was trying that but I couldn’t get it to work. In the server I had output$width <- renderUI(...) and in the ui I had column(width = uiOutput(‘width’) ...). I’m not sure what I’m doing wrong. – mosk915 Apr 25 '18 at 02:52
  • 1
    As is often the case on SO, talking about code in generalities is very difficult. Please post the relevant code into your question. – r2evans Apr 25 '18 at 04:29
  • See [here](https://stackoverflow.com/questions/48343080/how-to-convert-a-shiny-app-consisting-of-multiple-files-into-an-easily-shareable) for tips on how to create a reproducible Shiny example. – Florian Apr 25 '18 at 09:22

1 Answers1

1

Here's a single file script that lets the user choose the size of two panels. There were two challenges that I didn't see at first, and probably could have been handled in a cleaner way. They are:

  1. The user defined widths input box is within the panel whose width is defined by that input. Basically a chicken vs. the egg situation. You need to have some method of setting the width of the panels to some initial value when first run. I did it within that ifelse(...) function.
  2. If one panel's width is changed to be more than 6, then the other needs to shrink so that the sum is not greater than 12.

    old_panel_width1 <<- 6
    old_panel_width2 <<- 6
    
    
    ui <- bootstrapPage(
      uiOutput("dynamic_panels")
    
     )
    
    server <- function(input, output) {
    
     n1 <- reactive(input$n1)
     n2 <- reactive(input$n2)
    
     output$dynamic_panels <- renderUI({
    
    #assigns an initial value of 6 when first loaded
    panel_width1 <<- ifelse(is.null(input$n1), 6, n1())
    panel_width2 <<- ifelse(is.null(input$n2), 6, n2())
    
    #one way of detecting whether panel 1 or 2 was changed and then adjusting the sizes so that the sum < 12
    if (panel_width1!= old_panel_width1){
      if (panel_width1 > 6 && sum(panel_width1,panel_width2) > 12) panel_width2 <<- 12 - panel_width1
      old_panel_width1 <<- panel_width1
    }
    
    if (panel_width2!= old_panel_width2){
      if (panel_width2 > 6 && sum(panel_width1,panel_width2) > 12) panel_width1 <<- 12 - panel_width2
      old_panel_width2 <<- panel_width2
    }
    
    
    
    fluidRow(
    column(width = panel_width1,
           numericInput('n1', 'size of panel 1', min = 1, max = 11,value = panel_width1),
           plotOutput("plot1")
           ),
    column(width = panel_width2,
           numericInput('n2', 'size of panel 2',min = 1, max = 11,value = panel_width2),
           plotOutput("plot2")
           )
     )
    
    })
    
    output$plot1 <- renderPlot(hist(runif(100)))
    output$plot2 <- renderPlot(hist(runif(100)))
    
    }
    
    # Return a Shiny app object
    shinyApp(ui = ui,server = server)
    
Adam Birenbaum
  • 940
  • 9
  • 23