Advanced: Specification Objects

NoteWhen to Use This Page

Most users should start with forest_plot(), which accepts all the same arguments and is simpler for typical workflows.

Use web_spec() when you need to:

  • Build plot specifications programmatically (e.g., in functions or loops)
  • Reuse the same specification with different rendering options
  • Inspect or serialize the specification object
  • Work with multi-effect plots requiring explicit web_effect() definitions

Overview

The web_spec() function creates a WebSpec object—an intermediate representation that captures all the data, mappings, and styling for a forest plot. This object can then be rendered with forest_plot() or webtable().

Code
# Two equivalent approaches:

# Direct (recommended for most cases)
forest_plot(data,
  point = "hr", lower = "lower", upper = "upper", label = "study",
  scale = "log", null_value = 1
)

# Via WebSpec (for programmatic use)
spec <- web_spec(data,
  point = "hr", lower = "lower", upper = "upper", label = "study",
  scale = "log", null_value = 1
)
forest_plot(spec)

Core Specification

web_spec

Create a specification object for forest plot rendering.

web_spec(
  data,
  point,
  lower,
  upper,
  label = NULL,
  label_header = "Study",
  group = NULL,
  columns = NULL,
  scale = c("linear", "log"),
  null_value = NULL,
  axis_label = NULL,
  effects = NULL,
  annotations = NULL,
  title = NULL,
  subtitle = NULL,
  caption = NULL,
  footnote = NULL,
  row_bold = NULL,
  row_italic = NULL,
  row_color = NULL,
  row_bg = NULL,
  row_badge = NULL,
  row_icon = NULL,
  row_indent = NULL,
  row_type = NULL,
  row_emphasis = NULL,
  row_muted = NULL,
  row_accent = NULL,
  marker_color = NULL,
  marker_shape = NULL,
  marker_opacity = NULL,
  marker_size = NULL,
  theme = web_theme_default(),
  interaction = web_interaction()
)

Required Arguments

Argument Description
data A data.frame, data.table, or tibble
point Column name for point estimates
lower Column name for lower confidence bounds
upper Column name for upper confidence bounds

Optional Data Arguments

Argument Description
label Column name for row labels
label_header Header text for the label column (default: "Study")

Grouping

Argument Description
group Grouping specification (see below)

The group argument supports three modes:

  1. Single column: group = "category" — flat grouping by one column
  2. Hierarchical: group = c("region", "country") — nested grouping (region > country)
  3. Explicit: group = list(web_group(...)) — full control over group definitions

Display Arguments

Argument Description
columns List of column specifications (use col_*() helpers)
scale Scale type: "linear" or "log"
null_value Reference value (default: 0 for linear, 1 for log)
axis_label Label for the x-axis
title Plot title
subtitle Plot subtitle
caption Plot caption
footnote Plot footnote

Row Styling Arguments

All row styling arguments accept either a column name (string) or a formula expression (~ ...).

Argument Value Type Description
row_type string Row type: "header", "data", "summary", "spacer"
row_bold logical TRUE/FALSE for bold text
row_italic logical TRUE/FALSE for italic text
row_color string CSS color strings (e.g., "#1a365d")
row_bg string Background color strings
row_badge string Badge text to display
row_icon string Emoji or unicode icons
row_indent integer Indentation levels (0, 1, 2, …)
row_emphasis logical TRUE/FALSE for emphasis styling (bold + primary color)
row_muted logical TRUE/FALSE for muted styling (lighter, reduced prominence)
row_accent logical TRUE/FALSE for accent styling (theme accent color)

Formula expressions let you compute styling from your data without pre-creating columns:

Code
# Column name approach (traditional)
data <- data |> mutate(is_sig = pval < 0.05)
web_spec(data, ..., row_bold = "is_sig")

# Formula expression approach (NSE)
web_spec(data, ..., row_bold = ~ pval < 0.05)

Formulas can reference any column in your data:

Code
# Simple condition
row_bold = ~ pval < 0.05

# Multiple conditions
row_emphasis = ~ pval < 0.05 & hr < 0.8

# Conditional colors
row_color = ~ ifelse(pval < 0.05, "#16a34a", "#71717a")

# Complex logic with case_when
row_color = ~ case_when(
  upper < 1 ~ "#16a34a",  # Significant benefit
  lower > 1 ~ "#dc2626",  # Significant harm
  TRUE ~ "#71717a"        # Non-significant
)

Marker Styling Arguments

All marker styling arguments accept either a column name (string) or a formula expression (~ ...).

Argument Value Type Description
marker_color string CSS color strings for marker fill
marker_shape string Shape: "square", "circle", "diamond", "triangle"
marker_opacity numeric Opacity values from 0 to 1
marker_size numeric Size multipliers (1 = default size)

Example with formula expressions:

Code
forest_plot(data, ...,
  marker_shape = ~ ifelse(design == "RCT", "circle", "square"),
  marker_color = ~ ifelse(pval < 0.05, "#16a34a", "#94a3b8"),
  marker_opacity = ~ ifelse(pval < 0.01, 1, 0.7)
)

Advanced Arguments

Argument Description
effects List of web_effect() objects for multi-effect plots
annotations List of annotation objects (forest_refline(), forest_annotation())
theme Theme object (default: web_theme_default())
interaction Interaction settings (default: web_interaction())

Group Specification

web_group

Define a row group with optional nesting. Use this for explicit control over group structure when automatic grouping from column values isn’t sufficient.

web_group(id, label = id, parent = NULL, collapsed = FALSE)
Argument Description
id Unique identifier for the group (must match values in your data)
label Display label (defaults to id)
parent Parent group ID for creating nested hierarchies
collapsed Whether the group starts collapsed (TRUE/FALSE)

Example: Explicit Group Definitions

Code
# Data with group column
data <- data.frame(
  study = c("Trial A", "Trial B", "Trial C", "Trial D"),
  group_id = c("cardio", "cardio", "renal", "renal"),
  hr = c(0.72, 0.85, 0.91, 0.78),
  lower = c(0.55, 0.70, 0.75, 0.60),
  upper = c(0.95, 1.03, 1.10, 1.00)
)

# Explicit groups with custom labels
web_spec(data,
  point = "hr", lower = "lower", upper = "upper", label = "study",
  group = list(
    web_group("cardio", label = "Cardiovascular Outcomes"),
    web_group("renal", label = "Renal Outcomes", collapsed = TRUE)
  )
)

Effect Specification

web_effect

Define a single effect for multi-effect forest plots. Multi-effect plots display multiple intervals per row, useful for comparing different analyses (e.g., unadjusted vs. adjusted) or different outcomes.

web_effect(point, lower, upper, label = NULL, color = NULL, shape = NULL, opacity = NULL)
Argument Description
point Column name for point estimates
lower Column name for lower bounds
upper Column name for upper bounds
label Display label for legend (defaults to point column name)
color Override color for this effect (CSS color string)
shape Override shape: "square", "circle", "diamond", "triangle"
opacity Override opacity (0–1)

Example: Comparing Unadjusted and Adjusted Estimates

Code
data <- data.frame(
  study = c("Trial A", "Trial B", "Trial C"),
  # Unadjusted estimates
  hr_unadj = c(0.75, 0.82, 0.88),
  lo_unadj = c(0.58, 0.68, 0.72),
  hi_unadj = c(0.97, 0.99, 1.07),
  # Adjusted estimates
  hr_adj = c(0.72, 0.79, 0.85),
  lo_adj = c(0.55, 0.65, 0.70),
  hi_adj = c(0.94, 0.96, 1.03)
)

web_spec(data,
  point = "hr_unadj", lower = "lo_unadj", upper = "hi_unadj",
  label = "study",
  effects = list(
    web_effect("hr_unadj", "lo_unadj", "hi_unadj",
               label = "Unadjusted", color = "#64748b"),
    web_effect("hr_adj", "lo_adj", "hi_adj",
               label = "Adjusted", color = "#2563eb")
  ),
  scale = "log", null_value = 1
) |>
  forest_plot()

Interaction Specification

web_interaction

Configure interactive features for the rendered widget.

web_interaction(
  tooltip_fields = NULL,
  show_filters = FALSE,
  show_legend = TRUE,
  enable_sort = TRUE,
  enable_collapse = TRUE,
  enable_select = TRUE,
  enable_hover = TRUE,
  enable_resize = TRUE,
  enable_export = TRUE,
  enable_themes = "default"
)
Argument Description Default
tooltip_fields Column names to show in hover tooltip NULL (no tooltip)
show_filters Show filter panel FALSE
show_legend Show legend TRUE
enable_sort Enable column sorting TRUE
enable_collapse Enable group collapsing TRUE
enable_select Enable row selection TRUE
enable_hover Enable hover effects TRUE
enable_resize Enable column resizing TRUE
enable_export Enable download/export button TRUE
enable_themes Theme menu: "default", NULL, or list of WebTheme "default"

Tooltips

Tooltips are opt-in. Specify column names to display when hovering over interval markers:

web_interaction(
  tooltip_fields = c("n", "events", "pvalue")
)

The tooltip displays the row label, point estimate with CI, and each specified field.

Presets

# Read-only: hover effects only, no interactive features
web_interaction_minimal()

# Static: no interactive features at all (for publications)
web_interaction_publication()

Programmatic Construction Patterns

Building Specs in Functions

Code
create_forest_spec <- function(data, effect_col, ci_cols, ...) {
  web_spec(data,
    point = effect_col,
    lower = ci_cols[1],
    upper = ci_cols[2],
    ...
  )
}

# Use it
spec <- create_forest_spec(my_data, "hr", c("lower", "upper"),
  label = "study", scale = "log", null_value = 1
)
forest_plot(spec)

Reusing Specs with Different Renderings

Code
# Create base specification once
base_spec <- web_spec(data,
  point = "hr", lower = "lower", upper = "upper", label = "study",
  columns = list(col_n("n"), col_interval("HR (95% CI)")),
  scale = "log", null_value = 1
)

# Render with different themes
forest_plot(base_spec, theme = web_theme_jama())
forest_plot(base_spec, theme = web_theme_lancet())

# Render as table only
webtable(base_spec)

# Export to file
save_plot(forest_plot(base_spec), "forest.svg")

Inspecting Specifications

Code
spec <- web_spec(data, point = "hr", lower = "lower", upper = "upper")

# Print summary
print(spec)

# Convert to data frame
as.data.frame(spec)

# Access components
spec@data       # Original data
spec@theme      # Theme object
spec@columns    # Column specifications

See Also