PSet 1

Welcome to your first PSet! Two short stories, two figures:

The essentials
  • Released: Tuesday, October 13, 2026. Due: Sunday, October 25, 2026, 11:59 PM Pacific Time, on Bruin Learn.
  • What you need: Chapters 1–8 only. Anything beyond that is given to you in the Helpful tools boxes; you are not expected to know it already.
  • Workflow: make an R Project for this PSet (Chapter 7) and write everything in one R script, PSet1_LastName.R, that runs top to bottom. Start the script with library(tidyverse) and use tidyverse tools throughout: for example, read the data with read_csv() (from readr, part of the tidyverse), not base R’s read.csv().
  • You’ll submit (on Bruin Learn):
    1. Your R script, PSet1_LastName.R. Written answers go in the script as comments (# ...).
    2. Both figures exported with ggsave() as PDF and PNG: PSet1_LastName_nobel.pdf/.png and PSet1_LastName_kyoto.pdf/.png.
How you’ll be graded (30 points)
Part Items Points
Problem 1 — Chocolate & Nobel figure 5 requirements × 2 pts 10
Problem 2A — Detective work with dplyr 6 steps × 2 pts 12
Problem 2B — Cherry-blossom figure 3 requirements × 2 pts 6
Reproducibility — your script runs top to bottom and makes all four exports with ggsave() and explicit width/height 1 item × 2 pts 2
Total 30

Every item is worth 2 points: 2 if it is complete and correct, 1 if it is attempted but incomplete or partly wrong, 0 if it is missing.

Policies
  • AI tools: per the syllabus, do not use AI for this problem set, including coding, debugging, figures, or writing.
  • Collaboration: discussing ideas is fine; the code, figures, and words you submit must be your own. Name anyone you discussed the problem with in a comment at the top of your script.
  • Getting stuck is normal. Read the error message, check the Helpful tools boxes, and bring your code to office hours.

So, get your creativity (and code) fired up. Let’s begin!

Problem 1 — Why correlation is NOT causation (10 points)

We’ve all heard it a thousand times: correlation does not imply causation. In 2012, a cardiologist published a (half-joking) note in the New England Journal of Medicine showing that countries that eat more chocolate win more Nobel prizes. The correlation is real and surprisingly strong. Should you ask your doctor for a chocolate prescription before your thesis defense? Probably not.

The data for chocolate consumption (Chocolate, kg per person per year) and the number of Nobel laureates (Nobel, per 10 million people) in 25 countries is here. GDP is a per-country wealth measure, Country is the country name, and Flag is the lowercase two-letter country code:

library(tidyverse)
data_nobel <- read_csv("https://clsong.github.io/EEB_C234/data/data_nobel.csv")

A quick scatter plot:

ggplot(
    data = data_nobel,
    aes(x = Chocolate, y = Nobel)
) +
    geom_point() +
    theme_bw()

This quick plot is, well, meh. It is not something you’d proudly put on a slide. Even the original paper did better:

Messerli, F. H. (2012). Chocolate consumption, cognitive function, and Nobel laureates. New England Journal of Medicine

Make it publication-ready

Transform the quick plot. Your figure must include (2 pts each):

  1. Clear labels: a descriptive title that states the pattern, axis labels with units, and a caption crediting the data source (all with labs()).
  2. Country flags instead of points: replace geom_point() with a flag geom.
  3. The Pearson correlation coefficient (r) displayed on the plot (for example with ggpubr::stat_cor()).
  4. Readable text: all text at least 12 pt at the exported size. The defaults are almost always too small (Chapter 6).
  5. A non-default theme: pick one from jtools, hrbrthemes, ggthemes, etc., or carefully customize theme_minimal() (Chapter 6).

We did not cover everything in class, but it is easy to learn new ggplot2 tricks. You may use any package listed here.

Step 1 — Flags instead of points. Install the ggflags package and swap out geom_point():

# install once (installing from GitHub can fail on some machines;
# if it does, see the fallback below):
pak::pak("jimjam-slam/ggflags")

# then in your plot, use:
ggflags::geom_flag(aes(country = ___))  # which column holds the country codes?

ggflags needs lowercase two-letter (ISO-2) country codes, such as "us" or "jp"; one column in data_nobel already has them. If ggflags will not install, label each point with geom_text(aes(label = Country)) (or ggrepel::geom_text_repel()) instead, which still earns most of the credit for this requirement; say so in a comment.

Step 2 — Correlation coefficient. The ggpubr package stamps the Pearson correlation (shown as R) and the p-value onto the plot:

# install once:
pak::pak("ggpubr")

# add this layer to your plot:
ggpubr::stat_cor(method = "pearson", size = 6)

Step 3 (Optional) — Country name labels. Non-overlapping text labels:

# install once:
pak::pak("ggrepel")

ggrepel::geom_text_repel(aes(label = Country))

Problem 2 — The Kyoto cherry-blossom detective (18 points)

Every spring, cherry blossoms turn Kyoto into the destination for hanami, the Japanese tradition of picnicking under the flowers. Planning a trip sounds simple: show up when the trees are in full bloom. But the trees seem to have changed their schedule.

In March 2021, news outlets around the world reported that Kyoto’s cherry trees had reached full bloom on the earliest date in more than 1,200 years of records. That is not a typo: people in Kyoto have written down the blossom dates in diaries and court chronicles since the 9th century, and researchers pieced those notes together into one of the longest biological records on Earth.

Was 2021 a freak year, or part of a pattern? And is warming really the culprit? You have the data to find out: peak-bloom dates and monthly temperatures in Kyoto for every year from 1881 to 2024.

kyoto_raw <- read_csv("https://clsong.github.io/EEB_C234/data/kyoto_blossoms.csv")
Column Meaning
year Year, 1881–2024
month_01 … month_12 Mean air temperature in Kyoto for January … December, in °C
flowering_doy Day of year of peak bloom: 1 = January 1, 91 = April 1 (in non-leap years). Smaller = earlier.

Here is a cheat sheet for reading day-of-year values (non-leap years; leap years are one day off, which we ignore):

Day of year 81 85 91 101 111
Date Mar 22 Mar 26 Apr 1 Apr 11 Apr 21

A. Detective work with dplyr (12 points)

Use only the Chapter 8 verbs (filter(), select(), mutate(), arrange(), group_by(), summarize(), plus if_else() and case_when()). Each step is worth 2 points. For each step, keep your code in the script and write a short answer as a comment. The ✅ checkpoints let you check you are on track.

  1. Missing evidence. Some years have no bloom record. Use filter() to find them. Which years are they? Then create a table kyoto that drops those years. ✅ kyoto has 140 rows.

  2. Which month pulls the trigger? Cherry trees respond to temperature in the weeks before they bloom. Use summarize() to compute the correlation between flowering_doy and the temperature of each month from January to May (five correlations in one summarize() call). Which month has the strongest relationship? Is the sign what you expected? Now look at May. The blossoms are long gone by May, yet May temperature also correlates with bloom date. In one or two sentences, why might that be?

  3. Clean up. Use mutate() and select() to make kyoto contain just three columns: year, march_temp (a copy of month_03), and flowering_doy.

  4. New labels. Use mutate() to add:

    • decade, the decade of each year (1881 → 1880, 2024 → 2020). Hint: floor(year / 10) * 10.
    • era, using case_when(): "1881–1949", "1950–1999", and "2000–2024".
    • march_type, using if_else(): "warm" if march_temp is 9 °C or more, otherwise "cool".
  5. Record breakers. Use arrange() to list the 5 earliest and the 5 latest bloom years. Convert their dates with the cheat sheet. Was 2021 really the earliest year in this dataset? What do you notice about when the early years and the late years happened, and about their March temperatures? ✅ Both lists have exactly 5 rows, and every year in your “earliest” list blooms before April 2 (day 92).

  6. The big picture. Use group_by() and summarize() to make a table with one row per era containing: the number of years (n()), the mean bloom day, the mean March temperature, and the earliest bloom day. Then make a second table, decade_means, with one row per decade and its mean bloom day. In one sentence: by roughly how many days has peak bloom shifted from the first era to the last? ✅ The era table has 3 rows; decade_means has 15 rows.

Correlation inside summarize(). cor(x, y) returns the Pearson correlation between two columns, and summarize() can hold several calculations at once, each with its own name:

my_data |>
  summarize(
    r_ab = cor(column_a, column_b),
    r_ac = cor(column_a, column_c)
  )

cor() returns NA if any value is missing, which is one more reason to do Step 1 first.

Counting rows in each group. Inside summarize(), n() returns the number of rows in the group:

penguins |>
  group_by(species) |>
  summarize(n_penguins = n())

Showing just a few rows. After arrange(), pipe into head(5) to see only the top 5.

B. Make the cherry-blossom figure (6 points)

Now tell the story in one figure. Imagine it illustrating a short news article titled “Plan your hanami trip earlier”. Your figure must (2 pts each):

  1. The data layers: year on the x-axis, bloom day on the y-axis, one point per year (the kyoto table) colored by March temperature with a deliberate palette (not the default blues), plus the decade averages from decade_means as a second layer, for example a line with points.
  2. A readable y-axis and highlights: the y-axis shows dates (e.g. “Apr 1”) instead of day numbers, and the record-breaking years are labelled or annotated (Chapter 6). Putting earlier at the top is a nice touch.
  3. Clear labels: a takeaway title, a subtitle that explains what the dots and the line are, a caption crediting the data (see Sources below), and all text at least 12 pt at the exported size.

Step 1 — A layer with its own data. Every geom_*() can take its own data = argument, so one plot can show two different tables. Here, each penguin is a small point and each species’ average is a big point on top:

species_means <- penguins |>
  group_by(species) |>
  summarize(mean_length = mean(bill_length_mm, na.rm = TRUE),
            mean_depth = mean(bill_depth_mm, na.rm = TRUE))

ggplot(penguins, aes(x = bill_length_mm, y = bill_depth_mm)) +
  geom_point(alpha = 0.4) +
  geom_point(data = species_means, aes(x = mean_length, y = mean_depth), size = 5)

Use the same idea with kyoto and decade_means. Think about where on the x-axis the average for the 1880s should sit.

Step 2 — A continuous color palette. March temperature is a number, so it needs a gradient, not scale_color_manual():

scale_color_viridis_c(option = "plasma")
# or build a gradient from any palette in Chapter 6:
scale_color_gradientn(colors = MetBrewer::met.brewer("Hiroshige"))

Step 3 — Your own tick labels, and flipping an axis. breaks says where the ticks go and labels says what they read; the two vectors must be the same length. scale_y_reverse() takes the same arguments and also flips the axis upside down:

scale_y_continuous(
  breaks = c(10, 20, 30),
  labels = c("ten", "twenty", "thirty")
)

Use the day-of-year cheat sheet above to choose your breaks and labels.

Step 4 — Calling out the record years. Use annotate("text", x = ..., y = ..., label = "...") from Chapter 6. Or filter() a small table that holds only the years you found in Step 5, and label just those points with ggrepel::geom_text_repel(data = your_small_table, aes(label = year)).

Step 5 — Export. If the ° symbol shows up garbled in your exported figure, type it as "\u00B0" instead (e.g. "March temp (\u00B0C)"), and export the PDF with ggsave(..., device = cairo_pdf).

Sources

  • Messerli, F. H. (2012). Chocolate consumption, cognitive function, and Nobel laureates. New England Journal of Medicine 367, 1562–1564.
  • Pausas, J. G. (2025). The onset of phenological plant response to climate warming. New Phytologist 247, 2495–2498. Paper and supporting datasets. Flowering dates compiled by Yasuyuki Aono and colleagues; temperatures from the Japan Meteorological Agency.