0
votes

Trying to program a shiny app layout including rows and columns for inputs. Built in functions are best for simple column format. So far managed to nest a load of fluidRows to get the output in the sample code below.

Nesting fluidRow: R Shiny - how to generate this layout with nested rows in column 2

shiny 4 small textInput boxes side-by-side

Here is a subset of my code:

ui <- fluidPage(
  h1("XXX"), #Main page title
  fluidRow(
    column(3,
           wellPanel(
             sliderInput(inputId = "time.step",
                         label = "Time",
                         value = 100, min = 0, max = 1000),
             numericInput(inputId = "no_",
                          label = "choose number",
                          value = 8, min = 1, max = 10),
             checkboxGroupInput(inputId = "chr_vec",
                                label = "characters",
                                choices = c("a", "b", "c", "d", "e", "f",
                                            "g", "h", "i", "j", "k"),
                                selected = c("a", "b")
             ), #close checkboxGroupInput
             actionButton("runbutton", "Run")
           ) #close wellPanel
    ), #close column
    #### Parameters ####
    column(8,
           fluidRow(

             conditionalPanel(
               condition = "input.chr_vec.indexOf('a') !== -1",

                    column(12,
           splitLayout("Parameters",
                     numericInput(inputId = "1.numeric.flip.time",
                                  label = "1",
                                  value = 50, min = 0, max = 1000),

                     numericInput(inputId = "2.numeric.start.val",
                                  label = "2",
                                  value = 99, min = 0, max = 1000),

                     numericInput(inputId = "3.numeric.end.val",
                                  label = "3",
                                  value = 100, min = 0, max = 1000),

                     numericInput(inputId = "sd.numeric.stdev",
                                  label = "SD",
                                  value = 0, min = 0, max = 1000)
           ) #close splitLayout
                    ) #close column
             ) #close conditionslPanel
           ), #close fluidRow


           fluidRow(
             conditionalPanel(
               condition = "input.chr_vec.indexOf('b') !== -1",
             column(12,
                    splitLayout("Parameters2",
                                numericInput(inputId = "5.numeric.flip.time",
                                             label = "5",
                                             value = 50, min = 0, max = 1000),

                                numericInput(inputId = "6.numeric.start.val",
                                             label = "6",
                                             value = 99, min = 0, max = 1000)

                    ) #close splitLayout
             ) #cose column
             ) #close conditionalPanel
           ) # close fluidRow

    ) #close column
  )
)
shinyApp(ui, server = function(input, output) { })

Things I'm trying to solve:

1) The title 'parameters' is floating oddly like a input field taking up room.

2) in the real code there are roughly a dozen rows of parameters (one row per checkbox on the left), things get real messy especially when the number of rows extends beyond the check input column (aiming for something like the image below).

3) scale and justification - would help a lot if I could scale the font and input fields of the rows of parameters down a little and ideally justify the input fields left rather than centre so they line up nicely (tried this so far: Control the height in fluidRow in R shiny).

Desired layout

Finding some potential solutions using languages I'm not familiar with (CSS) so a little explanation would be very much appreciated :) Thanks in advance!

1

1 Answers

1
votes

CSS is the way to go here, you can do a lot in very few lines of CSS. See https://shiny.rstudio.com/articles/css.html for more information on integrating CSS in R.

In the course of writing this answer I found I could simplify some of your R code. Hierarchy-wise, I'm now just using a conditionalPanel wrapping a fluidRow. I also had to write a simple for loop to generate enough rows to check the overflow problem for 2). Updated R code here:

library(shiny)

choices <- c("a", "b", "c", "d", "e", "f",
             "g", "h", "i", "j", "k")


rows <- list(8)
for (choice in choices) {
  print(choice)
  row <- conditionalPanel(
    condition = paste0("input.chr_vec.indexOf('", choice, "') !== -1"),
    fluidRow(
      span(paste0("Parameters (", choice, ")")),
      numericInput(
        inputId = "1.numeric.flip.time",
        label = "1",
        value = 50,
        min = 0,
        max = 1000
      ),

      numericInput(
        inputId = "2.numeric.start.val",
        label = "2",
        value = 99,
        min = 0,
        max = 1000
      ),

      numericInput(
        inputId = "3.numeric.end.val",
        label = "3",
        value = 100,
        min = 0,
        max = 1000
      ),

      numericInput(
        inputId = "sd.numeric.stdev",
        label = "SD",
        value = 0,
        min = 0,
        max = 1000
      )
    )
  )
  rows <- append(rows, list(row))
}

ui <- fluidPage(theme = "custom.css",
                h1("XXX"), #Main page title
                fluidRow(
                  column(
                    3,
                    wellPanel(
                      sliderInput(
                        inputId = "time.step",
                        label = "Time",
                        value = 100,
                        min = 0,
                        max = 1000
                      ),
                      numericInput(
                        inputId = "no_",
                        label = "choose number",
                        value = 8,
                        min = 1,
                        max = 10
                      ),
                      checkboxGroupInput(
                        inputId = "chr_vec",
                        label = "characters",
                        choices = choices,
                        selected = c("a", "b")
                      ),
                      #close checkboxGroupInput
                      actionButton("runbutton", "Run")
                    ) #close wellPanel
                  ),
                  #close column
                  #### Parameters ####
                  do.call(column, rows)
                ))
shinyApp(
  ui,
  server = function(input, output) {

  }
)

I added theme = "custom.css", to your fluidPage call, and created www/custom.css with the below content:

.col-sm-8 .row .form-group,.form-control {
  display: inline-block;
  width: 100px;
}

.col-sm-8 .row span {
  width: 150px;
  display: inline-block;
}

.col-sm-8 .row .form-group,.form-control is a CSS selector that selects your numeric inputs, those that are in the column of width 8. You can find these class names / HTML structure by right clicking on a running version of your app and going Inspect. The contents of the curly brackets {} define the styling of the selected elements. Setting display to inline-block will cause the blocks to flow horizontally. Setting the width to 100px shrinks the size of your numeric inputs considerably (default is 300px). Swapping the .form-group,.form-control selectors for span will select the row heading. I set this to 150px as that gives enough space for the string "Parameters (a)".

I've deployed this to https://nyou045.shinyapps.io/test/ so you can see a live demo

Hope that helps!