+ - 0:00:00
Notes for current slide
Notes for next slide

Shiny v1.6 preview: improvements to caching and theming

Carson Sievert, Software Engineer @ RStudio

Slides: https://bit.ly/jj-shiny-2020

@cpsievert

@cpsievert

cpsievert.me

cpsievert1@gmail.com

1 / 41

Shiny v1.6 major features

  • New shiny::bindCache() function

    • Persistent caching for any reactive() or render*() function
  • Improved theming support

    • All of Shiny may now be (properly) themed via new {bslib} & {thematic} packages
  • Accessibility improvements and many bug fixes

Try v1.6 out today with:

remotes::install_github("rstudio/shiny")
2 / 41

Shiny v1.6 major features

  • New shiny::bindCache() function

    • Persistent caching for any reactive() or render*() function
  • Improved theming support

    • All of Shiny may now be (properly) themed via new {bslib} & {thematic} packages
  • Accessibility improvements and many bug fixes

Try v1.6 out today with:

remotes::install_github("rstudio/shiny")
3 / 41

A minimal example

library(shiny)
ui <- fluidPage(
sliderInput("x", "x", 0, 10, 5),
sliderInput("y", "y", 0, 10, 5),
verbatimTextOutput("val")
)
server <- function(input, output) {
r <- reactive({
Sys.sleep(2)
input$x + input$y
})
output$val <- renderPrint(r())
}
shinyApp(ui, server)

  • Everytime x or y changes, r() re-executes.
4 / 41

A minimal example

library(shiny)
ui <- fluidPage(
sliderInput("x", "x", 0, 10, 5),
sliderInput("y", "y", 0, 10, 5),
verbatimTextOutput("val")
)
server <- function(input, output) {
r <- reactive({
Sys.sleep(2)
input$x + input$y
})
output$val <- renderPrint(r())
}
shinyApp(ui, server)

  • Everytime x or y changes, r() re-executes.
  • r() can recall its most recent value (transient), but not its entire history (persistent)
5 / 41

bindCache(): persistent caching!

library(shiny)
ui <- fluidPage(
sliderInput("x", "x", 0, 10, 5),
sliderInput("y", "y", 0, 10, 5),
verbatimTextOutput("val")
)
server <- function(input, output) {
r <- reactive({
Sys.sleep(2)
input$x + input$y
}) %>%
bindCache(input$x, input$y)
output$val <- renderPrint(r())
}
shinyApp(ui, server)

  • Provide bindCache() a reactive and its input value(s).
6 / 41

bindCache(): persistent caching!

library(shiny)
ui <- fluidPage(
sliderInput("x", "x", 0, 10, 5),
sliderInput("y", "y", 0, 10, 5),
verbatimTextOutput("val")
)
server <- function(input, output) {
r <- reactive({
Sys.sleep(2)
input$x + input$y
}) %>%
bindCache(input$x, input$y)
output$val <- renderPrint(r())
}
shinyApp(ui, server)

  • Provide bindCache() a reactive and its input value(s).
  • r() can now retrieve x+y from cache! 🎉
7 / 41

bindCache(): persistent caching!

library(shiny)
ui <- fluidPage(
sliderInput("x", "x", 0, 10, 5),
sliderInput("y", "y", 0, 10, 5),
verbatimTextOutput("val")
)
server <- function(input, output) {
r <- reactive({
Sys.sleep(2)
input$x + input$y
}) %>%
bindCache(input$x, input$y)
output$val <- renderPrint(r())
}
shinyApp(ui, server)

  • Provide bindCache() a reactive and its input value(s).
  • r() can now retrieve x+y from cache! 🎉
  • Cache is configurable & can be shared across sessions (see ?bindCache)
    • Can vastly improve performance, especially in multi-user settings!
8 / 41

bindCache() also works with render functions

# requires dev version of plotly
# remotes::install_github("ropensci/plotly")
library(plotly)
ui <- fluidPage(
selectizeInput(
"cities", "Select a city",
choices = unique(txhousing$city)
),
plotlyOutput("p")
)
server <- function(input, output, ...) {
output$p <- renderPlotly({
Sys.sleep(2)
plot_ly(txhousing, x = ~date, y = ~median) %>%
filter(city %in% input$cities) %>%
group_by(city) %>%
add_lines()
}) %>%
bindCache(input$cities)
}
shinyApp(ui, server)

Some custom output bindings may need updating to cache correctly (see ?bindCache). Let us know if you run into issues!

9 / 41

Shiny v1.6 major features

  • New shiny::bindCache() function

    • Persistent caching for any reactive() or render*() function
  • Improved theming support

    • All of Shiny may now be (properly) themed via new {bslib} & {thematic} packages
  • Accessibility improvements and many bug fixes

Try v1.6 out today with:

remotes::install_github("rstudio/shiny")
10 / 41

New R 📦s for theming Shiny & R Markdown

{bslib}: tools for customizing Bootstrap CSS from R

{thematic}: simplified theming of R plots ({ggplot2}, {lattice}, & {base})

Also not yet on CRAN

remotes::install_github(c("rstudio/bslib", "rstudio/thematic"))
11 / 41

Start using {bslib} with Shiny

library(shiny)
library(bslib)
ui <- fluidPage(
theme = bs_theme(),
...
)
  • fluidPage(), navbarPage(), bootstrapPage(), etc. all have this theme argument.

  • You may already be using theme with {shinythemes} or your own custom Bootstrap CSS.

    • bs_theme() is way more powerful!
12 / 41

By default, upgrades app from Bootstrap 3 to 4

library(shiny)
library(bslib)
ui <- fluidPage(
theme = bs_theme(version = 4),
...
)
  • Special compatibility layer helps most Shiny apps & R Markdown docs upgrade to Bootstrap 4.

  • Upgrading may break some apps (try version = 3 in that case).

13 / 41

Continue using Bootswatch themes

library(shiny)
library(bslib)
# In the past, this was shinythemes::shinythemes("darkly")
ui <- fluidPage(
theme = bs_theme(bootswatch = "darkly"),
...
)
  • Now you can use Bootswatch with BS4 or BS3 (just change version).
    • Bootswatch 4 has some new themes (e.g., solar and minty)
14 / 41

Preview a theme

bs_theme_preview(
bs_theme(bootswatch = "darkly")
)

15 / 41

Create your own theme!

bs_theme(
bg = "black", fg = "white", primary = "red",
base_font = font_google("Grandstander")
)

16 / 41

font_google() makes it easy to import Google Font files

bs_theme(
bg = "black", fg = "white", primary = "red",
base_font = font_google("Grandstander")
)

17 / 41

All Shiny UI is now (properly) themable!

bs_theme(
bg = "black", fg = "white", primary = "red",
base_font = font_google("Grandstander")
)

18 / 41

Use a better palette (e.g., material dark)

bs_theme(
bg = "#202123", fg = "#B8BCC2", primary = "#EA80FC",
base_font = font_google("Grandstander")
)

19 / 41

Use with rmarkdown::html_document

---
output:
html_document:
theme:
bg: "#202123"
fg: "#B8BCC2"
primary: "#EA80FC"
base_font: !expr bslib::font_google("Grandstander")
---

Currently requires an experimental version of R Markdown remotes::install_github("rstudio/rmarkdown#1706")

20 / 41

Not everything is themable, but it's getting better!

  • Currently themable (in next CRAN release):

    • The {shiny} package

    • rmarkdown::html_document() and DT::datatable()

    • Any "Bootstrap compatible" HTML/CSS

21 / 41

Not everything is themable, but it's getting better!

  • Currently themable (in next CRAN release):

    • The {shiny} package

    • rmarkdown::html_document() and DT::datatable()

    • Any "Bootstrap compatible" HTML/CSS

  • Soon to be themable (we'd love your help!):

    • Other HTML-based R Markdown output formats

    • Other {htmlwidgets} packages (e.g., {plotly}, {reactable}, etc)

    • Other extension packages (e.g., {shinyWidgets}, etc)

22 / 41

Not everything is themable, but it's getting better!

  • Currently themable (in next CRAN release):

    • The {shiny} package

    • rmarkdown::html_document() and DT::datatable()

    • Any "Bootstrap compatible" HTML/CSS

  • Soon to be themable (we'd love your help!):

    • Other HTML-based R Markdown output formats

    • Other {htmlwidgets} packages (e.g., {plotly}, {reactable}, etc)

    • Other extension packages (e.g., {shinyWidgets}, etc)

  • Fundamentally un-themable via CSS:

    • plotOutput(): use {thematic} to "translate" CSS to R plots!
23 / 41

Plots don't reflect bs_theme() 😭

fluidPage(
theme = bs_theme(bg = "#002B36", fg = "#EEE8D5", primary = "#2AA198", base_fonts = font_google(("Pacifico")),
tabsetPanel(type = "pills", tabPanel("ggplot", plotOutput("ggplot")), tabPanel("lattice", plotOutput("lattice")), tabPanel("base", plotOutput("base")))
)

24 / 41

{thematic} to the rescue! 🎉

thematic::thematic_shiny()
fluidPage(
theme = bs_theme(bg = "#002B36", fg = "#EEE8D5", primary = "#2AA198", base_fonts = font_google("Pacifico")),
tabsetPanel(type = "pills", tabPanel("ggplot", plotOutput("ggplot")), tabPanel("lattice", plotOutput("lattice")), tabPanel("base", plotOutput("base")))
)

25 / 41

The {thematic} package, in general

  • {thematic} alters R plotting defaults using a few simple settings. Use thematic_on() to enable globally (until thematic_off() is called).
library(thematic)
library(ggplot2)
thematic_on(
bg = "black",
fg = "white",
accent = "red",
font = "Indie Flower"
)
ggplot(mtcars, aes(wt, mpg)) +
geom_point() +
geom_smooth()

26 / 41

The {thematic} package, in general

  • {thematic} alters R plotting defaults using a few simple settings. Use thematic_on() to enable globally (until thematic_off() is called).
library(thematic)
library(ggplot2)
thematic_on(
bg = "black",
fg = "white",
accent = "red",
font = "Indie Flower"
)
ggplot(mtcars, aes(wt, mpg)) +
geom_point() +
geom_smooth()

Since Indie Flower is a Google Font, {thematic} installs it if needed!

27 / 41

Auto-theming with {thematic}

  • Main colors and fonts can be "auto"-detected!
library(thematic)
library(ggplot2)
thematic_on(
bg = "auto",
fg = "auto",
accent = "auto",
font = "auto"
)
ggplot(mtcars, aes(wt, mpg)) +
geom_point() +
geom_smooth()

28 / 41

Auto-theming with {thematic}

  • Main colors and fonts can be "auto"-detected!
library(thematic)
library(ggplot2)
thematic_on(
bg = "auto",
fg = "auto",
accent = "auto",
font = "auto"
)
ggplot(mtcars, aes(wt, mpg)) +
geom_point() +
geom_smooth()

"auto" works best via shiny::renderPlot() (works with any CSS, not just bs_theme())!

29 / 41

Auto-theming with {thematic}

  • Main colors and fonts can be "auto"-detected!
library(thematic)
library(ggplot2)
thematic_on(
bg = "auto",
fg = "auto",
accent = "auto",
font = "auto"
)
ggplot(mtcars, aes(wt, mpg)) +
geom_point() +
geom_smooth()

"auto" can work with {bslib} in rmarkdown::html_document()

30 / 41

Auto-theming with {thematic}

  • Main colors and fonts can be "auto"-detected!
library(thematic)
library(ggplot2)
thematic_on(
bg = "auto",
fg = "auto",
accent = "auto",
font = "auto"
)
ggplot(mtcars, aes(wt, mpg)) +
geom_point() +
geom_smooth()

"auto" detects your RStudio Theme inside RStudio

31 / 41

Demo

bs_theme_preview() overlays a real-time theming widget, let's see it action!

32 / 41

Use real-time theming w/ any Shiny app

Call bs_themer() in the server code (also works with a runtime: shiny R Markdown doc)

33 / 41

Implement your own theming widgets w/ setCurrentTheme()

ui <- fluidPage(
theme = bs_theme(),
checkboxInput("dark_mode", "Dark mode", FALSE)
)
server <- function(input, output, session) {
observe(session$setCurrentTheme({
if (input$dark_mode) {
bs_theme(bg = "black", fg = "white", primary = "purple")
} else {
bs_theme()
}
}))
}
shinyApp(ui, server)

34 / 41

More targetted theming

Main colors (e.g., bg, fg, etc) "cascade" to 100s of other settings, all of which can be set via Bootstrap Sass variables (e.g., $progress-bar-bg)

bs_theme(
bg = "#002B36", fg = "#EEE8D5",
"progress-bar-bg" = "orange"
)

35 / 41

What's a Sass variable?

  • Sass is a more powerful way to write CSS (i.e., style HTML)
  • Sass variables provide "high-level controls" over CSS
  • bs_theme() works by overriding Bootstrap Sass variable defaults.

Learn more about Sass and the {sass} 📦 at https://rstudio.github.io/sass

36 / 41

Leverage the power of Bootstrap 4

Customize spacing, borders, modify colors, and more!

tabsetPanel(
tabPanel("One", "No padding"),
tabPanel("Two", "No padding")
)

tabsetPanel(
tabPanel(
"One", "With padding",
class = "p-3 border border-top-0 rounded-bottom"
),
tabPanel("Two", "No padding")
)

37 / 41

Leverage the power of Sass

Add Sass rules to do things like @extend all navs to be centered

fluidPage(
theme = bs_theme() %>%
bs_add_rules(".nav { @extend .justify-content-center; }"),
tabsetPanel(
tabPanel("One", "Centered w/ padding", class = "p-3 border border-top-0 rounded-bottom"),
tabPanel("Two", "No padding")
)
)

38 / 41

Create custom, themable, components

person <- function(name, title, company) {
div(
class = "person",
h3(class = "name", name),
div(class = "title", title),
div(class = "company", company)
)
}
fluidPage(
person("Andrew Carnegie", "Owner", "Carnegie Steel Company"),
person("John D. Rockefeller", "Chairman", "Standard Oil"),
theme = bs_theme(bg = "#002B36", fg = "#EEE8D5") %>%
bs_add_rules(sass::sass_file("person.scss"))
)
.person {
display: inline-block;
padding: $spacer;
border: $border-width solid $border-color;
@include border-radius;
@include box-shadow;
outline: 0;
width: 300px;
@include media-breakpoint-down(sm) {
display: block;
width: auto;
margin-right: $grid-gutter-width;
}
margin: $grid-gutter-width;
margin-right: 0;
.title { font-weight: bold; }
.title, .company { color: $gray-600; }
}
.person:last-of-type {
margin-right: $grid-gutter-width;
}
39 / 41

In summary

  • Use shiny::bindCache() to persistently cache reactive expressions

    • See ?bindCache for more details
  • Use bslib::bs_theme() to theme Shiny & R Markdown.

    • Upgrades to Bootstrap 4 by default (can also version = 3).

    • Use Bootswatch and/or design your own custom themes.

    • Use bs_theme_preview()/bs_themer() to quickly preview and update themes.

  • Use {thematic} for easier theming of R plots

    • Works with {ggplot2}, plotly::ggplotly(), {lattice}, and {base} R graphics.

    • Auto-theming (i.e., translating CSS to R defaults) works great on Shiny, but can also specify colors and fonts directly in {thematic}.

40 / 41

Shiny v1.6 major features

  • New shiny::bindCache() function

    • Persistent caching for any reactive() or render*() function
  • Improved theming support

    • All of Shiny may now be (properly) themed via new {bslib} & {thematic} packages
  • Accessibility improvements and many bug fixes

Try v1.6 out today with:

remotes::install_github("rstudio/shiny")
2 / 41
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow