ggplot2 Fundamentals
Reviewed & published by Brayan K
ggplot2 is R's most popular plotting package, built on the "grammar of graphics" — you describe a chart as data, aesthetic mappings, and geometric layers, then build it up with +.
Part of the free R course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end of this lesson you'll create scatter plots and bar charts, map columns to aesthetics with aes(), add layers like trend lines and labels, and apply a clean theme.
What You'll Learn in This Lesson
- The three parts of every ggplot: data, aes, geom
- How to build a scatter plot with geom_point()
- How aes() maps columns to x, y, and colour
- How to add layers with + (lines, labels, themes)
- The difference between geom_bar() and geom_col()
- How to title and style a plot with labs() and themes
1️⃣ Your First Plot: Data + aes + geom
Every plot starts with ggplot(data, aes(...)) to set the data and mappings, then adds at least one geom_ layer to draw it. geom_point() makes a scatter plot.
library(ggplot2)
# Every ggplot has 3 parts: DATA, aesthetic MAPPINGS (aes), and a GEOM layer.
df <- data.frame(
height = c(150, 160, 170, 180, 190),
weight = c(50, 60, 65, 80, 90)
)
ggplot(df, aes(x = height, y = weight)) + # data + mapping
geom_point() # draw points
# -> a scatter plot of weight vs height appears in the Plots pane
# ggplot prints a description of the object when saved, e.g.:
p <- ggplot(df, aes(height, weight)) + geom_point()
class(p) # -> [1] "gg" "ggplot"2️⃣ Adding Layers
Plots grow by adding layers with +. Style a geom directly (colour, size), overlay a trend line with geom_smooth(), label with labs(), and clean up with a theme.
library(ggplot2)
df <- data.frame(
height = c(150, 160, 170, 180, 190),
weight = c(50, 60, 65, 80, 90)
)
# Add LAYERS with +: a trend line, labels, and a theme.
ggplot(df, aes(x = height, y = weight)) +
geom_point(color = "steelblue", size = 3) +
geom_smooth(method = "lm", se = FALSE) + # add a linear trend line
labs(title = "Weight vs Height",
x = "Height (cm)", y = "Weight (kg)") +
theme_minimal()
# -> styled scatter plot with a fitted line and clean theme3️⃣ Bar Charts: geom_bar vs geom_col
Use geom_bar() to count how many rows fall in each category, and geom_col() when you already have the value to plot per category.
library(ggplot2)
sales <- data.frame(
product = c("pen", "pad", "ink", "pen", "pad"),
amount = c(20, 35, 50, 25, 40)
)
# Bar chart of COUNTS (one bar per category):
ggplot(sales, aes(x = product)) +
geom_bar(fill = "tomato")
# Bar chart of a VALUE per category needs stat = "identity":
ggplot(sales, aes(x = product, y = amount)) +
geom_col() # geom_col uses the y value directly
# -> a bar per product summing the amountsYour turn. Fill in the ___ blank, run it, and check the Plots pane.
library(ggplot2)
# 🎯 YOUR TURN — replace each ___ then run it.
df <- data.frame(
day = c("Mon", "Tue", "Wed", "Thu"),
visits = c(120, 150, 90, 200)
)
# 1) Make a bar chart of visits per day.
# Map x = day and y = visits, then add the right geom.
ggplot(df, aes(x = day, y = visits)) +
___ + # 👉 replace ___ with geom_col()
labs(title = "Visits by Day")
# ✅ Expected: a bar chart with one bar per day, heights = visits.
# (Plots don't print text output — check the Plots pane.)
print("Plot created")Mini-Challenge: Coloured Scatter
Write it from the outline using the built-in mtcars data, run it in RStudio, and check the plot. Mapping colour to a factor is how you reveal groups in a scatter.
# 🎯 MINI-CHALLENGE: a labelled scatter plot.
#
# Use the built-in mtcars dataset (no download needed):
# - x = wt (weight), y = mpg (miles per gallon)
#
# 1. Create a scatter plot with geom_point().
# 2. Colour the points by the number of cylinders:
# aes(color = factor(cyl)).
# 3. Add a title and axis labels with labs().
# 4. Apply theme_minimal().
#
# ✅ Expected: a scatter of mpg vs weight, points coloured by cylinders,
# with a clean theme. Confirm it draws in the Plots pane.
# your code here
print("Plot created")Common Errors (and the fix)
- + at the start of a line — the + must end the previous line, not begin the next, or R thinks the plot is finished.
- Colour mapped but not coloured — fixed colours go OUTSIDE aes(); only data-driven colour goes inside aes().
- "object not found" for a column — you referenced a column name not in the data, or forgot to pass the data frame to ggplot().
- Nothing appears — you built the plot but didn't print it. In a script, wrap it in print(p) or let it be the last line.
Pro Tips
- 💡 Save plots: ggsave("plot.png", width = 6, height = 4) writes the last plot to a file.
- 💡 Tidy data plots best: long format (from the tidyr lesson) maps cleanly onto aesthetics.
- 💡 Facet for small multiples: facet_wrap(~group) splits one plot into a grid by category.
📋 Quick Reference — ggplot2
| Task | R Syntax |
|---|---|
| Start a plot | ggplot(df, aes(x, y)) |
| Scatter | + geom_point() |
| Bars from values | + geom_col() |
| Trend line | + geom_smooth(method = "lm") |
| Labels | + labs(title = "...") |
| Theme | + theme_minimal() |
🎉 Lesson Complete!
- ✅ Every plot = data + aes + geom
- ✅ aes() maps columns to x, y, colour, etc.
- ✅ Add layers with + (geoms, lines, labels, themes)
- ✅ geom_bar() counts; geom_col() uses values
- ✅ labs() and themes polish a chart
Practice quiz
Which three parts make up every ggplot?
- Rows, columns, cells
- Title, axes, legend
- Mean, median, mode
- Data, aesthetic mappings, and a geom layer
Answer: Data, aesthetic mappings, and a geom layer. A ggplot is built from data, aes() mappings, and one or more geom layers.
What does aes() do?
- Maps data columns to visual properties like x, y, colour
- Saves the plot
- Loads the package
- Sets the file size
Answer: Maps data columns to visual properties like x, y, colour. aes() connects data columns to aesthetics such as x, y, and colour.
Which geom draws a scatter plot?
- geom_bar()
- geom_point()
- geom_line()
- geom_col()
Answer: geom_point(). geom_point() plots individual points for a scatter plot.
How do you add layers to a ggplot?
- With the | operator
- With commas
- With the + operator
- With %>%
Answer: With the + operator. ggplot2 stacks layers with +, each on the end of the previous line.
What is the difference between geom_bar() and geom_col()?
- They are identical
- geom_bar is for lines, geom_col for points
- geom_bar counts rows per category; geom_col uses a supplied y value
- geom_col counts rows; geom_bar uses a y value
Answer: geom_bar counts rows per category; geom_col uses a supplied y value. geom_bar() counts frequencies; geom_col() draws bars from a y value you provide.
Which function loads ggplot2 for the session?
- library(ggplot2)
- import ggplot2
- load(ggplot2)
- use(ggplot2)
Answer: library(ggplot2). library(ggplot2) attaches the package; install once with install.packages.
To set ONE fixed colour for all points, where does colour go?
- Inside aes()
- Outside aes(), in the geom, e.g. geom_point(color = "blue")
- In labs()
- In a theme() call
Answer: Outside aes(), in the geom, e.g. geom_point(color = "blue"). A constant style goes outside aes(); only data-driven colour goes inside aes().
Which layer adds a linear best-fit trend line?
- geom_trend()
- geom_fit()
- geom_smooth(method = "lm")
- geom_line(lm = TRUE)
Answer: geom_smooth(method = "lm"). geom_smooth(method = "lm") overlays a straight-line fit.
A common beginner mistake with + is:
- Putting + at the START of the next line instead of the end of the previous one
- Using + only once
- Using + with geoms only
- Never needing +
Answer: Putting + at the START of the next line instead of the end of the previous one. The + must END the previous line, or R thinks the plot is finished.
Which function sets the plot title and axis labels?
- title()
- theme()
- aes()
- labs()
Answer: labs(). labs(title = ..., x = ..., y = ...) sets the plot's text labels.
Continue this course
- Previous: Strings & Dates
- Next: group_by & summarise — Split-apply-combine: compute grouped statistics with dplyr
- Quick reference: R cheat sheet › ggplot2
Frequently asked questions
What is the 'grammar of graphics' that ggplot2 is based on?
The grammar of graphics is the idea that any statistical chart can be described as a combination of independent parts: the data, a mapping from data columns to visual properties (aesthetics like x, y, colour), and geometric layers (geoms like points, lines, bars) that draw it. ggplot2 implements this grammar, so you build plots by stating those parts and adding layers with +. Once you grasp the grammar, you can compose almost any chart from the same small vocabulary.
What does aes() do?
aes() defines the aesthetic mappings — it connects columns in your data to visual properties of the plot. aes(x = height, y = weight) says 'put height on the x-axis and weight on the y-axis'; you can also map colour, size, shape, and fill to columns, e.g. aes(color = group). The key distinction: properties that depend on data go inside aes(), while fixed styling (a single colour for all points) goes outside aes(), directly in the geom.
Why do I add plot elements with a + sign?
ggplot2 builds a plot as a stack of layers, and + adds the next layer or setting to the plot. You start with ggplot(data, aes(...)), then add a geom, then maybe a trend line, labels, and a theme — each joined with +. It reads like a sentence describing the chart. A common beginner slip is putting the + at the start of the next line; it must go at the END of the previous line so R knows the expression continues.
What's the difference between geom_bar() and geom_col()?
geom_bar() counts how many rows fall into each category and draws bars of those counts — you give it only an x mapping. geom_col() draws bars whose heights come directly from a y value you supply, so use it when your data already has the numbers you want to show (like total sales per product). In short: geom_bar for frequencies, geom_col for pre-computed values.