library(lt)
Pass any data frame to lt():
tbl_cars = lt(head(mtcars))
tbl_cars
tbl_iris = lt(head(iris))
tbl_iris |>
lt_header(title = "Iris Measurements", subtitle = "First six observations")
By default, numeric columns are right-aligned and character columns are
left-aligned. Override with lt_align():
tbl_cars |> lt_align(~ mpg + cyl, "center") |> lt_width(mpg = "6em")
tbl_cars |> lt_format(~ mpg + disp, decimals = 1)
Control the number of decimal places with decimals:
d = data.frame(
Metric = c("Revenue", "Costs", "Profit"),
Q1 = c(1234567.891, 987654.321, 246913.570),
Q2 = c(1345678.912, 1012345.678, 333333.234)
)
lt(d) |>
lt_format(~ Q1 + Q2, decimals = 2)
lt(d) |>
lt_format(~ Q1 + Q2, decimals = 0, big_mark = ",")
tbl_cars |>
lt_header(title = "Motor Trend Cars") |>
lt_footnote("Source: 1974 Motor Trend US magazine.", "title") |>
lt_footnote("Miles per US gallon.", "column", "mpg")
Notes appear in the footer below numbered footnotes:
tbl_cars |> lt_note("Data from the 1974 Motor Trend US magazine.")
A spanner groups contiguous columns under a shared label:
tbl_iris |>
lt_spanner(Sepal ~ Sepal.Length + Sepal.Width) |>
lt_spanner(Petal ~ Petal.Length + Petal.Width)
When column names share a common prefix separated by . or _, call
lt_spanner() with no arguments to infer spanners automatically:
tbl_iris |> lt_spanner()
tbl_iris |>
lt_header(title = "Iris Dataset") |>
lt_spanner(Sepal ~ Sepal.Length + Sepal.Width) |>
lt_spanner(Petal ~ Petal.Length + Petal.Width) |>
lt_format(~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, decimals = 1)
Pass a column name to lt_group() to partition rows by that column’s
values. The column is removed from the body and its values become group
headers:
d = data.frame(
Region = c("East", "East", "West", "West", "West"),
City = c("New York", "Boston", "Seattle", "Portland", "Denver"),
Population = c(8336817, 675647, 737015, 652503, 715522)
)
lt(d) |>
lt_group(~ Region) |>
lt_header(title = "US Cities by Region") |>
lt_format(~ Population, big_mark = ",")
d = data.frame(
Category = c("Fruits", "Fruits", "Vegetables", "Vegetables"),
Item = c("Apple", "Banana", "Carrot", "Broccoli"),
Calories = c(95, 105, 25, 55),
Fiber_g = c(4.4, 3.1, 2.8, 5.1)
)
lt(d) |>
lt_group(~ Category) |>
lt_header(title = "Nutritional Information") |>
lt_format(~ Fiber_g, decimals = 1)
Pass multiple columns to lt_group() to render hierarchical rowspan
cells on the left side of the table:
d = data.frame(
Region = c("East", "East", "East", "West", "West", "West"),
State = c("NY", "NY", "MA", "WA", "WA", "OR"),
City = c("New York", "Buffalo", "Boston", "Seattle", "Spokane", "Portland"),
Population = c(8336817, 278349, 675647, 737015, 228989, 652503)
)
lt(d) |>
lt_group(~ Region + State) |>
lt_header(title = "Cities by Region and State") |>
lt_format(~ Population, big_mark = ",")
Use sep = TRUE to render groups as full-width separator rows instead of
rowspan cells:
d = data.frame(
Region = c("East", "East", "West", "West", "West"),
City = c("New York", "Boston", "Seattle", "Portland", "Denver"),
Population = c(8336817, 675647, 737015, 652503, 715522)
)
lt(d) |>
lt_group(~ Region, sep = TRUE) |>
lt_header(title = "US Cities by Region") |>
lt_format(~ Population, big_mark = ",")
Use named arguments in lt_group() for explicit control over which rows
belong to each group:
tbl_cars |> lt_group("First three" = 1:3, "Last three" = 4:6)
Combine columns into one using a pattern. Source columns are hidden automatically:
d = data.frame(
stat = c("Age", "Weight", "Height"),
n = c(67, 65, 64),
pct = c(100, 97.0, 95.5)
)
lt(d) |>
lt_format(~ pct, decimals = 1) |>
lt_merge(~ n + pct, pattern = "{1} ({2}%)") |>
lt_label(n = "n (%)")
<< >>Wrap pattern sections in << and >> to drop them when any referenced
column is empty/NA:
d = data.frame(
endpoint = c("Primary", "Secondary", "Tertiary"),
est = c(0.61, 0.79, 0.45),
ci_lo = c(0.40, 0.57, NA),
ci_hi = c(0.82, 1.01, NA)
)
lt(d) |>
lt_format(~ est + ci_lo + ci_hi, decimals = 2) |>
lt_merge(~ est + ci_lo + ci_hi, pattern = "{1}<< ({2}, {3})>>") |>
lt_label(est = "Estimate (95% CI)")
Indent the first column to show hierarchy:
d = data.frame(
label = c("Any AE", "SOC: Cardiac", "Tachycardia", "Bradycardia",
"SOC: GI", "Nausea"),
n_pct = c("45 (67%)", "30 (45%)", "15 (22%)", "18 (27%)", "20 (30%)", "12 (18%)")
)
lt(d) |>
lt_header("Adverse Events", "Safety Population") |>
lt_indent(c(2, 5), level = 1) |>
lt_indent(c(3, 4, 6), level = 2)
d = data.frame(
Metric = c("HR", "p-value", "Events", "Rate"),
Value = c(0.62, 0.0003, 0, NA)
)
lt(d) |>
lt_format(~ Value, decimals = 2) |>
lt_sub(~ Value, missing = "n/a", zero = "—", small = 0.001, small_text = "< 0.001")
Highlight specific cells with bold, color, background, or any CSS property (camelCase or dash-case):
d = data.frame(
Endpoint = c("Primary", "Secondary", "Exploratory"),
HR = c(0.62, 0.79, 0.91),
P = c(0.001, 0.042, 0.38)
)
lt(d) |>
lt_format(~ HR, decimals = 2) |>
lt_format(~ P, decimals = 3) |>
lt_style("P", rows = 1:2L, bold = TRUE, color = "#06c") |>
lt_style("HR", rows = 1L, bg = "#e8f4e8", borderBottom = "2px solid #4a4")
Apply styles based on cell values using a JavaScript test function. Use
class to assign CSS classes, then define the rules with lt_css():
d = data.frame(
Endpoint = c("Primary", "Secondary", "Exploratory"),
HR = c(0.62, 0.79, 1.05),
P = c(0.001, 0.042, 0.38)
)
lt(d) |>
lt_format(~ HR + P, decimals = 3) |>
lt_style("HR", test = "v => v < 1", class = "good") |>
lt_style("P", test = "v => v < 0.05", class = "sig") |>
lt_css(.good = list(color = "green"), .sig = list(fontWeight = "bold"))
d = data.frame(
arm = c("Treatment", "Control", "Treatment"),
n = c(30, NA, 28),
response = c(0.67, NA, NA)
)
lt(d) |>
lt_style(test = "v => v == null", class = "na") |>
lt_css(.na = list(background = "#fee"))
tbl_cars |> lt_width(mpg = "8em", cyl = "5em", disp = "8em", hp = "6em")
tbl_iris |> lt_move(~ Petal.Length + Petal.Width, after = NULL)
d = data.frame(
arm = c("Placebo", "Placebo", "Treatment", "Treatment"),
stat = c("n", "Mean", "n", "Mean"),
value = c("30", "4.2", "31", "6.8")
)
lt(d) |>
lt_group(~ arm, sep = TRUE) |>
lt_group("Treatment", "Placebo")
d = data.frame(
Group = c("Treatment", "Treatment", "Control", "Control"),
Endpoint = c("Primary", "Secondary", "Primary", "Secondary"),
Estimate = c(0.6123, 0.7891, 0.4567, 0.5432),
CI_Lower = c(0.4012, 0.5678, 0.2345, 0.3210),
CI_Upper = c(0.8234, 1.0104, 0.6789, 0.7654),
P_Value = c(0.0012, 0.0456, 0.1234, 0.2345)
)
lt(d) |>
lt_group(~ Group) |>
lt_header(
title = "Study Results",
subtitle = "Primary and secondary endpoints"
) |>
lt_spanner(`95% CI` ~ CI_Lower + CI_Upper) |>
lt_format(~ Estimate + CI_Lower + CI_Upper, decimals = 3) |>
lt_format(~ P_Value, decimals = 4) |>
lt_footnote("Two-sided p-value from log-rank test.", "column", "P_Value")