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
})