R Markdown

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

Including Plots

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

RStudio Plot Examples with the Palmer Penguins Dataset

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.

1. Set up RStudio

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 species
  • island: island where the penguin was observed
  • bill_length_mm: bill length
  • bill_depth_mm: bill depth
  • flipper_length_mm: flipper length
  • body_mass_g: body mass
  • sex: penguin sex

Some observations have missing values, so many plots use na.omit().


2. Scatterplot: Bill Length and Bill Depth

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()`).

Add species colors

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()

Questions for students

  • Do the species form separate groups?
  • Which species tends to have the deepest bills?
  • Are there any unusual observations?
  • Does bill length appear related to bill depth?

3. Scatterplot with a Trend Line

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.

Questions for students

  • Is the relationship positive or negative?
  • Do heavier penguins generally have longer flippers?
  • Does the relationship look approximately linear?
  • Are there points far from the trend line?

4. Boxplot: Body Mass by Species

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.

Questions for students

  • Which species has the highest median body mass?
  • Which species has the greatest variability?
  • Are there possible outliers?
  • Do the distributions overlap?

5. Boxplot by Species and Sex

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()

Questions for students

  • Within each species, do males and females differ in body mass?
  • Is the sex difference similar across species?
  • Which combination has the highest median body mass?

6. Histogram: Distribution of Body Mass

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()

Compare distributions by species

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.


7. Bar Chart: Number of Penguins by Island

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()

Count penguins by species and island

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()

Questions for students

  • Which island has the most observations?
  • Are all species found on every island?
  • Which island appears most associated with a particular species?

8. Faceted Scatterplot

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.

Questions for students

  • Is the relationship similar for each species?
  • Which species has the widest range of body mass?
  • Does one species show a stronger pattern than the others?

9. Scatterplot with Both Color and Shape

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.


10. Add a Mean Point to a Boxplot

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.


11. Save a Plot

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:

  1. Create a bar chart showing the number of penguins on each island.
  2. Create a boxplot comparing body mass across species.
  3. Create a scatterplot of flipper length and body mass.
  4. Color the scatterplot by species.
  5. Add a regression line.
  6. Write three observations supported by the plots.
  7. Identify one limitation, such as missing values or the fact that association does not prove causation.

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: