Skip to content

Commit

Permalink
Increment version number
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholascarey committed Aug 29, 2020
1 parent 83693de commit 2d9a2d3
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 112 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: caRey
Type: Package
Title: Collection of Useful R Functions
Version: 0.2.0
Version: 0.2.1
Author: Nicholas Carey
Maintainer: Nicholas Carey <[email protected]>
Description: Collection of Useful R Functions
Expand Down
151 changes: 84 additions & 67 deletions R/peaks.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,62 @@
#' @details `peaks` scans a vector of numeric values and identifies peaks and
#' troughs.
#'
#' The required factor (`span`) and two optional factors (smoothing and
#' The required input (`span`) and two optional inputs (smoothing and
#' `height`), need to be balanced to successfully identify peaks and troughs.
#' Characteristics such as data noisiness, amplitude, etc will affect how
#' important these are and how successful the identification process is.
#' Characteristics such as data noisiness, amplitude, wavelength etc will
#' affect how important each of these are and how successful the
#' identification process is.
#'
#' **Span**
#' **span**
#'
#' The most important parameter in determining a peak is the \code{span}. This
#' sets the threshold for identification; to be designated a peak, a value
#' (after smoothing) must be the highest value within the `span` window
#' (lowest value for troughs).
#' The most important parameter in determining peaks is the `span`, which sets
#' the threshold for identification. A rolling window of width `span` moves
#' across the data, and to be designated a peak a value (after any smoothing)
#' must be the highest value within that window (or the lowest value for
#' troughs). The `span` window can be entered as an integer number of values
#' (e.g. `span = 11`), or if between 0 and 1 a proportion of the total data
#' length (e.g. `span = 0.1`). Note: strictly speaking, the function tests
#' `floor(span/2)` values before and after each central value, therefore any
#' even `span` inputs are rounded up. That is `span = 10` and `span = 11` will
#' both result in an effective moving window of 11 values, with the central
#' value tested against the 5 values before and after it.
#'
#' **Smoothing**
#'
#' For noisy data there is optional smoothing functionality via
#' `smooth_method`. See [smooth()] for the methods available and appropriate
#' `smooth.n` values. `smooth.method = "spline"` works particularly well for
#' oscillating data.
#' For noisy data there is optional smoothing functionality via the
#' `smooth_method` input. See [smooth()] for the methods available and
#' appropriate `smooth.n` values. `smooth.method = "spline"` works
#' particularly well for oscillating data.
#'
#' **Height**
#' **Prominence**
#'
#' Peak identification is also affected by the optional `height` argument.
#' This sets a threshold of 'prominence' for peak identification (or 'depth'
#' for a trough). This should be a value between 0 and 1 describing a
#' proportion of the total `range` of the data. Only peaks or troughs
#' containing a proportional range equal to or above this within their `span`
#' Peak identification is also affected by the optional `prominence` argument.
#' This sets a threshold of 'prominence' for peak identification (equivalent
#' to 'depth' for a trough). This should be a value between 0 and 1 describing
#' a proportion of the total range of the data. Only peaks or troughs
#' containing a range equal to or above this proportion within their `span`
#' window will be retained. Essentially the higher this is set, the more
#' prominent the peaks, or deeper the troughs, must be to be identified. To
#' help with appropriate values, range elements are included in the output.
#' Peaks and troughs can have different `height` thresholds: simply enter them
#' as a vector of two values in peak-trough order. E.g. `height = c(0.2,
#' 0.1)`.
#' prominent the peaks must be to be identified (or deeper the troughs). To
#' help with choosing appropriate values, ranges for peaks and troughs are
#' included in the output. Peaks and troughs can have different `prominence`
#' thresholds: simply enter them as a vector of two values in peak-trough
#' order. E.g. `prominence = c(0.2, 0.1)`.
#'
#' **Matching values**
#' **Equal values within a `span` window**
#'
#' If there happens to be equal values within the `span` range, the first
#' occurrence is designated as the peak. If peaks are being missed because of
#' this, use a lower `span`. If there are many instances of equal values, try
#' smoothing the data.
#' If there happens to be equal values within a `span` window, the first
#' occurrence is designated as the peak or trough. If peaks or troughs are
#' being missed because of this, use a lower `span`. If there are many
#' instances of equal values, try smoothing the data.
#'
#' **Partial windows**
#'
#' A rolling window of width `span` is used across the data to identify peaks.
#' At the start and end of the data vector this window will overlap the start
#' and end. The default `partial = TRUE` input tells the function to attempt
#' to identify peaks near the start/end of the data where the `span` input
#' would not supply enough data points. Change this to `FALSE` if you see odd
#' matching behaviour at the start or end of the data.
#' to identify peaks near the start/end of the data where the `span` width
#' window is not complete. Change this to `FALSE` if you see odd matching
#' behaviour at the start or end of the data.
#'
#' **Plot**
#'
Expand Down Expand Up @@ -93,21 +101,23 @@
#'
#' - `call` - the function call
#'
#' @usage peaks(x, span = NULL, partial = TRUE, height = NULL, smooth.method =
#' NULL, smooth.n = NULL, plot = TRUE, plot.which = "b")
#' @usage peaks(x, span = NULL, prominence = NULL, partial = TRUE, smooth.method
#' = NULL, smooth.n = NULL, plot = TRUE, plot.which = "b")
#'
#' @param x numeric. A numeric vector.
#' @param span integer. Sets window size for peak (or trough) identification; to
#' be designated a peak, a value must have \code{span} *lower* values on
#' *both* sides of it (higher for troughs).
#' @param partial logical. Default TRUE. Should the function attempt to identify
#' peaks or troughs at the start or end of the vector where `span` is
#' truncated. See Details.
#' @param height numeric. Value between 0 and 1. Sets threshold for peak or
#' @param span numeric. Sets window size for peak (or trough) identification; to
#' be designated a peak, a value must be the highest value (lowest for
#' troughs) within a rolling window of width `span`. Can be entered as either
#' a window of number of values, or value between 0 and 1 of proportion of
#' total data length. See Details.
#' @param prominence numeric. Value between 0 and 1. Sets threshold for peak or
#' trough 'prominence'. See Details.
#' @param partial logical. Default TRUE. Should the function attempt to identify
#' peaks or troughs at the start or end of the vector where the `span` window
#' is truncated? See Details.
#' @param smooth.method string. Method by which to smooth data before peak
#' identification. Optional, default is `NULL`. See [smooth()].
#' @param smooth.n string. Smoothing factor. See [smooth()].
#' identification. Optional. Default is `NULL`. See [smooth()].
#' @param smooth.n numeric. Smoothing factor. See [smooth()].
#' @param plot logical. Plots the result.
#' @param plot.which string. What to plot: "p" for peaks, "t" for troughs, or
#' the default "b" for both.
Expand All @@ -117,14 +127,14 @@
#'
#' @author Nicholas Carey - \email{[email protected]}
#' @importFrom zoo rollapply
#' @importFrom dplyr between
#' @md
#' @export


peaks <- function(x,
span = NULL,
prominence = NULL,
partial = TRUE,
height = NULL,
smooth.method = NULL,
smooth.n = NULL,
plot = TRUE,
Expand All @@ -135,20 +145,27 @@ peaks <- function(x,

## Stop if no span
if(is.null(span)) stop("peaks: please enter a 'span' value.")

## make heights zero if null
if(is.null(height)) {
height_p <- 0
height_t <- 0
## separate to peak and trough heights
} else if(length(height) == 1) {
height_p <- height
height_t <- height
} else if(length(height) == 2) {
height_p <- height[1]
height_t <- height[2]
if(!(dplyr::between(span, 0, 1)) && span %% 1 != 0)
stop("peaks: 'span' should be a value between 0 and 1, or an integer greater than 1.")

## make span
if(dplyr::between(span, 0, 1))
span <- round(length(x) * span)
span <- floor(span/2)

## make prominence zero if null
if(is.null(prominence)) {
prominence_p <- 0
prominence_t <- 0
## separate to peak and trough prominence
} else if(length(prominence) == 1) {
prominence_p <- prominence
prominence_t <- prominence
} else if(length(prominence) == 2) {
prominence_p <- prominence[1]
prominence_t <- prominence[2]
} else {
stop("peaks: 'height' input should be NULL, a single numeric value, or vector of two values.")
stop("peaks: 'prominence' input should be NULL, a single numeric value, or vector of two values.")
}

## set logicals
Expand All @@ -167,13 +184,13 @@ peaks <- function(x,
df <- data.frame(test_val, z)


# Height range ------------------------------------------------------------
# prominence range ------------------------------------------------------------

## determine y range within each span
heightrange <- zoo::rollapply(z, width = span * 2 + 1, FUN = range, align = "center", partial = TRUE)
heightrange <- abs(heightrange[,1] - heightrange[,2])
prominencerange <- zoo::rollapply(z, width = span * 2 + 1, FUN = range, align = "center", partial = TRUE)
prominencerange <- abs(prominencerange[,1] - prominencerange[,2])
## convert to proportion of total
heightrange <- heightrange / abs(diff(range(z)))
prominencerange <- prominencerange / abs(diff(range(z)))


# Detect peaks ------------------------------------------------------------
Expand All @@ -199,9 +216,9 @@ peaks <- function(x,

## index of peaks
peaks <- which(peaks)
## subset to peaks with range greater than 'height' input
peaks <- peaks[heightrange[peaks] >= height_p]
peakrange <- heightrange[peaks]
## subset to peaks with range greater than 'prominence' input
peaks <- peaks[prominencerange[peaks] >= prominence_p]
peakrange <- prominencerange[peaks]


# Detect troughs ----------------------------------------------------------
Expand All @@ -222,13 +239,13 @@ peaks <- function(x,
}

troughs <- which(troughs)
troughs <- troughs[heightrange[troughs] >= height_t]
troughrange <- heightrange[troughs]
troughs <- troughs[prominencerange[troughs] >= prominence_t]
troughrange <- prominencerange[troughs]

# Assemble both for output ------------------------------------------------

both <- sort(c(peaks,troughs))
bothrange <- heightrange[both]
bothrange <- prominencerange[both]

# Assemble output ---------------------------------------------------------

Expand Down
99 changes: 55 additions & 44 deletions man/peaks.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2d9a2d3

Please sign in to comment.