library(thematic) knitr::opts_chunk$set( message = FALSE, collapse = TRUE, comment = "#>", out.width = "70%", fig.align = 'center', fig.width = 6, fig.asp = 0.618, # 1 / phi fig.show = "hold" ) include_vimeo <- function(id, width = "100%", height = "400") { url <- sprintf("https://player.vimeo.com/video/%s?title=0&byline=0&portrait=0", id) htmltools::tags$iframe( src = url, width = width, height = height, frameborder = "0", seamless = "seamless", webkitAllowFullScreen = NA, mozallowfullscreen = NA, allowFullScreen = NA ) }
The most magical aspect of thematic is its auto theming capabilities, which gives R plots to ability to style themselves in Shiny (via CSS), R Markdown (via bslib), and RStudio (via RStudio themes). To gain a sense for how auto theming works, it's recommended you read through the next section, which walks through several variants on a basic Shiny app, and demonstrates how auto theming makes R plots responsive to changes in CSS styling. Also, as discussed in other scenarios, it possible to configure the information thematic uses for auto theming, but you can also opt-out of auto theming by providing desired colors and fonts to thematic (as discussed on custom themes).
One frustrating thing about styling Shiny apps is that R plots know nothing about CSS. That means, if you write custom CSS to style the app, you'll likely also want to translate those same styles to the R graphics. You may have never noticed this problem before if you just use the default styles in both systems because they're quite similar. Here's the default styles in a Shiny app with a few R plots inside a tabsetPanel()
:
library(shiny) library(ggplot2) tabs <- tabsetPanel(type = "pills", tabPanel("ggplot", plotOutput("ggplot")), tabPanel("lattice", plotOutput("lattice")), tabPanel("base", plotOutput("base")) ) ui <- fluidPage(tabs) server <- function(input, output) { output$ggplot <- renderPlot({ ggplot(mtcars, aes(wt, mpg, label = rownames(mtcars), color = factor(cyl))) + geom_point() + ggrepel::geom_text_repel() }) output$lattice <- renderPlot({ lattice::show.settings() }) output$base <- renderPlot({ image(volcano, col = thematic_get_option("sequential")) }) } shinyApp(ui, server)
knitr::include_graphics("tabsets.svg")
By bringing in a new set of CSS rules, say the darkly shinytheme, the difference in CSS vs R styles becomes much more apparent:
ui <- fluidPage( tabs, theme = shinythemes::shinytheme("darkly") ) shinyApp(ui, server)
knitr::include_graphics("tabsets-darkly.png")
By activating thematic auto coloring (as shown below), R plot(s) generated by the Shiny app gain new color defaults based on the surrounding CSS styles. This works because, at plot time, thematic grabs CSS styles from the plot(s) HTML container (via shiny::getCurrentOutputInfo()
)[^1] and uses that info to set new R styling defaults.
[^1]: If you're a shiny developer and wish to add similar auto theming capabilities to a custom output, you can add a .shiny-report-theme
class to the output container to obtain styles via getCurrentOutputInfo()
. And similarly, if you're an htmlwidgets developer, you can just set reportTheme = TRUE
in htmlwidgets::shinyWidgetOutput()
.
thematic_shiny() shinyApp(ui, server)
knitr::include_graphics("tabsets-darkly-thematic.png")
From the ggplot2 example above, we can see thematic_shiny()
has done the following for us:
ggplot2::theme()
-ing defaults based on the background and foreground colors (as well as appropriate mixtures of these colors for the panel background).scale_color_discrete()
(and scale_fill_discrete()
).Now, if we change our tabsetPanel()
from type="pills"
to type="tabs"
and look at a couple other ggplot2 examples, we can see that thematic_shiny()
does a few more things:
geom_*()
defaults using the new foreground (in this case, geom_point()
's color
) and accent color (in this case, geom_smooth()
's color).type="tabs"
the same as hyperlinks, but type="pills"
is colored differently.knitr::include_graphics("tabsets-geom-smooth.png")
Also:
scale_fill_continuous()
(and scale_color_continuous()
).knitr::include_graphics("tabsets-geom-raster.png")
As you'll learn in the custom themes article, you can always override the defaults set by thematic by using plot-specific code (i.e., by adding theme()
elements to the plot). However, if you want to use a different complete ggplot2 theme (e.g., theme_minimal()
instead of the default theme_gray()
), you should set the theme globally with ggplot2::theme_set()
.
ggplot2::theme_set(ggplot2::theme_minimal()) thematic_shiny() shinyApp(ui, server)
knitr::include_graphics("tabsets-darkly-thematic-minimal.png")
Since thematic knows the CSS rules on the plot's HTML container, auto theming works regardless of how the HTML is actually styled. That said, consider using the new bslib package to theme your Shiny apps (and R Markdown docs). It provides a rich set of tools for influencing Bootstrap CSS from R, including convenience functions for setting the main colors and fonts:
library(bslib) solar_theme <- bs_theme( bg = "#002B36", fg = "#EEE8D5", primary = "#2AA198", base_font = font_google("Pacifico") ) ui <- fluidPage(theme = solar_theme, tabs) thematic_shiny() shinyApp(ui, server)
knitr::include_graphics("tabsets-custom.png")
As shown in the image above, text rendered by the browser (i.e., tabsetPanel()
's titles) now uses the Pacifico font, but the R plots are still using the default font because, by default, thematic_shiny()
only enables automatic colors. To enable auto fonts, set font = "auto"
; and when doing so, make sure the font to be rendered is either a font already supported by R, or is Google Font and the showtext package is installed (learn more in the fonts article).
library(showtext) thematic_shiny(font = "auto") shinyApp(ui, server)
knitr::include_graphics("tabsets-custom-fonts.png")
knitr::include_graphics("tabsets-custom-fonts-lattice.png")
thematic also works great with bslib's realtime theming widget. This interactive widget influences the CSS on the page, so as long as thematic's auto theming enabled, those CSS changes automatically influence the R plot styling. Note how here we still have both auto fonts and colors, which means that as long as we choose Google Fonts (and/or fonts already known to R), the R plots can automatically render them.
bs_theme_preview(bs_theme(bg = "#444444", fg = "#E4E4E4", primary = "#E39777"))
include_vimeo("465527125")
Auto theming can also work with rmarkdown::html_document()
. The main catch is that, if R plots are not generated via Shiny, then any custom styling must be done via the bslib package in order for thematic to know about it. In the example below, we set a custom background, foreground, and accent color via bslib; then use thematic_rmd()
to apply automatic coloring to every R plot generated in the R Markdown document.
knitr::include_graphics("html-document.svg")
Auto theming doesn't necessarily work for non-HTML output formats. In that case, provide the document's colors and fonts either directly to thematic_rmd()
or to auto_config()
. To learn more about various options for
knitr::include_graphics("tufte.svg")
Here's a ggplot2 plot inside the RStudio IDE before thematic is enabled. Note the colors in the IDE are based on the Tomorrow Night 80s RStudio Theme and the editor's font is FiraCode.
knitr::include_graphics("r_studio.png")
After calling thematic_on(font = "Fira Sans Condensed")
to enable automatic colors and request the Fira Sans Condensed Google Font, the colors in the Plots viewer pane now match the RStudio theme[^2], and the fonts nicely complement the editor's font.
knitr::include_graphics("rstudio-thematic.png")
By the way, rendering of Google Fonts in RStudio requires a special setup that's discussed in the fonts article.
[^2]: Auto detection of background and foreground should always work in RStudio, but accent='auto'
is currently limited to non-custom RStudio themes. Moreover, font='auto'
is fully supported on RStudio Server Pro (1.4 or higher), but may not work on RStudio Desktop.
As the R Markdown section already eluded to (in reference to non-HTML output formats), thematic's auto theming won't know what styles to use in every scenario. In these scenarios, you have the following options:
'auto'
values entirely by providing the desired colors and fonts directly to thematic_on()
. The next article, Custom Themes, discusses this option in depth.auto_config()
and auto_config_set()
to set "fallbacks" for 'auto'
values. For example:library(ggplot2) library(thematic)
config <- auto_config(bg = "black", fg = "white", accent = "purple") auto_config_set(config) thematic_on() ggplot(faithfuld, aes(waiting, eruptions)) + geom_raster(aes(fill = density))
The main use case for auto_config()
is for developers of a custom rmarkdown output document that wish to provide an auto theming experience for users of the document (see auto_config()
for more details). However, there may also be scenarios where more control over the set and priority of information that auto_resolve_theme()
uses to resolve 'auto'
values. This can be done via the priority
argument of auto_config()
. The default priority
is:
shiny::getCurrentOutputInfo()
("shiny"
)auto_config_get()
("config"
)bslib::bs_get_variables()
("bslib"
)rstudioapi::getThemeInfo()
("rstudio"
)thematic_off()
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.