Search code examples
rspatialr-spspatstat

R function for creating discs around each point in a pattern, then counting number of points in each disc [spatial]


I am attempting to create a disc for each point in a pattern; each disc will have the same radius. Then for each disc, I want to count the number of points falling within the disc. Each pattern has 100-400 points. I have written code to do this, but it is quite slow. The code is below. I cannot provide the shapefile and points as that would be very difficult, but I could create some dummy data if need be.


  W <- as.owin(shape) 
  #Converts created .shp file into a "window" 
  #in which everything is plotted and calculated
  SPDF <- SpatialPointsDataFrame(P[,1:2], P) 
  #Converts data frame to spatial points data frame
  SP <- as(SPDF, "SpatialPoints") #Converts SPDF to spatial points
  SP1  <- as.ppp(coordinates(SP), W)

  SP2 <- as.ppp(SP1)

  attr(SP1, "rejects")
  attr(SP2, "rejects")  



  aw <- area.owin(W) #Area, in pixels squared, of leaf window created earlier
  #awm <- aw * (meas)^2 * 100 #Area window in millimeters squared

  # Trichome_Density_Count-----------------------------------------------------------------------------------------------

  TC <- nrow(P) #Counts number of rows in XY data points file,
  #this is number of trichomes from ImageJ

  TD <- TC/awm #Trichome density, trichomes per mm^2




#SPDF2 <- as.SpatialPoints.ppp(SP2)


#kg <- knn.graph(SPDF2, k = 1) 
#Creates the lines connecting each NND pairwise connection
#dfkg <- data.frame(kg) #Converts lines into a data frame
#dfkgl <- dfkg$length

meanlength <- 78

discstest <- discs(SP2, radii = meanlength, 
                   separate = TRUE, mask = FALSE, trim = FALSE,
                   delta = NULL, npoly=NULL) 
#Function creates discs for each trichome
#Using nearest neighbor lengths as radii


#NEED TO ADD CLIPPING

ratiolist <- c()

for (i in 1:length(discstest)) {



  ow2sp <- owin2SP(discstest[[i]])

  leafsp <- owin2SP(W)

  tic("gIntersection")

  intersect <-  rgeos::gIntersection(ow2sp, leafsp)

  Sys.sleep(1)
  toc()


  tic("over")


  res <- as.data.frame(sp::over(SP, intersect, returnList = FALSE))

  Sys.sleep(1)
  toc()

  res[is.na(res)] <- 0

  newowin <- as.owin(intersect)

  circarea <- area.owin(newowin)

  trichactual <- sum(res)

  trichexpect <- (TC / aw) * circarea

  ratio <- trichactual / trichexpect


  ratiolist[[i]] <- ratio


}

Solution

  • If I understand you correctly you want to loop through each point and check how many points fall within a disc of radius R centered in that point. This is done very efficiently in spatstat with the function closepaircounts:

    closepaircounts(SP2, r = meanlength)
    

    This simply returns a vector with the number of points contained in the disc of radius r for each point in SP2.

    I have just tried this for 100,000 points where each point on average had almost 3000 other points in the disc around it, and it took 8 seconds on my laptop. If you have many more points or in particular if the disc radius is so big that each disc contains many more points it may become very slow to calculate this.