Controlling the width of data frame tables
Joe Zhu
([shajoezhu])
2026-11-13
Source:vignettes/table_widths.Rmd
table_widths.RmdOverview
Data frame slides (the small tables made by df_*
programs, for example in dose-escalation decks) get their size from
autoslider.core, not from the PowerPoint theme. This guide shows how to
control:
- the width of the whole table on the slide, and
- the width of each column.
Widths are in inches. A 16:9 slide is 13.33 in wide in
basic.pptx and 10 in wide in the 10 x 5.625 in dose
themes.
How the width is set
When generate_slides() turns a data frame into a table,
it works in this order:
-
Size the columns.
-
dose_template = TRUE(dose decks): each column is sized to its content (flextable::autofit()), and the table is shrunk only if it is wider than 10 in (flextable::fit_to_width(10)). A small table stays small: it is not stretched to fill the slide or the placeholder. -
dose_template = FALSE(the default): the columns take the widths incol_width(when given). If the table is then wider than 10 in, all columns are scaled down to a total of 10.5 in.
-
-
Apply the table format (
table_format, e.g.autoslider_formator a study format). -
Place the table at
table_loc. A placeholder location such asofficer::ph_location_label("Content Placeholder 2")sets where the table goes, not how wide it is.
Two things follow from this order:
-
col_widthonly has an effect whendose_template = FALSE. - Anything the table format does to the widths comes last, so it always wins. A format function is therefore the way to control widths in a dose deck.
Example data and a helper
library(autoslider.core)
cohorts <- data.frame(
Cohort = c("Cohort 1", "Cohort 2", "Cohort 3"),
"IMP Dose" = c("10 mg QW", "20 mg QW", "40 mg QW"),
"No. pts dosed" = c(3, 3, 4),
"DLT details" = c("None", "Grade 3 rash in one patient", "None"),
check.names = FALSE
)The helper below reads the column widths of the table on the last slide of a deck, so we can see what each setting does. It is only for this guide; you do not need it in a study.
slide_col_widths <- function(pptx) {
dir <- tempfile()
utils::unzip(pptx, exdir = dir)
slides <- list.files(file.path(dir, "ppt", "slides"), pattern = "^slide[0-9]+\\.xml$", full.names = TRUE)
last <- slides[order(as.integer(gsub("\\D", "", basename(slides))))][length(slides)]
cols <- xml2::xml_find_all(xml2::read_xml(last), "//a:gridCol")
round(as.numeric(xml2::xml_attr(cols, "w")) / 914400, 2) # EMU to inches
}
make_slide <- function(..., table_format = autoslider_dose_format) {
out <- tempfile(fileext = ".pptx")
generate_slides(list(cohorts = cohorts), outfile = out, table_format = table_format, ...)
out
}Column widths
Default: sized to the content
In a dose deck each column is as wide as its content needs:
w <- slide_col_widths(make_slide(dose_template = TRUE))
w
#> [1] 0.94 1.09 1.34 2.39
sum(w)
#> [1] 5.76Set every column with col_width
Give one width per column. This needs
dose_template = FALSE:
slide_col_widths(make_slide(dose_template = FALSE, col_width = c(1.2, 1.4, 1, 3)))
#> [1] 1.2 1.4 1.0 3.0With dose_template = TRUE, col_width is
ignored and the columns are sized to their content again:
slide_col_widths(make_slide(dose_template = TRUE, col_width = c(1.2, 1.4, 1, 3)))
#> [1] 0.94 1.09 1.34 2.39Note that dose_template = FALSE also builds the header
from the data frame’s variable labels (or the column names when there
are none).
Set some columns in a table format
To keep the dose layout and change just the columns you care about,
set their width in a table format. A format receives the slide’s font
sizes (body_font_size, footer_font_size, …)
through .... Only pass ... on to a format that
accepts them, such as autoslider_format() or a study format
with those arguments; autoslider_dose_format() does not, so
the examples here call it with ft alone.
Columns can be named or numbered:
wide_dlt_format <- function(ft, ...) {
ft <- autoslider_dose_format(ft)
flextable::width(ft, j = "DLT details", width = 3.5)
}
slide_col_widths(make_slide(dose_template = TRUE, table_format = wide_dlt_format))
#> [1] 0.94 1.09 1.34 3.50Only the “DLT details” column changed; the others keep their content width.
Table width
Shrink a wide table
flextable::fit_to_width() scales the columns down so the
table is at most max_width inches wide. It never makes a
table wider.
narrow_format <- function(ft, ...) {
ft <- autoslider_dose_format(ft)
flextable::fit_to_width(ft, max_width = 4)
}
w <- slide_col_widths(make_slide(dose_template = TRUE, table_format = narrow_format))
w
#> [1] 0.60 0.70 0.94 1.53
sum(w)
#> [1] 3.77Stretch a table to a set width
To make a small table fill the slide, scale all columns so they add up to the width you want. The columns keep their relative sizes:
table_width <- function(ft, width) {
widths <- flextable::flextable_dim(ft)$widths
flextable::width(ft, width = dim(ft)$widths * width / widths)
}
full_width_format <- function(ft, ...) {
ft <- autoslider_dose_format(ft)
table_width(ft, width = 9)
}
w <- slide_col_widths(make_slide(dose_template = TRUE, table_format = full_width_format))
w
#> [1] 1.47 1.71 2.09 3.73
sum(w)
#> [1] 9On a 10 in dose slide, 9 in leaves a 0.5 in margin each side when the table starts 0.5 in from the left edge.
Fixed widths for every column
A format can also give every column a fixed width. The number of widths must match the number of columns, so this only suits a format used by one table:
cohort_table_format <- function(ft, ...) {
ft <- autoslider_dose_format(ft)
flextable::width(ft, width = c(1.2, 1.4, 1, 4.5))
}
slide_col_widths(make_slide(dose_template = TRUE, table_format = cohort_table_format))
#> [1] 1.2 1.4 1.0 4.5Using this in a dose speclayout
Put the format functions in the study’s R/formats.R
(which run_slides.R sources), then name them per slide in
dose_speclayout.yml. Keep the font-size arguments so a
per-slide font_size: block still reaches the format:
# R/formats.R
full_width_gred <- function(ft, body_font_size = 8, header_font_size = 8, ...) {
ft <- black_format_gred(ft, body_font_size = body_font_size, header_font_size = header_font_size, ...)
widths <- flextable::flextable_dim(ft)$widths
flextable::width(ft, width = dim(ft)$widths * 9 / widths)
}# Stretch this table to 9 in.
df_all_cohorts_demo1_DM:
program: df_all_cohorts_demo1
suffix: DM
table_format: full_width_gred
table_loc: officer::ph_location_label("Content Placeholder 2")
# Or set the column widths directly, without the dose layout.
df_patient_overview_slide_DM:
program: df_patient_overview_slide
suffix: DM
dose_template: FALSE
col_width: c(0.8, 0.8, 1.2, 1.5, 1, 1, 2)Values in a dose speclayout are evaluated as R code, so
col_width is written as c(...).
Summary
| Goal | Dose deck (dose_template = TRUE) |
dose_template = FALSE |
|---|---|---|
| Widths of all columns | Table format: flextable::width(ft, width = c(...))
|
col_width = c(...) |
| Width of one column | Table format:
flextable::width(ft, j = "name", width = )
|
Table format, as for dose decks |
| Shrink the table to a maximum | Table format: flextable::fit_to_width(ft, max_width = )
(wider than 10 in is shrunk automatically) |
Automatic above 10 in (scaled to 10.5 in) |
| Stretch the table to a width | Table format: scale dim(ft)$widths to the total you
want |
Same, or choose col_width to add up to it |
Table position comes from table_loc; width comes from
the steps above. See also vignette("using_formats") for
colors, fonts and borders.