ggplot2latex: Export ggplot2 Figures to LaTeX Without the Bloat
ggplot2latex lets you save any ggplot2 object as an optimised TikZ .tex file — vector-quality figures that slot straight into your LaTeX paper, up to 81% smaller than raw TikZ output.
The Problem: LaTeX + ggplot2 = Pain
If you write academic papers in LaTeX and produce figures in R, you have probably faced the same dilemma repeatedly:
- PNG/PDF exports look fine at the target size but degrade when reviewers zoom in, and they don’t inherit the document’s fonts.
- TikZ exports (via
tikzDevice) produce perfect vector figures that scale infinitely and match your paper’s font — but the generated.texfiles are enormous. A world map can exceed 2 MB; a network graph routinely hits 50 000 lines of raw TeX.
Large TikZ files stall LaTeX compilation, push projects over journal submission limits, and make version-controlled repos unwieldy.
ggplot2latex solves this by post-processing the raw TikZ output: it strips redundancy, rounds floating-point coordinates, and collapses duplicate draw commands — giving you the same vector figure at a fraction of the size.
Installation
# From CRAN
install.packages("ggplot2latex")
# Or latest from GitHub
devtools::install_github("RomanKyrychenko/ggplot2latex")Core Workflow: save_tex()
The main function mirrors ggsave() in spirit:
library(ggplot2)
library(ggplot2latex)
p <- ggplot(mtcars, aes(x = wt, y = mpg, colour = factor(cyl))) +
geom_point(size = 3) +
labs(title = "Fuel efficiency vs weight", colour = "Cylinders") +
theme_minimal()
save_tex(p, "figures/fuel_efficiency.tex")Drop the resulting file into your LaTeX document:
\usepackage{tikz}
\usepackage{pgfplots}
\begin{figure}[h]
\centering
\input{figures/fuel_efficiency}
\caption{Fuel efficiency vs weight (Motor Trend, 1974).}
\label{fig:fuel}
\end{figure}The figure inherits your document’s fonts automatically — no more mismatched typefaces between body text and axis labels.
What the Optimiser Does
save_tex() calls tikzDevice::tikz() internally, then runs a multi-pass post-processor on the generated source:
| Pass | What it does |
|---|---|
| Float rounding | Truncates coordinates like 12.3456789pt to 12.35pt — imperceptible visually, significant in file size |
| Deduplication | Removes repeated \path[...] clip and bounding-box commands that TikZ emits redundantly |
| Color simplification | Collapses \definecolor{pgfstrokecolor}{rgb}{0.00,0.00,0.00} duplicates |
| Bounding box pruning | Drops intermediate bounding-box resets not needed in the final figure |
Benchmarks
On five representative figure types, save_tex() consistently outperforms raw save_tikz():
| Plot type | Raw bytes | Optimised bytes | Reduction | Raw lines | Optimised lines | Line reduction |
|---|---|---|---|---|---|---|
| Scatter | 11,300 | 7,990 | 29 % | 269 | 134 | 50 % |
| Scatter + smooth | 10,106 | 7,929 | 22 % | 279 | 193 | 31 % |
| Faceted scatter | 20,750 | 15,014 | 28 % | 545 | 301 | 45 % |
| World map | 2,116,053 | 403,827 | 81 % | 102,620 | 21,999 | 79 % |
| Network graph | 45,299 | 19,835 | 56 % | 2,057 | 1,136 | 45 % |
Average: 43 % smaller files, 50 % fewer lines — with zero loss of visual fidelity since everything remains vector-based TikZ.
The gains are largest for figures with many repeated path commands: maps (repeated polygon edges), network graphs (many similar node/edge styles), and faceted plots (duplicate axis scaffold).
Resizing Figures
Academic journals often have strict column-width requirements. Use resize_tex() to rescale an existing .tex file without re-generating it:
# Resize to 8 cm wide (aspect ratio preserved)
resize_tex("figures/fuel_efficiency.tex", width_cm = 8)This rewrites the TikZ \begin{tikzpicture} scale parameter — no R re-render needed.
Helper Utilities
save_tikz() — Unoptimised Baseline
If you want the raw TikZ output for comparison or debugging:
save_tikz(p, "figures/fuel_efficiency_raw.tex")rgb2col() — Colour Debugging
Convert an RGB triplet to its nearest named R colour — useful when inspecting TikZ colour definitions:
rgb2col(r = 0.122, g = 0.471, b = 0.706)
#> [1] "steelblue"A Complete Example: Publication-Ready Map
library(ggplot2)
library(sf)
library(rnaturalearth)
library(ggplot2latex)
world <- ne_countries(scale = "medium", returnclass = "sf")
p_map <- ggplot(world) +
geom_sf(aes(fill = pop_est), colour = "white", linewidth = 0.1) +
scale_fill_viridis_c(
trans = "log10",
labels = scales::label_number(scale = 1e-6, suffix = "M"),
name = "Population"
) +
theme_void() +
labs(title = "World Population")
# Raw TikZ ≈ 2 MB; optimised ≈ 400 KB
save_tex(p_map, "figures/world_population.tex")The world-map case is where ggplot2latex earns its keep most dramatically: raw TikZ exports of sf geometries balloon to megabytes because each polygon vertex becomes a coordinate pair in the source. The optimiser trims these aggressively.
Comparison with Alternatives
| Approach | Vector? | Fonts match LaTeX? | File size | Compile speed |
|---|---|---|---|---|
ggsave(.pdf) |
✅ | ❌ | Small | Fast |
ggsave(.png) |
❌ | ❌ | Variable | Fast |
tikzDevice::tikz() |
✅ | ✅ | Large | Slow |
ggplot2latex::save_tex() |
✅ | ✅ | Small | Fast |
Summary
ggplot2latex fills a genuine gap in the R-for-academics toolkit. If you write papers in LaTeX and make figures in R, save_tex() gives you the best of both worlds: the expressiveness of ggplot2, the typographic consistency of TikZ, and file sizes small enough to not slow down your build or inflate your repository.
# Install once, use everywhere
install.packages("ggplot2latex")