bslib: input_task_button 소개

bslib의 0.7.0에서 새롭게 추가된 input_task_button에 대해 소개합니다.

R
shiny
bslib
ux
Author
Published

March 30, 2024

bslib

bslib is a package that makes bootstrap’s css available for use in R. The exact original description is Tools for theming Shiny and R Markdown via Bootstrap 3, 4, or 5. It allows you to utilize multiple themes in Shiny and Rmarkdown (including Quarto, naturally).

In this article, we’ll focus on Shiny as an example of how bslib can be utilized. In fact, Shiny uses bootstrap for its design by default. However, Shiny is known for its feature-oriented updates, as it has become a very heavy package with a lot of components and relationships that are affected by updates.This means that the bootstrap part, which mainly deals with the UI, is using version 3.4.1, which is 5 years old, and it defaults to a distinctive blue/gray theme unless you set a separate theme (the latest version is 5.3.3).

So in order to update the stagnant UI, shiny creates a separate R package that deals with the UI and overwrites it to provide the latest bootstrap features.

This article does not cover the main uses of bslib.

actionButton

Shiny has a lot of features, but one of the key ones is the actionButton.

An actionButton is a feature that allows the user to press a button to perform a specific pre-declared action on the server, most commonly used for uploading data and then using that data to generate a calculation result.

An example use of an actionButton is to allow the user to plot a histogram of the user’s selected observations, as shown in the code below (which can be found at ?shiny::actionButton).

library(shiny)

ui <- fluidPage(
  sliderInput("obs", "Number of observations", 0, 1000, 500),
  actionButton("goButton", "Go!", class = "btn-success"),
  plotOutput("distPlot")
)

server <- function(input, output) {
  output$distPlot <- renderPlot({
    input$goButton
    dist <- isolate(rnorm(input$obs))
    hist(dist)
  })
}

shinyApp(ui, server)

long actionButton

One of the problems with this actionButton is that if the computation takes a long time, the user can’t do anything while pressing the button and waiting for the result.

Worse than just not being able to do anything, they might think the button hasn’t been clicked and click it multiple times.

If your Shiny is for computations with large amounts of genomic data, you might need minutes per computation, which can cause a lot of problems.

Especially if you click multiple times, you can get stuck in a vicious cycle of waiting, waiting, waiting, waiting… right after finishing a calculation.

shiny with loading

There have been several ways to solve this issue with actionButton:

  1. Using a progress indicator

is a way to utilize the Progress Indicator UI provided by shiny natively, which allows you to show the user the progress as the process/step of the operation progresses.

server <- function(input, output) {
  output$plot <- renderPlot({
    input$goPlot 

    dat <- data.frame(x = numeric(0), y = numeric(0))

    withProgress(message = 'Making plot', value = 0, {
      n <- 10

      for (i in 1:n) {
        dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1)))
        incProgress(1/n, detail = paste("Doing part", i))
        Sys.sleep(0.1)
      }
    })

    plot(dat$x, dat$y)
  })
}

ui <- shinyUI(basicPage(
  plotOutput('plot', width = "300px", height = "300px"),
  actionButton('goPlot', 'Go plot')
))

shinyApp(ui = ui, server = server)

However, this has the disadvantage that functions and objects such as withProgress, incProgress, or Progress require extra code for time-consuming operations.

  1. Use separate R packages

In R’s ecosystem, it’s safe to assume that there are many problems to solve, and each problem has its own R package. The same is true for the ability to display the long gap between an actionButton and the result of an operation in the UI.

Similar to the progress indicator before, think of it as a custom feature that needs to be solved by writing additional code and allows for a little more design or customization.

Here are some example packages and examples (in alphabetical order)

input_task_button

Unlike the above methods, input_task_button is an extension of actionButton that provides the ability to deactivate the button when pressed to indicate that a task is in progress, and re-activate the button when the task is finished.

The biggest difference is that it can replace actionButton, so you don’t need to use any additional code.

library(shiny)

ui <- fluidPage(
  sliderInput("obs", "Number of observations", 0, 1000, 500),
  # actionButton("goButton", "Go!", class = "btn-success"),
  input_task_button("goButton", "Go!", type = "success"),
  plotOutput("distPlot")
)

server <- function(input, output) {
  output$distPlot <- renderPlot({
    input$goButton
    Sys.sleep(5)
    dist <- isolate(rnorm(input$obs))
    hist(dist)
  })
}

shinyApp(ui, server)

To use input_task_button, we replaced actionButton on line 5 with input_task_button on line 6, and additionally, to make the operation intentionally long, we utilized the Sys.sleep() code on line 13 to delay it by 5 seconds.

Here’s how to use input_task_button

The input_task_button can replace the actionButton without any difficulty, but requires some parameter modifications.

actionButton input_task_button role
inputId id button id
label label button label
icon icon button icon
label_busy inactive button label
icon_busy inactive button icon
class type button theme/color

Summary

In this post, we introduced the newest feature in bslib, input_task_button, and a simple use case.

This is a feature that potentially improves the user experience, and I think it solves a problem that traditionally requires additional code to be written in shiny.

In particular, unlike other web applications, Shiny often takes a long time due to large data operations, but it has a relatively poor UI/UX, so replacing the existing actionButton with input_task_button will go a long way to compensate for this.

I hope you found this article helpful, and I’ll see you in the next installment!

Reuse

Citation

BibTeX citation:
@online{kim2024,
  author = {Kim, Jinhwan},
  title = {Bslib: Input\_task\_button {소개}},
  date = {2024-03-30},
  url = {https://blog.zarathu.com/en/posts/2024-03-30-input-task-button},
  langid = {en}
}
For attribution, please cite this work as:
Kim, Jinhwan. 2024. “Bslib: Input_task_button 소개.” March 30, 2024. https://blog.zarathu.com/en/posts/2024-03-30-input-task-button.