A table built for a browser and a table built for a feed are not the
same object. gt::gtsave() writes what the browser rendered,
margins included, at whatever size the page happened to be. Posting
wants a trimmed image, a predictable width across a set, and often a
specific shape.
This vignette covers the export side of the package:
gt_save_crop(), gt_social_crop(),
gt_save_batch(), the "social" density on every
theme, and the two attribution functions, gt_watermark()
and gt_social_tag().
Everything below runs on mtcars.
cars <- head(mtcars, 8)
cars$car <- rownames(cars)
cars <- cars[c("car", "mpg", "hp", "wt")]
tbl <- gt(cars) %>%
gt_theme_broadsheet() %>%
tab_header("Fuel economy and power", "1974 Motor Trend road tests") %>%
fmt_number(c(mpg, wt), decimals = 1)Trimming and padding
gt_save_crop() renders the table, trims the whitespace
around it, then pads it back by a fixed amount so the image has an even
margin on all four sides.
tbl %>% gt_save_crop(file = "table.png")
whitespace sets that margin in pixels and
bg sets its color, which should match the theme’s
background. zoom controls the render scale, at
2 by default, so the output is retina-sized.
width is the one to know about for a series. Passing it
scales the finished image to an exact pixel width, holding the aspect
ratio. The table above comes out 696 by 814. With
width = 900 it becomes 900 by 1053.
tbl %>% gt_save_crop(file = "table.png", width = 900)Leave file unset and the image is returned rather than
written, which is useful when you want to keep working on it with
magick.
Sizing type for an image
Type sized for a browser reads small once the image is scaled into a
feed. Every theme in the package takes a density argument,
and "social" is the setting built for this (17px body,
roomier rows, and a larger title).
gt(cars) %>% gt_theme_broadsheet(density = "social")
A fixed canvas
Some destinations want a shape rather than a size.
gt_social_crop() centers the table on a canvas of a target
aspect ratio.
gt(cars) %>%
gt_theme_broadsheet(density = "social") %>%
gt_social_crop(aspect_ratio = "1:1", bg = "#FBFAF7", file = "square.png")
aspect_ratio reads "1:1",
"16:9", "4x5", or a bare number like
1.91.
The canvas always grows to fit. The same table comes out 834 by 834
at "1:1" and 1483 by 834 at "16:9", so the
height held and the width expanded. It works that way in both
directions, which means the table is never cropped to make the ratio.
gravity moves the table on the canvas if you do not want it
centered.
Attribution
gt_watermark() puts a faint wordmark behind the table
body, and gt_social_tag() puts handles and icons in the
source note.
tbl %>%
gt_watermark(text = "gtUtils", opacity = 0.06, size = "62%", angle = 20,
font = "Helvetica") %>%
gt_social_tag(c(x = "@andreweatherman", gh = "andreweatherman"),
caption = "Built with gtUtils") %>%
gt_save_crop(file = "branded.png")
Two things about the watermark.
It is drawn as an SVG background image, because that is the only way
to sit behind the body without taking up a row. An SVG background cannot
load the page’s webfonts, so font has to name a face
installed on the machine doing the rendering. "Helvetica"
and "Arial" are safe. A Google font named there will
silently fall back.
It also sits behind the body cells, so it disappears under any cell
that has its own fill. On a striped theme, or after
gt_color_ranks(), you will only see it in the gaps. Themes
without fills, like gt_theme_broadsheet() or
gt_theme_swiss(), show it cleanly.
gt_social_tag() takes a named vector where the names
pick the icon. It knows the common aliases (x,
bsky, ig, gh, yt,
web, email among others) and falls back to any
Font Awesome icon name. stack = TRUE puts one account per
line for a narrow table.
One image per group
gt_save_batch() splits the data, builds a table for each
group with a function you supply, and writes one image per group.
bcars <- mtcars
bcars$car <- rownames(bcars)
bcars <- bcars[c("car", "cyl", "mpg", "hp")]
gt_save_batch(
bcars,
group = cyl,
file = "cyl-{group}.png",
dir = "out",
fn = function(df, g) {
gt(df[c("car", "mpg", "hp")]) %>%
gt_theme_broadsheet() %>%
tab_header(paste0(g, "-cylinder cars"))
}
)
file is a pattern rather than a path.
{group} is replaced by each group’s value, so this writes
out/cyl-4.png, out/cyl-6.png, and
out/cyl-8.png. The directory is created if it does not
exist.
fn receives that group’s rows and the group value, and
has to return a gt_tbl. Anything else raises an error
naming what came back instead.
match_width is on by default and is the reason to use
this over a loop. The three groups here hold 11, 7, and 14 cars, so the
tables render at different widths. Every image is padded out to the
widest of them, giving 524 pixels across all three with heights of 680,
944, and 1142.
Set match_width = FALSE to keep each image at its
natural width, and quiet = TRUE to suppress the per-group
progress messages.
