I am trying to make a single sided buffer along ~600 transect lines, however the buffers are not working correctly.
- I have tried implementing in both sf (v1.0-16) and terra (v1.7-71).
- I have projected from lat/lon to UTM Zone 10 (and tried Zone 9 with similar results)
- I have tried making the buffers with sf_use_s2(FALSE) and also sf_use_s2(TRUE)
- The sf and terra implementations both are similarly wrong.
- Oddly yesterday the code worked somewhat better with more of the transects getting a correct buffer (but not all of them!).
What am I missing!?
library(sf) #v1.0 -16
library(ggplot2)
library(dplyr)
library(units)
library(terra)
library(tmap)
#Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; sf_use_s2() is TRUE
#code for building the Linestring from full dataset - multipoint saved for trouble shooting
obs_pt<-obs %>% filter(is.na(Transect_ID)==FALSE)%>%
st_as_sf(coords = c("lon", "lat"), na.fail = FALSE, crs = "epsg:4326") %>%
group_by(Transect_ID) %>%
summarize() %>%
filter(st_geometry_type(.) == "MULTIPOINT")
obs_ls<-obs_pt %>%
st_cast("LINESTRING", keep=TRUE)
#switch from lat/lon to UTM for planer geometry
obs_ls_planer<-obs_ls%>%st_transform("EPSG:32610") #Zone 10= most of study area
#filter data for reproducible example:
obs_ls_125<-obs_ls_planer%>%filter(Transect_ID==125)
saveRDS(obs_ls_125,paste0(usr,dir,"obs_ls_125.rda"))
[obs_ls_125](https://www.dropbox.com/scl/fi/47c83vgxeccphb1rkjumv/obs_ls_125.rda?rlkey=c1ymlbky7iohzhke6dap2x4ep&dl=0)
obs_ls_125<-readRDS("obs_ls_125.rda")
obs_ls_125
Simple feature collection with 1 feature and 5 fields Geometry type: LINESTRING Dimension: XY Bounding box: xmin: 361857.1 ymin: 4786302 xmax: 362981.9 ymax: 4787215 Projected CRS: WGS 84 / UTM zone 10N
A tibble: 1 × 6
Transect_ID geometry Cruise_ID date Condition ObsSidePS
-
<int> <LINESTRING [m]> <chr> <date> <chr> <chr>
1 125 (362210.4 4786933, 362299.5 4786863, 362378.3 4786793, … 202210 2022-10-14 1 Starboard
#buffer implementation in sf
obs_ls_125.b <- st_buffer(obs_ls_125, dist = 100, endCapStyle = "FLAT", singleSide = TRUE)
#buffer implementation in terra
vsp <- terra::vect(obs_ls_125)
buffer_terra <- terra::buffer(vsp, width = 100, capstyle = "FLAT", singlesided = TRUE)
buffer_terra.sf <- sf::st_as_sf(buffer_terra)
ggplot() +
geom_sf(data = obs_ls_125.b, fill = "yellow")+
geom_sf(data = obs_ls_125, color = "blue", linewidth = 1)+
geom_sf(data = obs_ls_125.b%>%st_cast("POINT"), color = "orange") #points of polygon
ggplot() +
geom_sf(data = buffer_terra.sf, fill = "pink")+
geom_sf(data = buffer_terra.sf%>%st_cast("POINT"), color = "orange")
Not really, it works as expected, the issue is with the geometry of transects. Not a issue per se, but it's not a straight line which makes the thing harder. As you can see below, the buffer is onesided, however the line is bent, so with bigger buffer radius the polygon surrounds the whole line.
Here is a details of
linestring:Created on 2024-03-27 with reprex v2.1.0
Edit
To deal with not straight transects is to simplify them. You can try
sf::st_simplify()function with big enoughdTolerance = 1000parameter, but it will move the most left/most right coordinates as well. Below simple approach how to create line just between most left/right coordinates and create buffer. Don't know what your transect source is, kind of GPS file? If the line coordinates are given, then we have deal with it somehow; if that's something you can choose/create, then have a look onsf::st_make_grid()function.Created on 2024-03-27 with reprex v2.1.0