1  Your first shiny app

1.1 Introduction

Objectives for Chapter 01

1.2 Create app directory and file

There are several ways to create a Shiny app. I am using the following procedure:

Procedure 1.1 : My preferred procedure to create a Shiny app

  1. In RStudio choose File | New File > Shiny Web App…
  2. In the window fill in the application name.
  3. This will create the directory with the file app.R in the directory. Additionally it will open app.R with a boiler template.
  4. Delete the boiler template, e.g. the whole content of the app.R file.
  5. Type sh1 followed by Shift TAB for my own boiler template1 with the following content:
My boiler template
library(shiny)

ui <- fluidPage(
  
)

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

}

shinyApp(ui, server)

See the help documentation for creating Code Snippets in the RStudio IDE.

Putting “Hello World” into the shiny::fluidPage() function results in the most basic example:

Code Collection 1.1 : Most basic {shiny} example

R Code 1.1 : Most basic {shiny} example

Minimum {shiny} example
library(shiny)
ui <- fluidPage(
  "Hello, world!"
)

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

    }

shinyApp(ui, server)

  1. It calls library(shiny) to load the shiny package.
  2. It defines the user interface, the HTML webpage that humans interact with. In this case, it’s a page containing the words “Hello, world!”.
  3. It specifies the behaviour of our app by defining a server function. It’s currently empty, so our app doesn’t do anything, but we’ll be back to revisit this shortly.
  4. It executes shinyApp(ui, server) to construct and start a Shiny application from UI and server.

1.3 Running and stopping

There are a few ways to run the app:

  • Click the Run App button in the document toolbar.
  • Use the keyboard shortcut on macOS: Cmd + Shift + Enter.

By choosing one of the options under the Run Appbutton you can specify if you want the results presented

  • in an extra browser window (shortcut: Alt + Shift + W)
  • in the RStudio viewer pane (shortcut: Alt + Shift + V) or
  • run external in your default browser (shortcut: Alt + Shift + E).

In the console I found the

Listening on http://127.0.0.1:5959

This tells me the URL where your app can be found: 127.0.0.1 is a standard address that means “this computer” and 5959 is a randomly assigned port number. Entering that URL into any compatible web browser opens another copy of the Shiny app.

The red stop sign in the top right console window means that R is busy. I have to stop the app before I can write commands in the console. There are several options to stop the server:

  • Click on the stop sign
  • Click in the console and type ESC
  • Close the Shiny app window(s)
Note

To speed up the development process you don’t need to stop and restart the server to see the changes. When the server is running the button Run app changes to Reload app. Click on it or use the Cmd + Shift + Enter keyboard shortcut to reload the (changed) app.

1.4 Adding UI controls

Replace your ui with this code:

Code Collection 1.2 : Add UI controls

R Code 1.3 : Add UI controls

Code
library(shiny)

ui <- fluidPage(
  selectInput("dataset", label = "Dataset", choices = ls("package:datasets")),
  verbatimTextOutput("summary"),
  tableOutput("table")
)

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

}

shinyApp(ui, server)

This example uses four new functions:

  1. shiny::fluidPage() is a layout function that sets up the basic visual structure of the page. (See Section 6.2)
  2. shiny::selectInput() is an input control that lets the user interact with the app by providing a value. In this case, it’s a select box with the label “Dataset” and lets you choose one of the built-in datasets that come with R. (See Section 2.2)
  3. shiny::verbatimTextOutput() is an output control that tell Shiny where to put rendered output, in this case where to display code.
  4. shiny::tableOutput() is another output controls that displays tables. (For output controls see Section 2.3)
Note

Layout functions, inputs, and outputs have different uses, but they are fundamentally the same under the covers: they’re all just fancy ways to generate HTML, and if you call any of them outside of a Shiny app, you’ll see HTML printed out at the console.

For instance:

> shiny::tableOutput("table") # results into:
<div id="table" class="shiny-html-output"></div>

Running the app again we’ll see a page containing a select box. We only see the input, not the two outputs, because we haven’t yet told Shiny how the input and outputs are related.

1.5 Adding behaviour

Shiny uses reactive programming to make apps interactive. (More about reactive programming in Chapter 3.) For now, just be aware that it involves telling Shiny how to perform a computation, not ordering Shiny to actually go do it.

We’ll tell Shiny how to fill in the summary and table outputs in the sample app by providing the “recipes” for those outputs. Replace your empty server function the folowing code:

Code Collection 1.3 : Add behaviour

R Code 1.5 : Add behaviour

Code
library(shiny)

ui <- fluidPage(
  selectInput("dataset", label = "Dataset", choices = ls("package:datasets")),
  verbatimTextOutput("summary"),
  tableOutput("table")
)

server <- function(input, output, session) {
  output$summary <- renderPrint({
    dataset <- get(input$dataset, "package:datasets")
    summary(dataset)
  })
  
  output$table <- renderTable({
    dataset <- get(input$dataset, "package:datasets")
    dataset
  })
}

shinyApp(ui, server)

  • The left-hand side of the assignment operator (<-), output$ID, indicates that you’re providing the recipe for the Shiny output with that ID.
  • The right-hand side of the assignment uses a specific render function to wrap some code that you provide. Each render{Type} function is designed to produce a particular type of output (e.g. text, tables, and plots), and is often paired with a {type}Output function. For example, in this app, shiny::renderPrint() is paired with shiny::verbatimTextOutput() to display a statistical summary with fixed-width (verbatim) text, and shiny::renderTable() is paired with shiny::tableOutput() to show the input data in a table.

Notice that the summary and table update whenever you change the input dataset. This dependency is created implicitly because we’ve referred to shiny::input$dataset() within the output functions. shiny::input$dataset() is populated with the current value of the UI component with id dataset, and will cause the outputs to automatically update whenever that value changes. This is the essence of reactivity: outputs automatically react (recalculate) when their inputs change.

1.6 Reducing duplication with reactive expressions

The following line is duplicated:
dataset <- get(input$dataset, "package:datasets")

In traditional R scripting, we use two techniques to deal with duplicated code: either we capture the value using a variable, or capture the computation with a function. Unfortunately neither of these approaches work here, for reasons you’ll learn about in (XXX_13.2?). Therefore we need a new mechanism: reactive expressions.

Creating reactive expressions

You create a reactive expression by wrapping a block of code in reactive({...}) and assigning it to a variable, and you use a reactive expression by calling it like a function. But while it looks like you’re calling a function, a reactive expression has an important difference: it only runs the first time it is called and then it caches its result until it needs to be updated.

We can update our shiny::server() function to use reactive expressions, as shown below. The app behaves identically, but works a little more efficiently because it only needs to retrieve the dataset once, not twice.

Code Collection 1.4 : Add reactive expression

R Code 1.7 : Add reactive expression to simplify the code

Listing / Output 1.1: Add reactive expression to simplify the code
Code
library(shiny)

ui <- fluidPage(
  selectInput("dataset", label = "Dataset", choices = ls("package:datasets")),
  verbatimTextOutput("summary"),
  tableOutput("table")
)

server <- function(input, output, session) {
  # Create a reactive expression
  dataset <- reactive({
    get(input$dataset, "package:datasets")
  })

  output$summary <- renderPrint({
    # Use a reactive expression by calling it like a function
    summary(dataset())
  })
  
  output$table <- renderTable({
    dataset()
  })
}

shinyApp(ui, server)

1.7 Summary

In this chapter we’ve created a simple app.

Resource 1.1 : Shiny cheatsheet

To remember the shiny components and functions download and use the shiny cheatsheet.

1.8 Exercises

1.8.1 Example 1: Greeting app

Create an app that greets the user by name. You don’t know all the functions you need to do this yet, so I’ve included some lines of code below.

Exercise 1.1 : Greeting app

Think about which lines you’ll use and then copy and paste them into the right place in a Shiny app.

R Code 1.9 : Greeting app

Which lines of code in which place for a Shiny greeting app?
tableOutput("mortgage")
output$greeting <- renderText({
  paste0("Hello ", input$name)
})
numericInput("age", "How old are you?", value = NA)
textInput("name", "What's your name?")
textOutput("greeting")
output$histogram <- renderPlot({
  hist(rnorm(1000))
}, res = 96)

Solution 1.1. : Greeting app

Code
library(shiny)

ui <- fluidPage(
    textInput("name", "What's your name?"),
    textOutput("greeting")
)

server <- function(input, output, session) {
    output$greeting <- renderText({
        paste0("Hello ", input$name)
    })
}

shinyApp(ui, server)

1.8.2 Example 2: Multiply x with 5

Suppose your friend wants to design an app that allows the user to set a number (x) between 1 and 50, and displays the result of multiplying this number by 5.

This is their first attempt but it has an error.

Exercise 1.2 : Multiply x with 5

R Code 1.10 : Multiply x with 5

Correct the error
library(shiny)

ui <- fluidPage(
  sliderInput("x", label = "If x is", min = 1, max = 50, value = 30),
  "then x times 5 is",
  textOutput("product")
)

server <- function(input, output, session) {
  output$product <- renderText({ 
    x * 5
  })
}

shinyApp(ui, server)

Solution 1.3. : Multiply x with 5

Code
library(shiny)

ui <- fluidPage(
    sliderInput("x", label = "If x is", min = 1, max = 50, value = 30),
    "then x times 5 is",
    textOutput("product")
)

server <- function(input, output, session) {
    output$product <- renderText({
        input$x * 5
    })
}

shinyApp(ui, server)

1.8.3 Example 3: Multiply x with y

Exercise 1.3 : Multiply x with y

Extend the app from the previous exercise to allow the user to set the value of the multiplier, y, so that the app yields the value of x * y. The final result should look like this:.

Solution 1.5. : Multiply x with y

Code
library(shiny)

ui <- fluidPage(
    sliderInput("x", label = "If x is", min = 1, max = 50, value = 30),
    sliderInput("y", label = "and y is", min = 1, max = 50, value = 5),
    "then x times y is",
    textOutput("product")
)

server <- function(input, output, session) {
    output$product <- renderText({
        input$x * input$y
    })
}

shinyApp(ui, server)

1.8.4 Example 4: Use reactive expression

Take the following app which adds some additional functionality to the last app described in the last exercise. What’s new? How could you reduce the amount of duplicated code in the app by using a reactive expression.

Exercise 1.4 : Simplify code with a reactive expression

R Code 1.11 : Simplify code with a reactive expression

Use a reactive expression
library(shiny)

ui <- fluidPage(
  sliderInput("x", "If x is", min = 1, max = 50, value = 30),
  sliderInput("y", "and y is", min = 1, max = 50, value = 5),
  "then, (x * y) is", textOutput("product"),
  "and, (x * y) + 5 is", textOutput("product_plus5"),
  "and (x * y) + 10 is", textOutput("product_plus10")
)

server <- function(input, output, session) {
  output$product <- renderText({ 
    product <- input$x * input$y
    product
  })
  output$product_plus5 <- renderText({ 
    product <- input$x * input$y
    product + 5
  })
  output$product_plus10 <- renderText({ 
    product <- input$x * input$y
    product + 10
  })
}

shinyApp(ui, server)

Solution 1.7. : Simplify code with a reactive expression

Code
library(shiny)

ui <- fluidPage(
    sliderInput("x", "If x is", min = 1, max = 50, value = 30),
    sliderInput("y", "and y is", min = 1, max = 50, value = 5),
    "then, (x * y) is", textOutput("product"),
    "and, (x * y) + 5 is", textOutput("product_plus5"),
    "and (x * y) + 10 is", textOutput("product_plus10")
)

server <- function(input, output, session) {
    # Create a reactive expression
    product <- reactive({
        input$x * input$y
    })

    output$product <- renderText({
        product()
    })
    output$product_plus5 <- renderText({
        product() + 5
    })
    output$product_plus10 <- renderText({
        product() + 10
    })
}

shinyApp(ui, server)

1.8.5 Example 5: Find three bugs

The following app is very similar to one you’ve seen earlier in the chapter: you select a dataset from a package (this time we’re using the {ggplot2} package) and the app prints out a summary and plot of the data. It also follows good practice and makes use of reactive expressions to avoid redundancy of code. However there are three bugs in the code provided below. Can you find and fix them?

Exercise 1.5 : Find three bugs

R Code 1.12 : Find three bugs

Find three bugs
library(shiny)
library(ggplot2)

datasets <- c("economics", "faithfuld", "seals")
ui <- fluidPage(
  selectInput("dataset", "Dataset", choices = datasets),
  verbatimTextOutput("summary"),
  tableOutput("plot")
)

server <- function(input, output, session) {
  dataset <- reactive({
    get(input$dataset, datasets)
  })
  output$summary <- renderPrint({
    summary(dataset())
  })
  output$plot <- renderPlot({
    plot(dataset)
  }, res = 96)
}

shinyApp(ui, server)

Solution 1.9. : Find three bugs

Code
library(shiny)
library(ggplot2)
library(munsell)

datasets <- c("economics", "faithfuld", "seals")
ui <- fluidPage(
    selectInput("dataset", label = "Dataset", choices = datasets),
    verbatimTextOutput("summary"),
    plotOutput("plot")
)

server <- function(input, output, session) {
    dataset <- reactive({
        get(input$dataset)
    })
    output$summary <- renderPrint({
        summary(dataset())
    })
    output$plot <- renderPlot({
        plot(dataset())
    }, res = 96)
}

shinyApp(ui, server)

  1. This works only in places where programming code is expected (and not in Markdown text passages).↩︎