diff --git a/docs/src/reference.md b/docs/src/reference.md index b820e75..cc39028 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -28,5 +28,6 @@ findnextmaxima findnextminima ismaxima isminima +isplateau ``` diff --git a/src/Peaks.jl b/src/Peaks.jl index f23f7ef..df8ca2a 100644 --- a/src/Peaks.jl +++ b/src/Peaks.jl @@ -2,7 +2,7 @@ module Peaks export argmaxima, argminima, maxima, minima, findmaxima, findminima, findnextmaxima, findnextminima, peakproms, peakproms!, peakwidths, peakwidths!, peakheights, - peakheights!, ismaxima, isminima, filterpeaks! + peakheights!, ismaxima, isminima, isplateau, filterpeaks! include("minmax.jl") include("utils.jl") diff --git a/src/minmax.jl b/src/minmax.jl index b66f1b0..fb2abcd 100644 --- a/src/minmax.jl +++ b/src/minmax.jl @@ -143,7 +143,7 @@ of a plateau must exist. For `strict == false`, a maxima is the maximum of all n `NaN`, or either end of the array, `x[begin-1]` or `x[end+1]`, may be treated as the bounds of a plateau). -See also: [`findmaxima`](@ref), [`findnextmaxima`](@ref) +See also: [`findmaxima`](@ref), [`findnextmaxima`](@ref), [`argminima`](@ref) # Examples ```jldoctest @@ -186,7 +186,7 @@ Find the values of local maxima in `x`, where each maxima `i` is either the maxi A plateau is defined as a maxima with consecutive equal (`===`/egal) maximal values which are bounded by lesser values immediately before and after the consecutive maximal values. -See also: [`argmaxima`](@ref), [`findnextmaxima`](@ref) +See also: [`argmaxima`](@ref), [`findnextmaxima`](@ref), [`minima`](@ref) """ function maxima( x::AbstractVector{T}, w::Int=1; strict::Bool=true @@ -208,7 +208,7 @@ the argument `x`. A plateau is defined as a maxima with consecutive equal (`===`/egal) maximal values which are bounded by lesser values immediately before and after the consecutive maximal values. -See also: [`argmaxima`](@ref), [`findnextmaxima`](@ref) +See also: [`argmaxima`](@ref), [`findnextmaxima`](@ref), [`findminima`](@ref) # Examples ```jldoctest @@ -252,6 +252,7 @@ julia> findnextminima([3,2,3,1,1,3], 3) ``` """ findnextminima(x, i, w=1; strict=true) = findnextextrema(>, x, i, w, strict) + """ isminima(i, x[, w=1; strict=true]) -> Bool @@ -360,3 +361,27 @@ function findminima(x, w::Int=1; strict::Bool=true) idxs = argminima(x, w; strict=strict) return (;indices=idxs, heights=x[idxs], data=x) end + +""" + isplateau(i, x[, w=1; strict=true]) -> Union{Missing,Bool} + +Test if `i` is a plateau in `x`, where a plateau is defined as a maxima or minima with +consecutive equal (`===`/egal) extreme values which are bounded by lesser values immediately +before and after the consecutive values. Returns `false` if `i` is the last index in `x`. + +See also: [`ismaxima`](@ref), [`isminima`](@ref) +""" +function isplateau(i, x, w=1; strict=true) + if ismaxima(i, x, w; strict) || isminima(i, x, w; strict) + if i === lastindex(x) + # default unstrict assumption that first/last element can be peak means that we + # should not assume first/last element is (also) a plateau (too much assuming) + return false + else + return x[i] === x[i+1] + end + else + return false + end +end + diff --git a/test/minmax.jl b/test/minmax.jl index 3abcdb7..dbecac2 100644 --- a/test/minmax.jl +++ b/test/minmax.jl @@ -151,7 +151,7 @@ x1 = a*sin.(2*pi*f1*T*t)+b*sin.(2*pi*f2*T*t)+c*sin.(2*pi*f3*T*t); @test isempty(argminima(reverse(mn))) end - @testset "is(minima|maxima)" begin + @testset "is(minima|maxima|plateau)" begin isx = [0,0,3,1,2,0,4,4,0,5] ispk = [0,0,1,0,1,0,1,0,0,1] # Not strict @@ -164,6 +164,13 @@ x1 = a*sin.(2*pi*f1*T*t)+b*sin.(2*pi*f2*T*t)+c*sin.(2*pi*f3*T*t); @test isminima(10, -isx; strict=true) == false @test isminima(10, -isx; strict=false) == true @test isminima.(eachindex(isx), Ref(-isx); strict=false) == ispk + + @test isplateau(7, isx) == true + @test isplateau(8, isx) == false + @test isplateau(3, isx) == false + + @test isplateau(10, isx; strict=true) == false + @test isplateau(10, isx; strict=false) == false end pks, vals = @test_nowarn findmaxima(x1)