This vignette dives deeper into BFHtheme for users who need more than the out-of-the-box defaults. You will learn how to:
| Customisation area | Key functions |
|---|---|
| Theme tweaks | theme_bfh_*(), theme() |
| Colours & palettes | bfh_cols(), bfh_pal(),
scale_*_bfh_*() |
| Branding elements | add_bfh_logo(), add_bfh_footer() |
| Layout helpers | bfh_combine_plots(), bfh_save() |
All BFH themes expose the standard ggplot2 base arguments. Adjust them to fit specific deliverables—larger fonts for accessibility, a fixed typeface for compliance, or heavier lines for print.
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
labs(title = "Custom Base Size") +
theme_bfh(
base_size = 14, # Larger text
base_family = "Arial", # Specific font
base_line_size = 0.6, # Thicker lines
base_rect_size = 0.6 # Thicker rectangles
)Layer additional ggplot2 theme calls on top of the BFH defaults to fine-tune individual components such as titles, panels, or grids.
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
labs(title = "Custom Theme Elements") +
theme_bfh() +
theme(
plot.title = element_text(color = bfh_cols("hospital_blue"), size = 18),
axis.title.x = element_text(face = "bold"),
panel.grid.major = element_line(color = "grey90", linewidth = 0.3)
)Legends inherit BFH styling but can be repositioned or reformatted to suit the layout.
ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
geom_point(size = 3) +
labs(
title = "Custom Legend Position",
color = "Cylinders"
) +
scale_color_bfh() +
theme_bfh() +
theme(
legend.position = "top",
legend.direction = "horizontal",
legend.box = "horizontal"
)Switch palettes dynamically to emphasise different aspects of the brand.
p <- ggplot(mtcars, aes(x = factor(cyl), fill = factor(cyl))) +
geom_bar() +
labs(title = "Hospital Blues Palette") +
theme_bfh()
p + scale_fill_bfh(palette = "hospital_blues")Reverse the palette order when a gradient needs to flow in the opposite direction.
ggplot(mtcars, aes(x = wt, y = mpg, color = hp)) +
geom_point(size = 3) +
labs(title = "Reversed Colour Scale") +
scale_color_bfh_continuous(palette = "blues", reverse = TRUE) +
theme_bfh()Combine individual colours or build a bespoke gradient with
bfh_pal() to match department-specific requirements.
# Create a custom palette with specific colours
custom_colors <- c(
bfh_cols("hospital_primary"),
bfh_cols("regionh_grey"),
bfh_cols("regionh_primary")
)
ggplot(mtcars, aes(x = factor(cyl), fill = factor(cyl))) +
geom_bar() +
labs(title = "Custom Colour Selection") +
scale_fill_manual(values = custom_colors) +
theme_bfh()
#> Warning: No shared levels found between `names(values)` of the manual scale and the
#> data's fill values.
#> No shared levels found between `names(values)` of the manual scale and the
#> data's fill values.Use bfh_pal() to generate smooth gradients or truncate
palettes for a precise number of categories.
# Generate colour ramp
blues_pal <- bfh_pal("hospital_blues")
# Use in continuous scale
ggplot(faithfuld, aes(waiting, eruptions, fill = density)) +
geom_tile() +
scale_fill_gradientn(colours = blues_pal(100)) +
theme_bfh()Extend a finished plot with branded components and annotations to convey context, ownership, or emphasis without redesigning the underlying chart.
Anchor a plot with official branding using
add_bfh_footer():
Combine multiple plots with a shared legend for consistent storytelling:
library(patchwork)
p1 <- ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) +
geom_point() +
labs(title = "Weight vs MPG") +
scale_color_bfh() +
theme_bfh()
p2 <- ggplot(mtcars, aes(hp, mpg, color = factor(cyl))) +
geom_point() +
labs(title = "Horsepower vs MPG") +
scale_color_bfh() +
theme_bfh()
# Combine with shared legend
p1 + p2 + plot_layout(guides = "collect") &
theme(legend.position = "bottom")Alternatively, call the BFH helper directly:
Tidy up axes with breaks, limits, and units that match your narrative:
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
labs(
title = "Custom Axis Formatting",
x = "Vehicle Weight (1000 lbs)",
y = "Fuel Efficiency (MPG)"
) +
scale_y_continuous(
breaks = seq(10, 35, 5),
limits = c(10, 35)
) +
theme_bfh()For time-series data, combine date scales with BFH colours:
library(lubridate)
date_data <- data.frame(
date = seq(as.Date("2024-01-01"), by = "month", length.out = 12),
value = cumsum(rnorm(12, 10, 3))
)
ggplot(date_data, aes(x = date, y = value)) +
geom_line(color = bfh_cols("hospital_primary"), linewidth = 1) +
labs(
title = "Monthly Trends",
x = "Month",
y = "Value"
) +
scale_x_date(
date_breaks = "2 months",
date_labels = "%b %Y"
) +
theme_bfh()Typography and copy tone are central to the BFH identity. These helpers keep labels consistent while still giving you room for context-specific annotations.
Use bfh_labs() to align subtitles, axis titles, and
captions with the uppercase convention while preserving the main title
casing:
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
bfh_labs(
title = "Fuel efficiency analysis", # Title unchanged
subtitle = "Motor trend data", # Converted to uppercase
x = "weight (1000 lbs)", # Converted to uppercase
y = "miles per gallon", # Converted to uppercase
caption = "Source: Motor Trend, 1974" # Converted to uppercase
) +
theme_bfh()For complete typographic consistency, use the position scale functions to convert axis tick labels (the actual values on the axes) to uppercase. This is particularly useful for date labels and categorical data:
# Discrete/categorical data with uppercase labels
ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
geom_boxplot() +
scale_x_discrete_bfh() + # "4" becomes "4", but categories like "low" become "LOW"
bfh_labs(
title = "Fuel efficiency by cylinder count",
x = "cylinders",
y = "miles per gallon"
) +
theme_bfh()
# Date data with uppercase month labels
df <- data.frame(
date = seq.Date(as.Date("2023-01-01"), as.Date("2023-12-31"), by = "month"),
value = rnorm(12, mean = 100, sd = 10)
)
ggplot(df, aes(x = date, y = value)) +
geom_line(color = bfh_cols("hospital_primary"), linewidth = 1) +
scale_x_date_bfh(date_labels = "%b %Y") + # "Jan 2023" becomes "JAN 2023"
scale_y_continuous_bfh() +
bfh_labs(
title = "Monthly trends",
x = "month",
y = "value"
) +
theme_bfh()The available position scale functions with uppercase support are:
scale_x_continuous_bfh() /
scale_y_continuous_bfh() - For numeric axesscale_x_discrete_bfh() /
scale_y_discrete_bfh() - For categorical datascale_x_date_bfh() / scale_y_date_bfh() -
For date axesscale_x_datetime_bfh() /
scale_y_datetime_bfh() - For datetime axesAll functions accept a custom labels argument if you
need different formatting.
The BFH position scales integrate seamlessly with the
scales package for even smarter formatting. You can use
breaks_pretty() for intelligent break positioning and any
label_*() function—output is automatically uppercased:
library(scales)
# Use label_date_short() for compact, hierarchical labels
ggplot(df, aes(x = date, y = value)) +
geom_line(color = bfh_cols("hospital_primary"), linewidth = 1) +
scale_x_date_bfh(
breaks = breaks_pretty(n = 8), # Smart break positioning
labels = label_date_short() # Compact labels (auto-uppercased)
) +
bfh_labs(
title = "Compact date labels with breaks_pretty",
x = "date",
y = "value"
) +
theme_bfh()
# Combine custom formatting with breaks
ggplot(df, aes(x = date, y = value)) +
geom_line(color = bfh_cols("hospital_blue"), linewidth = 1) +
scale_x_date_bfh(
breaks = breaks_width("2 months"), # Break every 2 months
labels = label_date("%B") # Full month names (uppercased)
) +
bfh_labs(
title = "Full month names with custom breaks",
x = "month",
y = "value"
) +
theme_bfh()Useful scales functions:
breaks_pretty(n) - Pretty breaks with desired
countbreaks_width("2 weeks") - Breaks at regular
intervalslabel_date("%b %Y") - Custom date formatlabel_date_short() - Compact hierarchical labelslabel_time() - Time formattingThe label_date_short() function is particularly powerful
for time series with many data points. It creates a hierarchical
labeling system that only shows what has changed, dramatically reducing
horizontal space requirements:
# Standard labels - repetitive and space-consuming
ggplot(df, aes(x = date, y = value)) +
geom_line(color = bfh_cols("hospital_primary"), linewidth = 1) +
scale_x_date_bfh(
date_breaks = "2 months",
labels = label_date("%b %Y") # "JAN. 2023", "MAR. 2023", etc.
) +
bfh_labs(title = "Standard labels", x = "date", y = "value") +
theme_bfh() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotation needed!
# label_date_short() - compact and hierarchical
ggplot(df, aes(x = date, y = value)) +
geom_line(color = bfh_cols("hospital_primary"), linewidth = 1) +
scale_x_date_bfh(
date_breaks = "2 months",
labels = label_date_short() # Shows year only when it changes
) +
bfh_labs(title = "Compact hierarchical labels", x = "date", y = "value") +
theme_bfh() # No rotation needed!Recommended combinations based on data duration:
# Short time series (< 1 year)
scale_x_date_bfh() # Default is fine
# Medium time series (1-3 years)
scale_x_date_bfh(
breaks = breaks_pretty(n = 6),
labels = label_date_short()
)
# Long time series (> 3 years)
scale_x_date_bfh(
breaks = breaks_pretty(n = 8),
labels = label_date_short()
)
# Weekly data
scale_x_date_bfh(
breaks = breaks_width("2 weeks"),
labels = label_date_short()
)Layer additional annotations for storytelling while staying within the BFH colour system:
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
annotate(
"text",
x = 4.5, y = 30,
label = "High efficiency zone",
color = bfh_cols("hospital_primary"),
size = 4
) +
annotate(
"rect",
xmin = 1.5, xmax = 3.5,
ymin = 25, ymax = 35,
alpha = 0.1,
fill = bfh_cols("hospital_blue")
) +
labs(title = "Annotated Plot") +
theme_bfh()Facets inherit BFH defaults, but subtle tweaks can make multi-panel layouts feel polished and balanced.
Adjust strip backgrounds and text to reinforce brand colours:
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point(color = bfh_cols("hospital_primary")) +
facet_wrap(~cyl, labeller = labeller(cyl = function(x) paste(x, "cylinders"))) +
labs(title = "Fuel Efficiency by Cylinder Count") +
theme_bfh() +
theme(
strip.background = element_rect(fill = bfh_cols("hospital_light_blue1")),
strip.text = element_text(color = bfh_cols("hospital_primary"), face = "bold")
)Produce publication-ready figures while keeping file sizes manageable.
Use bfh_save() presets for common outputs, or override
the size when you need an exact width and height.
p <- ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
theme_bfh()
# High-resolution PNG
bfh_save("figure.png", p, preset = "report_full", dpi = 600)
# Vector format for editing
bfh_save("figure.pdf", p, preset = "report_full")
# Custom dimensions
bfh_save("figure.png", p, width = 10, height = 8, units = "cm", dpi = 300)Query the recommended sizes directly from the helper for reproducible reporting:
# Get dimensions for different output types (internal function)
report_dims <- BFHtheme:::get_bfh_dimensions(type = "report", format = "standard")
print(report_dims)
#> $width
#> [1] 7
#>
#> $height
#> [1] 5
presentation_dims <- BFHtheme:::get_bfh_dimensions(type = "presentation", format = "wide")
print(presentation_dims)
#> $width
#> [1] 12
#>
#> $height
#> [1] 6.75Keep your workflow responsive when working with fonts or large datasets.
Font detection results are cached for speed. Clear or refresh the cache after adding or removing fonts mid-session:
High-volume data can strain rendering. Consider these approaches:
# Use alpha for overplotting
ggplot(large_data, aes(x, y)) +
geom_point(alpha = 0.3) +
theme_bfh()
# Use geom_hex or geom_bin2d
ggplot(large_data, aes(x, y)) +
geom_hex() +
scale_fill_bfh_continuous(palette = "blues") +
theme_bfh()
# Reduce point size
ggplot(large_data, aes(x, y)) +
geom_point(size = 0.5) +
theme_bfh()vignette("getting-started") for the
foundational workflow.vignette("theming") when you need hospital vs
Region H branding.help(package = "BFHtheme")) for parameter details.