webr::install("ggplot2")
webr::install("htmltools") #<- only needed to use SVG images 2 shiny(live)!
The Quarto doc will contain the shiny app using a code chunk. The type of code chunk should be {shinylive-r} (as opposed to {r}).
2.1 yml options
The main requirement for the code chunk yml is the option standalone: true.
For my application, I used the options:
```{shinylive-r}
#| label: fig-shiny-spline
#| viewerHeight: 500
#| standalone: trueThe label doesn’t make it a figure as it normally would but see the section below for details regarding this (and details like captions, etc.).
The standard fig-height (and width) options don’t apply to shiny apps; viewerHeight is used instead.
You also have to add a Quarto filter in your _quarto.yml file:
filters:
- shinyliveThere is a bit more to say about formatting the chunk for Quarto but we’ll show that later.
2.2 Package declarations
In our chunk that contains the shiny app (i.e., fig-shiny-spline in this example), let’s make sure to install packages that we need (besides shiny):
The base installation of webR includes its own webr utility package, so don’t worry about installing that.
2.3 User-interface function
The UI function is very simple and has no extra accouterments for shinylive
ui <- fluidPage(
fluidRow(
column(8,
sliderInput(
"deg_free",
label = "Spline degrees of freedom:",
min = 3L, value = 3L, max = 8L, step = 1L
)
),
imageOutput("spline_contours", height = "400px")
)
)2.4 The server function
This is where most of the customization happens.
server <- function(input, output, session) {
# ------------------------------------------------------------------------
# Input data from remote locations on GitHub
1 pred_path <-
paste(
"https://raw.githubusercontent.com",
"topepo", "shinylive-in-book-test",
"main", "predicted_values.RData",
sep = "/"
)
data_path <-
paste(
"https://raw.githubusercontent.com",
"topepo", "shinylive-in-book-test",
"main", "sim_val.RData",
sep = "/"
)
2 rdata_file <- tempfile()
download.file(pred_path, destfile = rdata_file)
load(rdata_file)
download.file(data_path, destfile = rdata_file)
load(rdata_file)
# Set some ranges for the plot
rngs <- list(A = c(-3.3, 3.3), B = c(-4.4, 4.4))
output$spline_contours <-
renderImage({
preds <- predicted_values[predicted_values$deg_free == input$deg_free,]
p <-
ggplot(preds, aes(A, B)) +
# Plot the validation set
geom_point(
data = sim_val,
aes(col = class, pch = class),
alpha = 1 / 2,
cex = 3
) +
# Show the class boundary
geom_contour(
aes(z = .pred_one),
breaks = 1 / 2,
linewidth = 3 / 2,
col = "black"
) +
# Formatting
lims(x = rngs$A, y = rngs$B) +
theme_bw() +
theme(legend.position = "top")
3 file <-
htmltools::capturePlot(
print(p),
tempfile(fileext = ".svg"),
grDevices::svg,
width = 4,
height = 4
)
list(src = file)
},
4 deleteFile = TRUE)
}
app <- shinyApp(ui = ui, server = server)- 1
- This block sets up URLs pointing to the GitHub raw objects.
- 2
- Both data sets are downloaded to a temporary file and loaded into the session.
- 3
- Code allowing us to save the visualization as an SVG image. This is an aesthetic choice and unrelated to the point of this repo.
- 4
- Clean up the SVG file passed between the server and UI.
2.5 The results
Our beautiful shiny app!
#| label: fig-shiny-spline
#| viewerHeight: 505
#| standalone: true
webr::install("ggplot2")
webr::install("htmltools")
library(ggplot2)
library(htmltools)
ui <- fluidPage(
fluidRow(
column(8,
sliderInput(
"deg_free",
label = "Spline degrees of freedom:",
min = 3L, value = 3L, max = 8L, step = 1L
)
),
imageOutput("spline_contours")
)
)
server <- function(input, output, session) {
# ------------------------------------------------------------------------
# Input data from remote locations on GitHub
pred_path <-
paste(
"https://raw.githubusercontent.com",
"topepo", "shinylive-in-book-test",
"main", "predicted_values.RData",
sep = "/"
)
data_path <-
paste(
"https://raw.githubusercontent.com",
"topepo", "shinylive-in-book-test",
"main", "sim_val.RData",
sep = "/"
)
rdata_file <- tempfile()
download.file(pred_path, destfile = rdata_file)
load(rdata_file)
download.file(data_path, destfile = rdata_file)
load(rdata_file)
# Set some ranges for the plot
rngs <- list(A = c(-3.3, 3.3), B = c(-4.4, 4.4))
output$spline_contours <-
renderImage({
preds <- predicted_values[predicted_values$deg_free == input$deg_free,]
p <-
ggplot(preds, aes(A, B)) +
# Plot the validation set
geom_point(
data = sim_val,
aes(col = class, pch = class),
alpha = 1 / 2,
cex = 3
) +
# Show the class boundary
geom_contour(
aes(z = .pred_one),
breaks = 1 / 2,
linewidth = 3 / 2,
col = "black"
) +
# Formatting
lims(x = rngs$A, y = rngs$B) +
theme_bw() +
theme(legend.position = "top")
file <-
htmltools::capturePlot(
print(p),
tempfile(fileext = ".svg"),
grDevices::svg,
width = 4,
height = 4
)
list(src = file)
},
deleteFile = TRUE)
}
app <- shinyApp(ui = ui, server = server)
A and B.
You can reference Figure 2.1 in the usual way (via @fig-shiny-spline).
2.6 Making the shiny app a figure
As previously mentioned, following the usual convention of using a fig- prefix for a chunk will not make the shiny app a figure. However, the 1.4 release of Quarto (pre-release version as of this writing) has a new feature to make anything a specific type of content (such as a figure).
We use the ::: syntax to declare the figure and any critical options. In my case above, this was
::: {#fig-shiny-spline}
::: {.figure-content}
```{shinylive-r}
#| label: fig-shiny-spline
#| viewerHeight: 500
#| standalone: true
<-- my shiny app code here-->
app <- shinyApp(ui = ui, server = server)
```
:::
A visualization of the class boundary for different numbers of degrees of
freedom for natural spline features in `A` and `B`.
:::You probably don’t have to use the same chunk name ({#fig-shiny-spline}) in two places; this is the more important place to specify it. I like having them the same.