---
title: "Columns"
---
```{r}
#| include: false
library(tabviz)
library(dplyr)
```
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 |
::: {.callout-tip}
## When in Doubt
Start with `col_text()` for any data, then upgrade to a specialized type when formatting becomes important.
:::
---
## Column Gallery
Here's every column type in action:
```{r}
#| fig-height: 5
# Create demo data showcasing all column types
gallery_data <- data.frame(
study = c("EMPA-REG 2015", "CANVAS 2017", "DECLARE 2019", "CREDENCE 2019"),
drug = c("Empagliflozin", "Canagliflozin", "Dapagliflozin", "Canagliflozin"),
hr = c(0.86, 0.86, 0.93, 0.70),
lower = c(0.74, 0.75, 0.84, 0.59),
upper = c(0.99, 0.97, 1.03, 0.82),
n = c(7020, 10142, 17160, 4401),
events = c(490, 585, 882, 245),
pvalue = c(0.04, 0.02, 0.17, 0.001),
on_time_pct = c(0.89, 0.85, 0.92, 0.88),
weight = c(20, 29, 36, 15),
quality = c(5, 4, 5, 4),
status = c("Published", "Published", "Published", "Published"),
age_min = c(55, 50, 40, 45),
age_max = c(80, 75, 85, 78),
trend = I(list(c(1,2,1.5,3,2.5), c(2,1,2,1.5,2), c(1,1.5,2,2.5,3), c(3,2,2.5,1.5,1)))
)
tabviz(gallery_data,
label = "study",
columns = list(
col_text("drug", "Drug"),
col_n("n", "N"),
col_events("events", "n", "Events"),
col_percent("on_time_pct", "Rate"),
col_bar("weight", "Weight", width = 70),
col_sparkline("trend", "Trend", width = 60),
viz_forest(point = "hr", lower = "lower", upper = "upper",
scale = "log", null_value = 1, width = 140),
col_interval(point = "hr", lower = "lower", upper = "upper", header = "HR (95% CI)"),
col_pvalue("pvalue", "P", stars = TRUE),
col_stars("quality", "Quality"),
col_badge("status", "Status")
),
theme = web_theme_modern(),
title = "Column Types Gallery"
)
```
## 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.
```{r}
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:
```{r}
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.
```{r}
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:
```{r}
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.
```{r}
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.
```{r}
# 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.
```{r}
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:
```{r}
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
```r
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:
```{r}
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](cell-styling.qmd) for more conditional formatting patterns.
***
## See Also
- [Package Data](package-data.qmd) — Built-in datasets for examples
- [Forest Plots](visualizations/forest-plots.qmd) — Detailed `viz_forest()` options
- [Cell Styling](cell-styling.qmd) — Conditional formatting