Themes control the visual appearance of forest plots—colors, typography, spacing, and shapes. You can use preset themes for common publication styles, or customize every aspect using a fluent pipe-based API.

TipTheme Design Philosophy

Each theme is designed with a specific context in mind:

  • Publication themes (JAMA, Lancet, Nature): Journal-specific styling for submissions
  • Presentation themes (modern, presentation, dark): Optimized for screen viewing
  • Utility themes (default, minimal, cochrane): Clean and adaptable

Component Summary

Component Function Key Properties
Colors set_colors() background, foreground, primary, interval, interval_line
Typography set_typography() font_family, font_size_, font_weight_, header_font_scale
Spacing set_spacing() row_height, header_height, padding, container_padding, cell_padding_x/y
Shapes set_shapes() point_size, summary_height, line_width, effect_colors, marker_shapes
Axis set_axis() range_min/max, tick_count, tick_values, gridlines, symmetric
Layout set_layout() plot_position, row_border, container_border
Group Headers set_group_headers() level*_font_size, level*_background, indent_per_level
Effects set_effect_colors(), set_marker_shapes() Multi-effect default colors/shapes

Color Architecture

Colors serve different purposes in tabviz:

Category Purpose Colors
Structural Define the canvas background, foreground, border
Semantic Convey meaning through styling primary, accent, muted
Data Visualize data elements interval, interval_line, summary_fill

How Palette Colors Connect to Styling

The palette defines what colors look like. Semantic styles apply those colors to specific elements:

┌─────────────────────────────────────────────────────────────────┐
│  PALETTE (set_colors)              STYLES (row_*/column)       │
│  ─────────────────────             ────────────────────        │
│  accent: "#8b5cf6"      ───────►   row_accent, cell accent     │
│  muted: "#94a3b8"       ───────►   row_muted, cell muted       │
│  foreground: "#333"     ───────►   row_emphasis (+ bold)       │
│  primary: "#0891b2"     ───────►   group headers, hover        │
└─────────────────────────────────────────────────────────────────┘

Key insight: Changing accent in the theme automatically updates all row_accent and cell accent styling.

NoteSemantic Styles at Row and Cell Level

The same semantic vocabulary works at both levels:

Style Effect Row Parameter Cell Parameter
Emphasis Bold + foreground color row_emphasis emphasis in web_col()
Muted Muted color (de-emphasized) row_muted muted in web_col()
Accent Accent color (highlighted) row_accent accent in web_col()

Row-level parameters accept column names with TRUE/FALSE values. Cell-level parameters in web_col() also accept column names.

Preset Themes

tabviz includes 9 preset themes designed for different use cases. All themes can be customized using a fluent API.

Clean, modern default with subtle cyan accents and system fonts.

Code
forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = web_theme_default())

JAMA journal style: maximum density, pure black & white, Arial font, compact rows (18px). Optimized for print.

Code
forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = web_theme_jama())

Elegant academic theme with Lancet navy blue (#00407A), warm off-white background, gold accents, and serif typography (Georgia).

Code
forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = web_theme_lancet())

Bold, vibrant design with Inter font, bright blue (#3B82F6) accents, larger elements (36px rows), and rounded corners.

Code
forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = web_theme_modern())

Oversized theme for slides and posters: extra large fonts (1-1.25rem), thick lines (2.5px), oversized markers (12px), and tall rows (44px).

Code
forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = web_theme_presentation())

Catppuccin Mocha-inspired dark mode with comfortable low-contrast colors for extended viewing.

Code
forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = web_theme_dark())

Academic publication-ready with pure black & white styling and Georgia serif font. Classic, authoritative look.

Code
forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = web_theme_minimal())

Cochrane systematic review style: teal accents (#0099CC), Arial font, very compact layout (20px rows).

Code
forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = web_theme_cochrane())

Nature journal family styling: Nature blue (#1976D2), Helvetica Neue font, tight typography, and precise aesthetic.

Code
forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = web_theme_nature())

Customizing Themes

Modify any preset theme using pipe-friendly set_*() functions:

Code
custom_theme <- web_theme_jama() |>
  set_colors(primary = "#0066cc", interval_line = "#0066cc") |>
  set_spacing(row_height = 24) |>
  set_axis(gridlines = TRUE, gridline_style = "dotted")

forest_plot(meta_data, point = "hr", lower = "lower", upper = "upper",
  label = "study", null_value = 1, scale = "log",
  theme = custom_theme)
NoteModifier Pattern

All set_*() functions follow the same pattern:

  1. Take a theme object as the first argument
  2. Accept named parameters for properties to change
  3. Return a modified theme object
  4. Can be chained with pipes
web_theme_default() |>
  set_colors(primary = "red") |>
  set_spacing(row_height = 32) |>
  set_axis(gridlines = TRUE)

Theme Components

Colors

set_colors(
  background = "#ffffff",      # Background color
  foreground = "#1a1a1a",      # Primary text color
  primary = "#2563eb",         # Primary accent for highlights
  secondary = "#64748b",       # Secondary text/UI color
  accent = "#8b5cf6",          # Accent color for emphasis
  muted = "#94a3b8",           # Muted/disabled text color
  border = "#e2e8f0",          # Border color for dividers
  interval = "#2563eb",        # Marker fill color
  interval_line = "#475569",   # Confidence interval line color
  summary_fill = "#2563eb",    # Summary diamond fill
  summary_border = "#1d4ed8"   # Summary diamond border
)
NoteColor Usage Reference
Color Where It’s Used
background Plot container background, table cells
foreground Primary text: study labels, data values, column headers; row_emphasis text
primary Row group header backgrounds (at reduced opacity), alternating row stripes, hover/selection highlights
secondary Subtitles, less prominent UI text
accent row_accent text styling; annotation labels
muted Footnotes, captions; row_muted text styling
border Row dividers, container borders, table grid lines
interval Confidence interval marker fill (squares, circles, diamonds)
interval_line CI whisker lines connecting lower to upper bounds
summary_fill Summary row diamond fill color
summary_border Summary diamond outline/stroke

Row styling colors: Use row_emphasis, row_muted, or row_accent parameters to apply these colors to specific rows. See Row Styling for details.

TipSemantic Color Tips
  • Set interval and primary to the same value for a cohesive look
  • Use a slightly darker interval_line than interval for subtle depth
  • For conditional coloring (e.g., significant vs non-significant), add a color column to your data and map it with marker_color in effect_forest()

Typography

set_typography(
  font_family = "system-ui, sans-serif",  # CSS font-family string
  font_size_sm = "0.75rem",               # Small text (badges, counts)
  font_size_base = "0.875rem",            # Default text size
  font_size_lg = "1rem",                  # Large text (headers)
  font_weight_normal = 400,               # Normal weight
  font_weight_medium = 500,               # Medium weight
  font_weight_bold = 600,                 # Bold weight
  header_font_scale = 1.05                # Header cell font scale relative to base
)

Spacing

set_spacing(
  row_height = 28,          # Data row height in pixels
  header_height = 36,       # Header row height in pixels
  padding = 12,             # Padding around forest plot SVG
  container_padding = 0,    # Left/right padding for outer container
  cell_padding_x = 10,      # Horizontal cell padding
  cell_padding_y = 4,       # Vertical cell padding
  axis_gap = 12             # Gap between table and x-axis
)
NoteRow Height Guidelines
Context Recommended Height
Compact/print 18-22px
Standard web 28-32px
Touch/mobile 36-40px
Presentation 40-48px

Shapes

set_shapes(
  point_size = 6,         # Point marker radius in pixels
  summary_height = 10,    # Summary diamond height
  line_width = 1.5,       # Confidence interval line width
  border_radius = 4,      # Container border radius
  effect_colors = NULL,   # Default colors for multi-effect visualizations
  marker_shapes = c("square", "circle", "diamond", "triangle")
)

Multi-Effect Color Defaults

For visualizations with multiple effects per row (forest plots, bar charts, boxplots, violin plots), colors cycle through theme-defined effect_colors:

Code
# Set custom effect colors and shapes for multi-effect visualizations
custom_theme <- web_theme_default() |>
  set_effect_colors(c("#2563eb", "#dc2626", "#16a34a")) |>
  set_marker_shapes(c("square", "circle", "diamond"))

forest_plot(data, ..., theme = custom_theme)

Effects without explicit color in their specification use these theme defaults in order, cycling if there are more effects than colors.

Built-in Theme Palettes

Each theme includes a curated 5-color effect_colors palette:

Theme Effect Colors Style
default #0891b2 #16a34a #f59e0b #ef4444 #8b5cf6 Balanced, accessible
modern #3b82f6 #22c55e #f59e0b #ef4444 #8b5cf6 Vibrant blue-first
jama #1a1a1a #4a4a4a #7a7a7a #9a9a9a #bababa Grayscale for print
lancet #00468b #ed0000 #42b540 #0099b4 #925e9f Journal-inspired reds/blues
nature #e64b35 #4dbbd5 #00a087 #3c5488 #f39b7f Warm coral palette
cochrane #0c4da2 #dd5129 #1a8a4f #6d4e92 #e89a47 Strong primaries
dark #89b4fa #a6e3a1 #fab387 #f38ba8 #cba6f7 Pastel for dark mode
minimal #64748b #94a3b8 #cbd5e1 #475569 #334155 Subtle slate tones
presentation #2563eb #16a34a #ea580c #dc2626 #7c3aed High-contrast for slides

Axis

set_axis(
  range_min = NULL,        # Minimum axis value (NULL = auto)
  range_max = NULL,        # Maximum axis value (NULL = auto)
  tick_count = 5,          # Target number of ticks
  tick_values = NULL,      # Custom tick positions (overrides tick_count)
  gridlines = FALSE,       # Show vertical gridlines
  gridline_style = "solid",# "solid", "dashed", or "dotted"
  symmetric = NULL,        # Force symmetric axis around null (NULL = auto)
  include_null = TRUE,     # Always include null value in range
  null_tick = TRUE         # Always show tick at null value
)
TipWhen to Use Symmetric Axes

Use symmetric = TRUE when comparing benefit vs harm magnitudes. This makes a HR of 0.5 and 2.0 appear equidistant from 1.0 on log scale.

Layout

set_layout(
  plot_position = "right",    # "left" or "right"
  row_border = TRUE,          # Show row borders
  row_border_style = "solid", # "solid", "dashed", "dotted"
  container_border = FALSE,   # Show border around container
  container_border_radius = 8 # Corner radius in pixels
)

Group Headers

Control the hierarchical styling for nested row groups (h1/h2/h3-style visual hierarchy):

set_group_headers(
  level1_font_size = "0.9375rem",
  level1_font_weight = 600,
  level1_background = NULL,      # NULL = 15% primary opacity
  level1_border_bottom = FALSE,

  level2_font_size = "0.875rem",
  level2_font_weight = 500,
  level2_italic = FALSE,
  level2_background = NULL,      # NULL = 10% primary opacity
  level2_border_bottom = FALSE,

  level3_font_size = "0.875rem",
  level3_font_weight = 400,
  level3_background = NULL,      # NULL = 6% primary opacity
  level3_border_bottom = FALSE,

  indent_per_level = 16          # Indentation per nesting level (px)
)
NoteAutomatic Background Colors

When levelN_background = NULL, the theme automatically computes a subtle background from the primary color at reduced opacity. Override with explicit hex colors for full control.

Creating Custom Themes

For extensive customization, use web_theme() to extend a base theme:

Code
publication_theme <- web_theme(
  name = "my_journal",
  colors = list(
    primary = "#1a365d",
    interval = "#1a365d",
    interval_line = "#2d3748"
  ),
  typography = list(
    font_family = "Georgia, serif",
    font_size_base = "0.8rem"
  ),
  spacing = list(
    row_height = 22
  ),
  base_theme = web_theme_minimal()  # Start from minimal
)

See Themes Reference for complete parameter documentation.