Shiny allows to use all of R to visualize information, no matter if it is a sophisticated statistical model or a simple plot. One of the features it does not provide out-of-the-box is adding the selected parameters to the URL, like this:
https://pacha.dev/palmerpenguinsshiny?inputs&species="Adelie"&island="Torgersen"
In order to have this type of URL I shall demonstrate a simple case with golem. Let’s start by creating a project:
golem::create_golem("palmerpenguinsshiny")
Open R/run_app.R and change enableBookmarking = NULL to enableBookmarking = "url".
Open R/app_server.R and add these lines at the end of app_server():
# Bookmarking ----
observe({
# Trigger this observer every time an input changes
# strip shiny related URL parameters
shiny::reactiveValuesToList(input)
setBookmarkExclude(c(
"parameter_not_in_url"
))
session$doBookmark()
})
onBookmarked(function(url) {
updateQueryString(url)
})Now we need to add contents to the app. Let’s create an app that allows the user to filter by species and island to obtain a plot of the body mass distribution.
Here’s a shortcut to simplify things and use the pipe operator:
usethis::use_pipe()
devtools::document()Create a copy of the data we need:
penguins_sib <- palmerpenguins::penguins[, c("species", "island", "body_mass_g")]
usethis::use_data(penguins_sib)Now let’s add contents to app_server(), like this:
#' The application server-side
#'
#' @param input,output,session Internal parameters for {shiny}.
#' DO NOT REMOVE.
#' @import shiny
#' @import ggplot2
#' @importFrom dplyr filter
#'
#' @noRd
app_server <- function(input, output, session) {
# Main plot ----
# Filter by species and island, then show the distribution of body_mass_g
output$main_plot <- renderPlot({
req(input$species, input$island)
penguins_sib %>%
filter(
species %in% input$species,
island %in% input$island
) %>%
ggplot(aes(x = body_mass_g)) +
geom_histogram(bins = input$bins, fill = input$fill, color = "black") +
labs(
title = "Distribution of Body Mass (g)",
x = "Body Mass (g)",
y = "Count"
) +
theme_minimal(base_size = 13)
})
# Bookmarking ----
observe({
# Trigger this observer every time an input changes
# strip shiny related URL parameters
shiny::reactiveValuesToList(input)
setBookmarkExclude(c(
"fill"
))
session$doBookmark()
})
onBookmarked(function(url) {
updateQueryString(url)
})
}Pass the server logic on UI side:
#' The application User-Interface
#'
#' @param request Internal parameter for `{shiny}`.
#' DO NOT REMOVE.
#' @import shiny
#' @noRd
app_ui <- function(request) {
tagList(
# Leave this function for adding external resources
golem_add_external_resources(),
# Your application UI logic
# Filters
sidebarLayout(
sidebarPanel(
selectInput("species", "Select Species:", choices = unique(penguins$species), multiple = TRUE),
selectInput("island", "Select Island:", choices = unique(penguins$island), multiple = TRUE),
selectInput("fill", "Select Fill Color:", choices = c("#3d809d", "#d04e66", "#365158"),
multiple = FALSE, selected = "#3d809d"),
sliderInput("bins", "Number of Bins:", min = 1, max = 50, value = 30)
),
mainPanel(
plotOutput("main_plot")
)
)
)
}
#' Add external Resources to the Application
#'
#' This function is internally used to add external
#' resources inside the Shiny application.
#'
#' @import shiny
#' @importFrom golem add_resource_path activate_js favicon bundle_resources
#' @noRd
golem_add_external_resources <- function() {
add_resource_path(
"www",
app_sys("app/www")
)
tags$head(
favicon(),
bundle_resources(
path = app_sys("app/www"),
app_title = "palmerpenguins"
)
# Add here other external resources
# for example, you can add shinyalert::useShinyalert()
)
}Now run:
devtools::load_all()
run_app()
You should see your app running locally, and when you select the two required fields (species and island) there will be a rendered plot and a URL of the form:
http://127.0.0.1:6736/?_inputs_&species=%22Adelie%22&island=%22Biscoe%22&bins=30
Note that the fill colour is not in the URL but that is intentional :)
The full code is here: https://github.com/pachadotdev/palmerpenguinsshiny.
Don’t forget to add a license to your app (e.g., open dev/01_start.R to select the MIT license, or use Apache with usethis::use_apache_license()).
If this resource was useful to you, please consider donating here: https://buymeacoffee.com/pacha.