Skip to content

Selecting environmentally unique locations

For some applications, we want to sample a set of locations that cover a broad range of values in environment space. Another way to rephrase this problem is to say we want to find the set of points with the least covariance in their environmental values.

To do this, we use a BONRefiner called Uniqueness. We'll start by loading the required packages.

using BiodiversityObservationNetworks
using SpeciesDistributionToolkit
using StatsBase
using NeutralLandscapes
using CairoMakie
┌ Error: Error during loading of extension SDMToolkitExt of BiodiversityObservationNetworks, use `Base.retry_load_extensions()` to retry.
│   exception =
│    1-element ExceptionStack:
│    ArgumentError: Package SDMToolkitExt [75f002dd-b8c9-5168-9854-88ac03dd3cdb] is required but does not seem to be installed:
│     - Run `Pkg.instantiate()` to install all recorded dependencies.
│
│    Stacktrace:
│      [1] _require(pkg::Base.PkgId, env::Nothing)
│        @ Base ./loading.jl:1774
│      [2] _require_prelocked(uuidkey::Base.PkgId, env::Nothing)
│        @ Base ./loading.jl:1660
│      [3] _require_prelocked(uuidkey::Base.PkgId)
│        @ Base ./loading.jl:1658
│      [4] run_extension_callbacks(extid::Base.ExtensionId)
│        @ Base ./loading.jl:1255
│      [5] run_extension_callbacks(pkgid::Base.PkgId)
│        @ Base ./loading.jl:1290
│      [6] run_package_callbacks(modkey::Base.PkgId)
│        @ Base ./loading.jl:1124
│      [7] _require_prelocked(uuidkey::Base.PkgId, env::String)
│        @ Base ./loading.jl:1667
│      [8] macro expansion
│        @ ./loading.jl:1648 [inlined]
│      [9] macro expansion
│        @ ./lock.jl:267 [inlined]
│     [10] require(into::Module, mod::Symbol)
│        @ Base ./loading.jl:1611
│     [11] eval
│        @ ./boot.jl:370 [inlined]
│     [12] #17
│        @ ~/.julia/packages/Documenter/bYYzK/src/Expanders.jl:629 [inlined]
│     [13] cd(f::Documenter.Expanders.var"#17#19"{Module, Expr}, dir::String)
│        @ Base.Filesystem ./file.jl:112
│     [14] (::Documenter.Expanders.var"#16#18"{Documenter.Documents.Page, Module, Expr})()
│        @ Documenter.Expanders ~/.julia/packages/Documenter/bYYzK/src/Expanders.jl:628
│     [15] (::IOCapture.var"#4#7"{DataType, Documenter.Expanders.var"#16#18"{Documenter.Documents.Page, Module, Expr}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}, Base.PipeEndpoint, Base.PipeEndpoint})()
│        @ IOCapture ~/.julia/packages/IOCapture/Rzdxd/src/IOCapture.jl:161
│     [16] with_logstate(f::Function, logstate::Any)
│        @ Base.CoreLogging ./logging.jl:514
│     [17] with_logger
│        @ ./logging.jl:626 [inlined]
│     [18] capture(f::Documenter.Expanders.var"#16#18"{Documenter.Documents.Page, Module, Expr}; rethrow::Type, color::Bool, passthrough::Bool, capture_buffer::IOBuffer)
│        @ IOCapture ~/.julia/packages/IOCapture/Rzdxd/src/IOCapture.jl:158
│     [19] runner(#unused#::Type{Documenter.Expanders.ExampleBlocks}, x::Markdown.Code, page::Documenter.Documents.Page, doc::Documenter.Documents.Document)
│        @ Documenter.Expanders ~/.julia/packages/Documenter/bYYzK/src/Expanders.jl:627
│     [20] dispatch(::Type{Documenter.Expanders.ExpanderPipeline}, ::Markdown.Code, ::Vararg{Any})
│        @ Documenter.Utilities.Selectors ~/.julia/packages/Documenter/bYYzK/src/Utilities/Selectors.jl:170
│     [21] expand(doc::Documenter.Documents.Document)
│        @ Documenter.Expanders ~/.julia/packages/Documenter/bYYzK/src/Expanders.jl:42
│     [22] runner(#unused#::Type{Documenter.Builder.ExpandTemplates}, doc::Documenter.Documents.Document)
│        @ Documenter.Builder ~/.julia/packages/Documenter/bYYzK/src/Builder.jl:226
│     [23] dispatch(#unused#::Type{Documenter.Builder.DocumentPipeline}, x::Documenter.Documents.Document)
│        @ Documenter.Utilities.Selectors ~/.julia/packages/Documenter/bYYzK/src/Utilities/Selectors.jl:170
│     [24] #2
│        @ ~/.julia/packages/Documenter/bYYzK/src/Documenter.jl:273 [inlined]
│     [25] cd(f::Documenter.var"#2#3"{Documenter.Documents.Document}, dir::String)
│        @ Base.Filesystem ./file.jl:112
│     [26] #makedocs#1
│        @ ~/.julia/packages/Documenter/bYYzK/src/Documenter.jl:272 [inlined]
│     [27] top-level scope
│        @ ~/work/BiodiversityObservationNetworks.jl/BiodiversityObservationNetworks.jl/docs/make.jl:10
│     [28] include(mod::Module, _path::String)
│        @ Base ./Base.jl:457
│     [29] exec_options(opts::Base.JLOptions)
│        @ Base ./client.jl:307
│     [30] _start()
│        @ Base ./client.jl:522
└ @ Base loading.jl:1261
[ Info: Loading NeutralLandscapes support for SimpleSDMLayers.jl...

Consider setting your SDMLAYERS_PATH

When accessing data using SimpleSDMDatasets.jl, it is best to set the SDM_LAYERSPATH environmental variable to tell SimpleSDMDatasets.jl where to download data. This can be done by setting ENV["SDMLAYERS_PATH"] = "/home/user/Data/" or similar in the ~/.julia/etc/julia/startup.jl file. (Note this will be different depending on where julia is installed.)

bbox = (left=-83.0, bottom=46.4, right=-55.2, top=63.7);
temp, precip, elevation =
    convert(Float32, SimpleSDMPredictor(RasterData(WorldClim2, AverageTemperature); bbox...)),
    convert(Float32, SimpleSDMPredictor(RasterData(WorldClim2, Precipitation); bbox...)),
    convert(Float32, SimpleSDMPredictor(RasterData(WorldClim2, Elevation); bbox...));
(SDM response → 105×167 grid with 11478 Float32-valued cells, SDM response → 105×167 grid with 11478 Float32-valued cells, SDM response → 105×167 grid with 11478 Float32-valued cells)

Now we'll use the stack function to combine our four environmental layers into a single, 3-dimensional array, which we'll pass to our Uniqueness refiner.

```@example 1 layers = BiodiversityObservationNetworks.stack([temp,precip,elevation]);

this requires NeutralLandscapes v0.1.2


```julia
uncert = rand(MidpointDisplacement(0.8), size(temp), mask=temp);
heatmap(uncert)

Now we'll get a set of candidate points from a BalancedAcceptance seeder that has no bias toward higher uncertainty values.

candpts, uncert = uncert |> seed(BalancedAcceptance(numpoints=100, α=0.0));
(CartesianIndex[CartesianIndex(40, 143), CartesianIndex(86, 59), CartesianIndex(4, 40), CartesianIndex(56, 96), CartesianIndex(17, 65), CartesianIndex(69, 121), CartesianIndex(63, 46), CartesianIndex(37, 102), CartesianIndex(24, 15), CartesianIndex(50, 127)  …  CartesianIndex(60, 28), CartesianIndex(34, 84), CartesianIndex(57, 127), CartesianIndex(30, 34), CartesianIndex(70, 53), CartesianIndex(11, 5), CartesianIndex(37, 117), CartesianIndex(24, 80), CartesianIndex(29, 67), CartesianIndex(68, 86)], [0.251900323340195 0.27347957539914114 … NaN NaN; 0.24274322050612135 0.2515882692635109 … NaN NaN; … ; NaN NaN … NaN NaN; NaN NaN … NaN NaN])

Now we'll refine our 100 candidate points down to the 30 most environmentally unique.

```@example 1 finalpts, uncert = refine(candpts, Uniqueness(;numpoints=30, layers=layers), uncert)

=

heatmap(uncert) scatter!([p[2] for p in candpts], [p[1] for p in candpts], fa=0.0, msc=:white, label="Candidate Points") scatter!([p[2] for p in finalpts], [p[1] for p in finalpts], c=:dodgerblue, msc=:white, label="Selected Points")=# ```