I have a list of dataframes (these are spatial dataframes) named for example "map_g1_r1_airport", "map_g1_r1_hotel", "map_g1_r2_bank", "map_g1_r2_market"
These are elements that were digitized from several maps. The maps were originally called "map_g1_r1", "map_g1_r2".
I am trying to add a column to each dataframe with the name of the original map using a loop.
Here is what I am trying to do:
map_g1_r1_airport$mapid<-map_g1_r1
With the loop (Unfortunately this does not do what I intend to do. Instead it simply creates a "content" field in the Values board.):
list_df<-c("map_g1_r1_airport", "map_g1_r1_hotel", "map_g1_r2_bank", "map_g1_r2_market")
for (df in 1:length(list_df)){
paste(list_df[df],"$mapid<-",
print(content<-gsub("(.*)_.*","\\1",
c(paste(list_df[df]))),sep=""),
quote=FALSE)}
Any help is most welcome!
Here is one example of the data before change:
structure(list(id = c(1, 2, 3), Name = structure(c(1L, 3L, 4L
), .Label = c("A", "B", "C", "D", "E"
), class = "factor"), Year = structure(c(NA_integer_, NA_integer_,
NA_integer_), .Label = character(0), class = "factor"), geometry = structure(list(
structure(c(41.4086152370865, 2.44718243982123), class = c("XY",
"POINT", "sfg")), structure(c(45.3852740543083, -4.31103098867136
), class = c("XY", "POINT", "sfg")), structure(c(38.4200314592624,
-6.96113884231683), class = c("XY", "POINT", "sfg"))), class = c("sfc_POINT",
"sfc"), precision = 0, bbox = structure(c(xmin = 41.4086152370865,
ymin = 2.31103098867136, xmax = 45.4200314592624, ymax = -4.44718243982123
), class = "bbox"), crs = structure(list(epsg = NA_integer_,
proj4string = NA_character_), class = "crs"), n_empty = 0L)), sf_column = "geometry", agr = structure(c(id = NA_integer_,
Name = NA_integer_, Year = NA_integer_), .Label = c("constant",
"aggregate", "identity"), class = "factor"), row.names = c(NA,
3L), class = c("sf", "data.frame"))
This is what I would like to get (with the mapid map_g1_r1):
structure(list(id = c(1, 2, 3), Name = structure(c(1L, 3L, 4L
), .Label = c("A", "B", "C", "D", "E"
), class = "factor"), Year = structure(c(NA_integer_, NA_integer_,
NA_integer_), .Label = character(0), class = "factor"), geometry = structure(list(
structure(c(41.4086152370865, 2.44718243982123), class = c("XY",
"POINT", "sfg")), structure(c(45.3852740543083, -4.31103098867136
), class = c("XY", "POINT", "sfg")), structure(c(38.4200314592624,
-6.96113884231683), class = c("XY", "POINT", "sfg"))), class = c("sfc_POINT",
"sfc"), precision = 0, bbox = structure(c(xmin = 41.4086152370865,
ymin = 2.31103098867136, xmax = 45.4200314592624, ymax = -4.44718243982123
), class = "bbox"), crs = structure(list(epsg = NA_integer_,
proj4string = NA_character_), class = "crs"), n_empty = 0L),
mapid = c("map_g1_r1", "map_g1_r1", "map_g1_r1")), sf_column = "geometry", agr = structure(c(id = NA_integer_,
Name = NA_integer_, Year = NA_integer_, mapid = NA_integer_), .Label = c("constant",
"aggregate", "identity"), class = "factor"), row.names = c(NA,
3L), class = c("sf", "data.frame"))
You can achieve that even without a loop.
I would first start by creating a list with the names you want to see in each spatial data.frame. I assume they are derived from the names of the list.
mapid = names(list_df)
following that you can employ mapply to use a function that takes
the first element of a list (or vector) and the first element of another list/vector. Them it moves on and apply the same function to the second elements of each vector. It is essentially a multiple input version of lapply.
The function we will give to mapply is cbind which creates takes takes two data.frames and joins them by column. In this case one data.frame will be your spatial object and the other will be a vector with one single element: the current map name. cbind will naturally convert this name to a 1-column data.frame and repeat the name to match the number of rows in the spatial object.
final = mapply(cbind, list_df, mapid)
I haven't tested it, but it should work.
You can get all the individual dataframes in a list using mget and add a new column with their name using mutate.
Using tidyverse functions you can do this as :
library(dplyr)
library(purrr)
list_df<-c("map_g1_r1_airport", "map_g1_r1_hotel", "map_g1_r2_bank", "map_g1_r2_market")
tmp <- mget(list_df)
result <- imap(tmp, ~.x %>% mutate(map_id = .y))
result will have all changed dataframes in a list, if you want these changes to reflect in the original object you can use list2env.
list2env(result, .GlobalEnv)
Related
I want to convert my dataframe from wide to long but based on the character vector in one column (based on residents number from the following dput.)
From the following dput, the outcome should have a total of three rows showing all the 3 residents. Is there a way to do it? I tried using seperate rows but the output is not what I desire.
Tried using
Building_Details_Trial_50 %>% tidyr::separate_rows(residents)
dput
structure(list(time = "Mar 22", buildingId = "50", region = "Central",
geometry = structure(list(structure(list(structure(c(-447.361154068258,
-447.557850744738, -533.811390293442, -536.961556093902,
-443.736917153567, -447.361154068258, 5919.51770006977, 5906.87385860642,
5908.2156806004, 5958.8966109417, 5959.54382538916, 5919.51770006977
), dim = c(6L, 2L))), class = c("XY", "POLYGON", "sfg"))), class = c("sfc_POLYGON",
"sfc"), precision = 0, bbox = structure(c(xmin = -536.961556093902,
ymin = 5906.87385860642, xmax = -443.736917153567, ymax = 5959.54382538916
), class = "bbox"), crs = structure(list(input = NA_character_,
wkt = NA_character_), class = "crs"), n_empty = 0L),
count = 3L, geom_points = structure(list(structure(c(-490.403818453599,
5933.7360887923), class = c("XY", "POINT", "sfg"))), class = c("sfc_POINT",
"sfc"), precision = 0, bbox = structure(c(xmin = -490.403818453599,
ymin = 5933.7360887923, xmax = -490.403818453599, ymax = 5933.7360887923
), class = "bbox"), crs = structure(list(input = NA_character_,
wkt = NA_character_), class = "crs"), n_empty = 0L),
long = -490.403818453599, lat = 5933.7360887923, residents = list(
c("556", "155", "143"))), row.names = 1L, sf_column = "geometry", agr = structure(c(time = NA_integer_,
buildingId = NA_integer_, region = NA_integer_, count = NA_integer_,
long = NA_integer_, lat = NA_integer_, residents = NA_integer_
), levels = c("constant", "aggregate", "identity"), class = "factor"), class = c("sf",
"tbl_df", "tbl", "data.frame"))
Ideal output
Residents
buildingId
Region
556
50
Central
155
50
Central
143
50
Central
I have a list of 72 datasets loaded in the Global Environment. Each dataset contains a column called uniqueID filled with unique identifiers.
I want to merge each dataset with another dataset based on these unique identifiers (i.e. uniqueID).
I can do the following on a dataset by dataset basis:
dataset1<-merge(dataset1,tomerge,by="uniqueID",all.x=TRUE)
However as I have many datasets I would like to do this using a loop.
Here is what I have tried:
dflist<-Filter(is.data.frame, as.list(.GlobalEnv))
dflist<-function(df,x){df<-merge(df,tomerge,all.x=TRUE)}
Here is an example of dataset1 and tomerge that I am trying to merge:
dput(dataset1[1:2, ])
structure(list(id = c(1, 2), geometry = structure(list(structure(c(12.7709873378252,
-2.34780379794057), class = c("XY", "POINT", "sfg")), structure(c(13.7404727250738,
-3.08397066598979), class = c("XY", "POINT", "sfg"))), class = c("sfc_POINT",
"sfc"), precision = 0, bbox = structure(c(xmin = 12.7709873378252,
ymin = -2.08397066598979, xmax = 13.7404727250738, ymax = -1.34780379794057
), class = "bbox"), crs = structure(list(epsg = NA_integer_,
proj4string = NA_character_), class = "crs"), n_empty = 0L),
uniqueID = c("id_1_v12_3", "id_2_v13_3")), sf_column = "geometry", agr = structure(c(id = NA_integer_,
shapefile = NA_integer_), .Label = c("constant", "aggregate",
"identity"), class = "factor"), row.names = 1:2, class = c("sf",
"data.frame"))
dput(tomerge[1:2, 2:3 ])
structure(list(uniqueID = c("id_1_v12_3", "id_2_v13_2"), todigit = c("y",
"y")), row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"
)) ```
We can use lapply to loop over the list of data.frame and merge with the 'tomerge' data
dfmergelist <- lapply(dflist, function(x)
merge(x, tomerge, by = "uniqueID", all.x = TRUE))
where
dflist <- Filter(is.data.frame, mget(ls()))
I'm trying to stretch what I can do in R and have hit a wall and hope you can point me in the right direction on how best I could accomplish what I want to do. I am plotting a bunch of polylines from a shape file whose data looks like this:
placename,placetype,placebook,numbooks,row_number,placelinecoords
Main Street,street,"BOOKTDS",1,1,LINESTRING(-3.700559678237278 40.42098474661999,-3.698346475125229 40.42033268716025,-3.69731867182242 40.42003534594848,-3.697243299580215 40.42003534594848)
First Street,street,"BOOKESM",3,1,LINESTRING(-3.710546258545151 40.41308011176736,-3.710213664627304 40.41309440722183,-3.709234658336868 40.41341707524381,-3.708880606746902 40.4135232694443,-3.708711627578964 40.41372748858957)
First Street,street,"BOOKTDS",3,2,LINESTRING(-3.710546258545151 40.41308011176736,-3.710213664627304 40.41309440722183,-3.709234658336868 40.41341707524381,-3.708880606746902 40.4135232694443,-3.708711627578964 40.41372748858957)
First Street,street,"BOOKLDE",3,3,LINESTRING(-3.710546258545151 40.41308011176736,-3.710213664627304 40.41309440722183,-3.709234658336868 40.41341707524381,-3.708880606746902 40.4135232694443,-3.708711627578964 40.41372748858957)
Loughborough Street,street,"BOOKESM",2,1,LINESTRING(-3.707336328013795 40.42433623251054,-3.707014282978915 40.42429971916709,-3.706726498054129 40.42429971916709,-3.706281116622912 40.42409628731927,-3.705390353760477 40.42377288157678,-3.704602371228324 40.42316257940762,-3.70376642454204 40.42259400231908)
Loughborough Street,street,"BOOKTDS",2,2,LINESTRING(-3.707336328013795 40.42433623251054,-3.707014282978915 40.42429971916709,-3.706726498054129 40.42429971916709,-3.706281116622912 40.42409628731927,-3.705390353760477 40.42377288157678,-3.704602371228324 40.42316257940762,-3.70376642454204 40.42259400231908)
Oak Street,street,"BOOKLMI",2,1,LINESTRING(-3.700391803697817 40.41664973667679,-3.700384951675798 40.41673842198933,-3.699754565650076 40.4176044018386,-3.699549004989513 40.41782350340716)
Oak Street,street,"BOOKLBU",2,2,LINESTRING(-3.700391803697817 40.41664973667679,-3.700384951675798 40.41673842198933,-3.699754565650076 40.4176044018386,-3.699549004989513 40.41782350340716)
"placebook" is a unique code for a book where a particular street name appears. I have assigned each book with a color and load in the data:
books = c("OBRAESM", "OBRAHOR", "OBRAINS", "OBRALBU", "OBRALCT", "OBRALDB","OBRALDE","OBRALMI","OBRALPI","OBRATDS")
color = c("red", "orange", "yellow", "green", "blue", "pink","gray","purple","black","white")
df = cbind.data.frame(books,color)
colnames(df) = c("books","color")
placeographypaths <- readOGR("shapefiles/places_paths.shp")
placeographypathsstreets <- subset(placeographypaths, placetype %like% "street")
What I would like to do is plot these lines onto the map by book, with each appearing as a different color. When there is more than one book assigned to a particular line, I would need to offset the lines so they are all visible. These lines will overlap in their entirety and in most cases there will only be a few lines overlapping in the same location (the maximum is 5, but most are 1-3).
So "First Street" would display three lines: red, gray, and white. I see there's a PolylineOffset tool, but I can't find any examples that use column values as the criteria for offsetting--and it seems to mostly apply to more complex situations where only a part of the line overlaps)--perhaps there's a simpler solution that I'm missing.
I spent some time to think what I could do since I do not know how to use PolylineOffset. It seems that this feature will be coming in the leaflet package. I want to suggest an alternative for your visualization. Reading your question, you would have five types of lines. That is, each line type can represent how many times streets appear in your data set. You said the maximum overlapping is five times. I think you can create five levels in in a grouping variable and create colors in leaflet.
First, I summarized your data grouping by placename. For each placename, I counted how many data points (rows) exist. I also created a string containing book names. The string is arranged for popups. Then, I created a color palette for leaflet. Finally, I drew a map. If you want something fancier, I think you can use the htmlTable package, for example.
library(dplyr)
library(leaflet)
library(sf)
library(viridis)
# Aggregate the data by placename. Note your data is called mysf, which is an
# sf object.
group_by(mysf, placename) %>%
summarize(frequency = factor(n(), levels = 1:3, labels = c("1", "2", "3")),
books = paste0("<br/>", paste0(placebook, collapse = "<br/>"))) -> mysf2
# Create categorical colors
# I am checking colors here
previewColors(colorFactor(palette = "viridis", domain = mysf2$frequency),
values = unique(mysf2$frequency))
# Create my own palette
mypal <- colorFactor(palette = "viridis", domain = mysf2$frequency)
# Draw a leaflet map
leaflet() %>%
addProviderTiles("CartoDB.Positron") %>%
addPolylines(data = mysf2, color = ~mypal(mysf2$frequency),
popup = paste("Place: ", mysf2$placename, "<br>",
"Book(s): ", mysf2$books, "<br>")) %>%
addLegend(position = "bottomright", pal = mypal, values = mysf2$frequency,
title = "Frequency",
opacity = 1)
Finally one note. The way you provided your data does not unfortunately work for anybody to replicate your situation. (I invested some good amount of time to manually create your data. I would not do this if I do not have enough time. Perhapd you would not want to as well, right?) If your data is large, you want to consider uploading it somewhere else. Otherwise, you can use dput() which creates a copy of your data. If you carefully see questions in R, many users provide their data with dput(). I highly recommend you to use this function when you ask more questions in the future.
DATA
mysf <- structure(list(placename = structure(c(3L, 1L, 1L, 1L, 2L, 2L,
4L, 4L), .Label = c("First Street", "Loughborough Street", "Main Street",
"Oak Street"), class = "factor"), placetype = structure(c(1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "placetype", class = "factor"),
placebook = structure(c(5L, 1L, 5L, 3L, 1L, 5L, 4L, 2L), .Label = c("BOOKESM",
"BOOKLBU", "BOOKLDE", "BOOKLMI", "BOOKTDS"), class = "factor"),
geometry = structure(list(structure(c(-3.70055967823728,
-3.69834647512523, -3.69731867182242, -3.69724329958022,
40.42098474662, 40.4203326871602, 40.4200353459485, 40.4200353459485
), .Dim = c(4L, 2L), class = c("XY", "LINESTRING", "sfg")),
structure(c(-3.71054625854515, -3.7102136646273, -3.70923465833687,
-3.7088806067469, -3.70871162757896, 40.4130801117674,
40.4130944072218, 40.4134170752438, 40.4135232694443,
40.4137274885896), .Dim = c(5L, 2L), class = c("XY",
"LINESTRING", "sfg")), structure(c(-3.71054625854515,
-3.7102136646273, -3.70923465833687, -3.7088806067469,
-3.70871162757896, 40.4130801117674, 40.4130944072218,
40.4134170752438, 40.4135232694443, 40.4137274885896), .Dim = c(5L,
2L), class = c("XY", "LINESTRING", "sfg")), structure(c(-3.71054625854515,
-3.7102136646273, -3.70923465833687, -3.7088806067469,
-3.70871162757896, 40.4130801117674, 40.4130944072218,
40.4134170752438, 40.4135232694443, 40.4137274885896), .Dim = c(5L,
2L), class = c("XY", "LINESTRING", "sfg")), structure(c(-3.70733632801379,
-3.70701428297891, -3.70672649805413, -3.70628111662291,
-3.70539035376048, -3.70460237122832, -3.70376642454204,
40.4243362325105, 40.4242997191671, 40.4242997191671,
40.4240962873193, 40.4237728815768, 40.4231625794076,
40.4225940023191), .Dim = c(7L, 2L), class = c("XY",
"LINESTRING", "sfg")), structure(c(-3.70733632801379,
-3.70701428297891, -3.70672649805413, -3.70628111662291,
-3.70539035376048, -3.70460237122832, -3.70376642454204,
40.4243362325105, 40.4242997191671, 40.4242997191671,
40.4240962873193, 40.4237728815768, 40.4231625794076,
40.4225940023191), .Dim = c(7L, 2L), class = c("XY",
"LINESTRING", "sfg")), structure(c(-3.70039180369782,
-3.7003849516758, -3.69975456565008, -3.69954900498951,
40.4166497366768, 40.4167384219893, 40.4176044018386,
40.4178235034072), .Dim = c(4L, 2L), class = c("XY",
"LINESTRING", "sfg")), structure(c(-3.70039180369782,
-3.7003849516758, -3.69975456565008, -3.69954900498951,
40.4166497366768, 40.4167384219893, 40.4176044018386,
40.4178235034072), .Dim = c(4L, 2L), class = c("XY",
"LINESTRING", "sfg"))), class = c("sfc_LINESTRING", "sfc"
), precision = 0, bbox = structure(c(xmin = -3.71054625854515,
ymin = 40.4130801117674, xmax = -3.69724329958022, ymax = 40.4243362325105
), class = "bbox"), crs = structure(list(epsg = 4326L, proj4string = "+proj=longlat +datum=WGS84 +no_defs"), class = "crs"), n_empty = 0L)), row.names = c(NA,
8L), sf_column = "geometry", agr = structure(c(placename = NA_integer_,
placetype = NA_integer_, placebook = NA_integer_), class = "factor", .Label = c("constant",
"aggregate", "identity")), class = c("sf", "data.frame"))
I have a fairly simple problem where I want to create a gif which loops through departure_hour and colors the lines based on link volumes. One caveat is the number of rows between states (i.e. departure_hour) may be different.
Here is the code I am trying:
vol <- ggplot() +
geom_sf(data = test, aes(color=link_volume)) +
scale_color_distiller(palette = "OrRd", direction = 1) +
ggtitle("{frame_time}") +
transition_time(departure_hour) +
ease_aes("linear") +
enter_fade() +
exit_fade()
animate(vol, fps = 10, width = 750, height = 450)
However, when I do this I am getting the error:
Error in tween_state(as.data.frame(full_set$from), as.data.frame(full_set$to),:
identical(classes, col_classes(to)) is not TRUE
First, I do not understand if the error is referring to column classes or color classes? If it is color classes am I correct in assuming that the color scales between each plot may be different and that is the reason for this error?
Second, how do I fix this error? There seems to be just one more question on this issue and it has no solution.
Sample data:
> dput(head(test,5))
structure(list(linkid = c(12698L, 26221L, 36429L, 36430L, 47315L
), departure_hour = c(14, 19, 11, 0, 18), link_volume = c(500L,
1550L, 350L, 100L, 550L), geometry = structure(list(structure(c(1065088.71736072,
1065084.18813218, 1253892.13487564, 1253935.59094818), .Dim = c(2L,
2L), class = c("XY", "LINESTRING", "sfg")), structure(c(1060907.62521458,
1060984.50834787, 1237578.71728528, 1237818.59111698), .Dim = c(2L,
2L), class = c("XY", "LINESTRING", "sfg")), structure(c(1063031.34624456,
1062955.36965935, 1241210.04281066, 1241498.76584417), .Dim = c(2L,
2L), class = c("XY", "LINESTRING", "sfg")), structure(c(1063031.34624456,
1063034.73081084, 1241210.04281066, 1241198.98905491), .Dim = c(2L,
2L), class = c("XY", "LINESTRING", "sfg")), structure(c(1058112.52771678,
1058131.02887377, 1236388.96345761, 1236342.13157851), .Dim = c(2L,
2L), class = c("XY", "LINESTRING", "sfg"))), class = c("sfc_LINESTRING",
"sfc"), precision = 0, bbox = structure(c(xmin = 1058112.52771678,
ymin = 1236342.13157851, xmax = 1065088.71736072, ymax = 1253935.59094818
), class = "bbox"), crs = structure(list(epsg = 5070L, proj4string = "+proj=aea +lat_1=29.5 +lat_2=45.5 +lat_0=23 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"), class = "crs"), n_empty = 0L)), sf_column = "geometry", agr = structure(c(linkid = NA_integer_,
departure_hour = NA_integer_, link_volume = NA_integer_), .Label = c("constant",
"aggregate", "identity"), class = "factor"), row.names = c(NA,
5L), class = c("sf", "data.table", "data.frame"))
I have the following map of Mexico. It shows all of its municipalities and around 400 weather stations.
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"))
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)