Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What unit is the `dist` argument in `st_buffer` set to by default?

Tags:

r

sf

I have the following map of Mexico. It shows all of its municipalities and around 400 weather stations.

Mexico

I want to create a 10km buffer around each station and eventually, associate each municipality to a station that is located within each radius.

The map and the stations are stored on separate sf objects. I tired the following:

buffers <- st_buffer(stations, dist = 1)

I thought the dist argument was set to kilometers, so I tried dist = 10. Unfortunately, this returned HUGE buffers for each station. That's why I am using dist = 1, but even these buffers are as big as a state! This question, suggests I transform my stations to Irish Grid, but I couldn't replicate the accepted answer. I am now wondering what unit the dist argument is set to.

From the aforementioned question, I assume it's set to degrees. How can I set a 10km buffer around each station?

Additional info:

My CRS is set to 4326 on both objects (the Mexican map and the stations).

This is my stations data:

> dput(head(stations))
structure(list(station_number = c(1004L, 1005L, 1008L, 1012L, 
1017L, 1018L), station_alt = c(1925, 1844, 2323, 1589, 2172, 
2053), month = c(9L, 9L, 9L, 9L, 9L, 9L), Mean_min = c(11.6, 
12.75, 12.25, 13.9666666666667, 12.9, 12.6833333333333), Mean_max = c(26.9333333333333, 
26.85, 24.0833333333333, 29.0333333333333, 24.8666666666667, 
26.1333333333333), months_observed = c(5L, 5L, 5L, 5L, 5L, 5L
), geometry = structure(list(structure(c(-102.199, 22.001), class = c("XY", 
"POINT", "sfg")), structure(c(-102.372, 21.781), class = c("XY", 
"POINT", "sfg")), structure(c(-102.135, 22.203), class = c("XY", 
"POINT", "sfg")), structure(c(-102.802, 21.794), class = c("XY", 
"POINT", "sfg")), structure(c(-102.444, 22.233), class = c("XY", 
"POINT", "sfg")), structure(c(-102.415, 22.141), class = c("XY", 
"POINT", "sfg"))), class = c("sfc_POINT", "sfc"), precision = 0, bbox = structure(c(xmin = -102.802, 
ymin = 21.781, xmax = -102.135, ymax = 22.233), class = "bbox"), crs = structure(list(
    epsg = NA_integer_, proj4string = NA_character_), class = "crs"), n_empty = 0L)), sf_column = "geometry", agr = structure(c(station_number = NA_integer_, 
station_alt = NA_integer_, month = NA_integer_, Mean_min = NA_integer_, 
Mean_max = NA_integer_, months_observed = NA_integer_), .Label = c("constant", 
"aggregate", "identity"), class = "factor"), row.names = c(NA, 
6L), class = c("sf", "data.frame"))
like image 783
Arturo Sbr Avatar asked Feb 18 '19 19:02

Arturo Sbr


1 Answers

Your coordinates are long/lat, so the distance will be in degrees. You should first project to a spatial reference in meter units and then take 10 000 meters.

The manual of st_buffer says this about the dist argument:

in case dist is a units object, it should be convertible to arc_degree if x has geographic coordinates, and to st_crs(x)$units otherwise

If you leave the coordinates in 4326 you should be able to take something like 0.1 which should be about 11 km for Mexico, but you will see a warning message:

In st_buffer.sfc(st_geometry(x), dist, nQuadSegs, endCapStyle = endCapStyle, : st_buffer does not correctly buffer longitude/latitude data

So first convert to another projection (in meter) and enter the distance in meters. This should work, which uses EPSG 7801:

library(sf)

pois <- st_as_sf(stations)
st_crs(pois) <- 4326
pois <- st_transform(pois, crs = 7801)
plot(st_geometry(pois))

buff <- st_buffer(pois, dist = 10000)
plot(st_geometry(buff), add = TRUE)

Control with leaflet and the measure tool:

buff <- st_transform(buff, crs = 4326)

library(leaflet)

leaflet() %>% 
  addTiles() %>% 
  addMeasure(primaryLengthUnit = "meters") %>% 
  addMarkers(data = pois) %>% 
  addPolygons(data = buff)
like image 124
SeGa Avatar answered Sep 24 '22 17:09

SeGa