diff --git a/data/spectral-indices-dict.json b/data/spectral-indices-dict.json index 90c0ed5..f4cff29 100755 --- a/data/spectral-indices-dict.json +++ b/data/spectral-indices-dict.json @@ -2644,7 +2644,7 @@ "MODIS" ], "reference": "https://doi.org/10.1016/j.jag.2015.02.010", - "short_name": "NDSoiI" + "short_name": "NDSoI" }, "NDTI": { "application_domain": "water", diff --git a/ext/SpectralIndicesDataFramesExt.jl b/ext/SpectralIndicesDataFramesExt.jl index 190b141..ce734d1 100644 --- a/ext/SpectralIndicesDataFramesExt.jl +++ b/ext/SpectralIndicesDataFramesExt.jl @@ -2,8 +2,10 @@ module SpectralIndicesDataFramesExt using SpectralIndices using DataFrames +import SpectralIndices: _create_params, AbstractSpectralIndex, compute_index, + _create_indices, linear, poly, RBF, load_dataset, _load_json -function SpectralIndices._create_params(kw_args::Pair{Symbol,DataFrame}...) +function _create_params(kw_args::Pair{Symbol,DataFrame}...) combined_df = DataFrame() for pair in kw_args @@ -14,52 +16,52 @@ function SpectralIndices._create_params(kw_args::Pair{Symbol,DataFrame}...) return combined_df end -function SpectralIndices.compute_index( - index::String, params::DataFrame; indices=SpectralIndices._create_indices() +function compute_index( + index::AbstractSpectralIndex, params::DataFrame; indices=_create_indices() ) # Convert DataFrame to a dictionary for each row and compute the index results = [ - SpectralIndices.compute_index( + compute_index( index, Dict(zip(names(params), row)); indices=indices ) for row in eachrow(params) ] # Return the results as a DataFrame with the column named after the index - return DataFrame(Symbol(index) => results) + return DataFrame(Symbol(index.short_name) => results) end -function SpectralIndices.compute_index( - index::Vector{String}, params::DataFrame; indices=SpectralIndices._create_indices() +function compute_index( + index::Vector{<:AbstractSpectralIndex}, params::DataFrame; indices=_create_indices() ) # Similar conversion and computation for a vector of indices result_dfs = DataFrame() for idx in index - result_df = SpectralIndices.compute_index(idx, params; indices=indices) - result_dfs[!, Symbol(idx)] = result_df[!, 1] + result_df = compute_index(idx, params; indices=indices) + result_dfs[!, Symbol(idx.short_name)] = result_df[!, 1] end # Return the combined DataFrame with columns named after each index return result_dfs end -function SpectralIndices.linear(params::DataFrame) +function linear(params::DataFrame) result = linear(params[!, "a"], params[!, "b"]) result_df = DataFrame(; linear=result) return result_df end -function SpectralIndices.poly(params::DataFrame) +function poly(params::DataFrame) result = poly(params[!, "a"], params[!, "b"], params[!, "c"], params[!, "p"]) result_df = DataFrame(; poly=result) return result_df end -function SpectralIndices.RBF(params::DataFrame) +function RBF(params::DataFrame) result = RBF(params[!, "a"], params[!, "b"], params[!, "sigma"]) result_df = DataFrame(; RBF=result) return result_df end -function SpectralIndices.load_dataset(dataset::String, ::Type{T}) where {T<:DataFrame} +function load_dataset(dataset::String, ::Type{T}) where {T<:DataFrame} datasets = Dict("spectral" => "spectral.json") if dataset in keys(datasets) @@ -68,7 +70,7 @@ function SpectralIndices.load_dataset(dataset::String, ::Type{T}) where {T<:Data error("Dataset name not valid. Datasets available for DataFrames: spectral") end - ds = SpectralIndices._load_json(datasets[dataset]) + ds = _load_json(datasets[dataset]) all_indices = Set{Int}() for val in values(ds) for idx in keys(val) diff --git a/ext/SpectralIndicesYAXArraysExt.jl b/ext/SpectralIndicesYAXArraysExt.jl index e0557ec..ec87835 100644 --- a/ext/SpectralIndicesYAXArraysExt.jl +++ b/ext/SpectralIndicesYAXArraysExt.jl @@ -3,8 +3,11 @@ module SpectralIndicesYAXArraysExt using SpectralIndices using YAXArrays using DimensionalData +import SpectralIndices: _check_params, _create_params, _order_params, + AbstractSpectralIndex, compute_index, _create_indices, + linear, poly, RBF, load_dataset, _load_json -function SpectralIndices._check_params(index, params::YAXArray) +function _check_params(index::AbstractSpectralIndex, params::YAXArray) for band in index.bands if !(band in params.Variables) throw( @@ -16,7 +19,7 @@ function SpectralIndices._check_params(index, params::YAXArray) end end -function SpectralIndices._order_params(index, params::YAXArray) +function _order_params(index::AbstractSpectralIndex, params::YAXArray) new_params = [] for (bidx, band) in enumerate(index.bands) push!(new_params, params[Variable=At(band)]) @@ -25,7 +28,7 @@ function SpectralIndices._order_params(index, params::YAXArray) return new_params end -function SpectralIndices._create_params(kw_args::Pair{Symbol,<:YAXArray}...) +function _create_params(kw_args::Pair{Symbol,<:YAXArray}...) params_yaxa = [] names_yaxa = [] for (key, value) in kw_args @@ -39,18 +42,19 @@ end ## TODO: simplify even further # this is same function contente as dispatch on Dict -function SpectralIndices.compute_index( - index::String, params::YAXArray; indices=SpectralIndices._create_indices() +function compute_index(index::AbstractSpectralIndex, + params::YAXArray; + indices=_create_indices() ) - SpectralIndices._check_params(indices[index], params) - params = SpectralIndices._order_params(indices[index], params) + _check_params(index, params) + params = _order_params(index, params) T = eltype(first(params)) - result = SpectralIndices._compute_index(T, indices[index], params...) + result = _compute_index(T, index, params...) return result end -function SpectralIndices.compute_index( - index::Vector{String}, params::YAXArray; indices=SpectralIndices._create_indices() +function compute_index( + index::Vector{<:AbstractSpectralIndex}, params::YAXArray; indices=_create_indices() ) results = [] for (nidx, idx) in enumerate(index) @@ -62,18 +66,18 @@ function SpectralIndices.compute_index( return result end -function SpectralIndices._compute_index( - ::Type{T}, idx::SpectralIndices.AbstractSpectralIndex, prms::YAXArray... +function _compute_index( + ::Type{T}, idx::AbstractSpectralIndex, prms::YAXArray... ) where {T<:Number} return idx.(T, prms...) end -function SpectralIndices.linear(params::YAXArray) - return SpectralIndices.linear(params[Variable=At("a")], params[Variable=At("b")]) +function linear(params::YAXArray) + return linear(params[Variable=At("a")], params[Variable=At("b")]) end -function SpectralIndices.poly(params::YAXArray) - return SpectralIndices.poly( +function poly(params::YAXArray) + return poly( params[Variable=At("a")], params[Variable=At("b")], params[Variable=At("c")], @@ -81,13 +85,13 @@ function SpectralIndices.poly(params::YAXArray) ) end -function SpectralIndices.RBF(params::YAXArray) - return SpectralIndices.RBF( +function RBF(params::YAXArray) + return RBF( params[Variable=At("a")], params[Variable=At("b")], params[Variable=At("sigma")] ) end -function SpectralIndices.load_dataset(dataset::String, ::Type{T}) where {T<:YAXArray} +function load_dataset(dataset::String, ::Type{T}) where {T<:YAXArray} datasets = Dict("sentinel" => "S2_10m.json") if dataset in keys(datasets) @@ -96,7 +100,7 @@ function SpectralIndices.load_dataset(dataset::String, ::Type{T}) where {T<:YAXA error("Dataset name not valid. Datasets available for YAXArrays: sentinel") end - ds = SpectralIndices._load_json(datasets[dataset]) + ds = _load_json(datasets[dataset]) matrices = [hcat(ds[i]...) for i in 1:length(ds)] data_3d = cat(matrices...; dims=3) x_dim = Dim{:x}(1:300) diff --git a/src/compute_index.jl b/src/compute_index.jl index f79dd98..8639b2e 100644 --- a/src/compute_index.jl +++ b/src/compute_index.jl @@ -53,47 +53,67 @@ julia> compute_index( ``` """ +function compute_index( + index::AbstractSpectralIndex, params=nothing, online::Bool=false; indices=indices, kwargs... +) + + if isnothing(params) + params = _create_params(kwargs...) + end + + return compute_index(index, params; indices=indices) +end + function compute_index( index::String, params=nothing, online::Bool=false; indices=indices, kwargs... ) names = keys(indices) @assert index in names "$index is not a valid Spectral Index!" + results = compute_index(indices[index], params; indices=indices, kwargs...) + return results +end + +function compute_index(index::Vector{<:AbstractSpectralIndex}, + params=nothing, + online::Bool=false; + indices=_create_indices(online), + kwargs... +) if isnothing(params) params = _create_params(kwargs...) end - results = compute_index(index, params; indices=indices) - return results + return compute_index(index, params; indices=indices) end -function compute_index(index::Vector{String}, params=nothing, online::Bool=false; kwargs...) - indices = _create_indices(online) +function compute_index(index::Vector{String}, + params=nothing, + online::Bool=false; + indices = _create_indices(online), + kwargs...) + names = keys(indices) for idx in index @assert idx in names "$index is not a valid Spectral Index!" end - - if isnothing(params) - params = _create_params(kwargs...) - end - - results = compute_index(index, params; indices=indices) + idxs = [indices[idx] for idx in index] + results = compute_index(idxs, params; indices=indices, kwargs...) return results end -function compute_index(index::String, params::Dict; indices=indices) - _check_params(indices[index], params) - params = _order_params(indices[index], params) +function compute_index(index::AbstractSpectralIndex, params::Dict; indices=indices) + _check_params(index, params) + params = _order_params(index, params) T = eltype(first(values(params))) - result = _compute_index(T, indices[index], params...) + result = _compute_index(T, index, params...) return result end # TODO: return results in a matrix columnswise #multi_result = compute_index(["NDVI", "SAVI"], N = fill(0.643, 5), R = fill(0.175, 5), L = fill(0.5, 5)) -function compute_index(index::Vector{String}, params::Dict; indices=indices) +function compute_index(index::Vector{<:AbstractSpectralIndex}, params::Dict; indices=indices) results = [] for (nidx, idx) in enumerate(index) result = compute_index(idx, params; indices=indices) @@ -104,29 +124,31 @@ function compute_index(index::Vector{String}, params::Dict; indices=indices) end #_compute_index(idx::AbstractSpectralIndex, prms::Number...) = idx(prms...) -function _compute_index( - ::Type{T}, idx::AbstractSpectralIndex, prms::Number... +function _compute_index(::Type{T}, + idx::AbstractSpectralIndex, + prms::Number... ) where {T<:Number} return idx(T, prms...) end #_compute_index(idx::AbstractSpectralIndex, prms::AbstractArray...) = idx.(prms...) -function _compute_index( - ::Type{T}, idx::AbstractSpectralIndex, prms::AbstractArray... +function _compute_index(::Type{T}, + idx::AbstractSpectralIndex, + prms::AbstractArray... ) where {T<:Number} return idx.(T, prms...) end -function compute_index(index::String, params::NamedTuple; indices=indices) - _check_params(indices[index], params) - params = _order_params(indices[index], params) +function compute_index(index::AbstractSpectralIndex, params::NamedTuple; indices=indices) + _check_params(index, params) + params = _order_params(index, params) T = eltype(first(values(params))) - result = _compute_index(T, indices[index], params...) - result_nt = (; Dict(Symbol(index) => result)...) + result = _compute_index(T, index, params...) + result_nt = (; Dict(Symbol(index.short_name) => result)...) return result_nt end -function compute_index(index::Vector{String}, params::NamedTuple; indices=indices) +function compute_index(index::Vector{<:AbstractSpectralIndex}, params::NamedTuple; indices=indices) results_dict = Dict{Symbol,Any}() for idx in index result_nt = compute_index(idx, params; indices=indices) @@ -165,7 +187,7 @@ indices = _get_indices() _check_params(index_name, parameters, indices) ``` """ -function _check_params(index, params::Dict) +function _check_params(index::AbstractSpectralIndex, params::Dict) for band in index.bands if !(band in keys(params)) throw( @@ -177,7 +199,7 @@ function _check_params(index, params::Dict) end end -function _order_params(index, params) +function _order_params(index::AbstractSpectralIndex, params) T = eltype(params) new_params = T[] for (bidx, band) in enumerate(index.bands) @@ -187,7 +209,7 @@ function _order_params(index, params) return new_params end -function _order_params(index, params::Dict) +function _order_params(index::AbstractSpectralIndex, params::Dict) T = eltype(values(params)) new_params = T[] for (bidx, band) in enumerate(index.bands) @@ -202,7 +224,7 @@ function _create_params(kw_args...) return params end -function _check_params(index, params::NamedTuple) +function _check_params(index::AbstractSpectralIndex, params::NamedTuple) for band in index.bands if !(Symbol(band) in keys(params)) throw( @@ -214,7 +236,7 @@ function _check_params(index, params::NamedTuple) end end -function _order_params(index, params::NamedTuple) +function _order_params(index::AbstractSpectralIndex, params::NamedTuple) T = eltype(values(params)) new_params = T[] for (bidx, band) in enumerate(index.bands) diff --git a/src/utils.jl b/src/utils.jl index 9e15890..8aee0f8 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -57,12 +57,13 @@ indices = _get_indices(true) function _get_indices( online::Bool=false; filename="spectral-indices-dict.json", - fileloc=joinpath(dirname(@__FILE__), "..", "data", filename), + fileloc=joinpath(dirname(@__FILE__), "..", "data"), ) + final_file = joinpath(fileloc, filename) if online indices_loc = Downloads.download( "https://raw.githubusercontent.com/awesome-spectral-indices/awesome-spectral-indices/main/output/spectral-indices-dict.json", - fileloc, + final_file, ) indices = JSON.parsefile(indices_loc) else diff --git a/test/compute_index.jl b/test/compute_index.jl index 0cf1e2c..060fa3b 100644 --- a/test/compute_index.jl +++ b/test/compute_index.jl @@ -29,8 +29,9 @@ end else params = Dict(band => rand(T) for band in idx.bands) end - #type extension result = compute_index(idx_name, params) + #result_idx = compute_index(idx, params) + #@test result == result_idx @test result isa T @test length(result) == 1 end @@ -41,6 +42,8 @@ end params = Dict(band => rand(T) for band in idx.bands) end result = compute_index(idx_name; convert_to_kwargs(params)...) + #result_idx = compute_index(idx; convert_to_kwargs(params)...) + #@test result == result_idx @test result isa T @test length(result) == 1 end @@ -119,6 +122,7 @@ end GC.gc() end + msi = custom_key_combinations(indices, 2, 200) @testset "Built-in types compute_index $T multiple indices tests: $idxs" for idxs in msi, diff --git a/test/utils.jl b/test/utils.jl index 93f6d4f..7d5afc9 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -12,13 +12,13 @@ using SpectralIndices test_dir = mktempdir() try # Define the file location within the test directory - test_fileloc = joinpath(test_dir, "spectral-indices-dict.json") + test_fileloc = test_dir # Run the _get_indices function with online = true indices = SpectralIndices._get_indices(true; fileloc=test_fileloc) # Test if the file was downloaded and parsed successfully - @test isfile(test_fileloc) + @test isfile(joinpath(test_dir, "spectral-indices-dict.json")) @test !isempty(indices) @test indices isa Dict