# Calculate distance between buffer and geographic points for grouped subsets (and get tally)

The data I used can be found here.

After importing my data, I select a subset of points (`Nest2017` in column `type`) to create 30 m buffers around:

``````library(dplyr)

nests<-df %>%
filter(type %in% "Nest2017")

library(maptools)
library(sp)
library(rgeos)

nests\$lon <- as.numeric(as.character(nests\$lon))
nests\$lat <- as.numeric(as.character(nests\$lat))
coordinates(nests) <- c("lon", "lat")

proj4string(nests) <- CRS("+init=epsg:3578") #setting the projection of the points

spTransform(nests,CRS("+init=epsg:3578")) #tranforming the coordinates

gBuffer(nests, width=30, byid=TRUE) #puts a circular buffer around each individual point
``````

I know `gBuffer()`requires the points in UTM, but my points go across two zones (7 and 8), so I used the Yukon Albers projection instead.

Now I am trying to figure out how to calculate the distance from the buffer around each `Nest2017` (in column `type`) to each point (`Foray`) within the same `NatalMidden` group.

A subset of my data looks as follows:

``````lat                  lon                NatalMidden   squirrelID    type
60.9577819984406    -138.0347849708050  -27           NA            Nest2017
60.9574120212346    -138.0345689691600  -27           NA            NatalMidden
60.9578209742904    -138.0346520338210  -27           23054         Foray
60.9575380012393    -138.0348329991100  -27           23054         Foray
60.9576250053942    -138.0339069664480  -27           23054         Foray
60.957643026486     -138.0338829942050  -27           23054         Foray
60.9575670026243    -138.0348739866170  -27           23054         Foray
60.9600000176579    -138.032592013478   -515          22780         Foray
60.9600180387497    -138.032631995156   -515          22780         Foray
60.9599519893527    -138.032342987135   -515          NA            NatalMidden
60.959974033758     -138.032317003235   -515          NA            Nest2017
``````

So, for example, `squirrelID` 23054 was located (`Foray`) multiple times (`type` column) and I have a corresponding latitude (`lat`) and longitude (`lon`) for each `Foray`. I am trying to calculate the distance between each `Foray` (`type` column) and the 30 m buffer (assuming I correctly created the buffers) around its corresponding `Nest2017` (`type` column) for each individual (`squirrelID`) separately. The common field that links `squirrelID` and `type` is the `NatalMidden` column.

Is there a way I could work within the `dplyr` framework to `group_by(squirrelID)` and then calculate the distances between (and tally) each `Foray` and its corresponding `Nest2017` 30 meter buffer (the common field being `NatalMidden` for both the `Foray` and `Nest2017`)? If not, how might I be able to do this?

My ultimate goal is to create new columns for:

1. distance between each `Foray` and its corresponding 30 meter buffer (centered on `Nest2017`) for each `squirrelID`
2. number of `Foray`s inside corresponding 30 meter buffer (centered on `Nest2017`) for each `squirrelID`
3. number of `Foray`s outside corresponding 30 meter buffer (centered on `Nest2017`) for each `squirrelID`
• You might consider splitting the data into two data frames - Forays and Nests, then join on the NatalMidden value so each row has two geometries, then compute the row-wise distance. You don't need `dplyr` for any of this. Jan 11, 2019 at 19:57
• If your 30m buffers are around single points and so are circles with a 30m radius then you don't need to compute them as a geometry - you can compute point-to-point distances and anything less than 30m would be inside the "buffer" (and have a distance-to-buffer of 0m) and anything > 30m from the point would have a distance-to-buffer of point-distance minus 30m. Jan 11, 2019 at 20:23

Read the data, convert to `sf`, set the CRS, transform to the new (metric) CRS and plot it:

``````> df = read.table("./figshare.txt",sep="\t",head=TRUE)
> df = st_as_sf(df, coords=c("lon","lat"))
> st_crs(df)=4326
> df = st_transform(df, 3578)
> plot(df\$geometry,col=df\$type,pch=19)
``````

Now split it into forays and nests - we only need the Natal Midden column for the nests (plus the geometry which we get for free anyway because these are `sf` spatial data frames).

``````> Forays = df[df\$type=="Foray",]
> Nests = df[df\$type=="Nest2017","NatalMidden"]
``````

Now join the Forays to the Nests via the NatalMidden column. I'll do this with `dplyr` but `merge` could do it too:

``````> Forays = dplyr::left_join(Forays, data.frame(Nests), c("NatalMidden"="NatalMidden"))
Simple feature collection with 6 features and 3 fields
Active geometry column: geometry.x
geometry type:  POINT
dimension:      XY
bbox:           xmin: 200427.2 ymin: 731035 xmax: 200451.7 ymax: 731043.8
epsg (SRID):    3578
proj4string:    +proj=aea +lat_1=61.66666666666666 +lat_2=68 +lat_0=59 +lon_0=-132.5 +x_0=500000 +y_0=500000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
NatalMidden sq_id  type                geometry.x                geometry.y
1        -515 22780 Foray   POINT (200427.3 731035) POINT (200465.3 731052.2)
2        -515 22780 Foray POINT (200446.1 731041.4) POINT (200465.3 731052.2)
3        -515 22780 Foray POINT (200450.9 731043.5) POINT (200465.3 731052.2)
4        -515 22780 Foray POINT (200451.7 731043.8) POINT (200465.3 731052.2)
5        -515 22780 Foray POINT (200448.5 731042.7) POINT (200465.3 731052.2)
6        -515 22780 Foray   POINT (200427.2 731035) POINT (200465.3 731052.2)
geometry
1 GEOMETRYCOLLECTION EMPTY
2 GEOMETRYCOLLECTION EMPTY
3 GEOMETRYCOLLECTION EMPTY
4 GEOMETRYCOLLECTION EMPTY
5 GEOMETRYCOLLECTION EMPTY
6 GEOMETRYCOLLECTION EMPTY
``````

Now each row has a geometry from Forays, a geometry from Nests, and an empty geometry because I don't know but its not important. Lets zap that column and then compute the element-wise distance from each Foray point to its Nest point:

``````> Forays\$geometry = NULL
> Forays\$dist = st_distance(Forays\$geometry.x, Forays\$geometry.y, by_element=TRUE)
Simple feature collection with 6 features and 4 fields
Active geometry column: geometry.x
geometry type:  POINT
dimension:      XY
bbox:           xmin: 200427.2 ymin: 731035 xmax: 200451.7 ymax: 731043.8
epsg (SRID):    3578
proj4string:    +proj=aea +lat_1=61.66666666666666 +lat_2=68 +lat_0=59 +lon_0=-132.5 +x_0=500000 +y_0=500000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
NatalMidden sq_id  type                geometry.x                geometry.y
1        -515 22780 Foray   POINT (200427.3 731035) POINT (200465.3 731052.2)
2        -515 22780 Foray POINT (200446.1 731041.4) POINT (200465.3 731052.2)
3        -515 22780 Foray POINT (200450.9 731043.5) POINT (200465.3 731052.2)
4        -515 22780 Foray POINT (200451.7 731043.8) POINT (200465.3 731052.2)
5        -515 22780 Foray POINT (200448.5 731042.7) POINT (200465.3 731052.2)
6        -515 22780 Foray   POINT (200427.2 731035) POINT (200465.3 731052.2)
dist
1 41.69695 [m]
2 21.97295 [m]
3 16.79233 [m]
4 15.91557 [m]
5 19.27717 [m]
6 41.79212 [m]
``````

That's probably the meat of the problem. The rest is just aggregate/summarise operations grouped over sq_id. Test `dist` against 30 metres to see if the point is in the "buffer" or not.

• My major problem was with calculating those distances as a first step, so thank you for explaining that in such detail. With those figured out, I can then `group_by` and calculate those other values. Thank you! Jan 12, 2019 at 22:16