Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Api rework #34

Merged
merged 64 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
baa439e
Ignore autogenerated .vscode folder
KronosTheLate Sep 14, 2023
d235238
Make parent file for rework, define "findpeaks"
KronosTheLate Sep 14, 2023
ccb918e
implement api_rework as discussed
KronosTheLate Sep 14, 2023
5cb66c3
Remove test code from Peaks.jl
KronosTheLate Sep 14, 2023
80b8280
Update readme to temp state
KronosTheLate Sep 14, 2023
7609635
Add sentence about mutation to todo section
KronosTheLate Sep 14, 2023
24e3892
add sentence about minima finding
KronosTheLate Sep 14, 2023
aac8d5a
Remove temporary content from readme
KronosTheLate Sep 22, 2023
9ccd30a
make `findpeaks` a oneliner
KronosTheLate Sep 24, 2023
4a0d9dc
Don't discard initially calculated heights
KronosTheLate Sep 27, 2023
0e20f16
Export filterpeaks, improve internals in new API
KronosTheLate Sep 27, 2023
369c072
Change linebreaks in "filterpeaks!"
KronosTheLate Sep 27, 2023
080e970
Make use of "strict" in all functions
KronosTheLate Sep 27, 2023
37839c8
Fix some bugs
KronosTheLate Sep 27, 2023
6edefcf
export old functions
KronosTheLate Oct 31, 2023
169e5dd
improvements, polish docstrings
KronosTheLate Oct 31, 2023
67cea1b
tag breaking version
KronosTheLate Oct 31, 2023
310fbfe
misc changes
KronosTheLate Oct 31, 2023
82c5b8e
comment out bad test
KronosTheLate Oct 31, 2023
639f212
minor changes
KronosTheLate Oct 31, 2023
8690fe2
fix docstrung for peakheights
KronosTheLate Oct 31, 2023
40ad1a7
un-commented failing test
KronosTheLate Nov 26, 2023
cf0d8c3
revert exports
KronosTheLate Nov 26, 2023
3c17d0c
move export of filterpeaks!
KronosTheLate Nov 26, 2023
21312b9
remove extra exports
KronosTheLate Nov 26, 2023
7f005f6
explicit about copying data in docstring
KronosTheLate Nov 26, 2023
11eb80d
Turn --> info ->
KronosTheLate Nov 26, 2023
df8537b
add sentence about not copying data
KronosTheLate Nov 26, 2023
5c82230
minheight -> min, same for proms,widths, and max
KronosTheLate Nov 26, 2023
779081e
some changes + better length check in filterpeaks!
KronosTheLate Nov 26, 2023
c19d483
add new method for filterpeaks!
KronosTheLate Nov 26, 2023
26cdb9d
Distribute contents of rework, structure exports
KronosTheLate Nov 26, 2023
c1d553d
Do not include api_work, which does not exist
KronosTheLate Nov 26, 2023
676a0b5
fixed a couple copy-paste errors
KronosTheLate Nov 26, 2023
b70804b
Revert function reordering (clarify changes in docstrings)
halleysfifthinc Jan 22, 2024
f9ab0f2
Example compromise docstrings and ordering
halleysfifthinc Jan 23, 2024
75a588e
Revert random change (fixes tests)
halleysfifthinc Jan 23, 2024
32b16e3
Separate docstring examples for APIs
KronosTheLate Jan 25, 2024
e98362d
Improve curried docstring
KronosTheLate Jan 25, 2024
aaf8b51
make known_fields a const
KronosTheLate Jan 25, 2024
613d0f0
explain what a named tuple slice is
KronosTheLate Jan 25, 2024
8ac658d
Make filterpeaks signature match
KronosTheLate Jan 25, 2024
9848205
swap check order filterpeaks!
KronosTheLate Jan 25, 2024
42aba3c
Swap check order filterpeaks!
KronosTheLate Jan 25, 2024
83c53cb
Merge branch 'master' into api_rework
halleysfifthinc Feb 26, 2024
36b71c7
[nfc] whitespace changes
halleysfifthinc Feb 28, 2024
df11d3a
Update/rewrite docstrings and doctests
halleysfifthinc Feb 28, 2024
bd468cc
Don't need to depwarn old kwargs for new functions
halleysfifthinc Feb 28, 2024
40ea9a3
Rename `up` => `hi`
halleysfifthinc Feb 28, 2024
9b7da88
Update `peakproms!`/`peakwidths!` to use `ismaxima`/`isminima` for ar…
halleysfifthinc Feb 28, 2024
5493b52
Rewrite error for bad min/max order
halleysfifthinc Feb 28, 2024
598477c
Fix unnecessary Missing union when input array doesn't have missings
halleysfifthinc Feb 28, 2024
d5b4281
Update doctest outputs
halleysfifthinc Feb 28, 2024
d805b04
Update deprecated kwargs in tests
halleysfifthinc Feb 28, 2024
5c98dab
Test doctests when running tests
halleysfifthinc Feb 28, 2024
e791292
Test depwarns
halleysfifthinc Feb 28, 2024
1c7180d
Test error for when first peak is not an extrema
halleysfifthinc Feb 28, 2024
66df7ad
Confirm error when namedtuple has widths OR edges
halleysfifthinc Feb 28, 2024
4939c3d
Confirm error in plotpeaks when first peak isnt an extrema
halleysfifthinc Feb 28, 2024
862ad61
Update docstrings/doctests for utils functions
halleysfifthinc Feb 28, 2024
adc1439
Add `filterpeaks!` to the docs
halleysfifthinc Feb 28, 2024
925c9af
Add julia cache to CI docs build
halleysfifthinc Feb 28, 2024
b2ec0a6
Dont try linking to Base docs (for the moment)
halleysfifthinc Feb 28, 2024
f8b6f0e
fix errant ref
halleysfifthinc Feb 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
- uses: julia-actions/setup-julia@v1
with:
version: '1'
- uses: julia-actions/cache@v1
- run: |
julia --project=docs -e '
using Pkg
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
Manifest.toml
docs/build/
docs/site/

.vscode/
7 changes: 0 additions & 7 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,3 @@ Compat = "2.1, 3, 4"
RecipesBase = "1.3"
julia = "1.6"

[extras]
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test", "OffsetArrays", "Plots"]
1 change: 1 addition & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ peakwidths
peakwidths!
peakheights
peakheights!
filterpeaks!
findnextmaxima
findnextminima
ismaxima
Expand Down
3 changes: 2 additions & 1 deletion src/Peaks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ using Compat

export argmaxima, argminima, maxima, minima, findmaxima, findminima, findnextmaxima,
findnextminima, peakproms, peakproms!, peakwidths, peakwidths!, peakheights,
peakheights!, ismaxima, isminima
peakheights!, ismaxima, isminima, filterpeaks!

include("minmax.jl")
include("utils.jl")
include("peakprom.jl")
include("peakwidth.jl")
include("peakheight.jl")
Expand Down
42 changes: 32 additions & 10 deletions src/minmax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -186,19 +186,31 @@ function maxima(
end

"""
findmaxima(x[, w=1; strict=true]) -> (idxs, vals)
findmaxima(x[, w=1; strict=true]) -> (;indices, heights, data)

Find the indices and values of local maxima in `x`, where each maxima `i` is either the
maximum of `x[i-w:i+w]` or the first index of a plateau.
Find the indices and values of local maxima in `x`, where each maxima `i` is
either the maximum of `x[i-w:i+w]` or the first index of a plateau.

Returns a `NamedTuple` contains the fields `indices`, `heights`, `data`, which are
equivalent to `heights = data[indices]`. The `data` field is a reference (not a copy) to
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)

# Examples
```jldoctest
julia> data = [1, 5, 1, 3, 2];

julia> pks = findmaxima(data)
(indices = [2, 4], heights = [5, 3], data = [1, 5, 1, 3, 2])
```
"""
function findmaxima(x, w::Int=1; strict::Bool=true)
idxs = argmaxima(x, w; strict=strict)
return (idxs, x[idxs])
return (;indices=idxs, heights=x[idxs], data=x)
end

"""
Expand Down Expand Up @@ -230,7 +242,6 @@ 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

Expand Down Expand Up @@ -313,18 +324,29 @@ function minima(
end

"""
findminima(x[, w=1; strict=true]) -> (idxs, vals)
findminima(x[, w=1; strict=true]) -> (;indices, heights, data)

Find the indices and values of local minima in `x`, where each minima `i` is either the
minimum of `x[i-w:i+w]` or the first index of a plateau.
Find the indices and values of local minima in `x`, where each minima `i` is
either the minimum of `x[i-w:i+w]` or the first index of a plateau.

Returns a `NamedTuple` contains the fields `indices`, `heights`, `data`, which are
equivalent to `heights = data[indices]`. The `data` field is a reference (not a copy) to
the argument `x`.

A plateau is defined as a minima with consecutive equal (`===`/egal) minimal values which
are bounded by greater values immediately before and after the consecutive minimal values.

See also: [`argminima`](@ref), [`findnextminima`](@ref)

# Examples
```jldoctest
julia> data = [1, 5, 1, 3, 2];

julia> valleys = findminima(data)
(indices = [3], heights = [1], data = [1, 5, 1, 3, 2])
```
"""
function findminima(x, w::Int=1; strict::Bool=true)
idxs = argminima(x, w; strict=strict)
return (idxs, x[idxs])
return (;indices=idxs, heights=x[idxs], data=x)
end

123 changes: 92 additions & 31 deletions src/peakheight.jl
Original file line number Diff line number Diff line change
@@ -1,73 +1,134 @@
"""
peakheights(peaks, heights;
minheight=nothing,
maxheight=nothing
Comment on lines -3 to -4
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to deprecate the minheight/maxheight to min/max here and elsewhere too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in the docstring, which is up for discussion in another comment of yours. We can revisit the docstrings after that has been resolved.

) -> (peaks, heights)
peakheights(indices, heights; [min, max]) -> (indices, heights)
peakheights(pks::NamedTuple; [min, max]) -> NamedTuple

Return a copy of `peaks` and `heights` where peak heights are removed if less than
`minheight` and/or greater than `maxheight`.

Return a copy of `indices` and `heights` where peaks are removed if their height is less than
`min` and/or greater than `max`.

If a NamedTuple `pks` is given, a new NamedTuple is returned with filtered copies of fields
from `pks`. `pks` must have `:indices` and `:heights` fields. The fields `:proms`,
`:widths`, and `:edges` will be filtered if present, and any remaining fields will be
copied unmodified.

See also: [`peakproms`](@ref), [`peakwidths`](@ref), [`findmaxima`](@ref)

# Examples
```jldoctest
julia> x = [0,5,2,3,3,1,4,0];

julia> xpks, vals = findmaxima(x)
([2, 4, 7], [5, 3, 4])
julia> pks = findmaxima(x)
(indices = [2, 4, 7], heights = [5, 3, 4], data = [0, 5, 2, 3, 3, 1, 4, 0])

julia> peakheights(xpks, vals; maxheight=4)
([4, 7], [3, 4])
julia> peakheights(pks; max=4)
(indices = [4, 7], heights = [3, 4], data = [0, 5, 2, 3, 3, 1, 4, 0])

julia> peakheights(xpks, vals; minheight=4.5)
([2], [5])
julia> inds, heights = peakheights(pks.indices, pks.heights; max=4)
([4, 7], [3, 4])
```
"""
function peakheights(
peaks::AbstractVector{Int}, heights::AbstractVector;
minheight=nothing, maxheight=nothing
indices::AbstractVector{Int}, heights::AbstractVector;
minheight=nothing, maxheight=nothing,
min=minheight, max=maxheight
)
peakheights!(copy(peaks), copy(heights); minheight=minheight, maxheight=maxheight)
if !isnothing(minheight)
Base.depwarn("Keyword `minheight` has been renamed to `min`", :peakheights!)
end
if !isnothing(maxheight)
Base.depwarn("Keyword `maxheight` has been renamed to `max`", :peakheights!)
end
peakheights!(copy(indices), copy(heights); min=min, max=max)
end

peakheights(pks::NamedTuple; kwargs...) = peakheights!(deepcopy(pks); kwargs...)

"""
peakheights(; [min, max]) -> Function

Create a function, `f(pks::NamedTuple)`, that copies and filters the peak heights of its
argument, `pks`, using any given keyword arguments.

# Examples
```jldoctest
julia> findmaxima([0, 5, 2, 3, 3, 1, 4, 0]) |> peakheights(; max=4)
(indices = [4, 7], heights = [3, 4], data = [0, 5, 2, 3, 3, 1, 4, 0])
```
"""
peakheights(; kwargs...) = function _curried_peakheights(pks)
return peakheights(deepcopy(pks); kwargs...)
end

"""
peakheights!(peaks, heights;
minheight=nothing,
maxheight=nothing
) -> (peaks, heights)
peakheights!(indices, heights; [min, max]) -> (indices, heights)
peakheights!(pks::NamedTuple; [min, max]) -> NamedTuple

Filter (mutate) and return `indices` and `heights` by removing peaks that are less than `min`
and/or greater than `max`.

Modify and return `peaks` and `heights` by removing peaks that are less than `minheight` or greater
than `maxheight`.
If a NamedTuple `pks` is given, a new NamedTuple is returned with the same fields
(references) from `pks`. `pks` must have `:indices` and `:heights` fields. The fields
`:proms`, `:widths`, and `:edges` will be filtered (mutated) if present, and any remaining
fields will be referenced unmodified.

See also: [`peakproms`](@ref), [`peakwidths`](@ref), [`findmaxima`](@ref)
[`filterpeaks!`](@ref)

# Examples
```jldoctest
julia> x = [0,5,2,3,3,1,4,0];

julia> xpks, vals = findmaxima(x)
([2, 4, 7], [5, 3, 4])
julia> pks = findmaxima(x)
(indices = [2, 4, 7], heights = [5, 3, 4], data = [0, 5, 2, 3, 3, 1, 4, 0])

julia> peakheights!(xpks, vals; maxheight=4);
julia> peakheights!(pks; max=4)
(indices = [4, 7], heights = [3, 4], data = [0, 5, 2, 3, 3, 1, 4, 0])

julia> xpks, vals
([4, 7], [3, 4])
julia> inds, heights = peakheights!(pks.indices, pks.heights; min=3.5)
([7], [4])
```
"""
function peakheights!(
peaks::Vector{Int}, heights::AbstractVector{T};
minheight=nothing, maxheight=nothing
minheight=nothing, maxheight=nothing,
min=minheight, max=maxheight
) where {T}
if !isnothing(minheight)
Base.depwarn("Keyword `minheight` has been renamed to `min`", :peakheights!)
end
if !isnothing(maxheight)
Base.depwarn("Keyword `maxheight` has been renamed to `max`", :peakheights!)
end
length(peaks) == length(heights) || throw(DimensionMismatch("length of `peaks`, $(length(peaks)), does not match the length of `heights`, $(length(heights))"))
if !isnothing(minheight) || !isnothing(maxheight)
lo = something(minheight, typemin(Base.nonmissingtype(T)))
up = something(maxheight, typemax(Base.nonmissingtype(T)))
matched = findall(x -> !(lo ≤ x ≤ up), heights)
if !isnothing(min) || !isnothing(max)
lo = something(min, typemin(Base.nonmissingtype(T)))
hi = something(max, typemax(Base.nonmissingtype(T)))
matched = findall(x -> !(lo ≤ x ≤ hi), heights)
deleteat!(peaks, matched)
deleteat!(heights, matched)
end

return peaks, heights
end

function peakheights!(pks::NamedTuple; min=nothing, max=nothing)
filterpeaks!(pks, :heights; min, max)
return pks
end

"""
peakheights!(; [min, max]) -> Function

Create a function, `f(pks::NamedTuple)`, that calculates peak heights and then filters
(mutates) the fields of its argument, `pks`, using any given keyword arguments.

# Examples
```jldoctest
julia> findmaxima([0, 5, 2, 3, 3, 1, 4, 0]) |> peakheights!(; max=4)
(indices = [4, 7], heights = [3, 4], data = [0, 5, 2, 3, 3, 1, 4, 0])
```
"""
peakheights!(; kwargs...) = function _curried_peakheights!(pks)
return peakheights!(pks; kwargs...)
end

Loading
Loading