Columns display data alongside the forest plot. Each column type has specialized formatting for different kinds of data.

Choosing Column Types

Not sure which column type to use? This guide helps you choose.

For Numeric Values

Data Type Recommended Column Why
General number col_numeric() Flexible formatting with decimals/digits
Sample size col_n() Handles abbreviation (e.g., “1.2K”)
Percentage col_percent() Auto-formats with % symbol
P-value col_pvalue() Scientific notation, star indicators
Count ratio col_events() Shows “45/120 (37.5%)” format

For Effect Estimates

Data Type Recommended Column Why
Point estimate + CI text col_interval() Clean “0.85 (0.70, 1.03)” format
Visual comparison viz_forest() Shows intervals graphically with shared axis
Publication tables Both Use together for visual + numeric precision

For Distributions

Question Recommended Notes
Compare single values across rows? viz_bar() Best for direct magnitude comparison
Show spread and outliers? viz_boxplot() Shows quartiles, median, outliers
Show full distribution shape? viz_violin() Reveals bimodal/skewed distributions
Just need a simple inline bar? col_bar() No axis, fits in cell
Show trends over time? col_sparkline() Compact line/area/bar charts

For Status/Categories

Data Type Recommended Column Why
Status labels col_badge() Colored chips (success/warning/error)
Quality scores col_stars() Visual star rating
Single indicators col_icon() Emoji or symbol mapping
Min-max ranges col_range() Shows “55 – 80” format
TipWhen in Doubt

Start with col_text() for any data, then upgrade to a specialized type when formatting becomes important.


Quick Reference

Column Purpose Example
col_text() Any text Study names, categories
col_numeric() Formatted numbers Means, counts
col_n() Sample sizes 1234 or 1.2K
col_percent() Percentages 85.2%
col_interval() Point (CI) 0.85 (0.70, 1.03)
col_pvalue() P-values 0.042 or **
col_events() Events/N 45/120 (37.5%)
col_range() Min–Max 55 – 80
col_bar() Horizontal bar Visual weight
col_sparkline() Mini chart Trends
viz_forest() Forest plot Effect estimates
col_badge() Status badge Labels
col_icon() Icons/emoji Status
col_stars() Star rating Quality
col_img() Images Logos
col_reference() Links DOIs
col_group() Group header Organize columns

Text & Numbers

Basic columns for displaying text and numeric data.

Code
data(glp1_trials)

glp1_trials |>
  filter(row_type == "data", group == "Main Trials") |>
  head(4) |>
  tabviz(
    label = "study",
    columns = list(
      col_text("drug", "Drug"),
      col_numeric("hr", "HR", decimals = 2),
      col_n("n", "N"),
      col_n("n", "N (abbrev)", abbreviate = TRUE),
      col_percent("pvalue", "As %", multiply = FALSE)
    )
  )

Formatting Options

See all formatting options side-by-side:

Code
options_data <- data.frame(
  item = c("Small study", "Medium study", "Large study"),
  n = c(125, 4520, 1250000),
  rate = c(0.156, 0.892, 0.034),
  value = c(1.234, 12.34, 123.4)
)

tabviz(options_data,
  label = "item",
  columns = list(
    col_n("n", "N"),
    col_n("n", "N (abbrev)", abbreviate = TRUE),
    col_numeric("value", "decimals=2", decimals = 2),
    col_numeric("value", "digits=3", digits = 3),
    col_percent("rate", "Percent")
  )
)

Effect Estimates

Columns for displaying statistical results.

Code
glp1_trials |>
  filter(row_type == "data", group == "Main Trials") |>
  head(4) |>
  tabviz(
    label = "study",
    columns = list(
      viz_forest(point = "hr", lower = "lower", upper = "upper",
                 scale = "log", null_value = 1, width = 180),
      col_interval(point = "hr", lower = "lower", upper = "upper",
                   header = "HR (95% CI)"),
      col_pvalue("pvalue", "P-value"),
      col_pvalue("pvalue", "P*", stars = TRUE)
    )
  )

Formatting Options

Compare interval and p-value formatting:

Code
pval_data <- data.frame(
  result = c("Significant", "Marginal", "Not significant", "Highly significant"),
  hr = c(0.72, 0.89, 1.05, 0.45),
  lower = c(0.58, 0.78, 0.85, 0.32),
  upper = c(0.89, 1.02, 1.30, 0.63),
  pval = c(0.003, 0.08, 0.45, 0.00001)
)

tabviz(pval_data,
  label = "result",
  columns = list(
    col_interval(point = "hr", lower = "lower", upper = "upper",
                 header = "Default", decimals = 2),
    col_interval(point = "hr", lower = "lower", upper = "upper",
                 header = "1 decimal", decimals = 1),
    col_pvalue("pval", "P"),
    col_pvalue("pval", "P*", stars = TRUE)
  )
)

Clinical Data

Specialized columns for clinical trial data.

Code
clinical_data <- data.frame(
  study = c("SUSTAIN-6", "PIONEER 6", "LEADER", "REWIND"),
  events = c(108, 137, 608, 594),
  n = c(3297, 3183, 9340, 9901),
  age_min = c(55, 50, 40, 45),
  age_max = c(80, 75, 85, 78)
)

tabviz(clinical_data,
  label = "study",
  columns = list(
    col_events("events", "n", "Events/N"),
    col_events("events", "n", "With %", show_pct = TRUE),
    col_range(min_field = "age_min", max_field = "age_max", header = "Age Range")
  )
)

Visualizations

Columns that display data graphically.

Code
# Create visualization demo data
viz_data <- data.frame(
  carrier = c("Delta", "United", "American", "Southwest"),
  on_time = c(0.84, 0.78, 0.76, 0.82),
  weight = c(35, 28, 25, 32)
)
# Add sparkline data as list column
viz_data$trend <- list(
  c(82, 85, 81, 88, 84, 86, 83, 87, 85, 89, 84, 86),
  c(75, 78, 74, 80, 77, 79, 76, 81, 78, 82, 77, 80),
  c(73, 76, 72, 79, 75, 77, 74, 80, 76, 78, 75, 77),
  c(80, 83, 79, 85, 81, 84, 80, 86, 82, 85, 81, 84)
)

tabviz(viz_data,
  label = "carrier",
  columns = list(
    col_bar("on_time", "On-Time", width = 100),
    col_bar("weight", "Weight", width = 80),
    col_sparkline("trend", "Line", width = 80),
    col_sparkline("trend", "Area", type = "area", width = 80),
    col_sparkline("trend", "Bars", type = "bar", width = 80)
  ),
  theme = web_theme_modern()
)

Note: Sparklines require list-columns with numeric vectors. Create with mutate(trend = list(c(1,2,3))).


Status Indicators

Columns for showing status, quality, or categories.

Code
status_data <- data.frame(
  study = c("Trial A", "Trial B", "Trial C", "Trial D"),
  hr = c(0.72, 0.85, 0.91, 0.68),
  lower = c(0.55, 0.70, 0.75, 0.52),
  upper = c(0.95, 1.03, 1.10, 0.89),
  quality = c(5, 3, 4, 5),
  status = c("Published", "Preprint", "Published", "Retracted"),
  direction = c("Benefit", "Neutral", "Neutral", "Benefit")
)

tabviz(status_data,
  label = "study",
  columns = list(
    viz_forest(point = "hr", lower = "lower", upper = "upper",
               scale = "log", null_value = 1),
    col_stars("quality", "Quality"),
    col_badge("status", "Status",
      variants = list(
        Published = "success",
        Preprint = "warning",
        Retracted = "error"
      )),
    col_icon("direction", "Effect",
      mapping = list(Benefit = "OK", Neutral = "-", Harm = "X"))
  )
)

Badge variants: "success" (green), "warning" (yellow), "error" (red), "info" (blue), "muted" (gray).


Column Groups

Group related columns under a shared header:

Code
outcomes_data <- data.frame(
  study = c("PARADIGM-HF", "DAPA-HF", "EMPEROR-Reduced"),
  primary_hr = c(0.80, 0.74, 0.75),
  primary_lower = c(0.73, 0.65, 0.65),
  primary_upper = c(0.87, 0.85, 0.86),
  primary_p = c(0.001, 0.001, 0.001),
  secondary_hr = c(0.84, 0.70, 0.69),
  secondary_p = c(0.01, 0.001, 0.001)
)

tabviz(outcomes_data,
  label = "study",
  columns = list(
    viz_forest(point = "primary_hr", lower = "primary_lower", upper = "primary_upper",
               null_value = 1, scale = "log"),
    col_group("Primary Endpoint",
      col_interval(point = "primary_hr", lower = "primary_lower", upper = "primary_upper",
                   header = "HR (95% CI)"),
      col_pvalue("primary_p", "P")
    ),
    col_group("Secondary Endpoint",
      col_numeric("secondary_hr", "HR", decimals = 2),
      col_pvalue("secondary_p", "P")
    )
  ),
  theme = web_theme_modern()
)

Use column groups for: - Multiple outcomes (primary, secondary) - Multiple time points (30-day, 1-year) - Multiple analyses (ITT, per-protocol)


Column Width & Styling

Width Control

col_numeric("n", "N", width = 60)       # Fixed width
col_text("notes", "Notes", width = 200) # Wide column
col_interval(...)                        # Auto-width (default)

Per-Cell Styling

Every column accepts styling parameters:

Code
glp1_trials |>
  filter(row_type == "data", group == "Main Trials") |>
  head(4) |>
  mutate(
    is_sig = upper < 1,
    hr_color = ifelse(upper < 1, "#166534", "#64748b")
  ) |>
  tabviz(
    label = "study",
    columns = list(
      col_interval(point = "hr", lower = "lower", upper = "upper",
                   header = "HR (95% CI)", bold = "is_sig", color = "hr_color"),
      col_pvalue("pvalue", "P", bold = "is_sig")
    )
  )

Available style parameters:

Parameter Type Effect
bold logical column Bold when TRUE
italic logical column Italic when TRUE
color color column Text color
bg color column Background color

See Cell Styling for more conditional formatting patterns.


See Also