Experiment
library(ggplot2)
library(patchwork)
# =====================================================================
# BUSINESS CARD SHEET LAYOUT
# Defaults below match the most common perforated sheet layout
# (Avery 5371 / 28371 / 8371 and most "10-up" business card stock):
# - US Letter page: 8.5 x 11 in
# - 10 cards per sheet: 2 columns x 5 rows
# - each card: 3.5 x 2 in
# - margins: 0.75 in left/right, 0.5 in top/bottom
# If your brand of card stock differs, just change these numbers —
# everything else derives from them.
# =====================================================================
page_width <- 8.5 # in
page_height <- 11 # in
card_width <- 3.5 # in
card_height <- 2 # in
ncol_cards <- 2
nrow_cards <- 5
left_margin <- 0.75 # in
top_margin <- 0.5 # in
# sanity check: grid + margins should equal the page exactly
stopifnot(abs((ncol_cards * card_width + 2 * left_margin) - page_width) < 1e-6)
stopifnot(abs((nrow_cards * card_height + 2 * top_margin) - page_height) < 1e-6)
# =====================================================================
# YOUR SUBPLOTS — replace make_plot() with your real plotting code.
# Each plot should be "clean" (theme_void or minimal theme, no titles
# that will get clipped) since it will be squeezed into a 3.5 x 2 card.
# =====================================================================
make_plot <- function(i) {
set.seed(i)
df <- data.frame(x = rnorm(40), y = rnorm(40))
ggplot(df, aes(x, y)) +
geom_point(size = 1, color = "steelblue") +
theme_void() +
theme(plot.margin = margin(4, 4, 4, 4)) +
labs(title = paste("Card", i)) +
theme(plot.title = element_text(size = 8, hjust = 0.5))
}
n_cards <- ncol_cards * nrow_cards
plots <- lapply(seq_len(n_cards), make_plot)
# =====================================================================
# ARRANGE WITH PATCHWORK
# =====================================================================
grid <- wrap_plots(plots, ncol = ncol_cards, nrow = nrow_cards)
# Push the whole grid into the page at the exact perforation margins.
# Because ggplot/grid honor absolute units ("in"), this stays pixel-
# perfect regardless of the output device size, as long as you save
# at exactly page_width x page_height below.
grid <- grid + plot_annotation(
theme = theme(
plot.margin = margin(
t = top_margin, r = left_margin,
b = top_margin, l = left_margin,
unit = "in"
)
)
)
# =====================================================================
# OPTIONAL: draw faint card outlines so you can test alignment on
# plain paper before committing to real perforated stock. Comment
# this block out once you've confirmed alignment.
# =====================================================================
grid <- grid & theme(
plot.background = element_rect(colour = "grey80", linewidth = 0.3, fill = NA)
)
# =====================================================================
# SAVE — width/height MUST equal page_width/page_height exactly.
# =====================================================================
ggsave(
filename = "business_card_plots.pdf",
plot = grid,
width = page_width,
height = page_height,
units = "in",
device = cairo_pdf # keeps vector output crisp; falls back to pdf() if unavailable
)
## Warning in grSoftVersion(): unable to load shared object '/Library/Frameworks/R.framework/Resources/modules//R_X11.so':
## dlopen(/Library/Frameworks/R.framework/Resources/modules//R_X11.so, 0x0006): Library not loaded: /opt/X11/lib/libSM.6.dylib
## Referenced from: <7ECC4104-EC6A-38FD-9BEA-BFE0B870925C> /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/modules/R_X11.so
## Reason: tried: '/opt/X11/lib/libSM.6.dylib' (fat file, but missing compatible architecture (have 'i386,x86_64', need 'arm64e' or 'arm64e.v1' or 'arm64' or 'arm64')), '/System/Volumes/Preboot/Cryptexes/OS/opt/X11/lib/libSM.6.dylib' (no such file), '/opt/X11/lib/libSM.6.dylib' (fat file, but missing compatible architecture (have 'i386,x86_64', need 'arm64e' or 'arm64e.v1' or 'arm64' or 'arm64')), '/Library/Frameworks/R.framework/Resources/lib/libSM.6.dylib' (no such file), '/Library/Java/JavaVirtualMachines/jdk-11.0.18+10/Contents/Home/lib/server/libSM.6.dylib' (no such file)
## Warning in cairoVersion(): unable to load shared object '/Library/Frameworks/R.framework/Resources/library/grDevices/libs//cairo.so':
## dlopen(/Library/Frameworks/R.framework/Resources/library/grDevices/libs//cairo.so, 0x0006): Library not loaded: /opt/X11/lib/libXrender.1.dylib
## Referenced from: <263B701F-2238-3478-A7D2-B7513231EF98> /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/library/grDevices/libs/cairo.so
## Reason: tried: '/opt/X11/lib/libXrender.1.dylib' (fat file, but missing compatible architecture (have 'i386,x86_64', need 'arm64e' or 'arm64e.v1' or 'arm64' or 'arm64')), '/System/Volumes/Preboot/Cryptexes/OS/opt/X11/lib/libXrender.1.dylib' (no such file), '/opt/X11/lib/libXrender.1.dylib' (fat file, but missing compatible architecture (have 'i386,x86_64', need 'arm64e' or 'arm64e.v1' or 'arm64' or 'arm64')), '/Library/Frameworks/R.framework/Resources/lib/libXrender.1.dylib' (no such file), '/Library/Java/JavaVirtualMachines/jdk-11.0.18+10/Contents/Home/lib/server/libXrender.1.dylib' (no [... truncated]
## Warning in device(filename = "business_card_plots.pdf", width = 8.5, height =
## 11, : failed to load cairo DLL
# Tip: print this PDF at 100% scale / "actual size" (NOT "fit to page")
# or the cards will drift off the perforations.