Homework 3: Explore the Saw Kill with ggplot
DATA 121 | Fall 2026 | Due Friday, October 16
Water conditions can differ from one location to another and change throughout the year. We reside in the Saw Kill Watershed, and activity within the watershed influences the quality of the water we drink and the health of the life in the area and connected to the broader Mahicannituck (Hudson) estuary. In this homework you will investigate those differences using measurements from the Saw Kill, a stream which runs through Dutchess County and Bard College campus.
This analysis focuses on water temperature and dissolved oxygen. This isthe oxygen in the water that fish and other aquatic organisms use to breathe. Each row records a sampling visit to a particular site on a particular date.
Dissolved oxygen (DO) is oxygen gas dissolved in water. Its concentration reflects several processes:
Temperature: cold water can hold more dissolved oxygen than warm water.
Mixing: turbulence/disturbance helps oxygen from the air enter the water.
Photosynthesis: algae and aquatic plants release oxygen when there is light.
Respiration and decomposition: organisms use oxygen, including microbes breaking down leaves and other organic matter.
These processes can change with the season, location, and time of day, so temperature alone does not determine DO. USGS
In this homework, you’ll practice exploratory data analysis using the Core steps in EDA (slides 7-10) as a guide. You will use tables and plots to investigate:
How do water temperature and dissolved oxygen vary across seasons in the Saw Kill? How are water temperature and dissolved oxygen related?
You will use bar charts to examine sampling coverage, histograms to explore temperature distributions, and scatterplots to investigate temperature and oxygen. Separate charts will help you compare seasons.
Use the R and tidyverse functions we have practiced since week 4, together with ggplot(), aes(), geom_bar(), geom_histogram(), geom_point(), and labs().
Set up your Quarto
Open your course RStudio project,
data121. Inside itshomeworkfolder, create ahomework3folder.Download saw_kill_hw3.csv and save it in the main
datafolder inside yourdata121RStudio project.Create a new Quarto document named
homework3_yourname.qmdand save it in your homework folder:homework/homework3.Put your name in the author field near the top of the document.
Overall guidelines for your work in the Quarto
- Copy the Step 1–7 headings from this homework into your QMD. Steps 1–6 cover exploratory data analysis, Step 7 is a short code-fixing exercise. Under each heading, complete that step’s tasks and written questions.
Your course project uses execute-dir: project, so file paths start from the main data121 folder. The file path you will use in Step 2 is data/saw_kill_hw3.csv.
Include comments: Add brief
#comments when you use several functions in a pipeline. This will help you practice understanding what each function is doing.For every plot, include a descriptive title and axis labels. Include units for measurements, such as degrees Celsius or mg/L, and label what counts represent. Give any color legend a descriptive title.
Step 1: Get to know the data (8 points)
Data source and variables
The Saw Kill Watershed Community Database makes local watershed monitoring data available through maps, charts, and downloadable files. It was created through a partnership between the Saw Kill Watershed Community and Bard Community Sciences Lab, with support from the Hudson River Foundation. Its purpose is to help community members investigate the health of the watershed and answer local environmental questions.
| Variable | What it records | Type and units | Measurement level |
|---|---|---|---|
site |
Sampling location identifier | Categorical label | Nominal |
sample_date |
Date of the sampling record | Date | Interval: differences in days are meaningful |
year |
Calendar year | Calendar field | Interval: differences in years are meaningful |
month |
Calendar month, numbered 1–12 | Calendar field; not an event count | Nominal |
season |
Winter, Spring, Summer, or Fall | Categorical | Nominal |
water_temp_c |
Water temperature | Continuous numerical measurement, degrees Celsius | Interval |
oxygen_mg_l |
Dissolved oxygen concentration, measured with a field meter | Continuous numerical measurement, milligrams per liter | Ratio |
ph |
Acidity/basicness of the water | Continuous numerical measurement on the pH scale; no mass or temperature units | Interval: logarithmic scale |
Measurement level describes which comparisons make sense. Interval variables have meaningful differences, but their zero does not mean the quantity is absent. Ratio variables have a meaningful zero representing absence, so ratios make sense: 8 mg/L is twice the oxygen concentration of 4 mg/L. Celsius temperature and pH are interval variables: 20 degrees Celsius is not twice as hot as 10 degrees Celsius, and pH 8 is not twice pH 4 in acidity. The pH scale is logarithmic; a decrease of one pH unit corresponds to a tenfold increase in hydrogen-ion activity. See USGS: pH and Water.
The eight variables above support the assigned work. The file also includes these measurements and observations:
| Variable | What it records | Units or format |
|---|---|---|
conductivity_us_cm |
How readily the water conducts electricity because of dissolved salts and minerals | Microsiemens per centimeter |
turbidity_ntu |
Water cloudiness from suspended particles; higher values mean cloudier water | Nephelometric turbidity units (NTU) |
ecoli_mpn_100ml |
Estimated concentration of E. coli, a fecal-indicator bacterium | Most probable number (MPN) per 100 mL |
enterococcus_mpn_100ml |
Estimated concentration of Enterococcus, another fecal-indicator bacterium | MPN per 100 mL |
chloride_mg_l |
Dissolved chloride, an ion present in salts | Milligrams per liter |
nitrate_mg_l |
Nitrate, a form of nitrogen that plants and algae can use | Milligrams per liter of nitrate |
phosphate_mg_l |
Phosphate, a form of phosphorus that plants and algae can use | Milligrams per liter of phosphate |
chlorophyll_rfu |
Chlorophyll a instrument signal, an indicator of algae | Relative fluorescence units (RFU) |
rain_7day_in |
Archived rainfall total for the seven days before sampling | Inches |
weather_notes |
Samplers’ weather observations | Original free text |
cloud_cover_notes |
Samplers’ descriptions of the sky | Original free text |
field_notes |
Observations about the water, sampling access, or other conditions | Original free text |
You do not need to analyze these additional variables for this homework, but you are welcome to explore. For example, you could investigate whether rainier periods have cloudier water, or compare chloride with conductivity. The complete variable guide includes definitions and the number of recorded and missing values for each variable.
Missing measurements are included as NA entries. Use the variable definitions table for a brief description of every column.
Answer these questions in your Quarto document:
Who collected these data, and why are they available through the community database?
What does a row represent?
Why does the same sampling site appear in multiple rows?
Step 2: Load the data into R and connect exploratory analysis questions to the forthcoming plots (10 points)
In your first code chunk, load the
tidyversepackage.Use
read_csv()to importdata/saw_kill_hw3.csvand save it in a new data frame object namedsaw_kill.Redefine
saw_killso thatsiteis stored as character data. Use mutate() to create a new version of the site variable that is stored as a character type. Assign the result back to the same object name to overwrite/redefine the data frame with this new version ofsite. Hint: Usemutate()andas.character().
Next, use the code provided below to redefine the season variable and again redefine the saw_kill data frame.
The code snippet sets the appropriate order of the seasons using the R data type factors.
A factor stores categories and influences their display order in plots. Here we want Winter, Spring, Summer, Fall so that tables and legends follow the calendar instead of alphabetical order.
Copy the following code into a code chunk after importing the data and updating site, run:
saw_kill <- saw_kill |> # Redefine the data frame
mutate(season = fct_relevel(season, "Winter", "Spring", "Summer", "Fall")) # Set the season factor levels for charts in this activityWhat the code does:
fct_relevel()takes the existingseasoncolumn and makes it a factor data type with the categories in the order of the seasons.mutate(season = ...)replaces the existingseasoncolumn with the updated version.saw_kill |>passes the data frame tomutate(), andsaw_kill <-saves the updated data frame under the same name.
This changes the display order in charts you create later.
Next:
- Run
glimpse(saw_kill)to check the column types and runlevels(saw_kill$season)to check the season order. - Copy the three questions below into your document. Write whether you will use:
geom_bar(),geom_histogram(), orgeom_point()and explain why it fits the question. You will make the plots in later steps.
How many sampling records come from each site?
Geom:
Why this geom fits:
How are recorded water temperatures distributed?
Geom:
Why this geom fits:
How does oxygen vary with water temperature?
Geom:
Why this geom fits:
Step 3: Identify missing data (5 points)
- Create a table named
missing_summarywith the number of missing values inwater_temp_c,oxygen_mg_l, andph. Display the table.
Hint: Use summarize() with sum() and is.na().
Continue using saw_kill in the steps below. Use na.rm = TRUE in statistical calculations to exclude missing measurements from that calculation. The plotting steps explain which missing measurements ggplot omits.
Step 4: Summarize variables with tables and plots (22 points)
Sampling coverage: A bar chart
Use
saw_killto make a bar chart of the number of sampling records at each site. In other words, count how many rows of data there are for each site location on the Saw Kill.Make the bar fill color
green.Create a frequency table to check the bar heights.
Hint: Use geom_bar() for the chart and count() for the table.
Include a response in your document:
- What does a bar represent / what does the height of each bar count?
- Which site or sites have the most observations? Mention the count of observations in your response.
Temperature distribution: Summary statistics and histograms
- Use the
saw_killdata frame to create a summary table namedtemp_summarywith the mean, median, standard deviation, minimum, and maximum ofwater_temp_c.
Hint: Use summarize() to calculate the five statistics in one table. Use na.rm = TRUE in each statistical function to exclude missing temperatures from that calculation.
- Use
saw_killto make a histogram ofwater_temp_cwithbinwidth = 2.
geom_histogram() omits missing temperatures and reports how many rows it omitted in a warning you will see in the Console. Check the number of rows mentioned in the warning against missing_summary from Step 3.
- What does each bar represent / what does its height represent?
- Include the meaning of
binwidth = 2in your explanation.
- Include the meaning of
Step 5: Wrangle and transform (15 points)
Starting with
saw_kill, create a summary table namedseason_summarythat groups the observations by season. Include:The total number of sampling records.
The number of non-missing temperature measurements.
Mean, median, and standard deviation of temperature in Celsius.
the number of non-missing oxygen measurements.
average dissolved oxygen in mg/L.
Hint: Use group_by() and summarize().
Recall the difference between counting rows with n() and counting non-missing measurements with sum() and !is.na(). Use na.rm = TRUE when calculating statistics from columns with missing values. See the multiple-summary-statistics example in the course notes.
Answer in your document:
- Which season has the highest mean temperature? Which has the highest mean oxygen? Include the values.
Step 6: Explore relationships and groups (34 points)
Scatterplots: Temperature and oxygen
- Use
saw_killto make a scatterplot comparingwater_temp_candoxygen_mg_l. Make every pointorange.- What does a point on the plot represent?
- Describe the direction and shape of the relationship: Use the plot to explain whether warmer measurements tend to have more or less dissolved oxygen.
Side note: geom_point() omits rows missing either temperature or oxygen and reports how many rows it omitted.
- Create a second scatter plot that uses color to show season: Modify your scatterplot so that point colors represent
season.- What do the seasonal colors help you see about the temperature–oxygen relationship?
Histograms: Compare temperature distributions
- Choose two seasons to compare. For each season, use
saw_killto make a separate histogram ofwater_temp_cwithbinwidth = 2. Include the season in each chart title. Hint: Usefilter()beforeggplot()to subset the observations for each season.- In your document, include an answer to: How do the temperature distributions differ between your two seasons? Use your charts and
season_summaryto support your answer.
- In your document, include an answer to: How do the temperature distributions differ between your two seasons? Use your charts and
Bar charts: Compare sampling coverage
Make two bar charts showing the number of sampling records by site:
Create a bar plot for each season you chose for the histograms above.
Include the season in each chart title.
Create a frequency table for each season to check the bar heights.
Hint: Use filter() to select a season before making the chart with geom_bar(). Use count(site) on the filtered data to create the frequency table.
In your document, in writing outside of the code chunk, answer:
Which sites have the most sampling records in each season? Include their counts.
How does sampling coverage differ between the two seasons?
What does each bar’s height represent?
Step 7: Fix the code (6 points)
The following code is intended to make a scatterplot with every point pink. Identify the two problems, correct the code, and explain each correction.
ggplot(saw_kill,
aes(x = water_temp_c, y = oxygen_mg_l, color = "pink")) |>
geom_point()Submit
Render your document. Check that your name, all seven steps, code, tables, plots, and written answers are visible.
Upload homework3_yourname.qmd and homework3_yourname.html to Brightspace by Friday, October 16.
Variable definitions
Each row is one sampling visit at one site on one date. NA means a value was not recorded or is unavailable in the archive.
| Variable | Brief definition |
|---|---|
site |
A label identifying where the sample was collected. |
sample_date |
The date the sample was collected. |
year |
The calendar year of the sampling visit. |
month |
The calendar month, from 1 (January) to 12 (December). |
season |
Winter, Spring, Summer, or Fall. |
water_temp_c |
How warm or cold the water was, in degrees Celsius. |
oxygen_mg_l |
Oxygen dissolved in the water, which fish and other aquatic life use to breathe (mg/L). |
ph |
How acidic or basic the water is. On the pH scale, 7 is neutral; lower values are more acidic and higher values are more basic. |
conductivity_us_cm |
How easily electricity passes through the water. More dissolved salts and minerals generally increase this reading (microsiemens/cm). |
turbidity_ntu |
How cloudy the water is because of suspended particles. Higher readings mean cloudier water (NTU). |
ecoli_mpn_100ml |
An estimate of E. coli bacteria in 100 mL of water, used as an indicator of fecal contamination. |
enterococcus_mpn_100ml |
An estimate of Enterococcus bacteria in 100 mL of water, also used as an indicator of fecal contamination. |
chloride_mg_l |
The amount of dissolved chloride, a component of salts such as road salt (mg/L). |
nitrate_mg_l |
The amount of nitrate, a nitrogen nutrient that plants and algae can use (mg/L). |
phosphate_mg_l |
The amount of phosphate, a phosphorus nutrient that plants and algae can use (mg/L). |
chlorophyll_rfu |
An instrument reading of chlorophyll a, a pigment in algae. It helps indicate algae levels (RFU). |
rain_7day_in |
Total rainfall during the seven days before sampling, in inches. |
weather_notes |
Samplers’ written descriptions of the weather. |
cloud_cover_notes |
Samplers’ written descriptions of how cloudy the sky was. |
field_notes |
Notes about water conditions, access to the site, or other sampling details. |
Units: mg/L means milligrams per liter. NTU is the unit used to measure water cloudiness. MPN means most probable number, an estimate of bacterial concentration. RFU means relative fluorescence units, an instrument signal rather than a concentration in mg/L.