ropensci / NLMR

📦 R package to simulate neutral landscape models 🏔
https://ropensci.github.io/NLMR/
65 stars 17 forks source link

function to create random points given a certain NLM #84

Open bniebuhr opened 2 years ago

bniebuhr commented 2 years ago

Hi,

I would like to suggest a feature: the possibility to simulate points in space that use a given nlm as input for defining the weights or probabilities of simulating a point in a given location. Often it is useful to have spatial point patterns to test or create hypothesis or models, and having the flexibility of the nlm's created through NLMR as a basis for that would be great!

Here is a suggestion of implementation that I am currently using in a working package right now. It seems to work well and is simple.

#' Simulate points using input raster as weights 
#'
#' This function simulate point patterns in space using the values of
#' an input raster as weights or probabilities for selecting a point in a 
#' given location. It was designed to simulate points based on  neutral landscape 
#' models but it works with other input rasters as well.
#' 
#' The function works by first selecting random pixels in the landscape and 
#' finding their centers, then adding random variation within each pixel to
#' define the final point locations. 
#' It was based on this StackExchange super useful answer from "Spacedman":
#' https://gis.stackexchange.com/questions/224321/randomly-generate-points-using-weights-from-raster
#'
#' TO IMPROVE: implement with terra package
#'
#' @param n_features `[integer(1)=1000]` \cr Total number of features to spread in space.
#' @param base_raster `[RasterLayer]` \cr Input raster used for defining the weights.
#'
#' @returns The coordinates (x,y) of the simulated points.
#'
#' @example examples/set_points_from_raster_example.R
#'
#' @export

# function to simulate points using input raster as weights 
set_points_from_raster <- function(base_raster, n_features = 1000) {

  # get parameters
  res = raster::res(base_raster)

  # random points in the center of the cells
  ptscell <- sample(1:length(base_raster), n_features, prob = base_raster[], replace = TRUE)
  # get the centers
  center <- raster::xyFromCell(base_raster, ptscell)
  # add random values within the pixels
  pts <- center + cbind(runif(nrow(center), - res[1]/2, res[1]/2),
                        runif(nrow(center), - res[2]/2, res[2]/2))

  # return the points
  data.frame(pts)
}

And here are some examples of use for the function.

#-----
# minimal example

# example based on
# https://gis.stackexchange.com/questions/224321/randomly-generate-points-using-weights-from-raster
library(raster)
library(landscapetools)
library(ggplot2)

# raster
set.seed(12)
r <- raster::raster(matrix(runif(12),3,4))

# points
pts <- set_points_from_raster(r, n_features = 300)

# plot
landscapetools::show_landscape(r) +
  geom_point(aes(x, y), data = pts)

image

#-----
# using NLMR
library(NLMR)

# example NLM
set.seed(123)
nlm1 <- NLMR::nlm_mpd(100, 100, 100, roughness = .5)

# points
pts <- set_points_from_raster(nlm1, n_features = 1000)

# plot
landscapetools::show_landscape(nlm1) +
  geom_point(aes(x, y), data = pts)

image

Tell me what you think. We can build upon this implementation, I can also make a pull request if this is interesting.