ggplot2 Facets Exercises in R: 25 Practice Problems
Twenty-five practice problems on ggplot2 facets: facet_wrap, facet_grid, scales, labels, strip styling. Hidden solutions.
By Selva Prabhakaran · Published May 11, 2026 · Last updated May 11, 2026
library(ggplot2)
library(dplyr)
Section 1. facet_wrap (8 problems)
Exercise 1.1: facet_wrap by Species
Difficulty: Beginner.
Show solution
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + facet_wrap(~ Species)
Exercise 1.2: ncol
Difficulty: Intermediate.
Show solution
ggplot(diamonds, aes(price)) + geom_histogram(bins = 30) + facet_wrap(~ cut, ncol = 5)
Exercise 1.3: nrow
Difficulty: Intermediate.
Show solution
ggplot(diamonds, aes(price)) + geom_histogram(bins = 30) + facet_wrap(~ cut, nrow = 1)
Exercise 1.4: facet_wrap by two variables
Difficulty: Intermediate.
Show solution
ggplot(mtcars, aes(wt, mpg)) + geom_point() + facet_wrap(cyl ~ am)
Exercise 1.5: free_y
Difficulty: Intermediate.
Show solution
ggplot(mpg, aes(displ, hwy)) + geom_point() + facet_wrap(~ drv, scales = "free_y")
Exercise 1.6: free both
Difficulty: Intermediate.
Show solution
ggplot(mpg, aes(displ, hwy)) + geom_point() + facet_wrap(~ drv, scales = "free")
Exercise 1.7: facet_wrap with as.table FALSE
Difficulty: Advanced.
Show solution
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() +
facet_wrap(~ Species, as.table = FALSE)
Exercise 1.8: drop = FALSE keeps empty levels
Difficulty: Advanced.
Show solution
df <- iris |> filter(Species != "virginica")
ggplot(df, aes(Sepal.Length, Petal.Length)) + geom_point() +
facet_wrap(~ Species, drop = FALSE)
Section 2. facet_grid (6 problems)
Exercise 2.1: rows ~ cols
Difficulty: Intermediate.
Show solution
ggplot(diamonds, aes(carat, price)) + geom_point(alpha = 0.1) +
facet_grid(cut ~ clarity)
Exercise 2.2: Rows only
Difficulty: Beginner.
Show solution
ggplot(mtcars, aes(wt, mpg)) + geom_point() + facet_grid(cyl ~ .)
Exercise 2.3: Cols only
Difficulty: Beginner.
Show solution
ggplot(mtcars, aes(wt, mpg)) + geom_point() + facet_grid(. ~ cyl)
Exercise 2.4: facet_grid with vars()
Difficulty: Intermediate. Modern syntax.
Show solution
ggplot(mtcars, aes(wt, mpg)) + geom_point() +
facet_grid(rows = vars(cyl), cols = vars(am))
Exercise 2.5: free_y in grid
Difficulty: Advanced.
Show solution
ggplot(mpg, aes(displ, hwy)) + geom_point() +
facet_grid(drv ~ class, scales = "free_y")
Exercise 2.6: space = "free"
Difficulty: Advanced.
Show solution
ggplot(mpg, aes(class)) + geom_bar() +
facet_grid(. ~ drv, space = "free", scales = "free_x")
Section 3. Strip labels (5 problems)
Exercise 3.1: Custom label vector
Difficulty: Intermediate.
Show solution
labs <- c(`4` = "4-cyl", `6` = "6-cyl", `8` = "8-cyl")
ggplot(mtcars, aes(wt, mpg)) + geom_point() +
facet_wrap(~ cyl, labeller = labeller(cyl = labs))
Exercise 3.2: as_labeller with function
Difficulty: Advanced.
Show solution
ggplot(mtcars, aes(wt, mpg)) + geom_point() +
facet_wrap(~ cyl, labeller = as_labeller(\(x) paste0(x, " cyl")))
Exercise 3.3: Strip background color
Difficulty: Intermediate.
Show solution
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() +
facet_wrap(~ Species) +
theme(strip.background = element_rect(fill = "lightblue"))
Exercise 3.4: Bold strip text
Difficulty: Intermediate.
Show solution
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() +
facet_wrap(~ Species) +
theme(strip.text = element_text(face = "bold"))
Exercise 3.5: Position strip on bottom
Difficulty: Advanced.
Show solution
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() +
facet_wrap(~ Species, strip.position = "bottom")
Section 4. Per-facet annotation (3 problems)
Exercise 4.1: Per-facet text
Difficulty: Advanced.
Show solution
counts <- mtcars |> count(cyl) |> mutate(label = paste("n =", n))
ggplot(mtcars, aes(wt, mpg)) + geom_point() +
geom_text(data = counts, aes(x = 5, y = 32, label = label), hjust = 1, color = "red") +
facet_wrap(~ cyl)
Exercise 4.2: Per-facet smoother
Difficulty: Advanced.
Show solution
ggplot(mpg, aes(displ, hwy)) + geom_point() +
geom_smooth(method = "lm") + facet_wrap(~ drv)
Exercise 4.3: Per-facet vline
Difficulty: Advanced.
Show solution
medians <- iris |> group_by(Species) |>
summarise(med = median(Sepal.Length), .groups = "drop")
ggplot(iris, aes(Sepal.Length)) + geom_density() +
geom_vline(data = medians, aes(xintercept = med), linetype = "dashed") +
facet_wrap(~ Species)
Section 5. Real workflows (3 problems)
Exercise 5.1: Compare distributions across drv
Difficulty: Intermediate.
Show solution
ggplot(mpg, aes(hwy, fill = drv)) + geom_histogram(bins = 20) +
facet_wrap(~ drv, ncol = 1)
Exercise 5.2: Yearly small multiples
Difficulty: Advanced.
Show solution
df <- economics |> mutate(year = format(date, "%Y"))
ggplot(df |> filter(as.integer(year) >= 2010),
aes(date, unemploy)) + geom_line() + facet_wrap(~ year, scales = "free_x")
Exercise 5.3: Two-way grid summary
Difficulty: Advanced.
Show solution
ggplot(diamonds, aes(carat, price)) + geom_point(alpha = 0.05) +
facet_grid(cut ~ color) +
theme(strip.text = element_text(size = 8))
What to do next
- ggplot2-Exercises (shipped), broader practice.
- ggplot2-Themes-Exercises (shipped), theme-only drills.