8: Layers & Aesthetics

Content for Wednesday, April 22, 2026

Before class

📖 Reading:

During class

We’ll cover:

  • Matching geom to data type — a decision guide
  • Distributions: geom_histogram() vs geom_density()
  • Comparing groups: geom_boxplot() vs geom_violin()
  • stat_summary() — means, error bars, and custom functions
  • What SE, SD, and CI error bars actually mean
  • Position adjustments: dodge, stack, fill, jitter
  • Scales: controlling axes, colors, and legends
  • coord_flip() vs coord_cartesian() — and why they’re different

Slides

View slides in new tab Download PDF

Embedded slides

After class

Practice:

  1. Create a histogram and a density plot of the same variable. When does each one work better?
  2. Make a boxplot and a violin plot side by side for the same data. What does the violin show that the boxplot hides?
  3. Build a bar chart with error bars using stat_summary(). Try both mean_se and mean_cl_normal — what changes?
  4. Practice position = "dodge" with a grouped bar chart
  5. Try coord_flip() on a plot with long category labels — does it help readability?
Notecoord_cartesian() vs scale limits

These do very different things:

# This ZOOMS — all data is still used for calculations
coord_cartesian(ylim = c(400, 600))

# This DROPS data outside the range — changes your summaries!
scale_y_continuous(limits = c(400, 600))

Use coord_cartesian() when you want to zoom in. Use scale limits only when you actually want to exclude data.

Psychology application: error bars

# The standard psych figure: mean + SE + individual points
data |>
  ggplot(aes(x = condition, y = score, fill = condition)) +
  geom_jitter(width = 0.2, alpha = 0.4) +
  stat_summary(fun = mean, geom = "bar", alpha = 0.6, width = 0.5) +
  stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.2) +
  labs(caption = "Error bars = SE of the mean.")