Builds a figure display, the "F" in TFL. figure() takes a ggplot, a
recorded base-R plot, a zero-argument drawing function, or a path to a
PNG / JPG file, and surrounds it with the same canonical submission
chrome as a table: up to four centred title lines, footnotes, and the
per-page header / footer drawn from the active preset(). Pass a
list to emit one figure per page in a single file.
The figure to display. One of: a ggplot object; a
recorded base plot from grDevices::recordPlot(); a
zero-argument function that draws to the active device when called;
a length-1 path to a .png, .jpg, or .jpeg file; or a list
of any of these for a multi-page figure.
Tip: a list may mix kinds freely — a ggplot, a recorded plot,
and a PNG path can share one multi-page figure.
titles
Title lines above the figure.<character> | NULL.
One element per line, up to four; same {glue} interpolation and
md() / html() inline formatting as tabular(). NULL
draws no titles.
footnotes
Footnote lines below the figure.<character> | NULL. One element per line; same interpolation and inline
formatting as titles. NULL draws no footnotes.
width
Drawn image width in inches.<numeric(1)> | NULL.
NULL fills the full printable width.
height
Drawn image height in inches.<numeric(1)> | NULL.
NULL fills the body box height (the printable height minus the title
and footnote chrome). Set a smaller value to leave vertical slack for
valign to place the image within.
halign
Horizontal placement in the content box.<character(1)>. One of:
"left"
"center" (default)
"right"
valign
Vertical placement in the content box.<character(1)>. One of:
"top"
"middle" (default)
"bottom"
Note: continuous backends (HTML / Markdown) render the figure
contained to the viewport with no fixed page height, so valign is a
no-op there; the paged backends honour it exactly.
dpi
Raster resolution for plot inputs.<numeric(1)>.
Resolution in dots per inch for PNG rasterisation. Ignored for file
inputs (passed through unchanged) and for vector PDF targets.
meta
Per-page token data frame.<data.frame> | NULL.
Multi-page only: one row per plot, whose columns become {token}
values in that page's titles / footnotes. Ignored (with a
warning) for a single-plot figure.
Value
A figure_spec. Pass it to emit() to write a file, or
print it to preview the figure inline.
Details
Two-axis placement. By default the image FILLS the body content box —
the full printable width by the box height (the printable height minus the
title / footnote chrome). Pass an explicit width / height smaller than
the box and halign / valign place the image within the resulting slack,
independently — horizontally (left / center / right) and vertically
(top / middle / bottom), both defaulting to centred. Paged backends
(RTF / PDF / DOCX) honour valign exactly against the content-box height;
with the box-filling default there is no vertical slack, so valign only
bites once you set a shorter height. The continuous backends (HTML /
Markdown) render the figure responsively, contained to the viewport, so
halign still applies but valign is a no-op there.
Format-aware rasterisation. Plot inputs render to vector PDF for
.pdf / .tex targets and to PNG at dpi for every other backend;
file inputs pass through byte-for-byte. No raster work happens until
emit().
Styling the chrome. A figure carries the same chrome surfaces as a
table, so style() and the preset() cosmetic knobs reach its
titles, footnotes, and page header / footer — e.g.
style(fig, font_size = 14, .at = cells_title()) or
preset(fig, colors = list(footnotes = c(text = "grey40"))). A figure
has no body, column headers, or subgroup banner, so styling those
surfaces is an error. Inter-section spacing follows the preset spacing
knob (title, footnote), exactly like a table.
See also
Terminal verb:emit() (write the figure to a file).
# ---- Example 1: a single base-R figure with submission chrome ----## A zero-argument drawing function is the simplest portable input: it# draws to whatever device the backend opens. Here, subjects enrolled# per treatment arm from the bundled BigN frame, wrapped in the# canonical title block and a population footnote.arms<-cdisc_saf_n[cdisc_saf_n$arm_short!="Total", ]draw_enrollment<-function(){barplot(arms$n, names.arg =arms$arm_short, ylab ="Subjects enrolled", col ="grey70")}fig<-figure(draw_enrollment, titles =c("Figure 14.1.1","Subjects Enrolled by Treatment Arm","Safety Population"), footnotes ="Total enrolled: N = 254.")fig
Figure 14.1.1
Subjects Enrolled by Treatment Arm
Safety Population
Total enrolled: N = 254.
# ---- Example 2: one figure per page from a list ----## A list input emits one figure per page in a single file. Each arm# gets its own page; the kinds may mix (a ggplot, a recorded plot, or# a PNG path could share the list). Bottom-anchored here to show the# two-axis placement.draw_arm<-function(i){force(i)function(){barplot(arms$n[i], names.arg =arms$arm_short[i], col ="grey70")}}per_arm<-figure(lapply(seq_len(nrow(arms)), draw_arm), titles =c("Figure 14.1.2", "Enrollment by Arm, One Page per Arm"), valign ="bottom")per_arm