Skip to content

Masking a layer

The process of masking refers to turning cells on a layer's grid to off, which will result in them being excluded from the analysis/display.

There are two ways to mask a layer – using the nodata! approach, and using the mask! approach. We use nodata! when working from a single layer, and mask! when using data stored in a second layer. Note that both approaches have a non-mutating version (nodata and mask, that return a modified copy of their layer).

julia
using SpeciesDistributionToolkit
using Dates, Statistics
using CairoMakie
Precompiling packages...
Info Given MakieExtension was explicitly requested, output will be shown live 
WARNING: Method definition plot!(Makie.Plot{Phylopic.silhouetteplot, var"#s38"} where var"#s38"<:Tuple{AbstractArray{var"#s37", 1} where var"#s37"<:Real, AbstractArray{var"#s36", 1} where var"#s36"<:Real, AbstractArray{var"#s35", 1} where var"#s35"<:Phylopic.PhylopicSilhouette}) in module MakieExtension at /home/runner/work/SpeciesDistributionToolkit.jl/SpeciesDistributionToolkit.jl/Phylopic/ext/MakieExtension.jl:45 overwritten at /home/runner/work/SpeciesDistributionToolkit.jl/SpeciesDistributionToolkit.jl/Phylopic/ext/MakieExtension.jl:55.
ERROR: Method overwriting is not permitted during Module precompilation. Use `__precompile__(false)` to opt-out of precompilation.
   5607.4 ms  ? Phylopic → MakieExtension
WARNING: Method definition plot!(Makie.Plot{Phylopic.silhouetteplot, var"#s38"} where var"#s38"<:Tuple{AbstractArray{var"#s37", 1} where var"#s37"<:Real, AbstractArray{var"#s36", 1} where var"#s36"<:Real, AbstractArray{var"#s35", 1} where var"#s35"<:Phylopic.PhylopicSilhouette}) in module MakieExtension at /home/runner/work/SpeciesDistributionToolkit.jl/SpeciesDistributionToolkit.jl/Phylopic/ext/MakieExtension.jl:45 overwritten at /home/runner/work/SpeciesDistributionToolkit.jl/SpeciesDistributionToolkit.jl/Phylopic/ext/MakieExtension.jl:55.
ERROR: Method overwriting is not permitted during Module precompilation. Use `__precompile__(false)` to opt-out of precompilation.

We will illustrate both approaches using the CHELSA2 temperature data for the month of September.

julia
spatial_extent = (left = 8.412, bottom = 41.325, right = 9.662, top = 43.060)
temp2 =
    SDMLayer(
        RasterData(CHELSA2, AverageTemperature);
        month = Month(9),
        spatial_extent...,
    )
🗺️  A 209 × 151 layer with 31559 Float64 cells
   Spatial Reference System: +proj=longlat +datum=WGS84 +no_defs

Code for the figure
julia
heatmap(temp2, colormap=:navia, axis=(;aspect=DataAspect())) # hide

Using nodata!

When using nodata!, we can either indicate a value to remove from the layer, or pass a function. For example, we can mask the layer to remove all cells where the temperature is in the upper and lower 5%:

julia
m, M = Statistics.quantile(values(temp2), [0.05, 0.95])
nodata(temp2, v -> !(m <= v <= M))
🗺️  A 209 × 151 layer with 28449 Float64 cells
   Spatial Reference System: +proj=longlat +datum=WGS84 +no_defs

Code for the figure
julia
heatmap(nodata(temp2, v -> !(m <= v <= M)), colormap=:navia, axis=(;aspect=DataAspect())) # hide

The function given as the second argument must return true for a point that will be excluded from the layer. In other words, this behaves as the opposite of filter!.

Using mask!

A note about how this works

The SDMLayer type stores a BitMatrix (in the indices field) that tracks which cells in the raster are visible. This costs a little more memory, but allows to rapidly turn pixels on and off.

When using mask!, the first layer will be modified so that only the cells that are also valued in the second layer are used. For example, we can use the fact that the CHELSA1 layers do not have values outside of land, to mask the CHELSA2 data:

julia
temp1 =
    SDMLayer(
        RasterData(CHELSA1, AverageTemperature);
        month = Month(9),
        spatial_extent...,
    )
🗺️  A 209 × 151 layer with 14432 Int16 cells
   Spatial Reference System: +proj=longlat +datum=WGS84 +no_defs
julia
mask(temp2, temp1)
🗺️  A 209 × 151 layer with 14432 Float64 cells
   Spatial Reference System: +proj=longlat +datum=WGS84 +no_defs

Code for the figure
julia
heatmap(mask(temp2, temp1), colormap=:navia, axis=(;aspect=DataAspect())) # hide
SimpleSDMLayers.nodata! Function
julia
nodata!(layer::SDMLayer{T}, nodata::T) where {T}

Changes the value of the layer representing no data. This modifies the layer passed as its first argument.

source
julia
nodata!(layer::SDMLayer{T}, f)

Removes the data matching a function

source
julia
nodata!(layer::SDMLayer, v)

Turns off all cells containing the value v. This is an overload only applied when v is not of the correct type for layer.

source
SimpleSDMLayers.nodata Function
julia
nodata(layer::SDMLayer, args...)

Makes a copy and calls nodata! on it

source
SimpleSDMLayers.mask! Function
julia
mask!(layer::SDMLayer, template::SDMLayer)

Updates the positions in the first layer to be those that have a value in the second layer.

source
julia
SimpleSDMLayers.mask!(layer::SDMLayer, poly::T) where T<:Union{Polygon,MultiPolygon}

Turns off all the cells outside the polygon (or within holes in the polygon). This modifies the object.

source
SimpleSDMLayers.mask Function
julia
mask(layer::SDMLayer, template::SDMLayer)

Returns a copy of the first layer masked according to the second layer. See also mask!.

source

SimpleSDMLayers.mask(layer::L, feature::T) where {L<:Union{<:SDMLayer,Vector{<:SDMLayer}}, T <: Union{Feature, FeatureCollection, Polygon, MultiPolygon}}

Returns a copy of the layer by the polygon.

source
julia
SimpleSDMLayers.mask(occ::T, poly::P) where {T <: AbstractOccurrenceCollection, P<:Union{Polygon,MultiPolygon}}

Returns a copy of the occurrences that are within the polygon.

source