4

I wanted to know if there is a way to add a buffer in the function spsample in the sp package. I am randomly selecting points within 28 polygons and would like to specific a minimum distance the points can be from each other. The examples I have found use the gBuffer function in the rgeos package, but if I am understanding the function correctly you need to supply gBuffer with a spatial dataset. I do not have a spatial dataset since I am asking spsample to generate the random samples.

Code used to generate random samples:

library(sp)
  #iterate through all polygons in survey domain shapefile and select n points from each

allocation <- sapply(1:length(info2), function(i) spsample(info2[i,],
    n=info2$Total_N[i], type='random'))

s.merged <- do.call('rbind', allocation)

ids <- sapply(slot(info2, 'polygons'), function(i) slot(i, "ID"))

npts <- sapply(allocation, function(i) nrow(i@coords))

pt_id <- rep(ids, npts)

s.final <- SpatialPointsDataFrame(s.merged, data=data.frame(poly_id=pt_id))

#use over function to get strata number for each random point
strata_assign<-over(s.final,info2)

Information about info2:

class(info2)
[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"

R information R version 3.2.1 (2015-06-18) Platform: i386-w64-mingw32/i386 (32-bit) Running under: Windows 7 x64 (build 7601) Service Pack 1

  • I have a function "sample.polygon" in the spatialEco package that will accomplish the polygon sampling much more efficiently than what you have implemented. – Jeffrey Evans Feb 18 '16 at 19:36
  • How can I vary n using the sample.poly function? – user41509 Feb 18 '16 at 19:48
  • I would sample a larger number than needed. Then make a distance matrix to remove points that are to close to another point. Then remove additional points above the desired number. – Robert Hijmans Feb 19 '16 at 4:28
2

What you want to do (random sample, min distance, variable n) is actually a bit complicated using a random sampling framework, because it will be difficult to ensure that you always get the desired number of samples.

One way to accomplish this is to create a systematic sample spaced to your desired minimum sampling distance, intersect the resulting points with your polygons and then randomly draw the number of variable samples for each polygon.

This method does not use spsample but rather creates a systematic, evenly spaced sample (representing minimum sampling distance) using the raster package. First, we add the require packages and create some example data.

library(sp)
library(spatialEco)
library(raster)

data(meuse)
coordinates(meuse) <- ~x+y
polys <- hexagons(meuse, res = 1000)
polys@data <- data.frame(polys@data, ID=1:length(polys), 
                   Total_N=round(runif(nrow(polys),10,50),0) )
proj4string(polys) <- CRS("+init=epsg:28992")
plot(polys)

We then specify the minimum sampling distance (in this case 20), create a raster sharing the same spatial extent then coerce to asystematic point sample.

min.dist = 20
s <- raster( ext = extent(polys), res = min.dist )
s <- rasterToPoints(s, spatial=TRUE)
s <- SpatialPointsDataFrame(s, data.frame(ID=1:length(s)))
  proj4string(s) <- CRS("+init=epsg:28992")

Using the spatialEco::point.in.poly function we assign polygon attributes and simultaneously subsetting to the polygons. To create the variable sample for each polygon we use and for loop and the sample function to randomly sample, using the variable N contains in the data. The resulting sample is held in a list object then combined using do.call.

s <- point.in.poly(s, polys)    
samples <- list()   
  for(i in 1:nrow(polys)) {
    s.sub <- s[s$HEXID == i,]
    n = unique( s.sub$Total_N ) 
    samples[[i]] <- s.sub[sample(1:nrow(s.sub),n),]
}
samples <- do.call("rbind", samples)

He we can check the resulting variable sample sizes and the distance constraint.

unique(samples$Total_N)
tapply( samples$ID, samples$HEXID, length) 

d <- spDists(samples)
diag(d) <- NA
min(d, na.rm=T)

Finally, we can plot the polygons and resulting samples.

plot(polys)
  plot(samples, pch=20, cex=0.50, add=TRUE)

The one issue here is that the samples will be aligned to the original sampling grid. To mitigate this a bit you could wrap this in a for loop and redo it for each subset polygon. This would realign the extent for each polygon and break up the alignment of your sample through the study area.

If you do not care about loosing samples and want to keep with a random sample then you could use a distance matrix to do something like this.

min.dist = 20
s <- list()
  for(i in 1:nrow(polys)) {
    s[[i]] <- spsample(polys[i,], n = polys[i,]$Total_N, type = "random")
    d <- spDists(s[[i]])
      diag(d) <- NA
    rm.dmin <- which(apply(d, MARGIN=1,min, na.rm=TRUE) <= min.dist)
      if(length(rm.dmin) > 0 ) s[[i]] <- s[[i]][-rm.dmin,]
        cat(i,length(s[[i]]),"\n")
}
s <- do.call("rbind", s)
  • I did look at that post, but wasn't sure it applied to my situation. I do not have any coordinates for points to start with so wasn't sure how to apply your code. The only coordinates I have are for the polygon shapes. – user41509 Feb 18 '16 at 19:52
  • Please look at help for spsample "returns an object of class SpatialPoints-class". – Jeffrey Evans Feb 18 '16 at 20:39
  • Yes - so the example you used in that post uses the meuse data which has coordinates for points associated with different variables. My data is a polygon shapefile with 28 strata. I have calculated the number of samples I need in each strata and then am using spsample to generate random points within the strata. I do not have coordinates to calculate a distance matrix until after I have generated random points. – user41509 Feb 18 '16 at 20:49
  • I updated my answer to more directly address your question. – Jeffrey Evans Feb 18 '16 at 23:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.