Week 2: Your First ggplot

From base R to the grammar of graphics

Introduction

In the content session, you learned about summarising data (mean, median, spread), honest data visualisation, and the grammar of graphics — the idea that a plot is built from layers: data, aesthetics, and geometries.

These two exercises let you practise the ggplot2 syntax before the application session, where you’ll build briefing-quality figures.

Goals:

  • Build a histogram with geom_histogram()
  • Build a scatter/line plot with colour mapping
  • Get comfortable with the ggplot(data, aes(...)) + geom_*() pattern

In GEOL1151 you built plots imperatively — one command per element:

plt.plot(year, bio, label="Bioenergy")
plt.xlabel("Year")
plt.legend()
plt.show()

ggplot2 works declaratively: you describe what the plot is, and ggplot2 figures out how to draw it.

Concept matplotlib ggplot2
Start a plot plt.figure() ggplot(data, aes(...))
Map columns to axes plt.plot(x, y) aes(x = year, y = value)
Choose a geometry plt.scatter(...) + geom_point()
Add layers Separate calls + operator
Labels plt.xlabel(...) + labs(x = ...)
Legend Manual label= args Automatic from colour/fill mapping

The biggest shift: aes() does the mapping. You tell ggplot2 which columns mean what (x position, y position, colour), then add a geometry that knows how to draw those mappings. No quoting column names inside aes() — just bare names like aes(x = year, y = bioenergy_twh).

Exercise 1: Distribution of bioenergy generation

Last week you plotted bioenergy over time. But what does the distribution look like? Make a histogram of bioenergy_twh to see how the values are spread. What shape is the distribution — and why might it look that way?

NoteHint 1

The first argument to ggplot() is the data frame. Inside aes(), map x to the column you want to histogram — no y needed.

NoteHint 2
ggplot(elec, aes(x = bioenergy_twh)) +
  geom_histogram(bins = 10) + ...
TipSolution
ggplot(elec, aes(x = bioenergy_twh)) +
  geom_histogram(bins = 10) +
  labs(x = "Bioenergy generation (TWh)",
       y = "Count",
       title = "Distribution of UK bioenergy generation (2000–2024)")

The distribution is right-skewed (or bimodal), with a cluster of low values (the early 2000s, when bioenergy was small) and a cluster of higher values (post-2015). This shape reflects a quantity that grew rapidly over time — it’s not random variation around a fixed average. The mean (~18 TWh) would be a misleading summary here.

Exercise 2: Generation over time, by fuel

Now make a scatter plot of electricity generation over time, with colour showing the fuel type. This exercise uses just two fuels — bioenergy and coal — to keep the syntax manageable.

The trick: you need one geom_point() layer per fuel, each with its own aes(). (In the application session, you’ll learn a cleaner way to handle multiple groups.)

NoteHint 1

Each geom_point() layer maps y to a different column. Setting colour = "Bioenergy" (a constant string) inside aes() creates a legend entry. Do the same for coal.

NoteHint 2
geom_point(aes(y = coal_twh, colour = "Coal", shape = "Coal"))
TipSolution
ggplot(elec, aes(x = year)) +
  geom_point(aes(y = bioenergy_twh, colour = "Bioenergy",
                 shape = "Bioenergy")) +
  geom_point(aes(y = coal_twh, colour = "Coal",
                 shape = "Coal")) +
  labs(x = "Year",
       y = "Generation (TWh)",
       colour = "Fuel", shape = "Fuel",
       title = "UK electricity: bioenergy vs coal")

Bioenergy rises while coal collapses — the same pattern you saw in Week 1, but now with a colour legend that makes the comparison explicit. Notice how ggplot2 automatically creates the legend from the colour aesthetic. Try adding geom_line() layers with the same aes() to connect the dots.

Next steps

You’ll use these ggplot2 skills extensively in the application session, where you’ll build the figures for your policy briefing.