Shiny Dashboards
shinydashboard

Colin Rundel

shinydashboard

is a package that enables the easy generation of bootstrap based dynamic Shiny dashboards.

The core of the package is a common dashboard layout and a number of specialized UI elements (static and reactive) for creating an attractive interface.

Dashboard basics

library(shiny)
library(shinydashboard)

shinyApp(
  ui = dashboardPage(
    dashboardHeader(
      title="shinydashboard"
    ),
    dashboardSidebar(),
    dashboardBody()
  ),
  server = function(input, output, session) {
  }
)

Dashboard header

This is a container for the title and any dropdownMenu()s

  • the latter are somewhat limited, support “messages”, “notifications”, “tasks” types

  • Dynamic menus can be generated using dropdownMenuOutput() and renderMenu() in the ui and server respectively.

Messages:

Notifications:

Tasks:

Dashboard sidebar

This functions in the same way as the sidebarPanel() in sidebarLayout(), allowing for the inclusion of inputs and any other html content.

Alternatively, it can also function as a tabPanel() like menu.

  • instead of tabsetPanel() we use sidebarMenu(),

  • text and icons are assigned using menuItem()

  • the panels being activated are contained in the body and not the sidebar

    • their UI code goes under dashboardBody() using tabItems() and tabItem().

    • menuItem()s are connected to tabItems() via matching the tabName arguments.

Demo 07-1 - sidebarMenu()

demos/demo07-1.R

library(tidyverse)
library(shiny)
library(shinydashboard)

ggplot2::theme_set(ggplot2::theme_bw())

d = readr::read_csv(here::here("data/weather.csv"))

d_vars = d |>
  select(where(is.numeric)) |>
  names()

shinyApp(
  ui = dashboardPage(
    dashboardHeader(
      title="shinydashboard"
    ),
    dashboardSidebar(
      selectInput(
        "city", "Select a city",
        choices = c("Chicago", "Durham", "Sedona", "New York", "Los Angeles")
      ),
      selectInput(
        "var", "Select a variable",
        choices = d_vars, selected = "humidity"
      ),
      sidebarMenu(
        menuItem(
          "Temperature", 
          tabName = "temp", 
          icon = icon("thermometer-half")
        ),
        menuItem(
          "Other", 
          tabName = "other"
        )
      )
    ),
    dashboardBody(
      tabItems(
        tabItem(
          "temp", 
          plotOutput("plot_temp")
        ),
        tabItem(
          "other", 
          plotOutput("plot_other")
        )
      )
    )
  ),
  server = function(input, output, session) {
    d_city = reactive({
      d |>
        filter(city %in% input$city)
    })
    
    output$plot_temp = renderPlot({
      d_city() |>
        ggplot(aes(x=time, y=temp)) +
        ggtitle("Temperature") +
        geom_line()
    })
    
    output$plot_other = renderPlot({
      d_city() |>
        ggplot(aes(x=time, y=.data[[input$var]])) +
        ggtitle(input$var) +
        geom_line()
    })
  }
)

Demo 07-2 - Dynamic sidebarMenu()

demos/demo07-2.R

library(tidyverse)
library(shiny)
library(shinydashboard)

ggplot2::theme_set(ggplot2::theme_bw())

d = readr::read_csv(here::here("data/weather.csv"))

d_vars = d |>
  select(where(is.numeric)) |>
  names()

shinyApp(
  ui = dashboardPage(
    dashboardHeader(
      title="shinydashboard"
    ),
    dashboardSidebar(
      selectInput(
        "city", "Select a city",
        choices = c("Chicago", "Durham", "Sedona", "New York", "Los Angeles")
      ),
      selectInput(
        "var", "Select a variable",
        choices = d_vars, selected = "humidity"
      ),
      sidebarMenuOutput("menu")
    ),
    dashboardBody(
      tabItems(
        tabItem(
          "temp", 
          plotOutput("plot_temp")
        ),
        tabItem(
          "other", 
          plotOutput("plot_other")
        )
      )
    )
  ),
  server = function(input, output, session) {
    output$menu = renderMenu(
      sidebarMenu(
        menuItem("Temperature", tabName = "temp", icon = icon("thermometer-half")),
        menuItem(input$var, tabName = "other")
      )
    )
    
    d_city = reactive({
      d |>
        filter(city %in% input$city)
    })
    
    output$plot_temp = renderPlot({
      d_city() |>
        ggplot(aes(x=time, y=temp)) +
        ggtitle("Temperature") +
        geom_line()
    })
    
    output$plot_other = renderPlot({
      d_city() |>
        ggplot(aes(x=time, y=.data[[input$var]])) +
        ggtitle(input$var) +
        geom_line()
    })
  }
)

Body building blocks

box()

infoBox()


valueBox()

Colors

The color of the various boxes is specified via status or background for box() or color for the others.

Available options include,

shinydashboard:::validStatuses
[1] "primary" "success" "info"    "warning" "danger" 


shinydashboard:::validColors
 [1] "red"        "yellow"     "aqua"       "blue"       "light-blue"
 [6] "green"      "navy"       "teal"       "olive"      "lime"      
[11] "orange"     "fuchsia"    "purple"     "maroon"     "black"     

Body layout

The layout of box elements on a dashboard is controlled by combining fluidRow() and column() (as is standard with regular shiny apps)

  • this layout is based on a page having width of 12 units

  • column() and box() elements take a width argument using these units

Row-based layout

dashboardBody(
  fluidRow(
    box(title = "Box title", ...),
    box(...)
  ),

  fluidRow(
    box(title = "Title 1", ...),
    box(title = "Title 2", ...),
    box(title = "Title 3", ...)
  ),

  fluidRow(
    box(...),
    box(title = "Title 5", ...),
    box(title = "Title 6", ...)
  )
)

Column-based layout

dashboardBody(
  fluidRow(
    column(width = 4,
      box(title = "Box title", ...),
      box(title = "Title 1", ...),
      box(...)
    ),
    column(width = 4,
      box(...),
      box(title = "Title 3", ...),
      box(title = "Title 5", ...)
    ),
    column(width = 4,
      box(title = "Title 2", ...),
      box(title = "Title 6", ...)
    )
  )
)

Mixed layout

dashboardBody(
  fluidRow(
    box(title = "Box title", ...),
    box(...)
  ),
  fluidRow(
    column(width = 4,
      box(title = "Title 1", ...),
      box(...)
    ),
    column(width = 4,
      box(title = "Title 3", ...),
      box(title = "Title 5", ...)
    ),
    column(width = 4,
      box(title = "Title 2", ...),
      box(title = "Title 6", ...)
    )
  )
)

Your turn - Exercise 06

Starting with the app from Demo 05 convert the app to use shinydashboard instead of flexdashboard - we have provided some basic scaffolding shinydashboard code in exercises/ex06.R and the demo code in exercises/ex06.Rmd.

Try to preserve the column-based layout and general proportions (i.e. column widths) of the original.

Since shinydashboard does not have a gauge element you can use a value box for everything - If you’re feeling adventurous try using a flexdashboard gauge in your shinydashboard, what happens?

10:00