Search code examples
rbuffercoordinatesgeospatialr-sf

How to Calculate the Number of Coordinate Points that Occur within X Radius of Other Coordinate Points?


I have two sets of coordinate data (lat and long). The first set denotes positions of restaurants within the city. The second set of coordinates represents parks in the city. For each restaurant, I want to calculate the number of parks that are within 160 meters.

I tried using the simple features (sf) package to perform this operation, per another post, but am not getting the output I want.

Sample data:

Restaurants:

45.59841    -122.3275           
45.59932    -122.3343           
45.59932    -122.3343           
45.59820    -122.3343           
45.59820    -122.3343           
45.59814    -122.3340           
45.59814    -122.3340           
45.60016    -122.3341           
45.60016    -122.3341           
45.60020    -122.3343   

Parks:

45.61221    -122.3426           
45.61065    -122.3402           
45.60868    -122.3384           
45.60624    -122.3361           
45.61082    -122.3388           
45.60983    -122.3379           
45.60910    -122.3372           
45.60829    -122.3365           
45.60653    -122.3349           
45.60503    -122.3335   

Using sf, I tried to perform the following operations:

Turn coordinates into geospatial data

library(tidyverse)
library(sf)

park_points <- st_as_sf(ride_coords, coords = c(x = "Latitude", y = "Longitude"), crs = 4326)
rest_points <- st_as_sf(can_coords, coords = c(x = "lat", "lon"), crs = 4326)

I then tried to create a 160m buffer around each restaurant, after which I was hoping to attempt to calculate the number of parks residing in each of the restaurant buffers.

buffer_160 <- park_points %>% st_transform(26910) %>% st_buffer(dist = 160) %>% st_transform(2926)

I then received the following error:

"Error in UseMethod("st_transform") : no applicable method for 'st_transform' applied to an object of class "data.frame"

Anyway, the goal is to create buffers around each restaurant, then count the number of parks within each buffer (I know there will be overlap, so I will have to figure out how to handle this too)

I'm very new with R spatial tools. Thanks for any help!


Solution

  • You could use spatialrisk::points_in_circle and map over the restaurants with purrr.

    Didn't find parks in a radius of 160 m, so extended radius to 1000 m :

    Restaurants <- read.table(text="
    lat         lon                          
     45.59841    -122.3275           
     45.59932    -122.3343           
     45.59932    -122.3343           
     45.59820    -122.3343           
     45.59820    -122.3343           
     45.59814    -122.3340           
     45.59814    -122.3340           
     45.60016    -122.3341           
     45.60016    -122.3341           
     45.60020    -122.3343",header = T)
    
    Parks <- read.table(text = "
    lat     lon                  
    45.61221    -122.3426           
    45.61065    -122.3402           
    45.60868    -122.3384           
    45.60624    -122.3361           
    45.61082    -122.3388           
    45.60983    -122.3379           
    45.60910    -122.3372           
    45.60829    -122.3365           
    45.60653    -122.3349           
    45.60503    -122.3335",header = T)
    
    
    
    library(purrr)
    library(spatialrisk)
    
    Restaurants %>% pmap(~with(list(...),points_in_circle(Parks, lon_center = lon, lat_center = lat,radius = 1000)))
    #> [[1]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   872.6082
    #> 
    #> [[2]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   638.6807
    #> 4  45.60624 -122.3361   782.9830
    #> 9  45.60653 -122.3349   803.9727
    #> 
    #> [[3]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   638.6807
    #> 4  45.60624 -122.3361   782.9830
    #> 9  45.60653 -122.3349   803.9727
    #> 
    #> [[4]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   762.8609
    #> 4  45.60624 -122.3361   905.9215
    #> 9  45.60653 -122.3349   928.4681
    #> 
    #> [[5]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   762.8609
    #> 4  45.60624 -122.3361   905.9215
    #> 9  45.60653 -122.3349   928.4681
    #> 
    #> [[6]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   767.9792
    #> 4  45.60624 -122.3361   916.4012
    #> 9  45.60653 -122.3349   936.5971
    #> 
    #> [[7]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   767.9792
    #> 4  45.60624 -122.3361   916.4012
    #> 9  45.60653 -122.3349   936.5971
    #> 
    #> [[8]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   544.1362
    #> 4  45.60624 -122.3361   694.5149
    #> 9  45.60653 -122.3349   711.8371
    #> 8  45.60829 -122.3365   924.1272
    #> 
    #> [[9]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   544.1362
    #> 4  45.60624 -122.3361   694.5149
    #> 9  45.60653 -122.3349   711.8371
    #> 8  45.60829 -122.3365   924.1272
    #> 
    #> [[10]]
    #>         lat       lon distance_m
    #> 10 45.60503 -122.3335   541.2711
    #> 4  45.60624 -122.3361   686.8285
    #> 9  45.60653 -122.3349   706.2001
    #> 8  45.60829 -122.3365   916.7284
    #> 3  45.60868 -122.3384   996.5307
    

    Or to summarize, use concentration which directly gives the number of parks around each restaurant:

    Parks$count <- 1
    spatialrisk::concentration(Restaurants, Parks, value = count, radius = 1000)
    
            lat       lon amount concentration
    1  45.59841 -122.3275      1             1
    2  45.59932 -122.3343      1             3
    3  45.59932 -122.3343      1             3
    4  45.59820 -122.3343      1             3
    5  45.59820 -122.3343      1             3
    6  45.59814 -122.3340      1             3
    7  45.59814 -122.3340      1             3
    8  45.60016 -122.3341      1             4
    9  45.60016 -122.3341      1             4
    10 45.60020 -122.3343      1             5