ggplot2 Bar Chart Exercises in R: 25 Practice Problems
Twenty-five practice problems on ggplot2 bar charts: count, explicit heights, stacked, dodged, filled, ordered, with labels. Hidden solutions.
By Selva Prabhakaran · Published May 11, 2026 · Last updated May 11, 2026
library(ggplot2)
library(dplyr)
library(forcats)
library(scales)
Section 1. Basic bars (8 problems)
Exercise 1.1: Count bars
Difficulty: Beginner.
Show solution
ggplot(diamonds, aes(cut)) + geom_bar()
Exercise 1.2: geom_col with explicit heights
Difficulty: Intermediate.
Show solution
counts <- diamonds |> count(cut)
ggplot(counts, aes(cut, n)) + geom_col()
Exercise 1.3: Horizontal bars (coord_flip)
Difficulty: Beginner.
Show solution
ggplot(diamonds, aes(cut)) + geom_bar() + coord_flip()
Exercise 1.4: Horizontal via aes(y)
Difficulty: Intermediate.
Show solution
ggplot(diamonds, aes(y = cut)) + geom_bar()
Exercise 1.5: Order by frequency
Difficulty: Intermediate.
Show solution
ggplot(diamonds, aes(forcats::fct_infreq(cut))) + geom_bar()
Exercise 1.6: Order by another variable
Difficulty: Advanced. Order cut by mean price.
Show solution
ggplot(diamonds, aes(forcats::fct_reorder(cut, price), price)) +
geom_col(stat = "summary", fun = mean)
Exercise 1.7: Custom width
Difficulty: Beginner.
Show solution
ggplot(diamonds, aes(cut)) + geom_bar(width = 0.5)
Exercise 1.8: Solid color bars
Difficulty: Beginner.
Show solution
ggplot(diamonds, aes(cut)) + geom_bar(fill = "steelblue")
Section 2. Grouped (stacked, dodge, fill) (6 problems)
Exercise 2.1: Stacked
Difficulty: Beginner.
Show solution
ggplot(diamonds, aes(cut, fill = clarity)) + geom_bar()
Exercise 2.2: Dodge
Difficulty: Intermediate.
Show solution
ggplot(diamonds, aes(cut, fill = clarity)) + geom_bar(position = "dodge")
Exercise 2.3: Fill (100%)
Difficulty: Intermediate.
Show solution
ggplot(diamonds, aes(cut, fill = clarity)) + geom_bar(position = "fill")
Exercise 2.4: Identity stack with geom_col
Difficulty: Intermediate.
Show solution
counts <- diamonds |> count(cut, clarity)
ggplot(counts, aes(cut, n, fill = clarity)) + geom_col()
Exercise 2.5: Reverse stack order
Difficulty: Advanced.
Show solution
ggplot(diamonds, aes(cut, fill = clarity)) +
geom_bar(position = position_stack(reverse = TRUE))
Exercise 2.6: Adjust dodge spacing
Difficulty: Advanced.
Show solution
ggplot(diamonds, aes(cut, fill = clarity)) +
geom_bar(position = position_dodge(width = 0.9))
Section 3. Labels and annotations (6 problems)
Exercise 3.1: Value labels above bars
Difficulty: Intermediate.
Show solution
counts <- diamonds |> count(cut)
ggplot(counts, aes(cut, n)) + geom_col() +
geom_text(aes(label = n), vjust = -0.3)
Exercise 3.2: Comma-formatted labels
Difficulty: Intermediate.
Show solution
counts <- diamonds |> count(cut)
ggplot(counts, aes(cut, n)) + geom_col() +
geom_text(aes(label = scales::comma(n)), vjust = -0.3)
Exercise 3.3: Headroom for labels
Difficulty: Advanced.
Show solution
counts <- diamonds |> count(cut)
ggplot(counts, aes(cut, n)) + geom_col() +
geom_text(aes(label = n), vjust = -0.3) +
scale_y_continuous(expand = expansion(mult = c(0, 0.1)))
Exercise 3.4: Percent labels on stacked
Difficulty: Advanced.
Show solution
diamonds |>
count(cut, clarity) |>
group_by(cut) |>
mutate(pct = n / sum(n)) |>
ggplot(aes(cut, pct, fill = clarity)) + geom_col() +
scale_y_continuous(labels = scales::percent_format())
Exercise 3.5: Inline labels inside bars
Difficulty: Advanced.
Show solution
counts <- diamonds |> count(cut)
ggplot(counts, aes(cut, n)) + geom_col() +
geom_text(aes(label = n), vjust = 1.5, color = "white")
Exercise 3.6: Add reference line
Difficulty: Intermediate.
Show solution
counts <- diamonds |> count(cut)
ggplot(counts, aes(cut, n)) + geom_col() +
geom_hline(yintercept = mean(counts$n), linetype = "dashed", color = "red")
Section 4. Real workflows (5 problems)
Exercise 4.1: Mean per group
Difficulty: Intermediate.
Show solution
mtcars |>
group_by(cyl) |>
summarise(mean_mpg = mean(mpg)) |>
ggplot(aes(factor(cyl), mean_mpg)) + geom_col()
Exercise 4.2: Percent per group
Difficulty: Advanced.
Show solution
diamonds |>
count(cut) |>
mutate(pct = n / sum(n)) |>
ggplot(aes(cut, pct)) + geom_col() +
scale_y_continuous(labels = scales::percent_format())
Exercise 4.3: Highlight top bar
Difficulty: Advanced.
Show solution
counts <- diamonds |> count(cut)
counts$top <- counts$n == max(counts$n)
ggplot(counts, aes(cut, n, fill = top)) + geom_col() +
scale_fill_manual(values = c("gray70","tomato"))
Exercise 4.4: Bar with error bars
Difficulty: Advanced.
Show solution
mtcars |>
group_by(cyl) |>
summarise(m = mean(mpg), s = sd(mpg)) |>
ggplot(aes(factor(cyl), m)) +
geom_col() +
geom_errorbar(aes(ymin = m - s, ymax = m + s), width = 0.2)
Exercise 4.5: Side-by-side comparison
Difficulty: Advanced.
Show solution
df <- data.frame(group = rep(c("A","B","C"), 2),
metric = rep(c("Q1","Q2"), each = 3),
val = c(10, 20, 30, 15, 25, 28))
ggplot(df, aes(group, val, fill = metric)) +
geom_col(position = "dodge")
What to do next
- ggplot2-Exercises (shipped), broader practice.
- ggplot2-Themes-Exercises (shipped), theme polish.