ETC5523: Communicating with Data

Workshop 9: Build a Shiny app from scratch

Author

Michael Lydeamore

Published

1 September 2001

🎯 Objectives

By the end of this workshop, you will be able to:

  • create a complete Shiny app in a new app.R file;
  • connect input controls to reactive outputs;
  • use a reactive expression to share filtered data; and
  • improve an app with purposeful labels, guidance and source information.
What you will build

You will build an app that lets a cricket follower choose a Women’s Premier League season and explore how leading batters score their runs.

Start with a blank app.R. Build and run each stage before moving to the next one.

1. Prepare the app and data (4 minutes)

  1. Create a new folder called wpl-app.
  2. Inside that folder, create a blank file called app.R.
  3. Download wpl_batters.csv and save it in the same folder.
  4. Add code to load these packages:
    • shiny
    • bslib
    • dplyr
    • ggplot2
  5. Read the CSV into an object called wpldata.

Run the first few lines and inspect the data with glimpse(wpldata).

Note

Each row describes one batter in one season. The variables include runs, balls faced, dot-ball percentage and boundary percentage. The data contain the 20 leading run-scorers in each season who faced at least 50 balls.

2. Create the smallest possible app (4 minutes)

A Shiny app needs a UI, a server function and a call to shinyApp().

Write these three components in app.R:

ui <- page_fluid(
  "My first Shiny app"
)

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

shinyApp(ui, server)

Run the app. You should see the text My first Shiny app in a browser or viewer window.

Tip

Run the app after every small change. When something breaks, the most recent change is the first place to look.

3. Give the user a choice (5 minutes)

Replace page_fluid() with page_sidebar() and add a sidebar containing a selectInput().

Your input should:

  • have the ID "season";
  • use the label Choose a season; and
  • take its choices from wpldata$season.

Run the app and change the selected season. Nothing else should happen yet.

4. Reserve a place for the plot (3 minutes)

Add this UI function after the sidebar:

plotOutput("batters_plot")

Answer these questions before continuing:

  1. Does plotOutput() draw a plot?
  2. What output ID have you created?
  3. What will that ID look like inside the server function?

5. Connect the input to the output (8 minutes)

Inside server(), assign renderPlot() to output$batters_plot.

The plotting code should:

  1. filter wpldata to season == input$season;
  2. map dot_percent to the x-axis;
  3. map boundary_percent to the y-axis; and
  4. draw the observations with geom_point().

Run the app and confirm that the plot changes when you select another season.

Note

Trace the reactive path:

selectInput("season", ...) → input$season → renderPlot() → plotOutput("batters_plot")

6. Add a second input (7 minutes)

Let the user choose how many leading run-scorers to display.

  1. Add a sliderInput() with the ID "top_n".
  2. Let the user choose from 5 to 20 batters, with a default of 10.
  3. After filtering by season, use slice_max() to keep input$top_n batters ranked by runs.
  4. Map balls_faced to point size.

Before running the app, predict which expression will rerun when the slider moves.

7. Create and reuse reactive data (7 minutes)

Move the filtering and ranking into a reactive expression called selected_batters.

Then:

  • use selected_batters() inside renderPlot(); and
  • create a dynamic plot title with renderText() and textOutput().

The title should include the selected season and number of batters.

8. Make the app communicate (7 minutes)

Improve the app for someone who did not write it.

Add:

  • an informative app title;
  • percentage labels on both axes;
  • a sentence explaining how to read the chart;
  • a note explaining which batters are included; and
  • a linked source for the data.

Do not add another feature until a reader can understand the current output.

9. Test another student’s app (5 minutes)

Swap with a partner. Do not explain your app before they use it.

The tester should:

  1. select another season;
  2. change the number of batters;
  3. explain what the upper-left of the chart means; and
  4. identify the data scope and source.

The author should record one programming problem and one communication problem, then fix the more consequential one.

Extension: choose one purposeful addition

If your app is working, add one feature that supports a clear user question:

  • colour points by batting_team;
  • label the three highest run-scorers;
  • add a table made with renderTable() and tableOutput(); or
  • add hover details with Plotly.

Before coding, complete:

This feature helps the user answer …