General outline for weeks 6 – 10

  • Week 6: Introduction to Shiny and Reactive Programming
  • Week 7: Input widgets and UI layout functions
  • Week 8: Building Interactive UI Components
  • Week 9: Linking ggplot2 with Shiny for Dynamic Visualisation
  • Week 10: Final support session

Objectives

By the end of this session (and your own reading), you should be able to \(\dots\)

  1. Start planning your own app.
  2. Create apps with interactive data visualisation features.

Building an app

  • Create page layout: Do you need different tabs
  • What do you want the plot to do?
  • What basic reactivity do you need?
  • What should the input options be?

Example data: spellname

Rows: 8,584
Columns: 12
$ ppt_id            <dbl> 40, 40, 40, 40, 40, 40…
$ resp              <chr> "almond", "ambulance",…
$ name_familiarised <lgl> TRUE, FALSE, FALSE, TR…
$ cat               <chr> "is natural", "is manm…
$ ppt_vocab         <dbl> 0.95, 0.95, 0.95, 0.95…
$ modality          <chr> "speech", "speech", "s…
$ rt                <dbl> 1312, 1057, 967, 1148,…
$ dur               <dbl> 649, 544, 800, 680, 58…
$ spell_div         <dbl> 0.5290947, 0.3919984, …
$ name_div          <dbl> 3.7269149, 0.1407271, …
$ nsyl              <dbl> 2, 3, 4, 3, 3, 3, 4, 2…
$ aoa               <dbl> 7.67, 6.16, NA, 6.28, …
  • How does familiariation affect reaction time and response duration?
  • Which naming features correlate with one another?
  • Do patterns reproduce across response modalities?
  • Plotting outcome variables individually or combined.
  • Are there any responses (images) that are worth excluding because they are “special”?
  • Is it worth excluding participants with low vaocabulary scores?

Building an app

Layout Type?

  • Multiple Tabs → navbarPage/tabsetPanel
  • Single View → fluidPage/dashboardPage

Plot Type?

  • Static → plotOutput + renderPlot
  • Interactive → plotlyOutput + renderPlotly

Inputs Needed?

  • Variable Selection → selectInput
  • Numeric Filter → sliderInput
  • Category Filter → checkboxGroupInput/radioButtons


Multiple Plot Types?

  • Yes → Separate tabPanels
  • No → Conditional logic in one panel

Reactivity?

  • Direct Mapping → renderPlot/renderPlotly
  • Data Transformation → reactive()

Your own app!

What would make a dataset interesting to explore interactively?

What’s the goal of your app?

If you have already identified a dataset:

  • What are its key variables? Which ones would users want to filter, compare, or visualise?

Identify user actions:

  • Filtering: by category, range sliders
  • Grouping: by factor levels
  • Visualising: scatterplots, histograms, time series
  • Comparing: two variables side by side

Which of these would make sense for your dataset?

Design

Element Your Idea
Dataset name
Key variables
Main question(s)
Filters to include
Visualisations
Extra features

We will build an app now!

  1. Create a new R project called psych40940-portfolio.Rproj.
  2. Move your date (or the spellname dataset) inside your new R project.
  3. Create an R script called app.R.
  4. Initialise your app code by typing shinyapp.

Static visualisation

Start by creating an app that displays a single visualisation. Use your own data or the spellname dataset.

# Load data
spellname <- read_csv("spellname.csv")

# Create user interface
ui <- fluidPage(
  plotOutput("myplot")
)

# Create server with a single plot
server <- function(input, output) {
  output$myplot <- renderPlot({
    # ... 
  })
}

Static visualisations: different tabs

Create a copy of your app and change fluidPage to navbarPage with a different visualisation per tab.

ui <- navbarPage("Many tabs app",
               tabPanel("My plot 1",
                    plotOutput("myplot1")
               ),
               tabPanel("My plot 2"
                          
              )
)

server <- function(input, output) {
  output$myplot1 <- renderPlot({
    # ...
  })
}

Static visualisations: different tabs

Then, create a sidebar layout within both tabs but leave the sidebar panel empty for now.

sidebarLayout(
  sidebarPanel(
      
  ),
  mainPanel(
        plotOutput("myplot1"),

  )
)

Static visualisation with user input

In a tab of your choice, allow users to select variables from the input.

Define options the user can select from:

choices <- names(spellname)

but make sure these contain only numeric variables; or at least 2-3 numeric variables.

Add selecting option to user interface:

selectInput("var", "Title", choices = choices)

Link the selected variable to the plot:

ggplot(spellname, aes(x = .data[[input$var]])) 

Static visualisation with user input

Allow user to filter the selected variables using a slider.

You need a placeholder in your UI for the user selection:

uiOutput("varout")

Static visualisation with user input

Add a reactivity that creates an input slider for the selected variable.

datavar <- reactive({
    spellname[[input$var]]
})

output$varout <- renderUI({
  # get the min and max values  
  rng <- range(datavar(), na.rm = TRUE)

  # create a slider for the
  sliderInput("dynamicVar", 
              input$var,
              value = rng,
              min = floor(rng[1]),
              max = ceiling(rng[2]))
})

Static visualisation with user input

Use the values from the new slider to limit the displayed information:

ggplot(...) +
  ...
  coord_cartesian(xlim = input$dynamicVar)

Repeat this for another variable (e.g. for the y axis).

Interactive visaulisation

?plotOutput

plotOutput(
  outputId,
  width = "100%",
  height = "400px",
  click = NULL,
  dblclick = NULL,
  hover = NULL,
  brush = NULL, # <- check this out!
  inline = FALSE,
  fill = !inline
)

See Chapter 16 in Andrews (2021).

Selecting points

mainPanel(
  plotOutput("scatterPlot", 
             brush = brushOpts(id = "selected_region")),
  h4("Selected data"),
  verbatimTextOutput("selected_info")
  )
output$selected_info <- renderPrint({
  brushedPoints(spellname, input$selected_region)
})

… allows the user to use their cursor to select data points and print them.

  • Add a tab for this functionality.
  • Add a scatterplot with two variables of your choice.
  • Add the selecting points functionality.

Selecting points

mainPanel(
  ...,
  DT::DTOutput("selected_info")
  )
output$selected_info <- DT::renderDT({
  brushedPoints(spellname, input$selected_region)
})
  • The DT package provides an interactive data table (hence, “DT”).
  • This can be used for selected data points.
  • Data table is rendered in the server via renderDT that is connected to the UI via DTOutput.

Zooming into data

mainPanel(
  plotOutput("scatterPlot", 
             brush = brushOpts(id = "selected_region")),
  plotOutput("subplot")
)
  • Allows the user to zoom into a section of the data.
  • Create a tab with a scatterplot of two hard coded variables (no user selection).
  • Add in an output for a subplot.

Zooming into data

xyrange <- reactiveValues(x = NULL, y = NULL)

observe({
  sel_reg <- input$selected_region
  xyrange$x <- c(sel_reg$xmin, sel_reg$xmax)
  xyrange$y <- c(sel_reg$ymin, sel_reg$ymax)
})

output$subplot <- renderPlot({
  ggplot(...) +
    coord_cartesian(xlim = xyrange$x, ylim = xyrange$y)
})
  • In the server, we need to create a new plot similar to the previous scatterplot but with a limited range for both axes.
  • Add zooming behaviour to this scatterplot and show both the plot with all data, and the zoomed-in plot.
  • Add a title to the plots so the user knows which one is which.

Zooming into data

Using fluidRow and column allows you to constrain the width of output elements.

mainPanel(
  fluidRow(
    column(5, # (must be between 1 and 12)
      plotOutput("myplot1")),
    column(5,
             
  )
)

Adjust columns that both plots (zoomed in and not zoomed in) fit next to each other.

Interactive visualisations using plotly

# Load package
library(plotly)

# Check documentation for plotly output function
?plotlyOutput

# Arguments for plotlyOutput
plotlyOutput(
  outputId,
  width = "100%",
  height = "400px",
  inline = FALSE,
  reportTheme = TRUE,
  fill = !inline
)

Interactive visualisations using plotly

# Load package
library(plotly)

# Create a ggplot2 plot and save it in `plot`
plot <- ggplot(d_blomkvist, aes(x = ...)) +
  geom_point()

# Make the visualisation interactive by using `ggplotly`
ggplotly(plot)

For the plot in your tab with user selected variables turn the visualisation into an interactive plotly visualisation.

Make sure you’re using plotlyOutput (user interface) and renderPlotly (server).

Interactive visualisations using plotly

library(plotly)
plot_ly(data = spellname,
        x = ~freq,
        y = ~rt,
        z = ~dur,
        color = ~modality,
        type = "scatter3d",
        mode = "markers",
        marker = list(size = 3)
)


Add a new tab with sidebar layout that displays a 3D scatterplot.

Allow the user to select variables for the x, y and z axis:

  • You’ll need selectInput to allow users to select variables.
  • Then connect the selected variables to the plotting function.

Use plotlyOutput (UI) and renderPlotly (server).

Preparation for our final session

  • Select a data set for your portfolio project.
  • Start developing an app around your data set.
    • Create a layout
    • Create visualisations
    • Add user input features

Review the assessment specification on NOW.

Some inspiration using features we discussed: Spellname-app

Recommended reading

User experience

Consider adding features that affect how to user is experiencing the app:

  • Meaningful labels for user input widgets (sliders, buttons).
  • Buttons (with reactiveEvent) to update plots and slides instead of instant updates.
  • Text that helps the user to identify what the can do; see helpText("Say something about the user's options.").
  • Progress feedback / bars for visualisations that take longer to generate (see Wickham, 2021: LINK)

You can also embed your app in an RMarkdown document: see “RMarkdown based Shiny apps” in (Andrews, 2021, Chapter 16: LINK)

References

Andrews, M. (2021). Doing data science in R: An introduction for Social Scientists. SAGE Publications Ltd.

Wickham, H. (2021). Mastering shiny. O’Reilly Media.