As we’ve learned in previous articles, thematic_on()
works by modifying global state (i.e., it changes global
par()
, palette()
,
ggplot2::theme_set()
, and various other settings). This
makes it simple to start using thematic everywhere, but
it comes at the cost of possibly introducing unwanted side-effects in
other R code. thematic_shiny()
and
thematic_rmd()
essentially solve this problem by
automatically cleaning up after themselves in an Shiny and R Markdown
context, but more generally, you might want lower-level tools for
scoping thematic themes to a particular context.
The recommended way to apply a thematic theme to a
single plot is to use thematic_with_theme()
. This requires
a thematic_theme()
object, which has the same arguments as
thematic_on()
, but just creates a theme object without
activating it.
library(ggplot2)
theme_purple <- thematic_theme("black", "white", accent = "purple")
ggsmooth <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + geom_smooth()
ggsmooth
thematic_with_theme(theme_purple, ggsmooth)
thematic_with_theme()
is particularly useful for use
inside a shiny app where you might want to only apply
thematic to specific plots and/or use different themes
for different plots:
library(shiny)
library(thematic)
purple <- thematic_theme(accent = "purple")
orange <- thematic_theme(accent = "orange")
ui <- fluidPage(
theme = shinythemes::shinytheme("darkly"),
plotOutput("purple"),
plotOutput("orange")
)
server <- function(input, output, session) {
output$purple <- renderPlot({
thematic_with_theme(purple, {
ggplot(faithfuld, aes(waiting, eruptions)) +
geom_raster(aes(fill = density))
})
})
output$orange <- renderPlot({
thematic_with_theme(orange, {
ggplot(faithfuld, aes(waiting, eruptions)) +
geom_raster(aes(fill = density))
})
})
}
shinyApp(ui, server)
If you find it annoying to supply both the
thematic_theme()
and the plot expr
to the same
function call, you can also use thematic_local_theme()
,
which cleans up after itself when R exits the current execution
environment. The one catch is that, in this case, you currently have to
print()
ggplot2 and
lattice objects. By the way, if your interesting in
learning more about how thematic_local_theme()
actually
works, and where else it might be useful (unit tests!), check out this
blog post by Jenny Bryan.
p <- ggplot(faithfuld, aes(waiting, eruptions)) +
geom_raster(aes(fill = density))
server <- function(input, output, session) {
output$purple <- renderPlot({
thematic_local_theme(purple)
print(p)
})
output$orange <- renderPlot({
thematic_local_theme(orange)
print(p)
})
}
shinyApp(ui, server)
To apply thematic to several plots at a time,
consider using thematic_on()
to modify state and
thematic_set_theme()
to restore state. Since
thematic_on()
returns a theme object that represents the
previously set theme (and, if none, returns NULL
), we can
use a pattern like this to set a theme for two plots, then restore the
previous theme:
old_theme <- thematic_on("black", "white", accent = NA)
plot(1:10)
qplot(1:10)
#> Warning: `qplot()` was deprecated in ggplot2 3.4.0.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
#> generated.
# equivalent of thematic_off() if old_theme is NULL
thematic_set_theme(old_theme)
plot(1:10)
When writing your own functions, this pattern useful in conjunction
with on.exit()
to temporarily apply a theme in such a way
that, even if the function errors out, the previous state is still
restored.
my_plot_function <- function(...) {
old_theme <- thematic_on("black", "white")
on.exit(thematic_set_theme(old_theme), add = TRUE)
# do stuff with ...
}