| Title: | Unified Brand Styling for Shiny and ggplot2 |
|---|---|
| Description: | Provides a complete styling system driven by a single '_brand.yml' file. Create consistent Bootstrap themes for Shiny applications, ggplot2 visualizations, and interactive plotly charts with unified colors, fonts, and styling. All components automatically share your brand identity. |
| Authors: | Lukas Willocx [aut, cre] |
| Maintainer: | Lukas Willocx <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.0.0.9000 |
| Built: | 2026-06-07 06:56:28 UTC |
| Source: | https://github.com/LukasWillocx/luwitemplate |
Automatically loads and registers Google Fonts specified in the brand YAML when the package is loaded. This ensures fonts are available for ggplot2 themes without requiring manual setup.
.onLoad(libname, pkgname).onLoad(libname, pkgname)
libname |
Character string giving the library directory where the package was installed. |
pkgname |
Character string giving the name of the package. |
NULL (invisibly). Called for side effects (font registration).
Generates a tags$style() block that overrides compiled colors in
third-party widget stylesheets (bootstrap-datepicker, Shiny input
containers) that load separately from the bslib theme. Place this in
your UI to ensure these widgets respect dark mode.
dark_mode_css()dark_mode_css()
Some Shiny widgets (datepicker, checkboxes, radios) load their own CSS
files independently of bslib. These files contain compiled hex values
that cannot be overridden from within the bslib theme. This function
injects a <style> tag into the page head that loads after all
widget CSS, ensuring the dark palette takes effect.
A shiny::tags$head() element to include in your UI
## Not run: ui <- page_sidebar( theme = my_theme(), dark_mode_css(), input_dark_mode(id = "dark_mode"), sidebar = sidebar( dateRangeInput("dates", "Date Range:"), checkboxInput("flag", "Show details") ) ) ## End(Not run)## Not run: ui <- page_sidebar( theme = my_theme(), dark_mode_css(), input_dark_mode(id = "dark_mode"), sidebar = sidebar( dateRangeInput("dates", "Date Range:"), checkboxInput("flag", "Show details") ) ) ## End(Not run)
Retrieves all theme color variables as an R-friendly named list. Useful for programmatically accessing your brand colors or building custom palettes.
get_theme_colors(theme = my_theme())get_theme_colors(theme = my_theme())
theme |
A bslib theme object (defaults to my_theme()) |
Color names are converted from CSS variable format (hyphenated) to R-friendly format (underscored). For example, "body-bg" becomes "body_bg".
Named list of hex color values with underscore-separated names:
primary, secondary, success, danger, warning, info, light,
dark, body_bg, body_color, input_border_color
scale_color_luwi_discrete(), scale_color_luwi_sequential(),
scale_color_luwi_diverging() for ready-to-use palettes
# Get all theme colors colors <- get_theme_colors() colors$primary # Your brand primary color # Use in custom visualizations plot(1:10, col = colors$primary, pch = 19) # Build a custom gradient my_gradient <- colorRampPalette(c(colors$light, colors$primary))# Get all theme colors colors <- get_theme_colors() colors$primary # Your brand primary color # Use in custom visualizations plot(1:10, col = colors$primary, pch = 19) # Build a custom gradient my_gradient <- colorRampPalette(c(colors$light, colors$primary))
Retrieves font families defined in your _brand.yml file. Returns a structured list with primary and secondary fonts for easy programmatic access in plots and custom themes.
get_theme_fonts(theme = my_theme())get_theme_fonts(theme = my_theme())
theme |
A bslib theme object (defaults to my_theme()). |
This function reads the typography.fonts section from your package's
_brand.yml file directly. The first font listed becomes primary, the
second becomes secondary.
Expected _brand.yml structure:
typography:
fonts:
- family: "Open Sans"
source: google
- family: "Merriweather"
source: google
Named list with three elements:
primaryMain font family (used for body text, labels, etc.)
secondarySecondary font family if defined (often used for headings), or NULL
all_familiesCharacter vector of all font families defined in brand file
If _brand.yml is not found, returns fallback values with "sans" as primary font.
get_theme_colors() for extracting theme colors,
theme_luwi() to use these fonts in ggplot2 automatically
# Get font configuration fonts <- get_theme_fonts() fonts$primary # "Open Sans" fonts$secondary # "Merriweather" or NULL # Use in ggplot2 library(ggplot2) fonts <- get_theme_fonts() ggplot(mtcars, aes(mpg, wt)) + geom_point() + labs(title = "My Plot") + theme_minimal(base_family = fonts$primary) + theme( plot.title = element_text(family = fonts$secondary %||% fonts$primary) ) # Check what fonts are available fonts <- get_theme_fonts() cat("Available fonts:", paste(fonts$all_families, collapse = ", "))# Get font configuration fonts <- get_theme_fonts() fonts$primary # "Open Sans" fonts$secondary # "Merriweather" or NULL # Use in ggplot2 library(ggplot2) fonts <- get_theme_fonts() ggplot(mtcars, aes(mpg, wt)) + geom_point() + labs(title = "My Plot") + theme_minimal(base_family = fonts$primary) + theme( plot.title = element_text(family = fonts$secondary %||% fonts$primary) ) # Check what fonts are available fonts <- get_theme_fonts() cat("Available fonts:", paste(fonts$all_families, collapse = ", "))
Converts a ggplot object to an interactive plotly visualization with brand styling automatically applied. Designed specifically for Shiny dashboards with transparent backgrounds, custom fonts, and branded grid lines.
luwi_ggplotly(p, theme = my_theme(), base_size = 14, tooltip = "y")luwi_ggplotly(p, theme = my_theme(), base_size = 14, tooltip = "y")
p |
A ggplot2 object to convert |
theme |
A bslib theme object (defaults to my_theme()) |
base_size |
Base font size in points (default: 14) |
tooltip |
Which aesthetics to display on hover. Can be a character vector
of aesthetic names (e.g., |
A plotly htmlwidget ready for Shiny rendering
theme_luwi() for static ggplot version,
plotly::ggplotly() for underlying conversion function,
plotly::config() for additional plotly configuration
Other ggplot-themes:
theme_luwi()
library(ggplot2) library(plotly) # Basic interactive plot p <- ggplot(mtcars, aes(mpg, wt)) + geom_point() + labs(title = "Fuel Economy vs Weight") luwi_ggplotly(p) # Custom tooltips showing multiple values p <- ggplot(mtcars, aes(mpg, wt, color = factor(cyl))) + geom_point(size = 3) luwi_ggplotly(p, tooltip = c("x", "y", "color")) # In a Shiny app ## Not run: library(shiny) ui <- page_fluid( theme = my_theme(), plotlyOutput("plot") ) server <- function(input, output) { output$plot <- renderPlotly({ p <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) + geom_point() luwi_ggplotly(p, tooltip = c("x", "y", "color")) }) } shinyApp(ui, server) ## End(Not run) # Custom hover text p <- ggplot(mtcars, aes(mpg, wt, text = paste("Car:", rownames(mtcars)))) + geom_point() luwi_ggplotly(p, tooltip = "text")library(ggplot2) library(plotly) # Basic interactive plot p <- ggplot(mtcars, aes(mpg, wt)) + geom_point() + labs(title = "Fuel Economy vs Weight") luwi_ggplotly(p) # Custom tooltips showing multiple values p <- ggplot(mtcars, aes(mpg, wt, color = factor(cyl))) + geom_point(size = 3) luwi_ggplotly(p, tooltip = c("x", "y", "color")) # In a Shiny app ## Not run: library(shiny) ui <- page_fluid( theme = my_theme(), plotlyOutput("plot") ) server <- function(input, output) { output$plot <- renderPlotly({ p <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) + geom_point() luwi_ggplotly(p, tooltip = c("x", "y", "color")) }) } shinyApp(ui, server) ## End(Not run) # Custom hover text p <- ggplot(mtcars, aes(mpg, wt, text = paste("Car:", rownames(mtcars)))) + geom_point() luwi_ggplotly(p, tooltip = "text")
Generates a Bootstrap 5 theme from your _brand.yml file with optional custom CSS. This is the central theming function that powers all other styling in the package - use it in your Shiny UI to ensure consistent branding across your application.
my_theme(mode = c("light", "dark"))my_theme(mode = c("light", "dark"))
mode |
Character. Either |
This function:
Reads your package's _brand.yml file (colors, fonts, spacing)
Creates a Bootstrap 5 theme using bs_theme
If mode = "dark", overrides color variables with the
color-dark palette from the same YAML
Applies custom CSS from inst/css/custom.css if available
The returned theme object is used as the default in other package functions
like theme_luwi, get_theme_colors, and
luwi_ggplotly, ensuring consistent styling across Shiny UI,
static plots, and interactive visualizations.
A bslib::bs_theme() object ready to use in Shiny applications
Dark mode uses the color-dark section of _brand.yml to
override Bootstrap Sass variables. This ensures the full cascade of
derived variables (RGB decompositions, emphasis colors, subtle backgrounds)
is recomputed by the Sass compiler. Use use_dark_mode in
your Shiny server to enable reactive toggling.
bs_theme for the underlying theme constructor,
get_theme_colors to extract colors from the theme,
get_theme_fonts to extract fonts from the theme,
theme_luwi for ggplot2 theme using these colors/fonts,
use_dark_mode for Shiny dark mode integration
Other theme-generators:
use_dark_mode()
# Light theme (default) theme <- my_theme() # Dark theme dark_theme <- my_theme("dark") # Use in Shiny app library(shiny) library(bslib) ui <- page_fluid( theme = my_theme(), h1("My Branded App"), p("All Bootstrap components use your brand colors automatically") ) ## Not run: # App with dark mode toggle ui <- page_fluid( theme = my_theme(), input_dark_mode(id = "dark_mode"), plotOutput("my_plot") ) server <- function(input, output, session) { dm <- use_dark_mode(input, session) output$my_plot <- renderPlot({ ggplot(mtcars, aes(mpg, wt)) + geom_point() + theme_luwi(theme = dm$theme()) }) } shinyApp(ui, server) ## End(Not run)# Light theme (default) theme <- my_theme() # Dark theme dark_theme <- my_theme("dark") # Use in Shiny app library(shiny) library(bslib) ui <- page_fluid( theme = my_theme(), h1("My Branded App"), p("All Bootstrap components use your brand colors automatically") ) ## Not run: # App with dark mode toggle ui <- page_fluid( theme = my_theme(), input_dark_mode(id = "dark_mode"), plotOutput("my_plot") ) server <- function(input, output, session) { dm <- use_dark_mode(input, session) output$my_plot <- renderPlot({ ggplot(mtcars, aes(mpg, wt)) + geom_point() + theme_luwi(theme = dm$theme()) }) } shinyApp(ui, server) ## End(Not run)
Apply a sequential gradient color scale for continuous data with brand colors.
Convenience wrapper around scale_color_gradientn().
scale_color_luwi_c(type = "warm", theme = my_theme(), ...)scale_color_luwi_c(type = "warm", theme = my_theme(), ...)
type |
|
... |
Additional arguments passed to |
A ggplot2 scale object
scale_fill_luwi_c() for fill aesthetic,
scale_color_luwi_sequential() for the underlying palette,
scale_color_luwi_div() for diverging data
Other ggplot-scales:
scale_color_luwi_d(),
scale_color_luwi_div(),
scale_fill_luwi_c(),
scale_fill_luwi_d(),
scale_fill_luwi_div()
library(ggplot2) # Continuous color scale ggplot(faithfuld, aes(waiting, eruptions, color = density)) + geom_point() + scale_color_luwi_c(type = "warm") + theme_luwi() # Cool palette with custom limits ggplot(diamonds, aes(carat, price, color = depth)) + geom_point(alpha = 0.3) + scale_color_luwi_c(type = "cool", limits = c(55, 70)) + theme_luwi()library(ggplot2) # Continuous color scale ggplot(faithfuld, aes(waiting, eruptions, color = density)) + geom_point() + scale_color_luwi_c(type = "warm") + theme_luwi() # Cool palette with custom limits ggplot(diamonds, aes(carat, price, color = depth)) + geom_point(alpha = 0.3) + scale_color_luwi_c(type = "cool", limits = c(55, 70)) + theme_luwi()
Apply brand colors for categorical/discrete data. Convenience wrapper around
scale_color_manual() with up to 15 distinct brand colors.
scale_color_luwi_d(theme = my_theme(), ...)scale_color_luwi_d(theme = my_theme(), ...)
... |
Additional arguments passed to |
Supports up to 15 categories with carefully selected high-contrast colors. For more than 8 categories, consider grouping into "Other" or using a continuous scale instead.
A ggplot2 scale object
scale_fill_luwi_d() for fill aesthetic,
scale_color_luwi_discrete() for the underlying palette
Other ggplot-scales:
scale_color_luwi_c(),
scale_color_luwi_div(),
scale_fill_luwi_c(),
scale_fill_luwi_d(),
scale_fill_luwi_div()
library(ggplot2) # Categorical scatter plot ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) + geom_point(size = 3) + scale_color_luwi_d() + theme_luwi() # Line plot with multiple groups ggplot(economics_long, aes(date, value01, color = variable)) + geom_line() + scale_color_luwi_d() + theme_luwi()library(ggplot2) # Categorical scatter plot ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) + geom_point(size = 3) + scale_color_luwi_d() + theme_luwi() # Line plot with multiple groups ggplot(economics_long, aes(date, value01, color = variable)) + geom_line() + scale_color_luwi_d() + theme_luwi()
Provides up to 15 distinct, high-contrast colors for categorical variables like groups, categories, or factors. Colors are carefully selected to be visually distinguishable while maintaining your brand aesthetic.
scale_color_luwi_discrete(theme = my_theme(), n = NULL)scale_color_luwi_discrete(theme = my_theme(), n = NULL)
theme |
A bslib theme object (defaults to my_theme()) |
n |
Number of colors needed. If |
The palette prioritizes your brand colors (primary, secondary, success, etc.) for the first few categories, then adds complementary colors for additional categories.
Character vector of hex color codes (length = n or 15 if n is NULL)
ggplot2::scale_color_manual() and ggplot2::scale_fill_manual() to use with ggplot2,
scale_color_luwi_sequential() for many categories (converts to gradient)
Other color-palettes:
scale_color_luwi_diverging(),
scale_color_luwi_sequential()
library(ggplot2) # Basic categorical plot ggplot(mpg, aes(class, hwy, fill = class)) + geom_boxplot() + scale_fill_manual(values = scale_color_luwi_discrete()) # Specify exact number needed ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) + geom_point(size = 3) + scale_color_manual(values = scale_color_luwi_discrete(n = 3)) # Preview all 15 colors scales::show_col(scale_color_luwi_discrete()) # Warning example: too many categories scale_color_luwi_discrete(n = 20) # Returns 15 with warninglibrary(ggplot2) # Basic categorical plot ggplot(mpg, aes(class, hwy, fill = class)) + geom_boxplot() + scale_fill_manual(values = scale_color_luwi_discrete()) # Specify exact number needed ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) + geom_point(size = 3) + scale_color_manual(values = scale_color_luwi_discrete(n = 3)) # Preview all 15 colors scales::show_col(scale_color_luwi_discrete()) # Warning example: too many categories scale_color_luwi_discrete(n = 20) # Returns 15 with warning
Apply a two-directional gradient color scale for data with a meaningful
midpoint. Convenience wrapper around scale_color_gradientn() using the
cool-to-warm diverging palette.
scale_color_luwi_div(theme = my_theme(), ...)scale_color_luwi_div(theme = my_theme(), ...)
... |
Additional arguments passed to |
Use this for data where deviations from a central value matter:
Positive/negative change
Above/below average
Correlation coefficients
Temperature anomalies
Consider setting midpoint to center the gradient on your neutral value.
A ggplot2 scale object
scale_fill_luwi_div() for fill aesthetic,
scale_color_luwi_diverging() for the underlying palette,
ggplot2::scale_color_gradient2() for manual midpoint control
Other ggplot-scales:
scale_color_luwi_c(),
scale_color_luwi_d(),
scale_fill_luwi_c(),
scale_fill_luwi_d(),
scale_fill_luwi_div()
library(ggplot2) # Correlation matrix cor_data <- reshape2::melt(cor(mtcars)) ggplot(cor_data, aes(Var1, Var2, color = value)) + geom_point(size = 5) + scale_color_luwi_div(limits = c(-1, 1)) + theme_luwi() # With custom midpoint ggplot(economics, aes(date, unemploy - mean(unemploy))) + geom_line() + scale_color_luwi_div(midpoint = 0) + theme_luwi()library(ggplot2) # Correlation matrix cor_data <- reshape2::melt(cor(mtcars)) ggplot(cor_data, aes(Var1, Var2, color = value)) + geom_point(size = 5) + scale_color_luwi_div(limits = c(-1, 1)) + theme_luwi() # With custom midpoint ggplot(economics, aes(date, unemploy - mean(unemploy))) + geom_line() + scale_color_luwi_div(midpoint = 0) + theme_luwi()
Generates a two-directional gradient palette for data where deviations from a central value are meaningful (e.g., positive/negative change, hot/cold, above/below average).
scale_color_luwi_diverging(theme = my_theme(), n = 11, reverse = FALSE)scale_color_luwi_diverging(theme = my_theme(), n = 11, reverse = FALSE)
theme |
A bslib theme object (defaults to my_theme()) |
n |
Number of colors to generate (default: 11). Use odd numbers to ensure a neutral midpoint color |
reverse |
Logical. Flip the palette direction (warm becomes cool and vice versa) |
The palette transitions: Teal (cold) → Light blue → Neutral warm → Coral → Red-orange (hot).
The neutral midpoint uses your theme's light color to maintain brand consistency.
When to use diverging palettes:
Temperature data (cold to hot)
Financial change (loss to gain)
Survey responses (disagree to agree)
Correlation coefficients (-1 to +1)
Character vector of n hex color codes transitioning from cool (teal)
through neutral (light) to warm (coral/red)
ggplot2::scale_fill_gradient2() to use with ggplot2,
scale_color_luwi_sequential() for one-directional data
Other color-palettes:
scale_color_luwi_discrete(),
scale_color_luwi_sequential()
library(ggplot2) # Correlation matrix ggplot(reshape2::melt(cor(mtcars)), aes(Var1, Var2, fill = value)) + geom_tile() + scale_fill_gradientn( colors = scale_color_luwi_diverging(n = 11), limits = c(-1, 1) ) # Temperature anomalies (reversed: red = hot) temp_palette <- scale_color_luwi_diverging(n = 9, reverse = TRUE) # Preview the palette scales::show_col(scale_color_luwi_diverging())library(ggplot2) # Correlation matrix ggplot(reshape2::melt(cor(mtcars)), aes(Var1, Var2, fill = value)) + geom_tile() + scale_fill_gradientn( colors = scale_color_luwi_diverging(n = 11), limits = c(-1, 1) ) # Temperature anomalies (reversed: red = hot) temp_palette <- scale_color_luwi_diverging(n = 9, reverse = TRUE) # Preview the palette scales::show_col(scale_color_luwi_diverging())
Generates a gradient palette suitable for continuous/ordered data. Choose from warm (coral-to-red), cool (teal-to-blue), or green (olive-to-dark) gradients.
scale_color_luwi_sequential( theme = my_theme(), type = "warm", n = 9, reverse = FALSE )scale_color_luwi_sequential( theme = my_theme(), type = "warm", n = 9, reverse = FALSE )
theme |
A bslib theme object (defaults to my_theme()) |
type |
Palette type:
|
n |
Number of colors to generate (default: 9). More colors = smoother gradient |
reverse |
Logical. Reverse the palette direction (dark to light instead of light to dark) |
These palettes are perceptually uniform and designed to work well in both digital and print contexts. They automatically use your theme's semantic colors as anchor points to ensure brand consistency.
Character vector of n hex color codes
ggplot2::scale_fill_gradient() and ggplot2::scale_color_gradient() to use with ggplot2,
scale_color_luwi_diverging() for data with a meaningful midpoint
Other color-palettes:
scale_color_luwi_discrete(),
scale_color_luwi_diverging()
library(ggplot2) # Warm palette for a heatmap ggplot(faithfuld, aes(waiting, eruptions, fill = density)) + geom_tile() + scale_fill_gradientn(colors = scale_color_luwi_sequential(type = "warm")) # Cool palette reversed (dark = high values) ggplot(economics, aes(date, unemploy)) + geom_area(fill = scale_color_luwi_sequential(type = "cool", n = 1)) # Preview the palette scales::show_col(scale_color_luwi_sequential(type = "green", n = 9))library(ggplot2) # Warm palette for a heatmap ggplot(faithfuld, aes(waiting, eruptions, fill = density)) + geom_tile() + scale_fill_gradientn(colors = scale_color_luwi_sequential(type = "warm")) # Cool palette reversed (dark = high values) ggplot(economics, aes(date, unemploy)) + geom_area(fill = scale_color_luwi_sequential(type = "cool", n = 1)) # Preview the palette scales::show_col(scale_color_luwi_sequential(type = "green", n = 9))
Apply a sequential gradient fill scale for continuous data with brand colors.
Convenience wrapper around scale_fill_gradientn().
scale_fill_luwi_c(type = "warm", theme = my_theme(), ...)scale_fill_luwi_c(type = "warm", theme = my_theme(), ...)
type |
Palette type: |
... |
Additional arguments passed to |
A ggplot2 scale object
scale_color_luwi_c() for color aesthetic,
scale_color_luwi_sequential() for the underlying palette,
scale_fill_luwi_div() for diverging data
Other ggplot-scales:
scale_color_luwi_c(),
scale_color_luwi_d(),
scale_color_luwi_div(),
scale_fill_luwi_d(),
scale_fill_luwi_div()
library(ggplot2) # Heatmap with warm colors ggplot(faithfuld, aes(waiting, eruptions, fill = density)) + geom_tile() + scale_fill_luwi_c(type = "warm") + theme_luwi() # Area chart with green gradient ggplot(economics, aes(date, unemploy)) + geom_area(fill = scale_color_luwi_sequential(type = "green", n = 1)) + theme_luwi()library(ggplot2) # Heatmap with warm colors ggplot(faithfuld, aes(waiting, eruptions, fill = density)) + geom_tile() + scale_fill_luwi_c(type = "warm") + theme_luwi() # Area chart with green gradient ggplot(economics, aes(date, unemploy)) + geom_area(fill = scale_color_luwi_sequential(type = "green", n = 1)) + theme_luwi()
Apply brand colors for categorical/discrete fill aesthetic. Convenience wrapper
around scale_fill_manual() with up to 15 distinct brand colors.
scale_fill_luwi_d(theme = my_theme(), ...)scale_fill_luwi_d(theme = my_theme(), ...)
... |
Additional arguments passed to |
Perfect for bar charts, boxplots, and violin plots with categorical groups. Colors are ordered by brand importance: primary, secondary, success, warning, danger.
A ggplot2 scale object
scale_color_luwi_d() for color aesthetic,
scale_color_luwi_discrete() for the underlying palette
Other ggplot-scales:
scale_color_luwi_c(),
scale_color_luwi_d(),
scale_color_luwi_div(),
scale_fill_luwi_c(),
scale_fill_luwi_div()
library(ggplot2) # Bar chart ggplot(mpg, aes(class, fill = class)) + geom_bar() + scale_fill_luwi_d() + theme_luwi() # Boxplot by category ggplot(mpg, aes(class, hwy, fill = class)) + geom_boxplot() + scale_fill_luwi_d() + theme_luwi() + theme(legend.position = "none") # Class already on x-axislibrary(ggplot2) # Bar chart ggplot(mpg, aes(class, fill = class)) + geom_bar() + scale_fill_luwi_d() + theme_luwi() # Boxplot by category ggplot(mpg, aes(class, hwy, fill = class)) + geom_boxplot() + scale_fill_luwi_d() + theme_luwi() + theme(legend.position = "none") # Class already on x-axis
Apply a two-directional gradient fill scale for data with a meaningful
midpoint. Convenience wrapper around scale_fill_gradientn() using the
cool-to-warm diverging palette.
scale_fill_luwi_div(theme = my_theme(), ...)scale_fill_luwi_div(theme = my_theme(), ...)
... |
Additional arguments passed to |
Ideal for heatmaps and tiles where deviations from center are meaningful.
A ggplot2 scale object
scale_color_luwi_div() for color aesthetic,
scale_color_luwi_diverging() for the underlying palette
Other ggplot-scales:
scale_color_luwi_c(),
scale_color_luwi_d(),
scale_color_luwi_div(),
scale_fill_luwi_c(),
scale_fill_luwi_d()
library(ggplot2) # Correlation heatmap cor_data <- reshape2::melt(cor(mtcars)) ggplot(cor_data, aes(Var1, Var2, fill = value)) + geom_tile() + scale_fill_luwi_div(limits = c(-1, 1)) + theme_luwi()library(ggplot2) # Correlation heatmap cor_data <- reshape2::melt(cor(mtcars)) ggplot(cor_data, aes(Var1, Var2, fill = value)) + geom_tile() + scale_fill_luwi_div(limits = c(-1, 1)) + theme_luwi()
A clean, publication-ready ggplot2 theme that automatically matches your
bslib/Shiny application styling. Built on theme_minimal() with transparent
backgrounds for seamless integration into dashboards.
theme_luwi(theme = my_theme(), base_size = 14)theme_luwi(theme = my_theme(), base_size = 14)
theme |
A bslib theme object (defaults to my_theme()) |
base_size |
Base font size in points (default: 14). All text elements scale proportionally from this value |
A ggplot2 theme object that can be added to plots with +
luwi_ggplotly() for interactive plotly version,
scale_color_luwi_d(), scale_fill_luwi_c() for matching color scales,
ggplot2::theme_set() to apply globally to all plots
Other ggplot-themes:
luwi_ggplotly()
library(ggplot2) # Basic usage ggplot(mtcars, aes(mpg, wt)) + geom_point() + theme_luwi() # With larger text for presentations ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) + geom_point(size = 3) + labs(title = "Iris Measurements") + theme_luwi(base_size = 16) # Set as default theme for all plots theme_set(theme_luwi()) # Customize further ggplot(economics, aes(date, unemploy)) + geom_line() + theme_luwi() + theme(panel.grid.major.x = element_blank()) # Remove vertical gridlibrary(ggplot2) # Basic usage ggplot(mtcars, aes(mpg, wt)) + geom_point() + theme_luwi() # With larger text for presentations ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) + geom_point(size = 3) + labs(title = "Iris Measurements") + theme_luwi(base_size = 16) # Set as default theme for all plots theme_set(theme_luwi()) # Customize further ggplot(economics, aes(date, unemploy)) + geom_line() + theme_luwi() + theme(panel.grid.major.x = element_blank()) # Remove vertical grid
Wires up reactive theme switching for dark mode. Call this once in your
Shiny server to get a reactive theme that tracks the toggle state.
Bootstrap components are styled via CSS custom property overrides injected
by my_theme — no full theme swap occurs on toggle.
use_dark_mode(input, session, input_id = "dark_mode")use_dark_mode(input, session, input_id = "dark_mode")
input |
The Shiny |
session |
The Shiny |
input_id |
Character. The ID of the |
The light theme is compiled at initialization. The dark theme is compiled
lazily on first toggle to avoid unnecessary startup cost. Bootstrap
components switch instantly via CSS custom property overrides (no
session$setCurrentTheme() call). Pass dm$theme() to plot
functions to make them reactive to the toggle.
A list with two reactive elements:
modeReactive returning "dark" or "light"
themeReactive returning the corresponding
bslib::bs_theme() object from my_theme
Your UI must include bslib::input_dark_mode(id = "dark_mode")
(or a matching input_id). Place it in your navbar, sidebar,
or wherever makes sense for your layout.
my_theme for the underlying theme constructor,
input_dark_mode for the toggle widget
Other theme-generators:
my_theme()
## Not run: library(shiny) library(bslib) library(ggplot2) ui <- page_sidebar( theme = my_theme(), title = "Dark Mode Demo", sidebar = sidebar( input_dark_mode(id = "dark_mode") ), card( card_header("Branded Plot"), plotOutput("plot") ) ) server <- function(input, output, session) { dm <- use_dark_mode(input, session) output$plot <- renderPlot({ ggplot(mtcars, aes(mpg, wt, color = factor(cyl))) + geom_point(size = 3) + scale_color_luwi_d() + theme_luwi(theme = dm$theme()) }) } shinyApp(ui, server) ## End(Not run)## Not run: library(shiny) library(bslib) library(ggplot2) ui <- page_sidebar( theme = my_theme(), title = "Dark Mode Demo", sidebar = sidebar( input_dark_mode(id = "dark_mode") ), card( card_header("Branded Plot"), plotOutput("plot") ) ) server <- function(input, output, session) { dm <- use_dark_mode(input, session) output$plot <- renderPlot({ ggplot(mtcars, aes(mpg, wt, color = factor(cyl))) + geom_point(size = 3) + scale_color_luwi_d() + theme_luwi(theme = dm$theme()) }) } shinyApp(ui, server) ## End(Not run)