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.

RRun this once before any exercise
library(ggplot2) library(dplyr)

  

Section 1. facet_wrap (8 problems)

Exercise 1.1: facet_wrap by Species

Difficulty: Beginner.

Show solution
RInteractive R
ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point() + facet_wrap(~ Species)

  

Exercise 1.2: ncol

Difficulty: Intermediate.

Show solution
RInteractive R
ggplot(diamonds, aes(price)) + geom_histogram(bins = 30) + facet_wrap(~ cut, ncol = 5)

  

Exercise 1.3: nrow

Difficulty: Intermediate.

Show solution
RInteractive R
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
RInteractive R
ggplot(mtcars, aes(wt, mpg)) + geom_point() + facet_wrap(cyl ~ am)

  

Exercise 1.5: free_y

Difficulty: Intermediate.

Show solution
RInteractive R
ggplot(mpg, aes(displ, hwy)) + geom_point() + facet_wrap(~ drv, scales = "free_y")

  

Exercise 1.6: free both

Difficulty: Intermediate.

Show solution
RInteractive R
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
RInteractive R
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
RInteractive R
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
RInteractive R
ggplot(diamonds, aes(carat, price)) + geom_point(alpha = 0.1) + facet_grid(cut ~ clarity)

  

Exercise 2.2: Rows only

Difficulty: Beginner.

Show solution
RInteractive R
ggplot(mtcars, aes(wt, mpg)) + geom_point() + facet_grid(cyl ~ .)

  

Exercise 2.3: Cols only

Difficulty: Beginner.

Show solution
RInteractive R
ggplot(mtcars, aes(wt, mpg)) + geom_point() + facet_grid(. ~ cyl)

  

Exercise 2.4: facet_grid with vars()

Difficulty: Intermediate. Modern syntax.

Show solution
RInteractive R
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
RInteractive R
ggplot(mpg, aes(displ, hwy)) + geom_point() + facet_grid(drv ~ class, scales = "free_y")

  

Exercise 2.6: space = "free"

Difficulty: Advanced.

Show solution
RInteractive R
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
RInteractive R
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
RInteractive R
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
RInteractive R
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
RInteractive R
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
RInteractive R
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
RInteractive R
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
RInteractive R
ggplot(mpg, aes(displ, hwy)) + geom_point() + geom_smooth(method = "lm") + facet_wrap(~ drv)

  

Exercise 4.3: Per-facet vline

Difficulty: Advanced.

Show solution
RInteractive R
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
RInteractive R
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
RInteractive R
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
RInteractive R
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.