Building a shiny app

SISBID 2026
https://github.com/dicook/SISBID

Shiny Apps in R

  • shiny package developed and supported by RStudio (Winston Chang, Joe Cheng, JJ Allaire and others)
  • Resources for shiny: https://shiny.rstudio.com/:

Are these notes genuine?

Swiss banknote data (Flury, B. and Riedwyl, H. 1988): measurements on 100 genuine and 100 counterfeit old-Swiss 1000-franc bank notes

Status: genuine or counterfeit

Can we classify the status visually?

Visual classification

banknote <- readr::read_csv(here::here("data/banknote.csv"))

banknote |> 
  ggplot(aes(x = Right, fill = Status)) + 
  geom_histogram(binwidth = .1)

Counterfeits have on average a wider right edge. What about the other measurements?

A first shiny app with ggpaintr

Make a shiny app to explore histograms:

{banknote |> 
  ggplot(aes(x = ppVar(Right), fill = Status)) + 
  geom_histogram(binwidth = .1) } |> ggpaintr::ptr_app()

ggpaintr keywords: ppVar (make a variable widget), ppNum (make a number widget)

check the Addins > ggpaintr placeholders

You do it

  1. Run the ggpaintr code in your session.

  2. Determine: which measurement does distinguishes the best between counterfeits and genuine banknotes

  3. Rewrite the expression to show a scatterplot of two measurements. Don’t forget to make the y-axis interactive as well!

  4. Which combination of variables allows a perfect distinction?

How does the magic work?

Create your second app

  • In RStudio, File menu, New file, Shiny web app to start a new app
  • The easiest start is the Single file, which will put both server and ui functions in the same file, app.R
  • Make sure to change the number of bins!

A gif showing how to create a new Shiny web app, using the instructions above

Two main parts

  • What we see and interact with:
    • user interface: layout with user input and (plot) output
  • What is going on underneath:
    • the server: glue between user input and output

A Minimal Example

library(shiny)

ui <- fluidPage(
)

server <- function(input, output, session) {
}

shinyApp(ui, server)

A bit more fancy

library(shiny)
sidebar <-  sidebarPanel(width = 3, "Fun inputs")

main_col <- column(width = 9, "Some results")

ui <- fluidPage(
  title = "App Title",
  sidebar, 
  main_col
)

server <- function(input, output, session) {
}

shinyApp(ui, server)

A bit more fancy

library(shiny)
sidebar <-  sidebarPanel(
  width = 3, 
  textInput("name", "Enter your name:", value = "Susan")
)

main_col <- column(width = 9, "Some results")

ui <- fluidPage(
  title = "App Title",
  sidebar, 
  main_col
)

server <- function(input, output, session) {
}

shinyApp(ui, server)

Shiny Inputs

Shiny has many different input options, see the widget gallery:

  • actionButton() - creates a clickable button
  • selectInput() create a select list
  • checkboxInput() and checkboxGroupInput()
  • dateInput() - calendar to select a date
  • dateRangeInput() - select a range of dates
  • fileInput() - upload a file
  • numericInput() - input a numeric value
  • radioButtons() - select one or more items
  • sliderInput() - slide along a range of values
  • textInput() - input a string

Your Turn

Add a list of your favorite countries to the sidebar panel:

library(shiny)

sidebar <-  sidebarPanel(
  width = 3, 
  textInput("name", "Enter your name:", value = "Susan")
)

main_col <- column(width = 9, "Some results")

ui <- fluidPage(
  title = "App Title",
  sidebar, 
  main_col
)

server <- function(input, output, session) {
}

shinyApp(ui, server)

Adding Output

  • Output needs to be specified in two places:
    • in the ui function we need to create a placeholder to reserve space for the output
    • in the server function, we need to create the output.
  1. ui components are usually xxxOutput (outputID)
    Output can be in form of tables, plots, text, …

  2. server components are renderXXX, where xxx is a table, plot, text, etc.

Shiny Outputs

Shiny also has a variety of different output options:

  • renderDataTable() - outputs an interactive, sortable data table
  • htmlOutput() - output html elements
  • renderPlot() - output an R plot
  • renderPrint() - output text from print() in R
  • renderTable() - output an HTML table
  • renderText() - output text from R
  • renderUI() - output a custom part of the user interface
  • renderImage() - print an image to the page

Adding a plot

library(shiny)
library(ggplot2)
library(dplyr)

sidebar <-  sidebarPanel(
  width = 3, 
  selectInput(
    "country", "Pick your favorite country:", 
              choices = c("Australia", "Brazil", "China")
  )
)

main_col <- column(                               #<<
  width = 9,                                      #<<
  plotOutput("scatter")                           #<<
)                                                 #<<

ui <- fluidPage(
  title = "App Title", sidebar, main_col
)

server <- function(input, output, session) {
  output$scatter <- renderPlot({                  #<<
    mtcars %>% ggplot(aes(x = disp, y = mpg)) +   #<<
      geom_point() +                              #<<
      ggtitle(input$country)                      #<<
  })                                              #<<
}

shinyApp(ui, server)

Your turn

  • Add an interactive plot of the TB data into your app.
  • Change the select box, so that the user can choose any country. Think of unique(tb$country) for defining the choices

Deploy an app

  • Sign up for an account on https://www.shinyapps.io/
  • Authenticate your account
  • You may need to do some setup in your session, e.g. install the library rsconnect

Resources