This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.
When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
summary(cars)
## speed dist
## Min. : 4.0 Min. : 2.00
## 1st Qu.:12.0 1st Qu.: 26.00
## Median :15.0 Median : 36.00
## Mean :15.4 Mean : 42.98
## 3rd Qu.:19.0 3rd Qu.: 56.00
## Max. :25.0 Max. :120.00
You can also embed plots, for example:
Note that the echo = FALSE parameter was added to the
code chunk to prevent printing of the R code that generated the
plot.
Palmer Penguins in RStudio
These examples use the penguins dataset from the
palmerpenguins package and the ggplot2
visualization package. They are appropriate for introductory college
statistics or data science courses.
Open RStudio and create a new R script:
File → New File → R Script
Install the packages once:
install.packages("tidyverse")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.6'
## (as 'lib' is unspecified)
install.packages("palmerpenguins")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.6'
## (as 'lib' is unspecified)
Load them each time you start a new R session:
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.2.1 ✔ readr 2.2.0
## ✔ forcats 1.0.1 ✔ stringr 1.6.0
## ✔ ggplot2 4.0.3 ✔ tibble 3.3.1
## ✔ lubridate 1.9.5 ✔ tidyr 1.3.2
## ✔ purrr 1.2.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(palmerpenguins)
##
## Attaching package: 'palmerpenguins'
##
## The following objects are masked from 'package:datasets':
##
## penguins, penguins_raw
View the data:
head(penguins)
## # A tibble: 6 × 8
## species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
## <fct> <fct> <dbl> <dbl> <int> <int>
## 1 Adelie Torgersen 39.1 18.7 181 3750
## 2 Adelie Torgersen 39.5 17.4 186 3800
## 3 Adelie Torgersen 40.3 18 195 3250
## 4 Adelie Torgersen NA NA NA NA
## 5 Adelie Torgersen 36.7 19.3 193 3450
## 6 Adelie Torgersen 39.3 20.6 190 3650
## # ℹ 2 more variables: sex <fct>, year <int>
glimpse(penguins)
## Rows: 344
## Columns: 8
## $ species <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adel…
## $ island <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgerse…
## $ bill_length_mm <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, …
## $ bill_depth_mm <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, …
## $ flipper_length_mm <int> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186…
## $ body_mass_g <int> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, …
## $ sex <fct> male, female, female, NA, female, male, female, male…
## $ year <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…
summary(penguins)
## species island bill_length_mm bill_depth_mm
## Adelie :152 Biscoe :168 Min. :32.10 Min. :13.10
## Chinstrap: 68 Dream :124 1st Qu.:39.23 1st Qu.:15.60
## Gentoo :124 Torgersen: 52 Median :44.45 Median :17.30
## Mean :43.92 Mean :17.15
## 3rd Qu.:48.50 3rd Qu.:18.70
## Max. :59.60 Max. :21.50
## NAs :2 NAs :2
## flipper_length_mm body_mass_g sex year
## Min. :172.0 Min. :2700 female:165 Min. :2007
## 1st Qu.:190.0 1st Qu.:3550 male :168 1st Qu.:2007
## Median :197.0 Median :4050 NAs : 11 Median :2008
## Mean :200.9 Mean :4202 Mean :2008
## 3rd Qu.:213.0 3rd Qu.:4750 3rd Qu.:2009
## Max. :231.0 Max. :6300 Max. :2009
## NAs :2 NAs :2
The main variables include:
species: penguin speciesisland: island where the penguin was observedbill_length_mm: bill lengthbill_depth_mm: bill depthflipper_length_mm: flipper lengthbody_mass_g: body masssex: penguin sexSome observations have missing values, so many plots use
na.omit().
A scatterplot helps students examine the relationship between two numerical variables.
ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
geom_point() +
labs(
title = "Penguin Bill Measurements",
x = "Bill Length (mm)",
y = "Bill Depth (mm)"
) +
theme_minimal()
## Warning: Removed 2 rows containing missing values or values outside the scale range
## (`geom_point()`).
ggplot(penguins, aes(
x = bill_length_mm,
y = bill_depth_mm,
color = species
)) +
geom_point(size = 3, na.rm = TRUE) +
labs(
title = "Bill Length and Depth by Penguin Species",
color = "Species"
) +
theme_minimal()
A trend line helps students examine a general relationship between two variables.
ggplot(na.omit(penguins), aes(
x = flipper_length_mm,
y = body_mass_g
)) +
geom_point(color = "steelblue", size = 3) +
geom_smooth(method = "lm", se = TRUE, color = "darkred") +
labs(
title = "Relationship Between Flipper Length and Body Mass",
x = "Flipper Length (mm)",
y = "Body Mass (g)"
) +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
method = "lm" adds a linear regression line. The shaded
area represents a confidence interval around the estimated trend.
A boxplot compares the distributions of a numerical variable across categories.
ggplot(na.omit(penguins), aes(
x = species,
y = body_mass_g,
fill = species
)) +
geom_boxplot() +
labs(
title = "Body Mass by Penguin Species",
x = "Species",
y = "Body Mass (g)"
) +
theme_minimal() +
theme(legend.position = "none")
The box shows the middle 50% of the data. The horizontal line inside the box is the median.
This plot introduces two categorical variables.
ggplot(na.omit(penguins), aes(
x = species,
y = body_mass_g,
fill = sex
)) +
geom_boxplot() +
labs(
title = "Body Mass by Species and Sex",
x = "Species",
y = "Body Mass (g)",
fill = "Sex"
) +
theme_minimal()
A histogram shows the shape of one numerical variable.
ggplot(penguins, aes(x = body_mass_g)) +
geom_histogram(
binwidth = 250,
fill = "skyblue",
color = "white",
na.rm = TRUE
) +
labs(
title = "Distribution of Penguin Body Mass",
x = "Body Mass (g)",
y = "Number of Penguins"
) +
theme_minimal()
ggplot(penguins, aes(
x = body_mass_g,
fill = species
)) +
geom_histogram(
binwidth = 250,
alpha = 0.6,
position = "identity",
na.rm = TRUE
) +
labs(
title = "Body Mass Distributions by Species",
x = "Body Mass (g)",
y = "Count",
fill = "Species"
) +
theme_minimal()
The alpha argument makes overlapping bars partly
transparent.
A bar chart displays counts for categorical data.
ggplot(penguins, aes(x = island)) +
geom_bar(fill = "darkseagreen") +
labs(
title = "Number of Penguins Observed on Each Island",
x = "Island",
y = "Number of Penguins"
) +
theme_minimal()
ggplot(penguins, aes(
x = island,
fill = species
)) +
geom_bar() +
labs(
title = "Penguin Counts by Island and Species",
x = "Island",
y = "Number of Penguins",
fill = "Species"
) +
theme_minimal()
Faceting creates separate panels for groups.
ggplot(na.omit(penguins), aes(
x = flipper_length_mm,
y = body_mass_g
)) +
geom_point(color = "purple", size = 2.5) +
facet_wrap(~ species) +
labs(
title = "Flipper Length and Body Mass by Species",
x = "Flipper Length (mm)",
y = "Body Mass (g)"
) +
theme_minimal()
Faceting is useful when overlapping colors make one plot difficult to interpret.
This example examines species and sex simultaneously.
ggplot(na.omit(penguins), aes(
x = bill_length_mm,
y = bill_depth_mm,
color = species,
shape = sex
)) +
geom_point(size = 3) +
labs(
title = "Penguin Bill Measurements by Species and Sex",
x = "Bill Length (mm)",
y = "Bill Depth (mm)",
color = "Species",
shape = "Sex"
) +
theme_minimal()
Using too many visual features can make a graph confusing, so students should use color and shape only when both variables are important.
This combines a boxplot with the mean for each species.
ggplot(na.omit(penguins), aes(
x = species,
y = body_mass_g,
fill = species
)) +
geom_boxplot() +
stat_summary(
fun = mean,
geom = "point",
shape = 23,
size = 3,
fill = "white"
) +
labs(
title = "Penguin Body Mass by Species",
subtitle = "White diamonds represent the mean",
x = "Species",
y = "Body Mass (g)"
) +
theme_minimal() +
theme(legend.position = "none")
This is a good example for discussing the difference between the mean and median.
First, create and store a plot in an object:
mass_plot <- ggplot(na.omit(penguins), aes(
x = species,
y = body_mass_g,
fill = species
)) +
geom_boxplot() +
labs(
title = "Penguin Body Mass by Species",
x = "Species",
y = "Body Mass (g)"
) +
theme_minimal() +
theme(legend.position = "none")
Display it:
mass_plot
Save it as an image:
ggsave(
filename = "penguin_body_mass.png",
plot = mass_plot,
width = 7,
height = 5,
dpi = 300
)
The file will usually be saved in RStudio’s current working directory. You can check that location with:
getwd()
## [1] "/cloud/project"
Complete the following analysis:
A strong final visualization might look like this:
ggplot(na.omit(penguins), aes(
x = flipper_length_mm,
y = body_mass_g,
color = species
)) +
geom_point(size = 3, alpha = 0.8) +
geom_smooth(method = "lm", se = FALSE) +
labs(
title = "Flipper Length Is Associated with Penguin Body Mass",
subtitle = "Observations are grouped by species",
x = "Flipper Length (mm)",
y = "Body Mass (g)",
color = "Species"
) +
theme_minimal(base_size = 13)
## `geom_smooth()` using formula = 'y ~ x'
The main lesson for students is to match the plot type to the variables: