Visualize Penguins with ggplot2
Build layered figures: histograms, scatterplots, and boxplots
In Coding 2 you plotted with base R’s hist(). Today you will build figures in layers with ggplot2.
The first time you click Run Code, your browser downloads R once (a few seconds). After that it is quick.
Every ggplot2 figure has three essential pieces:
- data — the dataset (for example
penguins) - aes — aesthetic mappings: which column goes on which axis, or which color
- geom — the geometric object: points, boxes, bars, histogram bins
You add layers with +. We will practice all three today. The two tables below are a reference for this activity and for your assignments.
| Geom | Shows | Needs in aes() |
Note |
|---|---|---|---|
geom_histogram() |
Distribution of one continuous variable | x |
bins = 30 by default; try binwidth = 100 |
geom_density() |
Smoothed outline of a histogram | x |
|
geom_bar() |
Count of rows in each category | x (categorical) |
Counts for you |
geom_col() |
Bars whose heights you already computed | x, y |
|
geom_point() |
Scatterplot of two continuous variables | x, y |
|
geom_jitter() |
Scatterplot with points nudged apart so they do not overlap | x, y |
width = 0.2 controls the nudge |
geom_boxplot() |
Median, quartiles, and outliers per group | x (group), y |
|
geom_violin() |
Full distribution shape per group | x (group), y |
|
geom_line() |
Values connected in order along x | x, y |
|
geom_smooth() |
A fitted trend line with a confidence band | x, y |
method = "lm" for a straight line |
geom_errorbar() |
Error bars around a summary | x, ymin, ymax |
Layers stack with + in the order you write them, so geom_point() + geom_smooth() draws the line on top of the points.
aes() can map a column to (click to expand)
| Aesthetic | Controls | Works best with | Example |
|---|---|---|---|
x, y |
Position on the axes | Any column | aes(x = flipper_length_mm, y = body_mass_g) |
color |
Outline or point color | Categories, or a continuous gradient | aes(color = species) |
fill |
Inside color of bars, boxes, and violins | Categories | aes(fill = island) |
size |
Point size or line thickness | Continuous | aes(size = bill_depth_mm) |
shape |
Point shape | Categories (six or fewer) | aes(shape = sex) |
alpha |
Transparency, 0 to 1 | Continuous, or a fixed value | geom_point(alpha = 0.5) |
group |
Which rows belong together for lines and boxes | Categories | aes(group = species) |
Inside aes(), a setting maps a column, so each species gets its own color. Outside aes(), it sets one constant for the whole layer: geom_point(color = "blue") makes every point blue.
Helpers you will add to almost every figure: labs() for the title and axis labels, theme_minimal() for a clean background, and facet_wrap(~ species) for one panel per group.
Posit, the company that makes RStudio, publishes a one-page summary of all of this: ggplot2 cheat sheet (web page) or PDF. Keep it open while you work on assignments.
1. Load the tidyverse
Coding Assignment 2 starts the same way. Run library(tidyverse) to load ggplot2 and friends. A conflicts message afterward is expected, not an error.
From ?library: library(package, ...) attaches a package so its functions become available. Replace package with the name of the collection you need (ggplot2 ships inside the tidyverse bundle).
Try ?library in R for the full help page.
library(tidyverse)On DataHub and in your graded assignment you will type exactly this.
2. Glimpse the penguins
glimpse() is a tidyverse way to inspect a dataset: rows, columns, and column types. Run it on penguins from the palmerpenguins package so you know which columns to map to axes and colors.
From ?glimpse: glimpse(x) — print a compact summary of a data frame (rows, columns, types).
Example with a built-in dataset:
glimpse(mtcars)Apply the same function to the dataset named in the exercise prompt.
glimpse(penguins)You should see 344 rows and 8 columns. species and island are <fct> (categories); measurements like body_mass_g are <dbl> (numbers).
From the glimpse() output:
- How many rows are there?
- What type is
body_mass_g? - Which column tells you which island each penguin was sampled on?
Answers: 344 rows; body_mass_g is <dbl>; island.
3. Histogram with ggplot2
Start a figure with ggplot(), map body_mass_g to the x-axis, and add geom_histogram(). Use the penguins dataset directly — an upgrade from Coding Activity 2’s hist(). Add a title with labs(title = "...").
From ?ggplot: ggplot(data = NULL, mapping = aes(), ...) — then add a layer with +.
From ?geom_histogram: bins one continuous variable.
Example:
ggplot(mtcars, aes(x = mpg)) +
geom_histogram() +
labs(title = "Car fuel economy")Map the x-axis to one continuous column from penguins and add your own title.
ggplot(penguins, aes(x = body_mass_g)) +
geom_histogram() +
labs(title = "Penguin body mass")A histogram shows how one continuous variable is distributed — how many penguins fall in each weight range. ggplot2 may warn about two rows with missing body mass; that is normal.
4. Scatterplot — two continuous variables
Build a scatterplot: flipper length on the x-axis, body mass on the y-axis. Map species to color so each species gets its own hue. Use geom_point().
From ?geom_point: scatterplot of two continuous variables. Map a third variable to color inside aes().
Example:
ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
geom_point()Use flipper length and body mass on the axes and map species to color on the penguin data.
ggplot(penguins, aes(
x = flipper_length_mm,
y = body_mass_g,
color = species
)) +
geom_point()Scatterplots relate two continuous measurements. Color adds a third variable — here, species — so you can see clusters.
5. Boxplot — compare groups
Coding Assignment 2 builds a boxplot one layer at a time. Here is the core pattern:
- Put island on the x-axis, body_mass_g on the y-axis
- Add
geom_boxplot()withfillmapped to island - Add
theme_minimal()and readablelabs()
From ?geom_boxplot: compare a numeric variable across groups.
Example pattern:
ggplot(mtcars, aes(
x = factor(cyl),
y = mpg,
fill = factor(cyl)
)) +
geom_boxplot() +
theme_minimal() +
labs(title = "MPG by cylinder count", x = "Cylinders", y = "MPG")Apply the same layering — boxplot, fill, theme_minimal(), labs() — to islands and body mass.
ggplot(penguins, aes(
x = island,
y = body_mass_g,
fill = island
)) +
geom_boxplot() +
theme_minimal() +
labs(
title = "Body mass by island",
x = "Island",
y = "Body mass (g)"
)Boxplots compare a continuous variable across groups. On your graded assignment you will add reorder() to sort groups by elevation after you join that metadata in Coding Activity 6.
6. Recap — ggplot functions you practiced
| Function | Role |
|---|---|
library(tidyverse) |
Loads ggplot2 and related packages |
glimpse() |
Quick look at rows, columns, and types |
ggplot() + aes() |
Starts a figure and maps columns to axes, color, or fill |
geom_histogram() |
Distribution of one continuous variable |
geom_point() |
Relationship between two continuous variables |
geom_boxplot() |
Compare a continuous variable across groups |
theme_minimal() + labs() |
Cleans appearance and adds titles/labels |
If you can explain each row in your own words, you have covered the figure-building core of Coding Assignment 2.
7. Transfer to Coding Assignment 2
On Canvas you will build figures step by step with hemoglobin measurements and population elevation data:
library(tidyverse)and read your dataset- Build a boxplot one layer at a time with
ggplot(),geom_boxplot(),fill,theme_minimal(), andlabs()
You practiced the layering here. Coding Activity 6 covers the wrangling steps — filtering, reshaping, and joining — that prepare the table for those plots.
Keep playing
No grading here. Try swapping geoms, mapping a different column to color, or predicting what a plot will look like before you run it.
Try this with a partner. One of you predicts the figure; the other runs the code. Swap roles. Saying your prediction out loud first is one of the fastest ways to learn.