Rice’s whale (Balaenoptera ricei) are a relatively new species discovered in our backyard. Their distribution is limited to the Gulf, and some have raised concerns about potential interactions with fishing gear for two reasons:
Rice’s whales sleep near the surface, which exposes them to early boat traffic (see figure below).
When Rice’s whales feed, they are thought to perform circling movements with the bottom. These could expose them to interactions with bottom set gear (see figure below).
Rice’s whale sleep near the surface. Source: Kok et al. (2023)
Rice’s whale exhibit circling behavior near the bottom. Source: Kok et al. (2023)
The task at hand
NOAA Fisheries has identified Rice’s whale core habitat. You have access to spatially-explicit fishing effort data for 2024 (via EVR628tools::data_fishing_effort). Your tasks are to measure the amount of fishing effort ocurring within Rice’s whale core habitat and produce a map.
Part 1: Set up
Exercise 1: Download datasets
Post-it up
Rice’s whale Core Habitat
Go to NOAA Fisheries and download the Shapefile for Rice’s Whale Core Distribution Area.
You will be prompted to download a zipped folder. Save it to your data/raw folder in the EVR_628 project.
Click here to download a global raster for depth.2
Save it to data/raw
Is this a vector or a raster file?
Post-it down
Exercise 2: Read datasets into R
Post-it up
Create a new R script called rices_whale.R and save it to your scripts/analysis folder.
Add a basic comment structure to your script.
Load all the packages that we will need: EVR628tools, ggspatial, rnaturalearth, tidyverse, sf, terra, tidyterra, and mapview.
You will now create three objects:
whale <-: Use read_sf() to load Rice’s whale core habitat vector. Note: you don’t need to list every file; simply list the path to the .shp file.
depth <-: Use rast() to load the depth raster.
coast <-: Use ne_countries() to load vector data for U.S.A, Mexico, Belize, and Guatemala3.
Use data() to load the data_fishing_effort dataset from the EVR628tools package.
Quickly inspect your whale and coast data using mapview(). Inspect depth with plot().
Post-it down
Code
# Load packages ----------------------------------------------------------------library(EVR628tools) # For fishing effort data and color paletteslibrary(ggspatial) # To add map elements to a ggplotlibrary(rnaturalearth) # To add country outlineslibrary(tidyverse) # General data wranglinglibrary(sf) # Working with vector datalibrary(terra) # Working with raster datalibrary(tidyterra) # Working with raster data in tidy approachlibrary(mapview) # To quickly inspect data# Load data --------------------------------------------------------------------# Load whale core habitatwhale <-read_sf("data/raw/shapefile_Rices_whale_core_distribution_area_Jun19_SERO/shapefile_Rices_whale_core_distribution_area_Jun19_SERO.shp")# Load depth rasterdepth <-rast("data/raw/depth_raster.tif")# Load world's coastlinecoast <-ne_countries(country =c("United States of America", "Mexico", "Belize", "Guatemala"))# Load fishing effort data.framedata("data_fishing_effort")# Quick inspectionsmapview(list(whale, coast))
Code
plot(depth)
Part 2: Data wrangling
Exercise 1: Rasterize fishing effort
Printing the data_fishing_effort object reveals that it contains monthly fishing effort by pixel4, but it is not yet a raster object… we’ll get there after some piping.
Post-it up
Look at the documentation for the ?rast() function. Scroll down to where it says “## S4 method for signature 'data.frame'”.
Start building a pipeline. Create a new object called effort_raster <- that receives the data_fishing_effort object.
Calculate total fishing effort (in hours) for each pixel (lon, lat) using group_by() and summarize(). Name the new column hours.
Post-it down
After the summarize(), pipe into rast(). For the crs argument, use crs = "EPSG:4326"5.
Print the new effort_raster to your console.
What is the class of effort_raster?
What is the res of effort_raster?
Make a quick plot of your new raster object.
Code
# Create a new object to contain a raster of fishing efforteffort_raster <- data_fishing_effort |># Start with my data.framegroup_by(lon, lat) |># group by lon and latsummarize(hours =sum(effort_hours)) |># Calculate total effort by pixelrast(crs ="EPSG:4326") # Build a raster# Print raster to consoleeffort_raster
class : SpatRaster
size : 129, 180, 1 (nrow, ncol, nlyr)
resolution : 0.1, 0.1 (x, y)
extent : -97.95, -79.95, 18.15, 31.05 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source(s) : memory
name : hours
min value : 0.00
max value : 6468.06
Code
# Quick plot of my rasterplot(effort_raster)
Exercise 2: Calculate total fishing in core habitat
We now want to extract the data associated with pixels inside the whale’s core habitat.
We’ll do this one together.
Look at the documentation for the ?extract() function in the terra package.
Pay attention to the section “## S4 method for signature 'SpatRaster,SpatVector'”
What are x and y?
What does the fun argument do?
What is the exact parameter for?
Extract all fishing effort occurring inside the whale’s core habitat. Use fun = sum and na.rm = T
Then try adding touches = T. What happens to the answer?
Now use exact = T. What happens now?
Code
# extract(effort_raster, whale) # Simple extraction (I'm not running it here to save space)extract(effort_raster, whale, fun = sum, na.rm = T) # Calculate sum
ID hours
1 1 2691.67
Code
extract(effort_raster, whale, fun = sum, na.rm = T, touches = T) # Keep all pixels touched by the raster
ID hours
1 1 2815.58
Code
extract(effort_raster, whale, fun = sum, na.rm = T, exact = T) # Calculate the weighted sum
ID hours
1 1 2664.666
Exercise 3: Prepare layers for plotting
We’ll do this one together.
What is the extent of the depth raster? How about the extent dor the coast vector? Clearly we will need to modify their extents.
Use crop() to crop the depth raster so that it matches the extent of the effort_raster6. Save the new depth raster to gulf_depth.
The coast vector data contains the entire boundaries for the four countries. Let’s also crop it to match effort_raster, but this time using st_crop(). Save the new vector file to gulf_coast.
# Start a plotggplot() +# Add the depth contours as the first laeyergeom_spatraster_contour(data = gulf_depth,aes(colour =after_stat(level)),linewidth =0.5) +# Add fishing effort raster on topgeom_spatraster(data =log(effort_raster)) +# Add gulf coast coastlinegeom_sf(data = gulf_coast,fill ="gray",color ="black") +# Add whale's core habitatgeom_sf(data = whale, fill ="transparent",color ="black",linewidth =2) +# Modify the colors for the depth contoursscale_color_viridis_c(option ="mako") +# Modify the fill of the effort rasterscale_fill_viridis_c(option ="magma",na.value ="transparent") +# Modify the themetheme_bw() +# Add a north arrow from ggspatialannotation_north_arrow(location ="tl") +# Add a scalebar from ggspatialannotation_scale(location ="bl") +# Trim whitespacescale_x_continuous(expand =c(0, 0)) +scale_y_continuous(expand =c(0, 0)) +# Update labelslabs(color ="Depth (m)",fill ="Effort [log(hours)]",x ="Longitude",y ="Latitude",title ="Fishing effort in and around Rice's whale core habitat",subtitle ="2664.6 hours inside core habitat detected during 2024",caption ="Data sources: NOAA Fisheries, GMED, GFW")
Extra
Rasterize a vector
Our exercises above had us take point data on a regular grid and convert them to a raster object. But what if we wanted to start with a spatial vector file? The chunk below takes the whale’s core habitat and produces a raster version of it. The key function is rasterize().
What about the opposite case? We might have raster data outlining, say, areas between 100–400 m deep (Rice’s whale depth range as reported by NOAA.)
Code
# Create a raster of depths that are relevantrange_rast <- (gulf_depth >-400) & (gulf_depth <-100)plot(range_rast)
Code
# Anything outside the range is now NArange_rast[!range_rast] <-NAplot(range_rast)
Code
# Polygonize the outlinerange_vect <-as.polygons(range_rast, dissolve = T)plot(range_vect)
Code
# Convert it to an sf objectrange_vect <-as.polygons(range_rast, dissolve = T) |>st_as_sf()plot(range_vect)
References
Kok, Annebelle C M, Maya J Hildebrand, Maria MacArdle, Anthony Martinez, Lance P Garrison, Melissa S Soldevilla, and John A Hildebrand. 2023. “Kinematics and Energetics of Foraging Behavior in Rice’s Whales of the Gulf of Mexico.”Sci. Rep. 13 (June): 8996.
Footnotes
Mac users double click on the zip folder. Windows users use the “Extract” or “Unzip” button in your toolbar.↩︎
The data come from GMED: Global Marine Environment Datasets for environment visualization and species distribution modelling, but UM’s firewall doesn’t allow access.↩︎
Hint: You will need to use country = c("United States of America", "Mexico", "Belize", "Guatemala")↩︎
Hint: Use ?data_fishing_effort to look at the documentation↩︎