Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into fm/rs
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinuzziFrancesco committed Mar 25, 2024
2 parents b78495c + ed6e091 commit a7af332
Show file tree
Hide file tree
Showing 28 changed files with 2,546 additions and 672 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/FormatCheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: format-check

on:
push:
branches:
- 'main'
- 'release-'
tags: '*'
pull_request:

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
julia-version: [1]
julia-arch: [x86]
os: [ubuntu-latest]
steps:
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.julia-version }}

- uses: actions/checkout@v4
- name: Install JuliaFormatter and format
# This will use the latest version by default but you can set the version like so:
#
# julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter", version="0.13.0"))'
run: |
julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter"))'
julia -e 'using JuliaFormatter; format(".", verbose=true)'
- name: Format check
run: |
julia -e '
out = Cmd(`git diff --name-only`) |> read |> String
if out == ""
exit(0)
else
@error "Some files have not been formatted !!!"
write(stdout, out)
exit(1)
end'
29 changes: 29 additions & 0 deletions .github/workflows/FormatPR.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: format-pr
on:
schedule:
- cron: '0 0 * * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install JuliaFormatter and format
run: |
julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter"))'
julia -e 'using JuliaFormatter; format(".")'
# https://github.com/marketplace/actions/create-pull-request
# https://github.com/peter-evans/create-pull-request#reference-example
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: Format .jl files
title: 'Automatic JuliaFormatter.jl run'
branch: auto-juliaformatter-pr
delete-branch: true
labels: formatting, automated pr, no changelog
- name: Check outputs
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "SpectralIndices"
uuid = "df0093a1-273d-40bc-819a-796ec3476907"
authors = ["MartinuzziFrancesco <[email protected]>"]
version = "0.2.3"
version = "0.2.4"

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Expand Down
37 changes: 19 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,22 @@
[jet-img]: https://img.shields.io/badge/%E2%9C%88%EF%B8%8F%20tested%20with%20-%20JET.jl%20-%20red
[jet-url]: https://github.com/aviatesk/JET.jl

## Overview
## Overview 📖

SpectralIndices.jl is a Julia package for working with spectral indices commonly used in remote sensing and earth observation applications. It provides a convenient way to compute various spectral indices using Julia's high-performance capabilities.

## Features
## Features 🚀

- Compute a wide range of spectral indices.
- Computation for a wide range of spectral indices
- Computation support for `Float64`, `Float32` and `Float16` at index formula level to support fast computation for ML applications
- Support for various data types, including but not limited to (see this [issue](https://github.com/awesome-spectral-indices/SpectralIndices.jl/issues/8) for an updated list and WIP)
- [x] Arrays
- [x] DataFrames
- [x] YAXArrays
- Flexible parameter input options.
- Compatibility with multiple remote sensing platforms and sensors.
- Flexible parameter input options
- Compatibility with multiple remote sensing platforms and sensors

## Installation
## Installation 💻
SpectralIndices.jl is registered in the general registry, please install it using the following:
```julia_repl
julia> ]
Expand All @@ -55,7 +56,7 @@ using Pkg
Pkg.add("SpectralIndices")
```

## Usage
## Usage 🛠️

You can compute spectral indices either by specifying the index and its parameters or using predefined SpectralIndex instances.

Expand All @@ -78,6 +79,12 @@ df = DataFrame(N = [0.643, 0.560], R = [0.175, 0.225], L = [0.5, 0.5])
result_df_multiple = compute_index(["NDVI", "SAVI"], df)
```

To compute at custom Float precision input the bands at the chosen precision and specify the Float type to the `compute_index` function
```julia
# Compute NDVI with direct parameter input
result = compute_index(Float32, "NDVI", N = Float32(0.643), R = Float32(0.175))
```

### Using `compute`
```julia
# Define a SpectralIndex instance
Expand All @@ -89,31 +96,25 @@ result = compute(NDVI, N = 0.643, R = 0.175) #NDVI is autmatically in namespace
array_result = compute(NDVI, N = fill(0.643, (5, 5)), R = fill(0.175, (5, 5)))
```

### Direct computation
SpectralIndices.jl also allows for direct computation using function calls:
```julia
result = NDVI(0.643, 0.175)
```

For more advanced usage and detailed documentation, please refer to the documentation.

## Contributing
## Contributing 🤝

Contributions to SpectralIndices.jl are welcome! If you would like to contribute, please see our Contribution Guidelines for more information.

## License
## License 📜

SpectralIndices.jl is licensed under the MIT License. See [LICENSE](https://github.com/awesome-spectral-indices/SpectralIndices.jl/blob/main/LICENSE) for more information.

## Acknowledgments
## Acknowledgments

This package is inspired by the [Spyndex](https://github.com/awesome-spectral-indices/spyndex) Python library for spectral indices. The logo is AI-generated by dalle3 through ChatGPT and modified by the talented [David Montero](https://github.com/davemlz).

## Support
## Support 🆘

If you have any questions, issues, or feature requests, please open an issue or contact us via email.

## Citation
## Citation 🔗

If you use SpectralIndices.jl in your research, please consider citing it using the following DOI:

Expand Down
9 changes: 5 additions & 4 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ makedocs(;
doctest=true,
linkcheck=true,
warnonly=[:missing_docs],
format = Documenter.HTML(
size_threshold = nothing,
prettyurls = get(ENV, "CI", nothing) == "true",
assets = ["assets/docs.css"]),
format=Documenter.HTML(;
size_threshold=nothing,
prettyurls=get(ENV, "CI", nothing) == "true",
assets=["assets/docs.css"],
),
pages=pages,
)

Expand Down
16 changes: 14 additions & 2 deletions docs/src/tutorials/basic_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ NDVI
This outputs the NDVI struct, containing all necessary information. The struct can also be used as a function to compute NDVI:

```@example basic
NDVI(nir, red)
NDVI(Float64, nir, red)
```

This method is direct but not the recommended approach for computing indices. When using this method, ensure the parameter order matches the `bands` field of the `SpectralIndex`:
Expand Down Expand Up @@ -144,7 +144,19 @@ savi = compute_index("SAVI", params)
savi = compute_index("SAVI"; N=nir, R=red, L=0.5)
```

### Computing Multiple Indices
## Float32, Float16
The package can compute indices at custom precision

```@example basic
T = Float32
savi = compute_index(T, "SAVI"; N=T(nir), R=T(red), L=T(0.5))
```
```@example basic
T = Float16
savi = compute_index(T, "SAVI"; N=T(nir), R=T(red), L=T(0.5))
```

## Computing Multiple Indices

Now that we have added more indices we can explore how to compute multiple indices at the same time. All is needed is to pass a Vector of `String`s to the `compute_index` function with the chosen spectral indices inside, as well as the chosen parameters of course:

Expand Down
56 changes: 41 additions & 15 deletions ext/SpectralIndicesDataFramesExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,52 +15,78 @@ function SpectralIndices._create_params(kw_args::Pair{Symbol,DataFrame}...)
end

function SpectralIndices.compute_index(
index::String, params::DataFrame; indices=SpectralIndices._create_indices()
)
::Type{T}, index::String, params::DataFrame; indices=SpectralIndices._create_indices()
) where {T<:Number}
# Convert DataFrame to a dictionary for each row and compute the index
results = [
compute_index(index, Dict(zip(names(params), row)); indices=indices) for
row in eachrow(params)
SpectralIndices.compute_index(
T, 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)
end

function SpectralIndices.compute_index(
index::Vector{String}, params::DataFrame; indices=SpectralIndices._create_indices()
index::String, params::DataFrame; indices=SpectralIndices._create_indices()
)
return SpectralIndices.compute_index(Float64, index, params; indices=indices)
end

function SpectralIndices.compute_index(
::Type{T},
index::Vector{String},
params::DataFrame;
indices=SpectralIndices._create_indices(),
) where {T<:Number}
# Similar conversion and computation for a vector of indices
result_dfs = DataFrame()
for idx in index
result_df = compute_index(idx, params; indices=indices)
result_df = SpectralIndices.compute_index(T, idx, params; indices=indices)
result_dfs[!, Symbol(idx)] = result_df[!, 1]
end
# Return the combined DataFrame with columns named after each index
return result_dfs
end

function SpectralIndices.linear(params::DataFrame)
result = linear(params[!, "a"], params[!, "b"])
function SpectralIndices.compute_index(
index::Vector{String}, params::DataFrame; indices=SpectralIndices._create_indices()
)
return SpectralIndices.compute_index(Float64, index, params; indices=indices)
end

function SpectralIndices.linear(::Type{T}, params::DataFrame) where {T<:Number}
result = linear(T, params[!, "a"], params[!, "b"])
result_df = DataFrame(; linear=result)
return result_df
end

function SpectralIndices.poly(params::DataFrame)
result = poly(params[!, "a"], params[!, "b"], params[!, "c"], params[!, "p"])
function SpectralIndices.linear(params::DataFrame)
return linear(Float64, params)
end

function SpectralIndices.poly(::Type{T}, params::DataFrame) where {T<:Number}
result = poly(T, params[!, "a"], params[!, "b"], params[!, "c"], params[!, "p"])
result_df = DataFrame(; poly=result)
return result_df
end

function SpectralIndices.RBF(params::DataFrame)
result = RBF(params[!, "a"], params[!, "b"], params[!, "sigma"])
function SpectralIndices.poly(params::DataFrame)
return poly(Float64, params)
end

function SpectralIndices.RBF(::Type{T}, params::DataFrame) where {T<:Number}
result = RBF(T, 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 SpectralIndices.RBF(params::DataFrame)
return RBF(Float64, params)
end

function SpectralIndices.load_dataset(dataset::String, ::Type{T}) where {T<:DataFrame}
datasets = Dict("spectral" => "spectral.json")

if dataset in keys(datasets)
Expand Down
Loading

0 comments on commit a7af332

Please sign in to comment.