Skip to contents

The following is an example of usage of the widget in a Shiny app.

First, install the dependencies:

install.packages("shiny")
install.packages("devtools")
devtools::install_github("satijalab/seurat-data")
devtools::install_github("vitessce/vitessceAnalysisR")

Next, create an output element in the UI with vitessce_output and a corresponding server response with render_vitessce.

The value for the output_id parameter in the vitessce_output function should match the key for the result of render_vitessce in the server.

library(shiny)
library(vitessceR)
library(vitessceAnalysisR)
library(SeuratData)

SeuratData::InstallData("pbmc3k")
data("pbmc3k.final")
force(pbmc3k.final)

adata_path <- file.path("data", "seurat", "pbmc3k.final.h5ad.zarr")
vitessceAnalysisR::seurat_to_anndata_zarr(pbmc3k.final, adata_path)

w <- AnnDataWrapper$new(
  adata_path=adata_path,
  obs_embedding_paths = c("obsm/X_pca", "obsm/X_umap"),
  obs_embedding_names = c("PCA", "UMAP"),
  obs_set_paths = c("obs/seurat_annotations", "obs/seurat_clusters")
)

ui <- fluidPage(
  "Vitessce in a Shiny app",
  vitessce_output(output_id = "vitessce_visualization", height = "600px"),
)

server <- function(input, output, session) {
  output$vitessce_visualization <- render_vitessce(expr = {
    vc <- VitessceConfig$new(schema_version = "1.0.16", name = "My config")
    dataset <- vc$add_dataset("My dataset")
    dataset <- dataset$add_object(w)
    scatterplot <- vc$add_view(dataset, Component$SCATTERPLOT, mapping = "PCA")
    vc$layout(scatterplot)
    vc$widget(theme="light")
  })
}

shinyApp(ui, server)

When running the Shiny app, the Vitessce widget will take a few seconds to appear on the screen. We plan to optimize the internal widget data preparation and conversion functions to reduce this delay.

Shiny apps on remote servers

When running a Shiny app on a remote server, you will need to use the base_url parameter of the vc$widget() function. When a value for base_url is provided, the default http://localhost base URL will be overridden, allowing the client of the Shiny app to be running on a different computer than the Shiny server.

You also may want to serve the Vitessce widget data files through a custom static web server rather than the built-in R plumber web server (either for security or scalability reasons). To do so, be sure to set the parameter out_dir when calling the SeuratWrapper$new() constructor. This will allow you to specify the output directory for the converted Vitessce data files. Then, you can set the parameter serve to FALSE in vc$widget() to prevent the built-in plumber server from starting when you launch the widget.

For example, if you know that your Shiny server will be running at http://example.com/shiny and you want to turn off the plumber server, then you would call vc$widget(base_url = "http://example.com/shiny", serve = FALSE).

The following example demonstrates swapping out the Vitessce widget’s built-in server for Shiny’s addResourcePath:

library(shiny)
library(vitessceR)
library(SeuratData)

SeuratData::InstallData("pbmc3k")
data("pbmc3k.final")
force(pbmc3k.final)

BASE_DIR <- file.path("data", "seurat")
adata_filename <- "pbmc3k.final.h5ad.zarr"
vitessceAnalysisR::seurat_to_anndata_zarr(pbmc3k.final, file.path(BASE_DIR, adata_filename))

w <- AnnDataWrapper$new(
  adata_path=adata_filename,
  obs_embedding_paths = c("obsm/X_pca", "obsm/X_umap"),
  obs_embedding_names = c("PCA", "UMAP"),
  obs_set_paths = c("obs/seurat_annotations", "obs/seurat_clusters")
)

ui <- fluidPage(
  "Vitessce in a Shiny app",
  vitessce_output(output_id = "vitessce_visualization", height = "600px"),
)

server <- function(input, output, session) {
  # Ask Shiny to also serve our data files in our local ./data/seurat folder from "/vitessce"
  addResourcePath("vitessce", BASE_DIR)
  
  # Render the Vitessce widget into the UI output.
  output$vitessce_visualization <- render_vitessce(expr = {
    
    # Tell Vitessce that file paths (in AnnDataWrapper) are relative to the BASE_DIR folder.
    vc <- VitessceConfig$new(schema_version = "1.0.16", name = "My config", base_dir = BASE_DIR)
    dataset <- vc$add_dataset("My dataset")
    dataset <- dataset$add_object(w)
    scatterplot <- vc$add_view(dataset, Component$SCATTERPLOT, mapping = "PCA")
    vc$layout(scatterplot)
    
    # Construct a base_url value dynamically based on the Shiny session info.
    BASE_URL <- paste0(
      session$clientData$url_protocol,
      "//",
      session$clientData$url_hostname,
      ":",
      session$clientData$url_port,
      session$clientData$url_pathname,
      "vitessce"
    )

    vc$widget(theme = "light", serve = FALSE, base_url = BASE_URL)
  })
}

shinyApp(ui, server)

Bidirectional communication example

Listen for input$vitessce_on_config_change events emitted by the Vitessce widget in order to observe user interactions and update the Shiny app in response.

library(shiny)
library(vitessceR)
library(vitessceAnalysisR)
library(SeuratData)

SeuratData::InstallData("pbmc3k")
data("pbmc3k.final")
force(pbmc3k.final)

adata_path <- file.path("data", "seurat", "pbmc3k.final.h5ad.zarr")
vitessceAnalysisR::seurat_to_anndata_zarr(pbmc3k.final, adata_path)

w <- AnnDataWrapper$new(
  adata_path=adata_path,
  obs_embedding_paths = c("obsm/X_pca", "obsm/X_umap"),
  obs_embedding_names = c("PCA", "UMAP"),
  obs_set_paths = c("obs/seurat_annotations", "obs/seurat_clusters")
)

ui <- fluidPage(
  "Vitessce in a Shiny app",
  vitessce_output(output_id = "vitessce_visualization", height = "600px"),
  verbatimTextOutput("vitessce_config")
)

server <- function(input, output, session) {
  output$vitessce_visualization <- render_vitessce(expr = {
    vc <- VitessceConfig$new(schema_version = "1.0.16", name = "My config")
    dataset <- vc$add_dataset("My dataset")
    dataset <- dataset$add_object(w)
    scatterplot <- vc$add_view(dataset, Component$SCATTERPLOT, mapping = "PCA")
    vc$layout(scatterplot)
    vc$widget(theme="light")
  })
  
  rv <- reactiveValues(current=NULL)
  
  observeEvent(input$vitessce_on_config_change, {
    # We can access any values from the coordination space here.
    # In this example, we access the ID of the currently-hovered cell.
    rv$current <- input$vitessce_on_config_change[['coordinationSpace']][['obsHighlight']]
  })
  
  output$vitessce_config <- renderPrint({ rv$current })
}

shinyApp(ui, server)