Skip to content

Commit 18e1ad8

Browse files
committed
BROKEN PA code
1 parent 4e47539 commit 18e1ad8

File tree

9 files changed

+165
-68
lines changed

9 files changed

+165
-68
lines changed

Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ version = "0.0.1"
55

66
[deps]
77
ArchGDAL = "c9ce4bd3-c3d5-55b8-8973-c0e20141b8c3"
8+
Distances = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7"
9+
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
810
Fauxcurrences = "a2d61402-033a-4ca9-aef4-652d70cf7c9c"
911
GBIF = "ee291a33-5a6c-5552-a3c8-0f29a1181037"
1012
GDAL = "add2ef01-049f-52c4-9ee2-e494f65e021a"
@@ -14,6 +16,7 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
1416
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
1517
SimpleSDMDatasets = "2c7d61d0-5c73-410d-85b2-d2e7fbbdcefa"
1618
SimpleSDMLayers = "2c645270-77db-11e9-22c3-0f302a89c64c"
19+
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
1720

1821
[compat]
1922
ArchGDAL = "0.9"

SimpleSDMLayers/src/SimpleSDMLayers.jl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,6 @@ include("lib/generated.jl")
3434
include("lib/basics.jl")
3535
export latitudes, longitudes, boundingbox, grid
3636

37-
include("pseudoabsences/main.jl")
38-
include("pseudoabsences/radius.jl")
39-
include("pseudoabsences/randomselection.jl")
40-
include("pseudoabsences/surfacerangeenvelope.jl")
41-
export WithinRadius, RandomSelection, SurfaceRangeEnvelope
42-
4337
include("operations/coarsen.jl")
4438
include("operations/sliding.jl")
4539
include("operations/mask.jl")
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# # Generating background points
2+
3+
# In this vignette, we will generate some background points (pseudo-absences) using the
4+
# different algorithms present in the package.
5+
6+
using SpeciesDistributionToolkit
7+
using CairoMakie
8+
9+
#
10+
11+
spatial_extent = (left = 3.032, bottom = 55.178, right = 19.687, top = 64.717)
12+
13+
#
14+
15+
rangifer = taxon("Rangifer tarandus tarandus"; strict = false)
16+
query = [
17+
"occurrenceStatus" => "PRESENT",
18+
"hasCoordinate" => true,
19+
"country" => "NO",
20+
"country" => "SE",
21+
"country" => "FI",
22+
"country" => "DE",
23+
"limit" => 300,
24+
]
25+
presences = occurrences(rangifer, query...)
26+
while length(presences) < 3000
27+
occurrences!(presences)
28+
end
29+
30+
#
31+
32+
dataprovider = RasterData(CHELSA1, BioClim)
33+
temperature = 0.1SimpleSDMPredictor(dataprovider; layer = "BIO1", spatial_extent...)
34+
35+
#
36+
37+
presence_only = mask(temperature, presences, Bool)
38+
39+
#
40+
41+
heatmap(sprinkle(presence_only)...)
42+
43+
# get a pseudo-absence
44+
45+
background = similar(presence_only, Bool)
46+
47+
# generate 200 pseudo-absences
48+
49+
for i in 1:2000
50+
pa = pseudoabsence(WithinRadius, presence_only; distance = 100.0)
51+
background[pa] = true
52+
end
53+
54+
#
55+
56+
heatmap(sprinkle(background)...)
57+
58+
scatter!(longitudes(presences), latitudes(presences))

src/SpeciesDistributionToolkit.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ module SpeciesDistributionToolkit
33
import ArchGDAL
44
import GDAL
55

6+
import Distances
7+
# TODO: call the one from Fauxcurrences when integrated
8+
const _distance_function = Distances.Haversine(6371.0)
9+
10+
import Distributions
11+
import StatsBase
12+
613
# We make ample use of re-export
714
using Reexport
815

@@ -29,6 +36,11 @@ include("integrations/datasets_layers.jl")
2936
# Integrate GBIF to the layers
3037
include("integrations/gbif_layers.jl")
3138

39+
# Functions for pseudo-absence generation
40+
include("pseudoabsences.jl")
41+
export WithinRadius, SurfaceRangeEnvelope, RandomSelection
42+
export pseudoabsence
43+
3244
# Function to turn a layer into something (Geo)Makie can use
3345
function sprinkle(layer::T) where {T <: SimpleSDMLayer}
3446
return (

src/pseudoabsences.jl

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
abstract type PseudoAbsenceGenerator end
2+
3+
struct WithinRadius <: PseudoAbsenceGenerator
4+
end
5+
6+
struct SurfaceRangeEnvelope <: PseudoAbsenceGenerator
7+
end
8+
9+
struct RandomSelection <: PseudoAbsenceGenerator
10+
end
11+
12+
function _random_point(ref, d; R = 6371.0)
13+
# Convert the coordinates from degrees to radians
14+
λ, φ = deg2rad.(ref)
15+
# Get the angular distance
16+
δ = d / R
17+
# Pick a random bearing (angle w.r.t. true North)
18+
α = deg2rad(rand() * 360.0)
19+
# Get the new latitude
20+
φ2 = asin(sin(φ) * cos(δ) + cos(φ) * sin(δ) * cos(α))
21+
# Get the new longitude
22+
λ2 = λ + atan(sin(α) * sin(δ) * cos(φ), cos(δ) - sin(φ) * sin(φ2))
23+
# Return the coordinates in degree
24+
return rad2deg.((λ2, φ2))
25+
end
26+
27+
function _invalid_pseudoabsence(pt, msk)
28+
isnothing(msk[pt...]) && return true
29+
msk[pt...] && return true
30+
return false
31+
end
32+
33+
function _layer_works_for_pseudoabsence(layer::T) where {T <: SimpleSDMLayer}
34+
@assert SimpleSDMLayers._inner_type(layer) <: Bool
35+
n_occ = sum(layer)
36+
return iszero(n_occ) && throw(ArgumentError("The presences layer is empty"))
37+
end
38+
39+
function _return_point_as_grid(pt, layer)
40+
cart = SimpleSDMLayers._point_to_cartesian(layer, Point(pt...))
41+
rtpt = Point((longitudes(layer)[cart[2]], latitudes(layer)[cart[1]]))
42+
return rtpt
43+
end
44+
45+
"""
46+
pseudoabsence
47+
48+
This method generates a possible pseudo-absence location around known observations in a Boolean layer. The observations are generated in a radius expressed in *kilometers* around the known presences. To generate many background points, call this method multiple times.
49+
"""
50+
function pseudoabsence(
51+
::Type{WithinRadius},
52+
presences::T;
53+
distance::Number = 100.0,
54+
) where {T <: SimpleSDMLayer}
55+
_layer_works_for_pseudoabsence(presences)
56+
k = rand(keys(presences))
57+
newpt = _random_point(k, sqrt(rand()) * distance)
58+
while _invalid_pseudoabsence(newpt, presences)
59+
newpt = _random_point(k, sqrt(rand()) * distance)
60+
end
61+
return _return_point_as_grid(newpt, presences)
62+
end
63+
64+
function pseudoabsence(
65+
::Type{SurfaceRangeEnvelope},
66+
presences::T,
67+
) where {T <: SimpleSDMLayer}
68+
_layer_works_for_pseudoabsence(presences)
69+
bbox = SpeciesDistributionToolkit.boundingbox(replace(presences, false => nothing))
70+
londist = Distributions.Uniform(bbox.left, bbox.right)
71+
latdist = Distributions.Uniform(bbox.bottom, bbox.top)
72+
newpt = (rand(londist), rand(latdist))
73+
while _invalid_pseudoabsence(newpt, presences)
74+
newpt = (rand(londist), rand(latdist))
75+
end
76+
return _return_point_as_grid(newpt, presences)
77+
end
78+
79+
function pseudoabsence(
80+
::Type{RandomSelection},
81+
presences::T,
82+
) where {T <: SimpleSDMLayer}
83+
_layer_works_for_pseudoabsence(presences)
84+
bbox = SpeciesDistributionToolkit.boundingbox(presences)
85+
londist = Distributions.Uniform(bbox.left, bbox.right)
86+
latdist = Distributions.Uniform(bbox.bottom, bbox.top)
87+
newpt = (rand(londist), rand(latdist))
88+
while _invalid_pseudoabsence(newpt, presences)
89+
newpt = (rand(londist), rand(latdist))
90+
end
91+
return _return_point_as_grid(newpt, presences)
92+
end

src/pseudoabsences/main.jl

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/pseudoabsences/radius.jl

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/pseudoabsences/randomselection.jl

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/pseudoabsences/surfacerangeenvelope.jl

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)