ggplot2latex: Export ggplot2 Figures to LaTeX Without the Bloat

R
ggplot2
LaTeX
ggplot2latex
visualizations
reproducibility

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.

Author
Published

March 31, 2026

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 .tex files 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")

Source: https://github.com/RomanKyrychenko/ggplot2latex