0

I'm working with spatstat package in R. I have marked point patterns with mark variables Name, boxA, boxB. BoxA and boxB are dimensions of a rectangle around each point (bounding boxes). here is an example:

>split(u) # splits pattern in two classes of cells accord. to Name

Point pattern split by factor
 
negat:
Marked planar point pattern: 843917 points
Mark variables: Name, boxA, boxB 
window: rectangle = [3164, 66924] x [25085, 84325] units

posit:
Marked planar point pattern: 93569 points
Mark variables: Name, boxA, boxB 
window: rectangle = [3164, 66924] x [25085, 84325] units

I want to delete points which lay inside the bounding boxes of other points. Previously I did it using closepairs and crosspairs and a fixed radius for neighbouring points like this:

for (i in 1:length(names(u))) {
  if (names(u)[i] == "posit"){ R <- 20 }else{R <- 13} 
     close_list = closepairs(u[[i]], rmax = R, twice = FALSE)
     close_index <- close_list$j
        if(is.empty(close_index) == F){ u[[i]] <- u[[i]][-close_index] } 
                               }
  close_list <- NULL
  close_list = crosspairs(u$negat, u$posit, 13)
  close_index <- close_list$i
  if(is.empty(close_index) == F){u$negat <- u$negat[-close_index]}

I used different radius for both classes of points because their bounding boxes differed in size. However now I have points with very different boxes within each class. Is where a build-in function in spatstat to determine radius for the "close_list" for each point individually according to boxA or boxB or even to use for each point rectangles with their box dimensions instead of circles?

@Adrian Baddeley offered a solution below to which I added a nested loop to find the numbers of points with overlapping boxes. Here is a small working example in which bounding boxes of points 3 and 4 overlap too much:

# pattern
X<-as.ppp(cbind(c(1,2.5,2,3),c(1,1,3,3)),c(0,5,0,5))

# marks (size of the bounding boxes (BB) around points)
M<-cbind("boxA"=c(1.5,2,4,3),"boxB"=c(1.5,2,4,3))
M<-as.data.frame(M)
X$marks<-M

# find and delete points inside BB of other points
df <- as.data.frame(X)
dx <- with(df, outer(x, x, "-"))
dy <- with(df, outer(y,y,"-"))
conflict <- (abs(dx) < df$boxA/2) & (abs(dy) < df$boxB/2)
diag(conflict) <- FALSE
conflict[upper.tri(conflict)] <- FALSE 
index<-c()
for(i in 1:dim(conflict)[1]){
   for(j in 1:dim(conflict)[2]){
      if(conflict[i,j] == TRUE){
      index <- c(index, i)}
   }
}
X<-X[-index]

This works fine with the small test pattern. I'll test it on real data though.

Sergej S
  • 37
  • 4
  • I don't quite understand what you are trying to achieve. Could you make a small reproducible example showing input and wanted output? Or maybe attach a figure/drawing explaining it. – Ege Rubak Jun 27 '23 at 00:04

1 Answers1

1

If all the boxes have the same aspect ratio (ratio of height to width) then you could use nndist.ppp or pairdist.ppp or nncross.ppp using the argument metric to specify a rectangular distance metric (see the help file and examples for convexmetric). For example if the aspect ratio is 1.5 then

m <- convexmetric(owin(c(-1,1)/2, c(-1.5, 1.5)/2)
D <- pairdist(X, metric=m)

gives you the rectangular distances between all pairs of points.

If the boxes can have different aspect ratios, then there is no existing support in spatstat for this calculation. I would recommend converting the point pattern data to a data frame using as.data.frame and then using outer to perform the calculation.

Adrian Baddeley
  • 2,534
  • 1
  • 5
  • 8
  • Thank you very much for the advice! I will have to play with these new possibilities to understand, how to use it. The boxes have different aspect ratios, e.g. median 1.1 range 0.2-5.9. – Sergej S Jun 27 '23 at 10:34
  • 1
    Then do something like `df <- as.data.frame(X)`; `dx <- with(df, outer(x, x, "-"))`; `dy <- with(df, outer(y,y,"-"))`; `conflict <- (abs(dx) < df$boxA/2) & (abs(dy) < df$boxB/2)`; `diag(conflict) <- FALSE`. Then `conflict[i,j]` is true if point j falls inside the box centred on point i. – Adrian Baddeley Jun 29 '23 at 02:58