1
votes

I have two separate but related questions.

First, I would like to determine the distance to the nearest construction site (construction_layer.csv) for every data point within the subset_original_data.csv file. I am trying to use the gDistance() function to calculate the nearest neighbor, but I am open to other ideas as well.

I want to append my subset_original_data.csv dataframe with this new vector of nearest neighbor distances from the construction_layer.csv. That is, for every row of my subset_original_data.csv dataframe, I want the minimum distance to the nearest construction site.

The second goal is to determine the nearest distance from each subset_original_data.csv row to a freeway shapefile (fwy.shp). I would also like to append this new vector back onto the subset_original.csv dataframe.

I have successfully converted the construction_layer.csv and subset_original_data.csv into SpatialPointsDataFrame. I have also converted the fwy.shp file into a SpatialLinesDataFrame by reading in the shape file with the readOGR() function. I am not sure where to go next. Your input is greatly appreciated!

~ $ spacedSparking

Here's my data: construction_layer.csv, fwy.shp, subset_original_data.csv

Here's my code:

#requiring necessary packages:
library(rgeos)
library(sp)
library(rgdal)

#reading in the files:
mydata <- read.csv("subset_original_data.csv", header = T)
con <- read.csv("construction_layer.csv", header = T)
fwy <- readOGR(dsn = "fwy.shp")

#for those who prefer not to download any files:
data.lat <- c(45.53244, 45.53244, 45.53244, 45.53244, 45.53245, 45.53246)
data.lon <-  c(-122.7034, -122.7034, -122.7034, -122.7033, -122.7033, -122.7032)
data.black.carbon <- c(187, 980, 466, 826, 637, 758)
mydata <- data.frame(data.lat, data.lon, data.black.carbon)

con.lat <- c(45.53287, 45.53293, 45.53299, 45.53259, 45.53263, 45.53263)
con.lon <- c(-122.6972, -122.6963, -122.6952, -122.6929, -122.6918, -122.6918)
con <- data.frame(con.lat, con.lon)

#I am not sure how to include the `fwy.shp` in a similar way, 
#so don't worry about trying to solve that problem if you would prefer not to download the file.

#convert each file to SpatialPoints or SpatialLines Dataframes:
mydata.coords <- data.frame(lon = mydata[,2], lat = mydata[,1], data = mydata)
mydata.sp <- sp::SpatialPointsDataFrame(mydata.coords, data = data.frame(BlackCarbon = mydata[,3])) #appending a vector containing air pollution data

con.coords <- data.frame(lon = con[,2], lat = con[,1])
con.sp <- sp:SpatialPointsDataFrame(con.coords, data = con)

str(fwy) #already a SpatialLinesDataFrame

#Calculate the minimum distance (in meters) between each observation between mydata.sp and con.sp and between mydata.sp and fwy objects. 

#Create a new dataframe appending these two nearest distance vectors back to the original mydata file. 

#Desired output:
head(mydata.appended)
  LATITUDE LONGITUDE  BC6. NEAREST_CON (m) NEAREST_FWY (m)
1 45.53244 -122.7034  187  ???              ???
2 45.53244 -122.7034  980  ???              ???
3 45.53244 -122.7034  466  ???              ???
4 45.53244 -122.7033  826  ???              ???
5 45.53245 -122.7033  637  ???              ???
6 45.53246 -122.7032  758  ???              ???   

EDIT:

SOLUTION: When in doubt, ask a friend who is an R wizard! He even made a map.

library(rgeos)
library(rgdal)
library(leaflet)
library(magrittr)

#Define Projections
wgs84<-CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0")
utm10n<-CRS("+proj=utm +zone=10 +ellps=GRS80 +datum=NAD83 +units=m +no_defs +towgs84=0,0,0")

#creating example black carbon data by hand:
lat <- c(45.5324, 45.5325, 45.53159, 45.5321, 45.53103, 45.53123)
lon <- c(-122.6972, -122.6963, -122.6951, -122.6919, -122.6878, -122.6908)
BlackCarbon <- c(187, 980, 466, 826, 637, 758)
bc.coords <- data.frame(lat, lon, BlackCarbon)
bc<-SpatialPointsDataFrame(data.frame(x=lon,y =lat),data=data.frame(BlackCarbon),proj4string = wgs84)

#  Project into something - Decimal degrees are no fun to work with when measuring distance!
bcProj<-spTransform(bc,utm10n)

#creating example construction data layer:
con.lat <- c(45.53287, 45.53293, 45.53299, 45.53259, 45.53263, 45.53263)
con.lon <- c(-122.6972, -122.6963, -122.6952, -122.6929, -122.6918, -122.6910)
con.coords <- data.frame(con.lat, con.lon)
con<-SpatialPointsDataFrame(data.frame(x=con.lon,y =con.lat),data=data.frame(ID=1:6),proj4string = wgs84)
conProj<-spTransform(con,utm10n)

#All at once (black carbon points on top, construction on the y-axis)
dist<-gDistance(bcProj,conProj,byid=T)

min_constructionDistance<-apply(dist, 2, min)

# make a new column in the WGS84 data, set it to the distance
# The distance vector will stay in order, so just stick it on!
bc@data$Nearest_Con<-min_constructionDistance
bc@data$Near_ID<-as.vector(apply(dist, 2, function(x) which(x==min(x))))

#Map the original WGS84 data
pop1<-paste0("<b>Distance</b>: ",round(bc$Nearest_Con,2),"<br><b>Near ID</b>: ",bc$Near_ID)
pop2<-paste0("<b>ID</b>: ",con$ID)
m<-leaflet()%>%
  addTiles()%>%
  addCircleMarkers(data=bc,radius=8,fillColor =   'red',fillOpacity=0.8,weight=1,color='black',popup=pop1)%>%
  addCircleMarkers(data=con,radius=8,fillColor = 'blue',fillOpacity=0.8,weight=1,color='black',popup=pop2)
m
1
Generally it's more appropriate to create an example dataset in your question, rather than attaching it - I can't speak for others but I'm not keen on downloading files from unknown sourcesSymbolixAU
That's understandable. I will try and figure out how to include sample data within the post.philiporlando
You can also make use of in-built datasets, such as the meuse one from the sp package : data("meuse")SymbolixAU
Thanks, I will keep that in mind for future posts. In this case, I'd still need an additional dataset to calculate nearest distances between two points. I ended up creating some example data by hand, although I am unable to do this for the shapefile unfortunately.philiporlando

1 Answers

1
votes

You can use the a haversine distance function and use functional programming to achieve the desired result.

library(geosphere)
find_min_dist <- function(site, sites) {
  min(distHaversine(site, sites))
}
#X is the data id, split into a list so you can iterate through each site point
data <- split(mydata[ , 3:2], mydata$X)
sapply(data, find_min_dist, sites = con.coords)