Generating background points
In this vignette, we will generate some background points (pseudo-absences) using the different algorithms present in the package. The pseudo-absences are generated through the PseudoAbsences component package.
using SpeciesDistributionToolkit
using CairoMakiePseudo-absence generation requires occurrences super-imposed on a layer, so we will collect a few occurrences:
records = OccurrencesInterface.__demodata()
landmass = getpolygon(PolygonData(OpenStreetMap, Places); place="Idaho")
records = Occurrences(mask(records, landmass))
spatial_extent = SpeciesDistributionToolkit.boundingbox(landmass)(left = -117.24303436279297, right = -111.04356384277344, bottom = 41.988834381103516, top = 49.0008430480957)We will get a single layer (elevation, but it's not important here):
dataprovider = RasterData(WorldClim2, Elevation)
layer = SDMLayer(dataprovider; resolution=2.5, spatial_extent...)
mask!(layer, landmass)🗺️ A 170 × 149 layer with 14104 Int16 cells
Projection: +proj=longlat +datum=WGS84 +no_defsPseudo-absences generations always starts by masking a layer by the observations. The output of this command is a layer with Boolean values, where the cells in which at least one occurrence is reported are true.
presencelayer = mask(layer, records)🗺️ A 170 × 149 layer with 14104 Bool cells
Projection: +proj=longlat +datum=WGS84 +no_defsWe can for example generate a buffer for pseudo-absences in a radius of 90km around each point. Note that the WithinRadius method uses kilometers and not minutes of arc, so that the actual area is the same regardless of the latitude of the points. Note that the speed of the operation depends on the number of cells with an observation (linearly), and of the radius and raster resolution (to a power of 2). Internally, the code uses a variety of tricks to only look at cells that are susceptible to being pseudo-absences, but the WithinRadius method in particular can take a bit of time.
background = pseudoabsencemask(WithinRadius, presencelayer; distance = 90.0)🗺️ A 170 × 149 layer with 14104 Bool cells
Projection: +proj=longlat +datum=WGS84 +no_defsThe pseudo-absence generation functions will return a mask, i.e. a boolean layer where the cells in which we can place a pseudo-absence are true, and the rest of the cells are false. This is useful for a variety of reasons, including adding more and more constraints to the locations of pseudo-absences. For example, we can decide that we do not want background points too close to the actual observations, and put a buffer around each.
buffer = pseudoabsencemask(WithoutRadius, presencelayer; distance = 15.0)🗺️ A 170 × 149 layer with 14104 Bool cells
Projection: +proj=longlat +datum=WGS84 +no_defsWe can now exclude the data that are in the buffer:
bgmask = background & buffer🗺️ A 170 × 149 layer with 14104 Bool cells
Projection: +proj=longlat +datum=WGS84 +no_defsFinally, we can plot the area in which we can put pseudo-absences as a shaded region over the layer, and plot all known occurrences as well:

Code for the figure
heatmap(
layer;
colormap = :darkterrain,
axis = (; aspect = DataAspect()),
figure = (; size = (800, 500)),
)
heatmap!(bgmask; colormap = cgrad([:transparent, :white]; alpha = 0.3))
scatter!(records; color = :black)
hidespines!(current_axis())
hidedecorations!(current_axis())Note that we can get the same information by using the BetweenRadius method:
pseudoabsencemask(BetweenRadius, presencelayer; closer = 15.0, further = 90.0)🗺️ A 170 × 149 layer with 14104 Bool cells
Projection: +proj=longlat +datum=WGS84 +no_defsThere are additional ways to produce pseudo-absences mask, notably the surface range envelope method, which uses the bounding box of observations to allow pseudo-absences:
sre = pseudoabsencemask(SurfaceRangeEnvelope, presencelayer)🗺️ A 170 × 149 layer with 14104 Bool cells
Projection: +proj=longlat +datum=WGS84 +no_defs
Code for the figure
heatmap(
layer;
colormap = :darkterrain,
axis = (; aspect = DataAspect()),
figure = (; size = (800, 500)),
)
heatmap!(sre; colormap = cgrad([:transparent, :white]; alpha = 0.3))
scatter!(records; color = :black)
hidespines!(current_axis())
hidedecorations!(current_axis())The RandomSelection method (not shown) uses the entire surface of the layer as a possible pseudo-absence location.
Note that we are not yet generating pseudo-absences, and in order to do so, we need to sample the mask generated by pseudoabsencemask. We can do so using backgroundpoints, which uses the StatsBase.sample function internally.
bgpoints = backgroundpoints(bgmask, 2sum(presencelayer))🗺️ A 170 × 149 layer with 14104 Bool cells
Projection: +proj=longlat +datum=WGS84 +no_defsAnd finally, we can make a plot:

Code for the figure
heatmap(
layer;
colormap = :darkterrain,
axis = (; aspect = DataAspect()),
figure = (; size = (800, 500)),
)
heatmap!(bgmask; colormap = cgrad([:transparent, :white]; alpha = 0.3))
scatter!(records; color = :black)
scatter!(bgpoints; color = :red, markersize = 4)
hidespines!(current_axis())
hidedecorations!(current_axis())We can also work with distances in degrees rather than kilometers – for example, this will create a rectangular buffer one degree wide and one degree tall around each observation. Using absolute=true will turn this into a circular buffer:
background = pseudoabsencemask(WithoutDegrees, presencelayer; distance = 0.5, absolute=false)🗺️ A 170 × 149 layer with 14104 Bool cells
Projection: +proj=longlat +datum=WGS84 +no_defs
Code for the figure
heatmap(
layer;
colormap = :darkterrain,
axis = (; aspect = DataAspect()),
figure = (; size = (800, 500)),
)
heatmap!(background; colormap = cgrad([:transparent, :white]; alpha = 0.3))
scatter!(records; color = :black)
hidespines!(current_axis())
hidedecorations!(current_axis())Related documentation
PseudoAbsences.PseudoAbsenceGenerator Type
PseudoAbsenceGeneratorAbstract type to which all of the pseudo-absences generator types belong. Note that the pseudo-absence types are singleton types, and the arguments are passed when generating the pseudo-absence mask.
sourcePseudoAbsences.WithinRadius Type
WithinRadiusGenerates pseudo-absences within a set radius (in kilometers) around each occurrence. Internally, this relies on DistanceToEvent.
PseudoAbsences.WithoutRadius Type
WithoutRadiusGenerates pseudo-absences outside of a set radius (in kilometers) around each occurrence. Internally, this relies on DistanceToEvent.
PseudoAbsences.BetweenRadius Type
BetweenRadiusGenerates pseudo-absences within two set radii (in kilometers) around each occurrence. Internally, this relies on DistanceToEvent.
PseudoAbsences.WithinDegrees Type
WithinDegreesEquivalent of WithinRadius with the distance measured in degrees.
PseudoAbsences.WithoutDegrees Type
WithoutDegreesEquivalent of WithoutRadius with the distance measured in degrees.
PseudoAbsences.BetweenDegrees Type
BetweenDegreesEquivalent of BetweenRadius with the distance measured in degrees.
PseudoAbsences.SurfaceRangeEnvelope Type
SurfaceRangeEnvelopeGenerates pseudo-absences at random within the geographic range covered by actual occurrences. Cells with presences cannot be part of the background sample.
sourcePseudoAbsences.RandomSelection Type
RandomSelectionGenerates pseudo-absences at random within the layer. The full extent is considered, and cells with a true value cannot be part of the background sample.
sourcePseudoAbsences.DistanceToEvent Type
DistanceToEventGenerates a weight for the pseudo-absences based on the distance to cells with a true value. The distances are always measured in km using the haversine formula.
PseudoAbsences.DegreesToEvent Type
DegreesToEventGenerates a weight for the pseudo-absences based on the distance to cells with a true value. The distances are measured as the Euclidean distance expressed in degrees around the point.
PseudoAbsences.pseudoabsencemask Function
pseudoabsencemask(::Type{RandomSelection}, presences::SDMLayer{Bool})Generates a mask for pseudo-absences using the random selection method. Candidate cells for the pseudo-absence mask are (i) within the bounding box of the layer (use SurfaceRangeEnvelope to use the presences bounding box), and (ii) valued in the layer.
pseudoabsencemask(::Type{SurfaceRangeEnvelope}, presences::SDMLayer{Bool})Generates a mask from which pseudo-absences can be drawn, by picking cells that are (i) within the bounding box of occurrences, (ii) valued in the layer, and (iii) not already occupied by an occurrence
sourcepseudoabsencemask( ::Type{DistanceToEvent}, presences::SDMLayer{Bool}; f = minimum, )Generates a mask for pseudo-absences using the distance to event method. Candidate cells are weighted according to their distance to a known observation, with far away places being more likely. Depending on the distribution of distances, it may be a very good idea to flatten this layer using log or an exponent. The f function is used to determine which distance is reported (minimum by default, but can be any other relevant function).
pseudoabsencemask(::Type{WithinRadius}, presences::SDMLayer{Bool}; distance::Number = 100.0, )Generates a mask for pseudo-absences where pseudo-absences can be within a distance (in kilometers) of the original observation. Internally, this uses DistanceToEvent. All other keyword arguments are passed to pseudoabsencemask.
pseudoabsencemask(::Type{WithoutRadius}, presences::SDMLayer{Bool}; distance::Number = 100.0, )Generates a mask for pseudo-absences where pseudo-absences can be outside of a distance (in kilometers) of the original observation. Internally, this uses DistanceToEvent. All other keyword arguments are passed to pseudoabsencemask.
pseudoabsencemask(::Type{BetweenRadius}, presences::SDMLayer{Bool}; closer::Number = 10.0, further::Number=100.0)Generates a mask for pseudo-absences where pseudo-absences can be in a band given by two distances (in kilometers) of the original observation. Internally, this uses DistanceToEvent. All other keyword arguments are passed to pseudoabsencemask.
pseudoabsencemask( ::Type{DegreesToEvent}, presences::SDMLayer{Bool}; f = minimum, absolute::Bool = false)Generates a mask for pseudo-absences using the distance to event method. Candidate cells are weighted according to their distance to a known observation, with far away places being more likely. The f function is used to determine which distance is reported (minimum by default, but can be any other relevant function). The distance is measured in degrees, and is therefore very sensitive to the projection / position.
When absolute is false (the default), the distance is measured as the absolute difference in coordinates instead of using the Euclidean distance.
pseudoabsencemask(::Type{WithinDegrees}, presences::SDMLayer{Bool}; distance::Number = 3.0, )Generates a mask for pseudo-absences where pseudo-absences can be within a distance (in degrees) of the original observation. Internally, this uses DegreesToEvent. All other keyword arguments are passed to pseudoabsencemask.
pseudoabsencemask(::Type{WithoutDegrees}, presences::SDMLayer{Bool}; distance::Number = 3.0, )Generates a mask for pseudo-absences where pseudo-absences can be outside of a distance (in degrees) of the original observation. Internally, this uses DegreesToEvent. All other keyword arguments are passed to pseudoabsencemask.
pseudoabsencemask(::Type{BetweenDegrees}, presences::SDMLayer{Bool}; closer::Number = 1.0, further::Number=3.0)Generates a mask for pseudo-absences where pseudo-absences can be in a band given by two distances (in degrees) of the original observation. Internally, this uses DegreesToEvent. All other keyword arguments are passed to pseudoabsencemask.
PseudoAbsences.backgroundpoints Function
backgroundpoints(layer::T, n::Int; kwargs...) where {T <: SimpleSDMLayer}Generates background points based on a layer that gives the weight of each cell in the final sample. The additional keywords arguments are passed to StatsBase.sample, which is used internally. This includes the replace keyword to determine whether sampling should use replacement.