ggplot2 Extensions: patchwork, ggrepel, gganimate

· 5 min read · Updated March 12, 2026 · intermediate
r ggplot2 data-viz patchwork ggrepel gganimate

ggplot2 is the most popular data visualization package in R, but its core functionality gets you only so far. The real power unlocks when you add extension packages from the ggplot2 library. Three extensions stand out for everyday use: patchwork for combining plots, ggrepel for readable labels, and gganimate for animations.

This guide shows you when and how to use each extension with practical examples.

Installing the Extensions

All three packages are available from CRAN:

install.packages(c("patchwork", "ggrepel", "gganimate"))

Load them alongside ggplot2:

library(ggplot2)
library(patchwork)
library(ggrepel)
library(gganimate)

ggplot2 Extensions: Combining Plots with patchwork

The patchwork package solves a common problem: how do you arrange multiple plots in one figure? Base R’s layout system is clunky, and gridExtra feels limited. patchwork integrates directly with ggplot2 using intuitive operators that feel natural.

The + Operator

The + operator places plots side by side in a row:

p1 <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
p2 <- ggplot(mtcars, aes(mpg, wt)) + geom_point()

p1 + p2

This creates a two-column layout with p1 on the left and p2 on the right.

The / Operator

The / operator stacks plots vertically:

p1 / p2

This creates two rows—one plot on top, another below.

Complex Layouts

Combine operators for complex arrangements:

(p1 + p2) / p1

This creates two plots on top (side by side) and one plot spanning the full width below.

Controlling Layout

Use plot_layout() for fine control over dimensions:

p1 + p2 + 
  plot_layout(widths = c(1, 2))

This makes the second plot twice as wide as the first.

You can also control heights and add guides:

p1 + p2 +
  plot_layout(heights = c(2, 1), guides = "collect")

The guides = "collect" option gathers legends from individual plots into one—useful when all plots share the same color mapping.

Adding Annotations Across Plots

Patchwork can add text annotations that span the entire figure:

p1 + p2 + 
  plot_annotation(
    title = "Motor Trend Car Data",
    subtitle = "Comparing displacement and weight to MPG",
    caption = "Source: mtcars dataset"
  )

This is much cleaner than manually adding text to each subplot.

Preventing Overlapping Labels with ggrepel

When you add text labels to a plot, they often overlap—especially with many points or long label text. ggrepel pushes labels away from each other and from the data points, keeping everything readable.

Basic Usage

Replace geom_text() with geom_text_repel():

ggplot(mtcars, aes(mpg, disp, label = rownames(mtcars))) +
  geom_point() +
  geom_text_repel()

The labels now have room to breathe. The algorithm finds positions that minimize overlaps while keeping each label near its data point.

Highlighting Selected Points

You rarely want to label every single point. Use the data argument to label only certain observations:

top_cars <- mtcars[order(mtcars$mpg, decreasing = TRUE)[1:5], ]

ggplot(mtcars, aes(mpg, disp)) +
  geom_point() +
  geom_text_repel(data = top_cars, aes(label = rownames(top_cars)))

This approach works well for highlighting outliers, top performers, or any subset worth emphasizing.

Styling the Labels

Control appearance through standard ggplot2 aesthetics:

ggplot(mtcars, aes(mpg, disp, label = rownames(mtcars))) +
  geom_point() +
  geom_text_repel(
    color = "red",
    size = 3,
    fontface = "bold"
  )

Using Boxes Instead of Text

For better visibility against busy backgrounds, use geom_label_repel() instead:

ggplot(mtcars, aes(mpg, disp, label = rownames(mtcars))) +
  geom_point() +
  geom_label_repel(
    box.color = "darkgray",
    fill = "white",
    alpha = 0.8
  )

Controlling Label Behavior

Fine-tune the algorithm with parameters:

geom_text_repel(
  max.overlaps = 15,      # Skip labels if too many
  min.segment.length = 0, # Always draw segment
  nudge_x = 0.5,          # Offset from point
  direction = "both"     # Allow movement in any direction
)

Creating Animations with gganimate

Static plots show one moment in time. gganimate extends ggplot2 to show how your data changes across states—whether time periods, categories, or steps in an algorithm.

Your First Animation

Start with a static plot, then add transition functions:

ggplot(iris, aes(Petal.Length, Petal.Width, color = Species)) +
  geom_point(size = 3) +
  transition_states(Species, transition_length = 2, state_length = 1)

Each species appears sequentially, with points fading in and out as the animation progresses.

Animating Over Time

Use a dataset with a time variable:

# Sample time series data
set.seed(123)
dates <- seq(as.Date("2024-01-01"), by = "day", length.out = 30)
df <- data.frame(
  date = dates,
  value = cumsum(rnorm(30))
)

ggplot(df, aes(date, value)) +
  geom_line() +
  geom_point() +
  transition_reveal(date)

The line draws itself as time progresses—the reveal animation traces from left to right.

Animation Easing

Control how values transition between states:

ggplot(iris, aes(Petal.Length, Petal.Width, color = Species)) +
  geom_point(size = 3) +
  transition_states(Species, transition_length = 2, state_length = 1) +
  ease_aes("cubic-in-out")

Common options include linear, cubic, and elastic easing.

Saving Animations

Use anim_save() to export your work:

animated_plot <- ggplot(df, aes(date, value)) +
  geom_line() +
  transition_reveal(date)

anim_save("animation.gif", animation = animated_plot)

For higher quality, save as MP4:

anim_save("animation.mp4", animation = animated_plot, renderer = av_renderer())

Performance Tips

Animations can get heavy. Keep these tips in mind:

  • Fewer frames render faster. Use nframes to control this.
  • Complex geometries slow things down. Keep animations simple.
  • Test with print() before saving to catch errors quickly.

Conclusion

Each extension serves a different purpose in your visualization workflow:

  • Use patchwork when you need to combine multiple plots into one figure. The operator syntax makes layouts intuitive, and the annotation features add professional polish.
  • Use ggrepel whenever text labels crowd your visualization. It handles the hard work of positioning so you don’t have to manually adjust coordinates.
  • Use gganimate to show change over time or across categories. Keep animations simple—too much motion confuses rather than informs.

All three ggplot2 extensions integrate seamlessly with ggplot2, so your existing knowledge transfers directly. Start with patchwork if you combine plots regularly; add ggrepel next time your labels overlap. Once you’re comfortable, gganimate opens up new ways to tell data stories with ggplot2 extensions.

See Also