I have a dataframe of longitude and latitude points which when plotted look like: I want to define a seperate dataframe which contains all of the outer left edge. I have highlighted a few of the points here: .
I have tried using the st_convex_hull() function as well as getBorders() which is part of the cartography package, but this gives me the whole outer edge, not just this left edge I want.
This solution uses the northermost and southermost points to split the border with lwgeom
. The desired "edge" need to be selectionned manually (two lines among three). I used meuse
as example. The border is obtained with st_concave_hull(ratio=0.1)
and the points are tested on it. Adjustement might be needed depending of the concavity.
library(tidyverse)
library(sf)
#> Linking to GEOS 3.11.2, GDAL 3.7.2, PROJ 9.3.0; sf_use_s2() is TRUE
library(lwgeom) # for lwgeom::st_split
#> Warning: le package 'lwgeom' a été compilé avec la version R 4.3.3
#> Linking to liblwgeom 3.0.0beta1 r16016, GEOS 3.11.2, PROJ 9.3.1
#> Warning in fun(libname, pkgname): PROJ versions differ: lwgeom has 9.3.1 sf has
#> 9.3.0
#>
#> Attachement du package : 'lwgeom'
#> L'objet suivant est masqué depuis 'package:sf':
#>
#> st_perimeter
library(sp) # for meuse
data(meuse)
df_sf = meuse %>% st_as_sf(coords= c("x","y"),remove= FALSE) %>%
mutate(ID= 1:n())
ggplot(data=df_sf)+geom_sf()
# Boundary
st_simplify(df_sf %>% summarise() %>% st_concave_hull(ratio=0.1) %>% st_cast(to ="LINESTRING")) %>%
st_as_sfc() %>% ggplot(data=.)+geom_sf()
# Getting the points
border_point = df_sf %>% summarise() %>% st_concave_hull(ratio=0.1) %>% st_cast(to ="POINT") %>%
st_join(df_sf, .predicate = st_equals)
# Choosing start/end point.
MinMax = bind_rows(border_point %>% slice_max(y),
border_point %>% slice_min(y))
# Splitting along those points
boundary_split =
lwgeom::st_split(df_sf %>% summarise() %>% st_concave_hull(ratio=0.1) %>% st_cast(to ="LINESTRING"),
MinMax ) %>%
st_collection_extract(., "LINESTRING") %>%
mutate(id_line = 1:n())
# Three lines are generated, since the start/end of the linestring acts as a splitting point as well
# Plotting to identify the releveants id_line (left shore),
boundary_split %>%
ggplot(data=.)+geom_sf( aes(col = id_line %>% as.factor()))
# manually selecting
left_boundary = boundary_split %>% filter( id_line %in% c(1,2))
left_points = st_join(df_sf,left_boundary ) %>%
# Removing unjoinned point (NA), there is certainly a better way
filter( id_line %in% c(1,2))
# Ploting elements
ggplot()+
geom_sf(data=df_sf %>% summarise() %>% st_concave_hull(ratio=0.1),fill=NA)+
geom_sf(data=df_sf,col ="grey")+
geom_sf(data =MinMax, col ="green", size =5)+
geom_sf(data = boundary_split,aes(col = id_line %>% as.factor()) )+
geom_sf(data = left_points, col ="red")
Created on 2024-04-16 with reprex v2.1.0