I am working on creating a spatial network in R where I need to consider several connected LINESTRINGs as a single line in the network. Each LINESTRING represents a segment of a rail network, and they are connected end-to-end. My goal is to simplify these connections so that the entire sequence of connected lines is treated as a single LINESTRING from start to end point.
Here is what my LINESTRINGs look like (each color represents a different LINESTRING):
However they have grouping Variable indicating which linestrings belong together (they touch each other at the ends)
So my aim is, that as sfn_network() not every single LINESTRING is considerered (with corresponding nodes) but at the end, the only the START/ END of the grouped LINESTRINGs are considered as nodes.
I tried something like:
rails1 <- rails %>% group_by(GROUP) %>%
summarise(do_union =TRUE)%>%
ungroup() %>%
st_cast("MULTILINESTRING") %>%
st_cast("LINESTRING")
structure(list(id = c(1, 1, 1, 1, 1, 6, 7), ID_1 = c(1, 2, 3,
4, 5, 6, 7), GROUP = c(1, 1, 1, 2, 2, 3, 3), geometry = structure(list(
structure(c(9.49750923562068, 9.25766974945376, 51.3143637469628,
51.1041822177009), dim = c(2L, 2L), class = c("XY", "LINESTRING",
"sfg")), structure(c(9.25766974945376, 8.943977955227, 51.1041822177009,
51.0783319880388), dim = c(2L, 2L), class = c("XY", "LINESTRING",
"sfg")), structure(c(8.943977955227, 8.773918358099, 51.0783319880388,
51.1867877726016), dim = c(2L, 2L), class = c("XY", "LINESTRING",
"sfg")), structure(c(8.773918358099, 8.57243470497997, 51.1867877726016,
51.1786769084193), dim = c(2L, 2L), class = c("XY", "LINESTRING",
"sfg")), structure(c(8.57243470497997, 8.56919987568677,
51.1786769084193, 51.144914596165), dim = c(2L, 2L), class = c("XY",
"LINESTRING", "sfg")), structure(c(9.25766974945376, 9.36450576334242,
51.1041822177009, 50.9477904259333), dim = c(2L, 2L), class = c("XY",
"LINESTRING", "sfg")), structure(c(9.36450576334242, 9.21755208973725,
50.9477904259333, 50.9058462470297), dim = c(2L, 2L), class = c("XY",
"LINESTRING", "sfg"))), n_empty = 0L, crs = structure(list(
input = "WGS 84", wkt = "GEOGCRS[\"WGS 84\",\n DATUM[\"World Geodetic System 1984\",\n ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n LENGTHUNIT[\"metre\",1]]],\n PRIMEM[\"Greenwich\",0,\n ANGLEUNIT[\"degree\",0.0174532925199433]],\n CS[ellipsoidal,2],\n AXIS[\"latitude\",north,\n ORDER[1],\n ANGLEUNIT[\"degree\",0.0174532925199433]],\n AXIS[\"longitude\",east,\n ORDER[2],\n ANGLEUNIT[\"degree\",0.0174532925199433]],\n ID[\"EPSG\",4326]]"), class = "crs"), class = c("sfc_LINESTRING",
"sfc"), precision = 0, bbox = structure(c(xmin = 8.56919987568677,
ymin = 50.9058462470297, xmax = 9.49750923562068, ymax = 51.3143637469628
), class = "bbox"))), row.names = c(NA, -7L), class = c("sf",
"data.frame"), sf_column = "geometry", agr = structure(c(id = NA_integer_,
ID_1 = NA_integer_, GROUP = NA_integer_), class = "factor", levels = c("constant",
"aggregate", "identity")))
A combination of dplyr::summarise()
and sf::st_line_merge()
will achieve your desired outcome. Including directed = TRUE
ensures only lines in the same direction (within each group in this reprex) are merged.
library(sf)
library(dplyr)
library(ggplot2)
rails1 <- rails |>
summarise(geometry = st_combine(geometry), .by = GROUP) |>
st_line_merge(directed = TRUE) |>
st_cast("LINESTRING")
rails1
# Simple feature collection with 3 features and 1 field
# Geometry type: LINESTRING
# Dimension: XY
# Bounding box: xmin: 8.5692 ymin: 50.90585 xmax: 9.497509 ymax: 51.31436
# Geodetic CRS: WGS 84
# GROUP geometry
# 1 1 LINESTRING (9.497509 51.314...
# 2 2 LINESTRING (8.773918 51.186...
# 3 3 LINESTRING (9.25767 51.1041...
ggplot() +
geom_sf(data = rails1, aes(colour = factor(GROUP))) +
labs(colour = "GROUP") +
theme_void()