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"#5#9"{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/Y5rEA/src/IOCapture.jl:170
│     [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, io_context::Vector{Any})
│        @ IOCapture ~/.julia/packages/IOCapture/Y5rEA/src/IOCapture.jl:167
│     [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...
┌ Warning: Error requiring `SpeciesDistributionToolkit` from `NeutralLandscapes`
│   exception =
│    LoadError: UndefVarError: `SimpleSDMLayer` not defined
│    Stacktrace:
│      [1] getproperty(x::Module, f::Symbol)
│        @ Base ./Base.jl:31
│      [2] top-level scope
│        @ ~/.julia/packages/NeutralLandscapes/KXn74/src/integrations/simplesdmlayers.jl:3
│      [3] include(mod::Module, _path::String)
│        @ Base ./Base.jl:457
│      [4] include(x::String)
│        @ NeutralLandscapes ~/.julia/packages/NeutralLandscapes/KXn74/src/NeutralLandscapes.jl:1
│      [5] top-level scope
│        @ none:1
│      [6] eval
│        @ ./boot.jl:370 [inlined]
│      [7] eval
│        @ ~/.julia/packages/NeutralLandscapes/KXn74/src/NeutralLandscapes.jl:1 [inlined]
│      [8] (::NeutralLandscapes.var"#60#63")()
│        @ NeutralLandscapes ~/.julia/packages/Requires/Z8rfN/src/require.jl:101
│      [9] macro expansion
│        @ timing.jl:393 [inlined]
│     [10] err(f::Any, listener::Module, modname::String, file::String, line::Any)
│        @ Requires ~/.julia/packages/Requires/Z8rfN/src/require.jl:47
│     [11] (::NeutralLandscapes.var"#59#62")()
│        @ NeutralLandscapes ~/.julia/packages/Requires/Z8rfN/src/require.jl:100
│     [12] withpath(f::Any, path::String)
│        @ Requires ~/.julia/packages/Requires/Z8rfN/src/require.jl:37
│     [13] (::NeutralLandscapes.var"#58#61")()
│        @ NeutralLandscapes ~/.julia/packages/Requires/Z8rfN/src/require.jl:99
│     [14] #invokelatest#2
│        @ ./essentials.jl:819 [inlined]
│     [15] invokelatest
│        @ ./essentials.jl:816 [inlined]
│     [16] foreach(f::typeof(invokelatest), itr::Vector{Function})
│        @ Base ./abstractarray.jl:3075
│     [17] loadpkg(pkg::Base.PkgId)
│        @ Requires ~/.julia/packages/Requires/Z8rfN/src/require.jl:27
│     [18] #invokelatest#2
│        @ ./essentials.jl:819 [inlined]
│     [19] invokelatest
│        @ ./essentials.jl:816 [inlined]
│     [20] run_package_callbacks(modkey::Base.PkgId)
│        @ Base ./loading.jl:1129
│     [21] _require_prelocked(uuidkey::Base.PkgId, env::String)
│        @ Base ./loading.jl:1667
│     [22] macro expansion
│        @ ./loading.jl:1648 [inlined]
│     [23] macro expansion
│        @ ./lock.jl:267 [inlined]
│     [24] require(into::Module, mod::Symbol)
│        @ Base ./loading.jl:1611
│     [25] eval
│        @ ./boot.jl:370 [inlined]
│     [26] #17
│        @ ~/.julia/packages/Documenter/bYYzK/src/Expanders.jl:629 [inlined]
│     [27] cd(f::Documenter.Expanders.var"#17#19"{Module, Expr}, dir::String)
│        @ Base.Filesystem ./file.jl:112
│     [28] (::Documenter.Expanders.var"#16#18"{Documenter.Documents.Page, Module, Expr})()
│        @ Documenter.Expanders ~/.julia/packages/Documenter/bYYzK/src/Expanders.jl:628
│     [29] (::IOCapture.var"#5#9"{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/Y5rEA/src/IOCapture.jl:170
│     [30] with_logstate(f::Function, logstate::Any)
│        @ Base.CoreLogging ./logging.jl:514
│     [31] with_logger
│        @ ./logging.jl:626 [inlined]
│     [32] capture(f::Documenter.Expanders.var"#16#18"{Documenter.Documents.Page, Module, Expr}; rethrow::Type, color::Bool, passthrough::Bool, capture_buffer::IOBuffer, io_context::Vector{Any})
│        @ IOCapture ~/.julia/packages/IOCapture/Y5rEA/src/IOCapture.jl:167
│     [33] 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
│     [34] dispatch(::Type{Documenter.Expanders.ExpanderPipeline}, ::Markdown.Code, ::Vararg{Any})
│        @ Documenter.Utilities.Selectors ~/.julia/packages/Documenter/bYYzK/src/Utilities/Selectors.jl:170
│     [35] expand(doc::Documenter.Documents.Document)
│        @ Documenter.Expanders ~/.julia/packages/Documenter/bYYzK/src/Expanders.jl:42
│     [36] runner(#unused#::Type{Documenter.Builder.ExpandTemplates}, doc::Documenter.Documents.Document)
│        @ Documenter.Builder ~/.julia/packages/Documenter/bYYzK/src/Builder.jl:226
│     [37] dispatch(#unused#::Type{Documenter.Builder.DocumentPipeline}, x::Documenter.Documents.Document)
│        @ Documenter.Utilities.Selectors ~/.julia/packages/Documenter/bYYzK/src/Utilities/Selectors.jl:170
│     [38] #2
│        @ ~/.julia/packages/Documenter/bYYzK/src/Documenter.jl:273 [inlined]
│     [39] cd(f::Documenter.var"#2#3"{Documenter.Documents.Document}, dir::String)
│        @ Base.Filesystem ./file.jl:112
│     [40] #makedocs#1
│        @ ~/.julia/packages/Documenter/bYYzK/src/Documenter.jl:272 [inlined]
│     [41] top-level scope
│        @ ~/work/BiodiversityObservationNetworks.jl/BiodiversityObservationNetworks.jl/docs/make.jl:10
│     [42] include(mod::Module, _path::String)
│        @ Base ./Base.jl:457
│     [43] exec_options(opts::Base.JLOptions)
│        @ Base ./client.jl:307
│     [44] _start()
│        @ Base ./client.jl:522
│    in expression starting at /home/runner/.julia/packages/NeutralLandscapes/KXn74/src/integrations/simplesdmlayers.jl:3
└ @ Requires ~/.julia/packages/Requires/Z8rfN/src/require.jl:51

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.)

```@example 1 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...));

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

```@example 1 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.


```@example 1
candpts, uncert = uncert |> seed(BalancedAcceptance(numpoints=100, α=0.0)); 

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")=# ```