Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Identifying peaks in hydrological time series

I'm working with a time series of 15-minute river flow observations collected over a 2-week period, and I'm trying to determine the dateTime of the peaks in river flow during this time. I've tried a number of packages/functions including ggpmisc::stat_peaks() (example below), pracma::findpeaks(), and cardidates::peakwindow(), which claim to identify peaks in a time series, but I haven't been able to achieve realistic results with any of them. Can anyone advise how to identify realistic peaks in a time series using ggpmisc::stat_peaks()? I'm also open to answers from other packages if ggpmisc isn't the best option.

library(tidyverse)
library(dataRetrieval)
library(ggpmisc)

# 1. Download time series of river water flow
dat <- readNWISuv(siteNumbers = "01576381",
                  parameterCd = "00060",
                  startDate = "2024-04-01",
                  endDate = "2024-04-15",
                  tz = "America/New_York") %>% 
  renameNWISColumns() %>% 
  rename(flow = Flow_Inst) %>% 
  select(dateTime, flow)

# 2. See data structure
head(dat)
#>              dateTime flow
#> 1 2024-04-01 00:00:00 25.0
#> 2 2024-04-01 00:15:00 25.6
#> 3 2024-04-01 00:30:00 25.0
#> 4 2024-04-01 00:45:00 25.6
#> 5 2024-04-01 01:00:00 25.1
#> 6 2024-04-01 01:15:00 25.6

# 3. Visualize time series of river flow over 2-week period
dat %>% 
  ggplot(aes(x = dateTime, y = flow)) +
  geom_line() +
  theme_bw()

# 4. Attempt to use stat_peaks to identify peaks in time series
dat %>% 
  ggplot(aes(x = dateTime, y = flow)) +
  geom_line() +
  stat_peaks(color = 'red') +
  theme_bw()

# 4. Attempt to use stat_peaks to identify peaks in time series
dat %>% 
  ggplot(aes(x = dateTime, y = flow)) +
  geom_line() +
  stat_peaks(color = 'red',
             strict = TRUE) +
  theme_bw()

The ideal output (based on "eye-balling" the peaks) would look something like this: enter image description here Created on 2025-03-17 with reprex v2.1.1

like image 618
tassones Avatar asked Sep 17 '25 22:09

tassones


1 Answers

cardidates::peakwindow works fine, you just need to adjust mincut to detect more or fewer peaks:

ggplot(dat, aes(x = dateTime, y = flow)) +
  geom_line() + # geom_point() +
  geom_point(
    aes(as.POSIXct(x), y),
    cardidates::peakwindow(dat$dateTime, dat$flow, mincut = 0.9)$peaks,
    color = 'red'
  ) +
  theme_bw()

One reason stat_peaks struggles is that some of your peaks have duplicated values at the top, and algorithms looking for strict increases and decreases will fail.

a plot with annotated peaks

like image 194
Axeman Avatar answered Sep 20 '25 13:09

Axeman