webR and Shiny

news
Author

David Granjon

Published

September 27, 2023

Introduction

webR allows to run R in the browser without any installation. That was one of the main motivation for its creator, George Stagg. The goal of this article is not to describe how webR was developed but what you can do with it.

Under the hood, webR is a JavaScript package which can be downloaded from npm (see it as a sort of CRAN for JS packages but fairly less strict regarding the content formatting). As you may imagine, one can’t use the existing CRAN repositories as they are not made for web assembly (wasm), which powers webR. Therefore, the webR team made it possible to compile your own packages, owing to a rather complex toolchain involving Emscripten. The currently provided repository is deployed at https://repo.r-wasm.org/.

shinylive is a JavaScript app (React) leveraging webR as well as Pyodide (See more here), a Python web browser version. In this article, we’ll only focus on the R side but keep in mind that the shinylive repository supports both. This repository allows to export a working shinylive app.

The resulting app may have different layouts:

  • App only.
  • App + header for sharing code.
  • App + editor + terminal.
  • App + examples… That’s the one you can access here.

A tiny R package called {shinylive} creates plug and play shiny apps for the browser by downloading all the necessary files from the shinylive repository. Be careful not to be confused!

A cool feature about the shinylive app is code sharing. The app code is compressed to base64 and shared via the url. Therefore, you can build your app in the editor and share it to others.

Customizing it

At the time of writing, 18094 packages are built for wasm (10379 also have their dependencies available), as shown below.

webR CRAN packages

What if you want to install packages not available on https://repo.r-wasm.org/? You’d have to compile your own packages as described earlier:

  • Build webR and all the system libraries.
  • Build this repository and add your packages to the existing https://github.com/r-wasm/webr-repo/blob/main/repo-packages list. Note that in the Makefile you’ll have to give the link to the webR installation by passing WEBR_ROOT=<WEBR_PATH>.

The first step is really not straightforward.

I was able to compile a customized repository which powers my own shinylive app. I had to slightly change the code to remove the Python support, as it was not necessary.

Usage examples

  • {pkgdown} + shinylive: https://github.com/DivadNojnarg/shinylivePkgDown.
  • shinylive + quarto: have a shiny app without having to go back and forth between windows.

Embedded app

Below is an embedded R shinylive app running in a separate server hosted on Netlify. The iframe is included in a {bslib} card.

Embedded app + editor

An embedded shinylive app editor. User can share the code. Note: the plot won’t likely show on smaller screen leading to an error in the R console.

shinylive Quarto extension

Within a Quarto document

Below is a simple shiny app powered by the shinylive extension.

To get it working you must:

  • Install the shinylive quarto extension, run within your project:

    quarto add quarto-ext/shinylive
  • Edit index.qmd by passing the appropriate filter:

    ---
    ... other options ...
    filters: 
      - shinylive
    ---
  • Create the app code:

    ```{shinylive-r}
    #| standalone: true
    #| components: [editor, viewer]
    #| column: screen-inset-shaded
    library("shiny")
    
    ui <- fluidPage(
      numericInput("obs", "Number of observations:",
        min = 0, max = 1000, value = 500
      ),
      plotOutput("distPlot")
    )
    
    # Server logic
    server <- function(input, output) {
      output$distPlot <- renderPlot({
        hist(rnorm(input$obs))
      })
    }
    
    shinyApp(ui, server)
    ```
#| standalone: true
#| components: [editor, viewer]
#| column: screen-inset-shaded
library("shiny")

ui <- fluidPage(
  numericInput("obs", "Number of observations:",
    min = 0, max = 1000, value = 500
  ),
  plotOutput("distPlot")
)

# Server logic
server <- function(input, output) {
  output$distPlot <- renderPlot({
    hist(rnorm(input$obs))
  })
}

shinyApp(ui, server)

Quarto revealjs slides

Below is a simple shiny app embedded in a quarto revealjs presentation. The process is the same as described above, except that the index.qmd file to change is the one from the Quarto slides.

The result is shown below. As you can see, there is currently a layout issue, as there is an offset in the editor pane.

Limitations

Currently, there are few limitations:

  • Have to install all packages on app load, which takes some time for R. It will be fixed soon.
  • Necessary to have your own CRAN-like for wasm at some point. The webR team won’t be able to compile any single package on request.
  • Few R functions don’t work well.
  • Data are available in the browser. Not suitable for clinical apps in the pharma world, except if data are publicly made available on purpose (synthetic data …).

I personally think webR will be great for teaching and presentations. However, I don’t see it replacing the current infrastructures for more complex apps.

Back to top