How to combine sf_intersects and sf_touches within a function - r

Hi All,
I'm trying to develop a function which maps point coordinates in the UK to the UK local authority areas in which they reside in.
I've developed a function using the st_intersects function of the sf package and it works to identify cases where the centroid intersects with the shapefile of a given area.
However, I also want to identify cases where the centroid actually touches the LA area boundary line.
I'm aware that where LA areas share a boundary this would map the centroid to two LAs but that's ok for my purposes.
I tried to adapt my function to include st_touches however it produces an empty table.
Would be very grateful if someone could take a look and suggest where I might be going wrong.
Reprex below:
The LA area shapefile is publicly available here (the shapefile from the downloads section):
https://geoportal.statistics.gov.uk/datasets/97a614bdcc6043bd9a3cbfbba8a1f302_0/explore?location=55.230176%2C-3.316939%2C6.92
The set of long/lat coordinates to map:
data = structure(list(longitude = c(-2.87481491108804, -2.87127368026435,
-2.96479539064797, -2.92511948140495, -3.01836788419, -2.98402990798746,
-2.9077264274875, -2.89347586558879, -2.97850780890271, -3.02924916756829,
-3.05411812798672, -2.93694678850526, -2.88306663657761, -2.9845903484732,
-3.05984423623939, -2.90909675996297, -2.92181750227365, -3.02464633153093,
-3.02123789197677, -3.09890063032602, -2.96844903903745, -2.86785459942595,
-2.9321154435321, -3.10888230637966, -2.97222428832271, -2.89647987410202,
-3.03027882189321, -2.97866205698605, -2.99429382433499, -3.05246646242959,
-2.89616224682703, -2.98563264041128, -2.95302953391751, -2.91151041579422,
-2.97953110815078, -3.10796669571098, -2.94570764658262, -2.97301831593517,
-2.89323494964768, -2.97063026715387, -2.92198857953645, -3.03675565980253,
-2.83891728241267, -2.91861697258726, -3.06892905484705, -2.99398588944906,
-2.93551831989608, -2.82716052265689, -3.01724727594163, -2.92682901324458,
-2.91803014985187, -2.99284666045525, -2.97786793943296, -2.9230445053825,
-2.95481455034888, -2.93676036122089, -2.96585002429569, -2.86998042564442,
-2.93970334000959, -2.98376964052552, -2.87448694998545, -2.95369805041689,
-2.877566853416, -2.99224636258483, -3.09026039652281, -2.95817525261748,
-2.95017575249327, -2.94359797634677, -2.96710539009414, -3.07792734952214,
-3.17993626061202, -2.97741036119629, -2.95222841522805, -2.95965218909241,
-2.9459062849359, -2.86310994503288, -3.03906859820527, -3.02177819639329,
-2.97166265836844, -3.08145848394861, -3.03808462354296, -2.96263651468074,
-2.95851898803173, -3.02221082538059, -2.89362064147485, -2.8993882625834,
-2.92770961205626, -2.96369118745873, -2.89571920584541, -3.09314291426038,
-3.0919937117765, -3.03611523902419, -2.93117415659881, -2.97460696743252,
-2.85036432827623, -2.94987226425819, -2.95390181653767, -2.91019481240696,
-2.99966589456369, -2.93169619777761, -3.08411731249804, -3.1706199707398,
-2.91896769518433, -2.97090655977713, -3.11395127242533, -3.04781510226649,
-3.18378788354865, -2.90075209953503, -2.93948388571496, -2.98732033573349,
-2.96611890948035, -2.87803392597212, -3.02717324311628, -2.90642650501013,
-3.0181126772633, -2.98716889544258, -2.95609545040814, -2.89457583588837,
-2.9183348068514, -2.88807533717785, -3.02947911076491, -2.98582946684398,
-2.90956913387858, -2.92612896591959, -2.8618485532865, -2.93181934586936,
-2.99086525128266, -2.88799987536917, -3.18188458893135, -2.92530589829918,
-2.84517946221428, -3.02066308251878, -2.943131290944, -2.9316549262618,
-2.89416059133544, -3.03093156077094, -3.03954865354919, -3.02892322932484,
-3.15157580297919, -2.97019350603118, -2.95926518021845, -3.12995261693527,
-3.0178786559463, -2.96998299026556, -2.92983501387733, -2.91526010044323,
-2.98893750456704, -2.93303968342649, -2.97826195863277, -3.10231870679243,
-2.86918162475871, -2.94860479427078, -2.89593919501248, -3.04120959095772,
-3.08974718532665, -3.05135478822517, -2.98129768711627, -3.03665798566578,
-2.89429626072004, -2.92008555617904, -2.87339557195832, -2.89374834459854,
-2.97879863154011, -2.95902409390154, -2.8950914531408, -2.96902081781808,
-2.95976145407803, -2.92255923707144, -3.05150511302466, -3.05903671872711,
-2.95262009289705, -3.00863929575895, -3.0547892173777, -3.03276242335601,
-2.84477534615073, -3.11863250997746, -3.03915412086859, -2.93123288923061,
-3.11376765617702, -3.15438194594307, -3.02283334806073, -2.95561312619315,
-3.02508648595712, -3.15483442747855, -2.96632534070746, -2.98706717919529,
-2.86455911629215, -2.97919924773756, -3.14477357952329, -2.91786092204208,
-3.048045603786, -2.92396930828526, -2.87962098053312, -2.93684151727313,
-3.11262802664107, -2.90201460498108, -2.94757682014421, -2.97896151794228,
-2.98981135039931, -2.95833097373606), latitude = c(53.4379570197908,
53.4201221364593, 53.3942986189115, 53.3842844842061, 53.3617791885161,
53.4151651024398, 53.4508620255715, 53.3939173214826, 53.4064101823484,
53.3718255079932, 53.4378662280985, 53.4375126675335, 53.4206467370139,
53.4029535199428, 53.4259950343029, 53.4140285695349, 53.3888028546485,
53.3879553701277, 53.383130581584, 53.3980816902538, 53.4094946698524,
53.4280841646817, 53.4251728245991, 53.4065738999879, 53.4338598436095,
53.4259310929223, 53.3889496585032, 53.3412480513966, 53.4088327587453,
53.4282695483082, 53.3714698780691, 53.3992414758791, 53.4283426004897,
53.3694659558339, 53.4034617561608, 53.3852333876622, 53.4307199421458,
53.4145901432611, 53.3443452440954, 53.3896653425554, 53.408541145569,
53.4215685101068, 53.3869120986626, 53.3861128798233, 53.4347861533497,
53.4001430176595, 53.3902962809302, 53.3444171680078, 53.3626786684076,
53.3737795084725, 53.4356820437825, 53.4061211555453, 53.4062807459519,
53.4440809390267, 53.4300901595633, 53.4454602665698, 53.4136326339338,
53.3744591704793, 53.4266774115989, 53.4103300396462, 53.4245895519719,
53.4252630671781, 53.4012893604736, 53.4258121557628, 53.3283517163451,
53.4296137958026, 53.3894613832297, 53.3911944946134, 53.4311598021066,
53.4019404403309, 53.3660259655574, 53.4066620280597, 53.4052301130645,
53.4610898898285, 53.3834008004254, 53.396693596265, 53.3732415469181,
53.3830899845843, 53.4145203148397, 53.384011307051, 53.385933567503,
53.4418746881753, 53.3893676837379, 53.3754186100903, 53.3477042237358,
53.4268260826889, 53.4529736611373, 53.4009301384742, 53.4255412928395,
53.3799946476186, 53.3832592444011, 53.4280280487181, 53.4371892773805,
53.3873993179818, 53.387265880647, 53.4311902629893, 53.4000835375925,
53.416299149301, 53.3472942931141, 53.4335267442322, 53.3780004976281,
53.3901906552793, 53.3856427565351, 53.4064274548061, 53.3915868687672,
53.3988915899388, 53.38243801477, 53.3582036174684, 53.4310567146736,
53.4071737491274, 53.4613164150686, 53.4509761373123, 53.3767513171219,
53.4386111541956, 53.3813234955064, 53.4115730142442, 53.4690375638476,
53.3925877169023, 53.4149064630925, 53.4378681311582, 53.363283937878,
53.3439845549594, 53.3919170930087, 53.4003921305836, 53.3729720867359,
53.3971837533247, 53.4043577837836, 53.4356933993701, 53.3940528400041,
53.4497743100287, 53.3896667782373, 53.4087450666446, 53.4421561637244,
53.4419585659703, 53.3476642223286, 53.3773841273259, 53.4318096029357,
53.359549289032, 53.3954996343164, 53.4603395616878, 53.3790873492044,
53.3995806276861, 53.3923100412117, 53.4610154343059, 53.4344581137143,
53.4181570758271, 53.4185223637193, 53.3972820875749, 53.402475229261,
53.4081268716824, 53.4237868466879, 53.3959009588377, 53.4045147184146,
53.4117047911735, 53.3747671044637, 53.4265465099582, 53.3173604267677,
53.3853886811948, 53.4071671211117, 53.4458146150033, 53.4509562137809,
53.3545258760886, 53.4081608055445, 53.4639623704057, 53.4066875108909,
53.4326544056812, 53.3958027859543, 53.378011861023, 53.4143471677853,
53.3916913284024, 53.3831046999105, 53.3526121691896, 53.424242035722,
53.4170165452222, 53.3426757282892, 53.3946264472929, 53.4299953680367,
53.3730800431989, 53.3787971976028, 53.3974951074273, 53.3894123258524,
53.4079890811827, 53.3898479198151, 53.4014279834277, 53.4445415555092,
53.4092342886507, 53.3858335487274, 53.4380366162007, 53.4083295907901,
53.4145595413981, 53.4247867968646, 53.4332901497374, 53.4017057070297,
53.4238324512685, 53.3875542058095, 53.3639110429771, 53.4288174617707,
53.3844646095652, 53.4258501205813, 53.4004076184837)), row.names = c(NA,
-200L), class = c("tbl_df", "tbl", "data.frame"))
Loading the shapefile
library(dplyr)
library(data.table)
library(sf)
library(purrr)
shapefile <- sf::read_sf("downloads/LAD_MAY_2021_UK_BFC.shp")
The function with st_intersects only (works):
getBuildings <- function(data, shapefile) {
shapefile <- sf::st_transform(shapefile, crs = 4326)
pnts_sf <- sf::st_as_sf(data, coords = c('longitude', 'latitude'), crs = sf::st_crs(shapefile))
locations_by_area<- pnts_sf %>%
dplyr::mutate(
intersection = as.integer(sf::st_intersects(geometry, shapefile$geometry))
, LAD21NM = dplyr::if_else(is.na(intersection), '', shapefile$LAD21NM[intersection])
) %>%
data.table::setDT() %>%
dplyr::mutate(latitude = unlist(purrr::map(geometry,2)),
longitude = unlist(purrr::map(geometry,1)))
locations_by_area
}
results = getBuildings(data = data, shapefile = shapefile)
The function with st_touches (doesn't provide any results):
getBuildings <- function(data, shapefile) {
shapefile <- sf::st_transform(shapefile, crs = 4326)
pnts_sf <- sf::st_as_sf(data, coords = c('longitude', 'latitude'), crs = sf::st_crs(shapefile))
locations_by_area<- pnts_sf %>%
dplyr::mutate(
intersection = as.integer(sf::st_intersects(geometry, shapefile$geometry))
touch = as.integer(sf::st_touches(geometry, shapefile$geometry))
, LAD21NM = dplyr::if_else(is.na(intersection), '', shapefile$LAD21NM[intersection])
, LAD21NM2 = dplyr::if_else(is.na(touch), '', shapefile$LAD21NM[touch])
) %>%
data.table::setDT() %>%
dplyr::mutate(latitude = unlist(purrr::map(geometry,2)),
longitude = unlist(purrr::map(geometry,1)))
locations_by_area
}
results = getBuildings(data = data, shapefile = shapefile)
The end result I'm looking for is a table of the original coordinates with another column indicating which LA area they reside in and another column indicating which LA the centroid touches the border of (I'm guessing there would be two rows for some centroids where they touch a border shared by two LA areas).
Any help would be greatly appreciated, please and thank you.

Related

Creating a route from a list of points and Overlaying the route (list of points) on the road segment/ road network in R

I have a road network shapefile and list of points. I have to create a route from the list of points and then overlay/ spatially join (integrate the attributes of points that are overlaying the road segments)
The sample road network shape file can be found here https://drive.google.com/drive/folders/103Orz6NuiWOaFoEkM18SlzFTjGYi1rju?usp=sharing
The following is the code for points with lat (x) and long (y) information. The "order" column means, the order of destinations in the route .
points <-tribble (
~x,~y, ~order,
78.14358, 9.921388,1,
78.14519, 9.921123,2,
78.14889, 9.916954,3,
78.14932, 9.912807,4,
78.14346, 9.913828,5,
78.13490, 9.916551,6,
78.12904, 9.918782,7
)
What I want as an output is a layer of the route joining all the points in the order as mentioned. And I also want to integrate/ do a spatial join of the route to the road segments.
Thanks in advance
The following answer is based on the R package sfnetworks which can be installed as follows:
install.packages("remotes")
remotes::install_github("luukvdmeer/sfnetworks")
First of all, load packages
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(sfnetworks)
library(tidygraph)
and data. The points object is converted to sf format.
roads <- st_read("C:/Users/Utente/Desktop/Temp/roads_test.shp") %>% st_cast("LINESTRING")
#> Reading layer `roads_test' from data source `C:\Users\Utente\Desktop\Temp\roads_test.shp' using driver `ESRI Shapefile'
#> Simple feature collection with 785 features and 0 fields
#> geometry type: MULTILINESTRING
#> dimension: XY
#> bbox: xmin: 78.12703 ymin: 9.911192 xmax: 78.15389 ymax: 9.943905
#> geographic CRS: WGS 84
points <- tibble::tribble (
~x,~y, ~order,
78.14358, 9.921388,1,
78.14519, 9.921123,2,
78.14889, 9.916954,3,
78.14932, 9.912807,4,
78.14346, 9.913828,5,
78.13490, 9.916551,6,
78.12904, 9.918782,7
)
points <- st_as_sf(points, coords = c("x", "y"), crs = 4326)
Plot network and points (just to understand the problem a little bit better)
par(mar = rep(0, 4))
plot(roads, reset = FALSE)
plot(points, add = TRUE, cex = (1:7)/1.5, col = sf.colors(7), lwd = 4)
Convert roads to sfnetwork object
network <- as_sfnetwork(roads, directed = FALSE)
Subdivide edges and select the main component. Check https://luukvdmeer.github.io/sfnetworks/articles/preprocess_and_clean.html for more details.
network <- network %>%
convert(to_spatial_subdivision, .clean = TRUE) %>%
convert(to_components, .select = 1, .clean = TRUE) %E>%
mutate(weight = edge_length())
Now I want to estimate the shortest paths between each pair of consecutive points. sfnetwork does not support many-to-many routing, so we need to define a for-loop. If you need to repeat this operation for several points, I think you should check the R package dodgr.
routes <- list()
for (i in 1:6) {
path <- st_network_paths(
network,
from = st_geometry(points)[i],
to = st_geometry(points)[i + 1]
)
routes[[i]] <- path
}
Extract the id of the edges that compose all shortest paths
idx <- unlist(pull(do.call("rbind", routes), edge_paths))
Hence, if you want to extract the edges from the original network
network_shortest_path <- network %E>% slice(idx)
roads_shortest_path <- network_shortest_path %E>% st_as_sf()
Plot network and points
par(mar = rep(0, 4))
plot(roads, reset = FALSE)
plot(st_geometry(roads_shortest_path), add = TRUE, col = "darkgreen", lwd = 4)
plot(points, add = TRUE, cex = (1:7)/1.5, col = sf.colors(7), lwd = 4)
Created on 2021-03-07 by the reprex package (v0.3.0)

Visualising MODIS Vegetation layers for a specific country (using R-package MODISttsp)

I am trying to download and visualise the NDVI data in Kenya (and other countries similarly).
For this, I retrieved the bounding box for Kenya using osmdata and used this when downloading NDVI data from MODIStsp
library(osmdata)
library(MODIStsp)
kenya_bb <- osmdata::getbb("Kenya")
MODIStsp(gui = FALSE,
out_folder = "Data",
out_folder_mod = "Data",
selprod = "Vegetation_Indexes_16Days_1Km (M*D13A2)",
bbox = kenya_bb,
bandsel = "NDVI",
user = "mstp_test" ,
password = "MSTP_test_01",
start_date = "2020.06.01",
end_date = "2020.06.15",
verbose = FALSE)
Then I simply visualised the downloaded data, but it hasn't seemed to crop out Kenya
library(raster)
library(here)
library(ggplot2)
NDVI_raster <- raster(here::here("Data/VI_16Days_1Km_v6/NDVI/MOD13A2_NDVI_2020_161.tif"))
NDVI_df <- as.data.frame(NDVI_raster, xy = TRUE, na.rm = TRUE)
rownames(NDVI_df) <- c()
ggplot(data = NDVI_df,
aes(x=x,y=y)) +
geom_raster(aes(fill = MOD13A2_NDVI_2020_161))
Any ideas on how to crop out single countries are appreciated
The reason of this behaviour is that the default value of argument spatmeth is "tiles", so values specified with arguments start_x, end_x, start_y and end_y (and, if not explicitly specified, their defaults) are used.
From the function documentation:
bbox numeric(4) Output bounding box (xmin, ymin, xmax, ymax) in out_proj coordinate system. Ignored if spatmeth == "tiles", Default: NULL
spatmeth character ["tiles" | "bbox" | "file"], indicates how the processing extent is retrieves. if "tiles", use the specified tiles (start_x....). If "file", retrieve extent from spatial file specifies in spafile. If "bbox", use the specified bounding box, Default: "tiles"
To use the kenya_bb extent you have to:
add spatmeth = "tiles";
correct bbox = kenya_bb to bbox = as.vector(kenya_bb)
Moreover, there was a bug affecting this case, recently fixed.
You should also reinstall the package from GitHub:
remotes::install_github("ropensci/MODIStsp")

Unable to project simple features or change projection

I am trying to convert a csv to an sf spatial data file, however I'm getting errors that I cant' figure out.
Example:
library(tidyverse)
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
point_df <- tibble::tribble(
~city_name, ~longitude, ~latitude,
"Akron", -81.5190053, 41.0814447,
"Albany", -73.7562317, 42.6525793,
"Schenectady", -73.9395687, 42.8142432,
"Albuquerque", -106.650422, 35.0843859,
"Allentown", -75.4714098, 40.6022939,
"Bethlehem", -75.3704579, 40.6259316,
"Atlanta", -84.3879824, 33.7489954,
"Augusta", -82.0105148, 33.4734978,
"Austin", -97.7430608, 30.267153,
"Bakersfield", -119.0187125, 35.3732921
)
point_sf <- st_as_sf(point_df, coords = c("longitude", "latitude"))
point_sf <- st_set_crs(point_sf, 4326)
st_transform(point_sf, 102003)
#> Warning in CPL_crs_from_input(x): GDAL Error 1: PROJ: proj_create_from_database:
#> crs not found
#> Error in CPL_transform(x, crs, aoi, pipeline, reverse): crs not found: is it missing?
Any help would be greatly appreciated.
EDIT
I found a kludgy solution which I adapted from this github page, but I am stil looking for a more systematic solution if possible. https://github.com/r-spatial/sf/issues/1419
The solution here is to convert the sf object into sp then change back to sf.
reProject <- function (sf, proj_in = "+init=epsg:4326",
proj_out = "+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs") {
require(sp)
data_sp <- as(sf, "Spatial")
proj4string(data_sp) <- CRS(proj_in)
sf_out <- st_as_sf(spTransform(data_sp, CRS(proj_out)))
}
dat_out <- reProject(point_sf)
It appears something was expected to happen with the following line of code. But that something is not happening.
point_sf <- st_as_sf(point_df, coords = c("longitude", "latitude"))
While this line of code creates the simple feature geometric point objects, this code does not create the simple feature geometry column (sfc) object. And since there is no sfc object, the next line of code does not work.
point_sf <- st_set_crs(point_sf, 4326)
In this other line of code, the function, st_set_crs(), retrieves a coordinate reference system from sf or sfc objects. But neither the sf or the sfc objects currently exist.
Therefore, the sfc object must be first created before using the function: st_set_crs().
It really helps to follow the following steps whenever doing these types of simple feature projects.
x.sfg <- st_multipoint(c(lon,lat), dim = "XY") # create sf geometry from lon/lat
x.sfc <- st_sfc(x.sfg, crs = 4326) # create sfc from geometry
x.sf <- st_sf(df, x.sfc) # create sf object from sfc
First convert the log and lat to vectors, then create the matrix, and then create the simple feature objects in the correct progression.
lon <- c(-81.5190053, -73.7562317, -73.9395687, -106.650422, -75.4714098, -75.3704579, -84.3879824, -82.0105148, -97.7430608, -119.0187125)
lat <- c(41.0814447, 42.6525793, 42.8142432, 35.0843859, 40.6022939, 40.6259316, 33.7489954, 33.4734978, 30.267153, 35.3732921)
m <- matrix(data = c(lon, lat), nrow = 10, ncol = 2, byrow = FALSE)
m.sfg <- st_multipoint(m, dim = "XY")
m.sfc <- st_sfc(m.sfg, crs = 4326)
m.sf <- st_sf(df, m.sfc)
head(m.sf, 3)
Then create a base plot of the continental US, and then plot the simple feature object onto the base map.
plot(US_48, axes = TRUE)
plot(m.sf, add= TRUE, pch = 19, col = "red")
The link shown above with the question does not seem to have anything related to this question. The answer shown here does not convert the sf object into sp then change back to sf.
The plot is shown at link:

Using R to identify nearest point to a location and calculate the distance between them along a network/road

I have a series of locations (Points_B) and would like to find the closest point to them from a different set of points (Points_A) and the distance between them in kms. I can do this as the crow flies but cannot work out how to do the same along a road network (the 'Roads' object in the code). The code I have so far is a follows:
library(sp)
library(rgdal)
library(rgeos)
download.file("https://dl.dropboxusercontent.com/u/27869346/Road_Shp.zip", "Road_Shp.zip")
#2.9mb
unzip("Road_Shp.zip")
Roads <- readOGR(".", "Subset_Roads_WGS")
Points_A <- data.frame(ID = c("A","B","C","D","E","F","G","H","I","J","K","L"), ID_Lat = c(50.91487, 50.92848, 50.94560, 50.94069, 50.92275, 50.94109, 50.92288, 50.92994, 50.92076, 50.90496, 50.89203, 50.88757), ID_Lon = c(-1.405821, -1.423619, -1.383509, -1.396910, -1.441801, -1.459088, -1.466626, -1.369458, -1.340104, -1.360153, -1.344662, -1.355842))
rownames(Points_A) <- Points_A$ID
Points_B <- data.frame(Code = 1:30, Code_Lat = c(50.92658, 50.92373, 50.93785, 50.92274, 50.91056, 50.88747, 50.90940, 50.91328, 50.91887, 50.92129, 50.91326, 50.91961, 50.91653, 50.90910, 50.91432, 50.93742, 50.91848, 50.93196, 50.94209, 50.92080, 50.92127, 50.92538, 50.88418, 50.91648, 50.91224, 50.92216, 50.90526, 50.91580, 50.91203, 50.91774), Code_Lon = c(-1.417311, -1.457155, -1.400106, -1.374250, -1.335896, -1.362710, -1.360263, -1.430976, -1.461693, -1.417107, -1.426709, -1.439435, -1.429997, -1.413220, -1.415046, -1.440672, -1.392502, -1.459934, -1.432446, -1.357745, -1.374369, -1.458929, -1.365000, -1.426285, -1.403963, -1.344068, -1.340864, -1.399607, -1.407266, -1.386722))
rownames(Points_B) <- Points_B$Code
Points_A_SP <- SpatialPoints(Points_A[,2:3])
Points_B_SP <- SpatialPoints(Points_B[,2:3])
Distances <- (gDistance(Points_A_SP, Points_B_SP, byid=TRUE))*100
Points_B$Nearest_Points_A_CF <- colnames(Distances)[apply(Distances,1,which.min)]
Points_B$Distance_Points_A_CF <- apply(Distances,1,min)
The output I am after would be two additional columns in 'Points_B' with 1) having the nearest Point A object ID along the road network and 2) having the distance along the network in km. Any help would be appreciated. Thanks.
I've been working on this kind of problem all day. Try mapdist() in the ggmap package and see if this works:
library(dplyr)
library(ggmap)
#Your data
Points_A <- data.frame(ID = c("A","B","C","D","E","F","G","H","I","J","K","L"), ID_Lat = c(50.91487, 50.92848, 50.94560, 50.94069, 50.92275, 50.94109, 50.92288, 50.92994, 50.92076, 50.90496, 50.89203, 50.88757), ID_Lon = c(-1.405821, -1.423619, -1.383509, -1.396910, -1.441801, -1.459088, -1.466626, -1.369458, -1.340104, -1.360153, -1.344662, -1.355842))
Points_B <- data.frame(Code = 1:30, Code_Lat = c(50.92658, 50.92373, 50.93785, 50.92274, 50.91056, 50.88747, 50.90940, 50.91328, 50.91887, 50.92129, 50.91326, 50.91961, 50.91653, 50.90910, 50.91432, 50.93742, 50.91848, 50.93196, 50.94209, 50.92080, 50.92127, 50.92538, 50.88418, 50.91648, 50.91224, 50.92216, 50.90526, 50.91580, 50.91203, 50.91774), Code_Lon = c(-1.417311, -1.457155, -1.400106, -1.374250, -1.335896, -1.362710, -1.360263, -1.430976, -1.461693, -1.417107, -1.426709, -1.439435, -1.429997, -1.413220, -1.415046, -1.440672, -1.392502, -1.459934, -1.432446, -1.357745, -1.374369, -1.458929, -1.365000, -1.426285, -1.403963, -1.344068, -1.340864, -1.399607, -1.407266, -1.386722))
#Combine coords into one field (mapdist was doing something funny with the commas so I had to specify "%2C" here)
Points_A$COORD <- paste(ID_Lat, ID_Lon, sep="%2C")
Points_B$COORD <- paste(Code_Lat, Code_Lon, sep="%2C")
#use expand grid to generate all combos
get_directions <- expand.grid(Start = Points_A$COORD,
End = Points_B$COORD,
stringsAsFactors = F,
KEEP.OUT.ATTRS = F) %>%
left_join(select(Points_A, COORD, ID), by = c("Start" = "COORD")) %>%
left_join(select(Points_B, COORD, Code), by = c("End" = "COORD"))
#make a base dataframe
route_df <- mapdist(from = get_directions$Start[1],
to = get_directions$End[1],
mode = "driving") %>%
mutate(Point_A = get_directions$ID[1],
Point_B = get_directions$Code[1])
#get the rest in a for-loop
start <- Sys.time()
for(i in 2:nrow(get_directions)){
get_route <- mapdist(from = get_directions$Start[i],
to = get_directions$End[i],
mode = "driving") %>%
mutate(Point_A = get_directions$ID[i],
Point_B = get_directions$Code[i])
route_df <<- rbind(route_df, get_route) #add to your original file
Sys.sleep(time = 1) #so google doesn't get mad at you for speed
end <- Sys.time()
print(paste(i, "of", nrow(get_directions),
round(i/nrow(get_directions),4)*100, "%", sep=" "))
print(end-start)
}
#save if you want
write.csv(route_df, "route_df.csv", row.names = F)
#Route Evaluation
closest_point <-route_df %>%
group_by(Point_A) %>%
filter(km == min(km)) %>%
ungroup()
I'm still kind of new at this so there may be a better way to do the data wrangling. Hope this helps & good luck
The packages igraph, osmr and walkalytics all seem to provide this functionality these days. Mode-specific routing networks exist (in various degrees of functionality).

Minimum elevation within km

Trying to find the minimum elevation within 10km of a certain latitude and longitude using R.
So far I have
dem <- getData("SRTM", lat=42.90, lon=-78.85, path = datadir)
plot(dem)
I know I need to create spatial points and eventually buffer/extract the information.
When I try:
buffdem <- buffer(dem, width=10000)
It does not work because I don't have any points.
I tried
dem <- getData("SRTM", lat=42.90, lon=-78.85, path = datadir)
coords <- data.frame(
x = rnorm(100),
y = rnorm(100)
)
coordinates(dem)
spdf = SpatialPointsDataFrame(coords, dem)
I get the following error:
Error in validObject(.Object) : invalid class
“SpatialPointsDataFrame” object: invalid object for slot "data" in
class "SpatialPointsDataFrame": got class "RasterLayer", should be or
extend class "data.frame"
I think this accomplishes what you need:
library(raster)
#elevation <- getData("SRTM", lat=42.90, lon=-78.85)
#poi <- cbind(lon=-78.85, lat=42.90)
using a smaller example data set for quicker download:
elevation <- getData('alt', country='CHE')
poi <- cbind(8.13, 46.47)
e <- extract(elevation, poi, buffer=10000)
sapply(e, min, na.rm=TRUE)
By the way, this is a duplicate of this and this question.

Resources