Peaks.jl
Peaks.jl is a library for finding peaks (i.e. local maxima and minima) and peak characteristics (e.g. how prominent or wide are peaks, etc) in vector (1D) data signals.
Installation
Peaks.jl can be installed from the Julia REPL by running
] add Peaks
Resolving package versions...
Updating `~/.julia/environments/v1.10/Project.toml`
[18e31ff7] + Peaks v0.5.3
Updating `~/.julia/environments/v1.10/Manifest.toml`
[18e31ff7] + Peaks v0.5.3
[aea7be01] + PrecompileTools v1.2.1
[21216c6a] + Preferences v1.4.3
[3cdcf5f2] + RecipesBase v1.3.4
[fdea26ae] + SIMD v3.5.0
[ade2ca70] + Dates
[de0858da] + Printf
[fa267f1f] + TOML v1.0.3
[4ec0a83e] + Unicode
Getting started
Finding peaks
To find the peaks in your data you can use the findmaxima
function, which returns a NamedTuple
with fields for each calculated peak characteristic (indices, heights) and a reference to the data.
julia> indices, heights = findmaxima(y)
(indices = [36, 100, 183, 273, 345, 445, 536], heights = [3.300118034348511, 4.982232717207901, 1.197072463435926, 1.2276270625137882, -0.6496226560177698, -3.0322485466891145, 3.300118034348519], data = [0.0, 0.1632851160646655, 0.32610451181030864, 0.4879949200150502, 0.6484979658187734, 0.8071625784012266, 0.9635473614762452, 1.1172229092385426, 1.2677740547092151, 1.4148020378099078 … 3.2394249315275934, 3.2820555214196987, 3.3284358209806952, 3.3784081950151283, 3.4317863042827303, 3.4883561669665792, 3.5478773815030995, 3.6100845038112075, 3.674688571077937, 3.7413787634226736])
When the peaks are plotted over the data, we see that all the local maxima have been identified.
Peak characteristics
Peaks have various characteristics, including height, prominence, and width. Peaks.jl exports functions for finding each characteristic: peakheights
, peakproms
, peakwidths
:
julia> indices, proms = peakproms(indices, y)
([36, 100, 183, 273, 345, 445, 536], [0.2678694876593948, 4.982232717207901, 0.5474498074181589, 2.4552541250275763, 0.5474498074181591, 0.2678694876593921, 0.26786948765940455])
julia> indices, widths, edges... = peakwidths(indices, y, proms)
([36, 100, 183, 273, 345, 445, 536], [17.62631562198532, 111.3881252794683, 24.143545188509734, 44.44393283928167, 23.091125504863612, 18.893643387694567, 17.626315621985214], [28.48833894440662, 18.671388334872134, 169.46890657137365, 251.0, 332.5310934286264, 436.9917020459134, 528.4883389444067], [46.11465456639194, 130.05951361434043, 193.61245175988338, 295.4439328392817, 355.62221893349, 455.885345433608, 546.1146545663919])
Mutating bang ('!'
) functions are available (i.e. peakproms!
, etc.) when allocations are a concern.
Peaks NamedTuple
& pipable API
There are Peaks.jl functions that bundle the peaks, peak characteristics, and signal into a convenient NamedTuple
:
julia> pks = findmaxima(y);
julia> pks = peakproms(pks);
julia> pks = peakwidths(pks)
(indices = [36, 100, 183, 273, 345, 445, 536], heights = [3.300118034348511, 4.982232717207901, 1.197072463435926, 1.2276270625137882, -0.6496226560177698, -3.0322485466891145, 3.300118034348519], data = [0.0, 0.1632851160646655, 0.32610451181030864, 0.4879949200150502, 0.6484979658187734, 0.8071625784012266, 0.9635473614762452, 1.1172229092385426, 1.2677740547092151, 1.4148020378099078 … 3.2394249315275934, 3.2820555214196987, 3.3284358209806952, 3.3784081950151283, 3.4317863042827303, 3.4883561669665792, 3.5478773815030995, 3.6100845038112075, 3.674688571077937, 3.7413787634226736], proms = [0.2678694876593948, 4.982232717207901, 0.5474498074181589, 2.4552541250275763, 0.5474498074181591, 0.2678694876593921, 0.26786948765940455], widths = [17.62631562198532, 111.3881252794683, 24.143545188509734, 44.44393283928167, 23.091125504863612, 18.893643387694567, 17.626315621985214], edges = [(28.48833894440662, 46.11465456639194), (18.671388334872134, 130.05951361434043), (169.46890657137365, 193.61245175988338), (251.0, 295.4439328392817), (332.5310934286264, 355.62221893349), (436.9917020459134, 455.885345433608), (528.4883389444067, 546.1146545663919)])
Mutating functions are also available for the NamedTuple
functions; the vectors within the NamedTuple
are mutated and re-used in the returned tuple. The NamedTuple
functions can also be chained/piped:
julia> pks = findmaxima(y) |> peakproms!(;strict=false) |> peakwidths!(; max=100)
(indices = [36, 183, 273, 345, 445, 536], heights = [3.300118034348511, 1.197072463435926, 1.2276270625137882, -0.6496226560177698, -3.0322485466891145, 3.300118034348519], data = [0.0, 0.1632851160646655, 0.32610451181030864, 0.4879949200150502, 0.6484979658187734, 0.8071625784012266, 0.9635473614762452, 1.1172229092385426, 1.2677740547092151, 1.4148020378099078 … 3.2394249315275934, 3.2820555214196987, 3.3284358209806952, 3.3784081950151283, 3.4317863042827303, 3.4883561669665792, 3.5478773815030995, 3.6100845038112075, 3.674688571077937, 3.7413787634226736], proms = [0.2678694876593948, 0.5474498074181589, 2.4552541250275763, 0.5474498074181591, 0.2678694876593921, 0.26786948765940455], widths = [17.62631562198532, 24.143545188509734, 44.44393283928167, 23.091125504863612, 18.893643387694567, 17.626315621985214], edges = [(28.48833894440662, 46.11465456639194), (169.46890657137365, 193.61245175988338), (251.0, 295.4439328392817), (332.5310934286264, 355.62221893349), (436.9917020459134, 455.885345433608), (528.4883389444067, 546.1146545663919)])
Be aware that the NamedTuple
functions allocate more memory than the functions with direct/explicit arguments. If maximum performance is needed, mutating functions (e.g. peakproms!
, etc) and/or the direct, non-NamedTuple
methods are a better choice.
Plotting
The peaks, prominences, and widths can be visualized all together using a Plots.jl
recipe plotpeaks
:
using Plots
plotpeaks(t, y; peaks=indices, prominences=true, widths=true)