diff --git a/src/SpeciesDistributionToolkit.jl b/src/SpeciesDistributionToolkit.jl index 5416a9559..ac026d956 100644 --- a/src/SpeciesDistributionToolkit.jl +++ b/src/SpeciesDistributionToolkit.jl @@ -45,6 +45,9 @@ include("integrations/makie.jl") # SDeMo include("integrations/sdemo.jl") +# OccurrencesInterface +include("integrations/occurrence_interface.jl") + # Functions for pseudo-absence generation include("pseudoabsences.jl") export WithinRadius, SurfaceRangeEnvelope, RandomSelection, DistanceToEvent diff --git a/src/integrations/gbif_layers.jl b/src/integrations/gbif_layers.jl index 968a5d0b8..7bec2b1d2 100644 --- a/src/integrations/gbif_layers.jl +++ b/src/integrations/gbif_layers.jl @@ -1,86 +1,11 @@ -import Base: getindex -import Base: setindex! -import SimpleSDMLayers: mask!, mask - -""" - Base.getindex(p::T, occurrence::GBIF.GBIFRecord) where {T <: SimpleSDMLayer} - -Extracts the value of a layer at a given position for a `GBIFRecord`. If the -`GBIFRecord` has no latitude or longitude, this will return `nothing`. -""" -function Base.getindex(layer::SDMLayer, record::GBIF.GBIFRecord) - ismissing(record.latitude) && return nothing - ismissing(record.longitude) && return nothing - return layer[record.longitude, record.latitude] -end - -""" - Base.setindex!(layer::SDMLayer, v, record::GBIFRecord) - -Changes the values of the cell including the point at the requested latitude and -longitude. -""" -function Base.setindex!( - layer::SDMLayer{T}, - v::T, - record::GBIF.GBIFRecord, -) where {T} - ismissing(record.latitude) && return nothing - ismissing(record.longitude) && return nothing - return setindex!(layer, v, record.longitude, record.latitude) -end - -""" - Base.getindex(layer::T, records::GBIF.GBIFRecords) where {T <: SimpleSDMLayer} - -Returns the values of a layer at all occurrences in a `GBIFRecords` collection. -""" -function Base.getindex(layer::SDMLayer, records::GBIF.GBIFRecords) - K = eltype(layer) - return convert( - Vector{K}, - filter(!isnothing, [layer[r] for r in records]), - ) -end - -""" - Base.getindex(layer::SDMLayer, records::Vector{GBIF.GBIFRecord}) - -Returns the values of a layer at all occurrences in a `GBIFRecord` array. -""" -function Base.getindex(layer::SDMLayer, records::Vector{GBIF.GBIFRecord}) - return [layer[record] for record in records] -end - -function SimpleSDMLayers.quantize(layer::SDMLayer, records::GBIFRecords) - ef = StatsBase.ecdf(layer[records]) - return ef.(layer) -end - -function SimpleSDMLayers.mask(layer::SDMLayer, records::GBIF.GBIFRecords) - out = zeros(layer, Bool) - for record in records - out[record] = true - end - return out -end - -function SimpleSDMLayers.mask( - layer::SDMLayer, - records::GBIF.GBIFRecords, - ::Type{T}, -) where {T <: Number} - out = zeros(layer, T) - for record in records - out[record] += one(T) - end - return out -end - function _bbox_from_layer(layer::SDMLayer) EL = eastings(layer) NL = northings(layer) - prj = SimpleSDMLayers.Proj.Transformation(layer.crs, "+proj=longlat +datum=WGS84 +no_defs"; always_xy = true) + prj = SimpleSDMLayers.Proj.Transformation( + layer.crs, + "+proj=longlat +datum=WGS84 +no_defs"; + always_xy = true, + ) b1 = [prj(EL[1], n) for n in NL] b2 = [prj(EL[end], n) for n in NL] @@ -107,4 +32,4 @@ function GBIF.occurrences(layer::SDMLayer, query::Pair...) query = (query..., "decimalLongitude" => (spatial_extent.left, spatial_extent.right)) query = (query..., "hasCoordinate" => true) return occurrences(query...) -end \ No newline at end of file +end diff --git a/src/integrations/makie.jl b/src/integrations/makie.jl index 81b99fb22..847c68df9 100644 --- a/src/integrations/makie.jl +++ b/src/integrations/makie.jl @@ -8,15 +8,9 @@ function sprinkle(layer::SDMLayer) ) end -function sprinkle(records::GBIFRecords) - lon = Float32.(replace(longitudes(records), missing => NaN)) - lat = Float32.(replace(latitudes(records), missing => NaN)) - return (lon, lat) -end - -function sprinkle(records::Vector{GBIFRecord}) - lon = Float32.(replace(longitudes.(records), missing => NaN)) - lat = Float32.(replace(latitudes.(records), missing => NaN)) +function sprinkle(coll::T) where {T <: AbstractOccurrenceCollection} + lon = Float32.(replace(longitudes(coll), missing => NaN)) + lat = Float32.(replace(latitudes(coll), missing => NaN)) return (lon, lat) end @@ -42,7 +36,7 @@ end function MakieCore.convert_arguments( P::MakieCore.PointBased, - layer::T + layer::T, ) where {T <: SDMLayer{Bool}} return MakieCore.convert_arguments(P, sprinkle(ones(nodata(layer, false), Float32))...) -end \ No newline at end of file +end diff --git a/src/integrations/occurrence_interface.jl b/src/integrations/occurrence_interface.jl new file mode 100644 index 000000000..4b7662330 --- /dev/null +++ b/src/integrations/occurrence_interface.jl @@ -0,0 +1,73 @@ +import Base: getindex +import Base: setindex! +import SimpleSDMLayers: mask!, mask + +""" + Base.getindex(p::T, occ::AbstractOccurrence) + +Extracts the value of a layer at a given position for a `AbstractOccurrence`. If the +`AbstractOccurrence` has no latitude or longitude, this will return `nothing`. +""" +function Base.getindex(layer::SDMLayer, occ:T) where {T <: AbstractOccurrence} + ismissing(place(occ)) && return nothing + return layer[place(occ)...] +end + +""" + Base.setindex!(layer::SDMLayer, v, occ::T) where {T <: AbstractOccurrence} + +Changes the values of the cell including the point at the requested latitude and +longitude. +""" +function Base.setindex!( + layer::SDMLayer{T}, + v::T, + occ::O, +) where {T, O <: AbstractOccurrence} + ismissing(place(occ)) && return nothing + return setindex!(layer, v, place(occ)...) +end + +""" + Base.getindex(layer::SDMLayer, occ::T) where {T <: AbstractOccurrenceCollection} + +Returns the values of a layer at all occurrences in a `AbstractOccurrenceCollection`. +""" +function Base.getindex(layer::SDMLayer, occ::T) where {T <: AbstractOccurrenceCollection} + K = eltype(layer) + return convert( + Vector{K}, + filter(!isnothing, [layer[o] for o in elements(occ)]), + ) +end + +function SimpleSDMLayers.quantize( + layer::SDMLayer, + occ:T, +) where {T <: AbstractOccurrenceCollection} + ef = StatsBase.ecdf(layer[occ]) + return ef.(layer) +end + +function SimpleSDMLayers.mask( + layer::SDMLayer, + occ::T, +) where {T <: AbstractOccurrenceCollection} + out = zeros(layer, Bool) + for record in elements(occ) + out[record] = presence(occ) + end + return out +end + +function SimpleSDMLayers.mask( + layer::SDMLayer, + occ::O, + ::Type{T}, +) where {T <: Number, O <: AbstractOccurrenceCollection} + out = zeros(layer, T) + for record in elements(occ) + out[record] += one(T) + end + return out +end