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.
ggplot2 can be used with the standard plotOutput() and renderPlot({}) functions.
# 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, 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)
})
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.
df %>% arrange(count)ggplot(df, aes(x = year, y = count))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.
.data[[ <insert data-variable> ]]across(all_of( <insert data-variable> ))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
})