Site icon R-bloggers

Adding Shiny app’s parameters to the URL

[This article was first published on pacha.dev/blog, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

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.

To leave a comment for the author, please follow the link and comment on their blog: pacha.dev/blog.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Exit mobile version