Packages I

dplyr and plots with ggplot2 & Plotly

Shiny provides the basic tools for client-server interaction, but a lot of parts that make up an app–how it wrangles and displays data, can come from packages of your choice. All of the packages introduced in the R Learning Series so far (dplyr, ggplot2, plotly, data.table, R markdown, sf, leaflet) can be included in Shiny.

Plots

ggplot2 can be used with the standard plotOutput() and renderPlot({}) functions.

ggplot2

# Server

  output$plot <- renderPlot({
    filtered_df() %>% 
      ggplot(aes(x = year, y = count, color = state)) +
        geom_line() +
        facet_wrap(vars(sex), nrow = 2, scales = "free_y")
  })

To add more content to our plot (and table), enable the dropdown menu to allow the user to select multiple states.

# UI 

  # add multiple argument to allow more than one selection
  selectInput("state",
              label = 'Select State',
              choices = unique(df$state),
              selected = 'Washington',
              multiple = TRUE)
# Server

 # allow filtering of multiple states with `%in%`
  filtered_df <- eventReactive(input$go, {
    df %>% 
      filter(name == clean_name() & state %in% input$state)
  })

Plotly

Plotly, a package that helps create interactive graphs, can be used to convert a static ggplot2 graph into an interactive one. Plotly on its own can also be used in lieu of ggplot2.

To render Plotly graphs in Shiny, use plotlyOutput() and renderPlotly({}) in lieu of the standard plot output and render functions.

Include the plotly package in the global section.

Convert existing plot output and render functions to their respective Plotly equivalent.

# UI

  # convert plotOutput to a Plotly Output
  plotlyOutput("plot")
# Server
  
  # convert renderPlot to renderPlotly
  output$plot <- renderPlotly({
    
    # create ggplot object
    p <- filtered_df() %>% 
      ggplot(aes(x = year, y = count, color = state)) +
        geom_line() +
        facet_wrap(vars(sex), nrow = 2, scales = "free_y")
    
    # wrap ggplot object with ggplotly
    ggplotly(p)
  })

Extra: Tidy Evaluation

Typically in dplyr functions, data-variables (a.k.a column names) are entered directly in the function without any extra syntax ($ or quotation marks). Data-variables mapped in ggplot2’s aes() also follow the same concept.

However when the data-variable (e.g. count) is stored in a variable (e.g. my_column <- 'count'), or as part of another object (e.g. input$my_input_widget), additional syntax is required to accommodate this indirection.

Let’s add a dropdown menu that allows the user to choose which column to sort the table by.

ui <- fluidPage(
  
  title,
  src,
  
  sidebarLayout(
    sidebarPanel(
      txt_box,
      actionButton("clear", label = "Clear Name"),
      txt_disp,
      selectInput("state",
                  label = 'Select State',
                  choices = unique(df$state),
                  selected = 'Washington',
                  multiple = TRUE),
      
      # add dropdowns for user to decide how table is sorted 
      selectInput('table_sort',
                  label = 'Sort table by',
                  choices = c('count', 'sex', 'year')),
      
      actionButton("go", label = "Enter")
    ),
    mainPanel(
      fluidRow(
        column(
          width = 6,
          h3("Table"),
          tbl_disp
        ),
        column(
          width = 6,
          h3("Plot"),
          plotlyOutput("plot")
        )
      )
    )
  )
  
)

In the server, apply the .data[[]] wrapper inside arrange().

# Server

  filtered_df <- eventReactive(input$go, {
    df %>%
      filter(name == clean_name() & state %in% input$state) %>% 
      arrange(.data[[input$table_sort]]) # add arrange, pass input value using tidy evaluation syntax
  })

If there are multiple values selected by the user for an input and applied in dplyr, wrap the reactive source within across(all_of()).

# UI

# add dropdowns for user to decide how table is sorted 
selectInput('table_sort',
            label = 'Sort table by',
            choices = c('count', 'sex', 'year'),
            multiple = TRUE) # allow more than one selection
# Server

  filtered_df <- eventReactive(input$go, {
    df %>%
      filter(name == clean_name() & state %in% input$state) %>% 
      arrange(across(all_of(input$table_sort))) # add arrange, pass input value using tidy evaluation syntax
  })