Screen Points by Proximity
Problem
You want to remove points from a SpatialPointsDataframe that are too close to other points.
Solution
The following example illustrates how to screen points from a built-in example dataset that are closer than 150 meters from another point.
"OutputPoints" is the resulting SpatialPointsDataframe produced.
#This code removes points from a SpatialPointsDataFrame that do not meet a user-specified proximity #rule, i.e., tosses out points that are within some specified distance of another point in the same #SpatialPointsDataFrame. #Note that this code is not necessarily optimized, meaning it may be possible to remove points in a #different order that would result in fewer points having to be removed. #Load required packages require(sp) #for handling spatial data types require(rgeos) #for the gDistance function #Load example data for use as InputPoints data(meuse) #Part of sp package coordinates(meuse) <- ~x+y #Make SpatialPointsDataframe InputPoints <- meuse #Save as InputPoints head(InputPoints@data) #View first few lines of data slot plot(InputPoints, pch=1) #Plot to visualize

#Specify the minimum distance points can be from eachother MinDist <- 150 #unit is meters for projected coordinate systems #Create a temp.id column used later in data.frame manipulation InputPoints@data$temp.id<- 1:nrow(InputPoints) #Create a complete distance matrix d<- gDistance(InputPoints, byid=TRUE) #uses rgeos package #Remove the 0s on the diagonal (distance of point to itself) d[row(d) == col(d)] <- NA #Loop through each point and determine which points are within MinDist outDF<- data.frame() for(i in 1:nrow(d)){ d.match<- unique(which(d[i,]<MinDist)) if(length(d.match)>0){ outDF<- rbind(outDF, data.frame(inPt=i, closePt=paste(d.match, collapse=","))) }#close if statement }#close for loop #Loop through each close point and remove points as needed to produce OutputPoints outDF$closePt<- as.character(outDF$closePt) #Adjust data type in outDF OutputPoints<- InputPoints #Copy InputPoints to OutputPoints for(i in 1:nrow(outDF)){ #First check to see if current outDF point still exists in the OutputPoints dataset if(!is.na(match(outDF$inPt[i], OutputPoints$temp.id))){ #Point still exists in the dataset, so remove the other points that are too close kill<- which(OutputPoints@data$temp.id %in% unlist(strsplit(outDF[i,2], ","))) if(length(kill)>0){ OutputPoints<- OutputPoints[-kill,] }#close inner if statement }#close outer if statement }#close for loop #Plot to visualize plot(InputPoints, col="dark gray", pch=1) #started with 155 points in example plot(OutputPoints, col="green", pch=20, add=TRUE) #83 retained in example legend("topleft", cex = 1.2, bty = "n", legend = c("InputPoints", "OutputPoints"), col = c("gray", "green"), pch = c(1,20))

#Print summary of the fraction of InputPoints retained in OutputPoints print(paste(nrow(OutputPoints), " (or", round((nrow(OutputPoints)/nrow(InputPoints))*100, 1), "%) of your original points were retained.", sep=""),quote=FALSE) #Test to make sure no points are now too close in OutputPoints g<- gDistance(OutputPoints, byid=TRUE) #Uses rgeos package g[row(g) == col(g)] <- NA #Remove the 0s on the diagonal min(g, na.rm=TRUE) #Print the minimum distance between points #Remove temporary data created in the process rm(d,g,outDF,MinDist,d.match,i,kill)
Notes
Shannon Albeke, Jason Carlisle, and Dylan Perkins contributed to the development of this tool.