Seasonal cetacean sighting records in the Hawaiian Islands EEZ

What nine survey cruises between 2009 and 2017 do and do not show

Théophile L. Mouton

2026-09-23

readRDS() — load prepared objects, running 01_prepare_data.R if needed
library(dplyr); library(here); library(knitr)

if (!file.exists(here("data", "derived", "usable.rds")))
  source(here("R", "01_prepare_data.R"))

usable <- readRDS(here("data", "derived", "usable.rds"))
funnel <- readr::read_csv(here("outputs", "funnel.csv"))
by_mon <- readr::read_csv(here("outputs", "effort_by_month.csv"))

# Monthly totals with the empty months present, so they can be named in prose.
mon <- tibble::tibble(month = 1:12) |>
  left_join(count(usable, month), by = "month") |>
  mutate(n = tidyr::replace_na(n, 0),
         name = month.name[month])

peak     <- slice_max(mon, n, n = 1)
empty    <- filter(mon, n == 0)$name
n_usable <- nrow(usable)
n_spp    <- n_distinct(usable$CommonName)

This is a companion note to an animated map of cetacean sighting records in the Hawaiian Islands Exclusive Economic Zone, built from NOAA’s public WinCruz sighting archive. It sets out where the data came from, what was excluded and why, what the seasonal pattern is, and — the part that matters most — what the map cannot be read as saying.

The map

The seasonal animation (rendered by R/02_seasonal_map.R)
include_graphics(here("outputs", "figures", "still_september.png"))

September, the densest month. The full twelve-month animation is at outputs/hawaii_cetacean_seasonal.mp4.

Twelve frames, January to December, pooling all years. Each amber point is one sighting. Bathymetry is underneath, the EEZ boundary is outlined, and the species recorded that month are named down the right-hand side.

Plotting code is in R/02_seasonal_map.R rather than inline, since it runs to a couple of hundred lines and renders 240 frames.

What a WinCruz sighting record is

Each row is one group of one species, seen once, from a ship. The archive carries the date, the ship’s position at the start of the sighting, species, group-size estimates, the EEZ and PIFSC region, what cued the observation, whether the sighting was mixed-species, and the NMFS permit it was collected under.

One absence shapes everything below: there is no effort or trackline information. The archive contains sightings and nothing else. It cannot say where the ship went, how far it steamed, or how long observers were searching.

That single fact is why this note is careful about the word “distribution”.

Filtering

Three exclusions, in order.

Non-cetaceans. SpeciesCode is numeric for cetaceans and alphabetic for sea turtles (CC, CM, DC, EI) and Hawaiian monk seal (MS). One record in the archive is not a cetacean.

Records not identified to species. Unid. Dolphin, Unid. Beaked whale, Mesoplodon sp., Sei/Bryde's whale and similar are records of a cetacean, not of a species. A map that names species can only draw records that name one.

Effort type. From the InPort entity metadata:

Did the sighting occur when the survey effort was systematic (S), non-systematic (N), fine-scale (F), or off (O)

Only S denotes systematic line-transect effort, where the ship is running a planned track with observers on watch. The rest happen while transiting, closing on a group, or otherwise not surveying — real sightings, but not comparable between months or places. Note that O means off-effort; it reads like “on”, and filtering on it silently selects the wrong records.

The exclusion sequence, in counts
kable(funnel, col.names = c("Step", "Records"), format.args = list(big.mark = ","))
Step Records
all records 1,492
cetaceans 1,491
identified to species 1,042
Hawaiian Islands EEZ 882
systematic effort 370

370 sightings across 24 species remain. Group size was deliberately not required: the map draws one point per sighting regardless of how many animals were in the group, so a missing group-size estimate is no reason to drop a record here.

Seasonal coverage

Sightings by month and effort type, Hawaiian Islands EEZ
by_mon |>
  right_join(tibble::tibble(month = 1:12), by = "month") |>
  arrange(month) |>
  mutate(across(where(is.numeric) & !month, ~ tidyr::replace_na(.x, 0)),
         Month = month.name[month]) |>
  select(Month,
         `Systematic (S)`     = S,
         `Non-systematic (N)` = N,
         `Fine-scale (F)`     = F,
         `Off-effort (O)`     = O) |>
  kable(format.args = list(big.mark = ","))
Effort types: systematic (S) is planned line-transect effort with observers on watch; non-systematic (N) and fine-scale (F) are other on-water modes; off-effort (O) is transiting or closing on a group. Only S is comparable between months.
Month Systematic (S) Non-systematic (N) Fine-scale (F) Off-effort (O)
January 1 0 0 0
February 59 42 0 17
March 0 10 0 1
April 0 38 0 16
May 75 12 0 11
June 6 3 0 5
July 48 114 7 76
August 56 30 4 18
September 171 34 8 82
October 68 100 2 48
November 47 28 0 16
December 0 0 0 0

The record is heavily skewed toward the second half of the year. September alone holds 117 of the 370 systematic sightings.

March, April, and December contain none at all.

The distinction between effort types earns its keep here. March and April are empty of systematic records, but both carry sightings under other effort types — vessels were present, they were simply not running line-transect effort. December is the only month with no records of any kind.

So the accurate statement is not that three months went unsurveyed. It is that systematic effort is concentrated in the second half of the year, and that the winter record rests almost entirely on a single February.

Cruises

Sightings by cruise — the unit the seasonal pattern actually reflects
usable |>
  count(CruiseID, name = "Sightings") |>
  arrange(CruiseID) |>
  kable(col.names = c("Cruise", "Sightings"))
Cruise Sightings
2009 Main Hawaiian Islands_ SE 19-01 46
2010 Guam-Hawaii transit_SE 10-04 5
2010 HICEAS_MAC 1641 92
2010 HICEAS_SE 10-08 47
2010 Hawaii-Guam transit_SE 10-01 1
2013 PACES_SE 13-03 58
2016 HI-TEC_SE 16-04 20
2017 HICEAS_LSK 17-05 36
2017 HICEAS_SE 17-06 65

Nine cruises, five years. The monthly pattern above is better read as a record of when these cruises sailed than as a seasonal schedule: 2010 and 2017 — both HICEAS years — contribute 145 and 101 sightings respectively, two-thirds of the total, and every cruise working in September belongs to one of them. September’s apparent peak is the HICEAS field season sampled twice.

Two of the nine are transits rather than surveys, contributing six sightings in total. One of those six is the entire January record.

Building the map

Two things about this region caused more trouble than the data did.

The EEZ crosses the antimeridian. Its bounding box in conventional −180/180 longitude spans the entire globe, and eight sightings sit east of the line. Everything is handled in 0–360 instead. The source polygon is also split at 180°, and that seam survives the shift as an interior line which geom_path will happily draw straight across the map; it is stripped before plotting.

The bathymetry arrives on two different grids. marmap’s antimeridian mode fetches the halves either side of 180° separately, and they come back with different cell sizes — 0.06694° and 0.06793°, plus a 0.035° sliver at the join. geom_raster assumes a regular grid and draws every cell at one nominal width, so the mismatch renders as vertical striping across the whole panel. The data is resampled onto a single regular 0.07° grid, with an assertion afterwards so a future regression fails loudly rather than quietly.

What this map does not show

It shows records, not animals. With no effort data in the archive, the points describe where observations were written down. Reading spatial pattern from them means reading wherever the ship happened to go.

Blank months mean no systematic effort, not an absence of animals — and in two of the three cases, not even an absence of survey activity.

Species identification varies in resolution. Around 30% of the archive is cetaceans not identified to species, and those records are unlikely to be distributed evenly across taxa. Excluding them is necessary for a species-labelled map and is not neutral.

Sightings are not corrected for detectability. Sea state, group size and species behaviour all affect whether an animal present is an animal seen, and none of that is accounted for in a plot of raw records.

Nine cruises, not twelve years. The record spans 2009–2017 but comprises nine cruises in five years, two of them transits. Any monthly or annual comparison is a comparison between a handful of voyages, and a month’s total can rest on a single one — January’s does.

Data and attribution

Sightings — NOAA Pacific Islands Fisheries Science Center, Cetacean Research Program. Shipboard Cetacean Surveys — Visual Surveys — WinCruz Sighting Records, InPort 18141. Collected under NMFS permits PIFSC 15240, PIFSC 20311, SWFSC 14097, SWFSC 774-1714. Citing the permit numbers is a condition of use.

Bathymetry — NOAA ETOPO, via marmap.

EEZ boundary — Flanders Marine Institute, Maritime Boundaries Geodatabase v12 (2023), marineregions.org, CC BY 4.0.

Silhouettes — PhyloPic via rphylopic; per-image contributors and licences in outputs/phylopic_credits.csv. Three species have no PhyloPic image and use a genus- or family-level stand-in.

Code: github.com/TheophileMt92/hawaii-cetacean-seasonality