Introduction
Interactive documents built with Quarto Live can seamlessly combine pre-rendered static content with live, reactive code. By using OJS variables, you can pre-compute data during build time and then import it into live code cells that update instantly based on user inputs. This hybrid approach delivers high performance while providing dynamic interactivity.
1. What is Reactivity?
Reactivity enables your document to update automatically when data or inputs change. By pre-rendering heavy computations and exporting them as OJS variables, you can pass these values to live interactive cells—ensuring quick load times and immediate feedback.
2. Using OJS Variables in Interactive Documents
Creating Reactive Inputs with OJS
OJS blocks allow you to create interactive widgets that capture user input. For example, the following code defines a checkbox input for selecting species and a dropdown menu for choosing a measure from the iris dataset.
Source
reactivity.qmd
```{ojs}
//| echo: false
viewof selected_species = Inputs.checkbox(
["setosa", "versicolor", "virginica"],
{ value: ["setosa", "versicolor", "virginica"], label: "Select Iris Species:" }
)
viewof measure = Inputs.select(
["Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"],
{ label: "Select Measure:" }
)
```
Output
Importing OJS Variables into R Code Cells
Once defined, these OJS variables can be imported into R code blocks using the input
option, enabling live reactivity.
Source
reactivity.qmd
```{webr}
#| input:
#| - selected_species
#| - measure
cat("Selected Species:", selected_species, "\n")
cat("Selected Measure:", measure, "\n")
```
Output
3. Pre-Rendering Data and Importing it Live
Pre-Rendering with R
You can pre-compute data during the build phase and export it as an OJS variable. For example, the following R block pre-renders a summary of the mtcars
dataset.
library(dplyr)
# Pre-compute a subset of mtcars and export as an OJS variable
<- mtcars %>% select(mpg, hp) %>% filter(mpg < 25)
mpg_data ojs_define(mpg_data)
Live Interactive Plot Using Pre-Rendered Data in Python
Next, import the pre-rendered data into a Python interactive cell to create a scatter plot.
Source
```{pyodide}
#| input:
#| - mpg_data
import pandas as pd
import matplotlib.pyplot as plt
# Convert the pre-rendered mpg_data into a DataFrame
df = pd.DataFrame(mpg_data)
plt.figure(figsize=(8, 4))
plt.scatter(df['mpg'], df['hp'], color='darkgreen')
plt.title("MPG vs Horsepower")
plt.xlabel("Miles per Gallon")
plt.ylabel("Horsepower")
plt.show()
```
This cross-engine data sharing enables you to combine static processing with live interactivity.
4. Additional Practical Examples
Interactive Histogram with Live and Pre-Rendered Data
This example demonstrates an interactive histogram using live Python code, with the bin count controlled by an OJS slider.
Source
histogram.qmd
```{webr}
#| input:
#| - bin_count
# Live R Histogram
hist(rnorm(1000), breaks = bin_count, col = "steelblue", border = "white")
```
```{ojs}
//| echo: false
// OJS Input for Bin Count
viewof bin_count = Inputs.range([5, 50], { value: 15, step: 1, label: "Number of Bins:" })
```
Output
Reactive Boxplot with iris Dataset
This interactive boxplot allows users to select iris species and a measure to display.
Steps:
- Create an R function taking reactive inputs as arguments
- Export the function as an OJS variable
dashboard.qmd
```{webr}
#| edit: false
#| output: false
#| define:
#| - do_reactive_boxplot
library(ggplot2)
library(dplyr)
do_reactive_boxplot <- function(selected_species, measure) {
# Filter the iris dataset based on selected species
filtered_iris <- iris %>% filter(Species %in% selected_species)
# Create an interactive boxplot using the chosen measure
p <- ggplot(filtered_iris, aes(x = Species, y = .data[[measure]], fill = Species)) +
geom_boxplot() +
labs(title = paste("Boxplot of", measure, "by Species"),
x = "Species",
y = measure) +
theme_minimal()
print(p)
}
```
Next, create OJS reactive inputs for species and measure selection to invoke the exported function do_reactive_boxplot()
.
dashboard.qmd
```{ojs}
//| echo: false
viewof species = Inputs.checkbox(
["setosa", "versicolor", "virginica"],
{ value: ["setosa", "versicolor", "virginica"], label: "Select Iris Species:" }
);
viewof measures = Inputs.select(
["Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"],
{ label: "Select Measure:" }
);
do_reactive_boxplot(species, measures);
```
Output
As you adjust the selections in the OJS widgets, the boxplot updates automatically.
5. Best Practices for Reactive Documents
Separate Static from Live Code:
Pre-render heavy computations and export them as OJS variables to keep live code lightweight.Minimize Data Payload:
Export only necessary data to ensure fast load times.Test Interactivity:
Validate that changes in OJS inputs correctly trigger updates in your interactive cells.Monitor Console Logs:
Check browser developer tools for errors or warnings during the initial load.
Further Reading
- Interactive Code Blocks Explained
Dive into how interactive code blocks work in Quarto Live. - Loading and Using Packages
Learn techniques for managing and installing packages. - Managing Execution Environments
Discover methods for controlling variable sharing and isolation. - Cell Options Reference
Explore advanced configuration options for interactive code blocks.
Conclusion
By leveraging OJS variables, you can blend pre-rendered data with live, reactive code to create highly dynamic interactive documents. These techniques—demonstrated through examples like interactive histograms and boxplots—allow you to optimize performance while delivering rich, real-time interactivity. Experiment with these approaches to build engaging, responsive documents with Quarto Live and WebAssembly.
Explore More Articles
Here are more articles from the same category to help you dive deeper into the topic.
Reuse
Citation
@online{kassambara2025,
author = {Kassambara, Alboukadel},
title = {Reactivity in {Interactive} {Documents}},
date = {2025-03-21},
url = {https://www.datanovia.com/learn/interactive/advanced/reactivity.html},
langid = {en}
}