5

I have a dataset with geometry column in which there are linestrings and multilinestrings. While keeping the linestrings I want to convert the multilinestrings to linestrings (which should potentially increase the number of rows of the sf dataframe). Unfortunately when I use sf::st_cast("LINESTRING") there is a warning telling me that it is getting rid of all except the first linestring when transforming. Is there a way to keep all linestrings from the multilinestring when using sf::st_cast. Reproducible example with warning below:

library(sf)
library(dplyr)

# sample dataframe - creating linestrings
df1 <- data.frame(lon = 1:10, lat = 1:10, var = c(1,1,1,2,2,2,3,3,4,4)) %>%
  st_as_sf(coords = c("lon", "lat"), dim = "XY") %>% group_by(var) %>%
  summarise(geometry = st_union(geometry), do_union = F) %>% 
st_cast("LINESTRING")

# creating a multilinestring
df2 <- df1[1:2,] %>% mutate(var = c(1,1)) %>% group_by(var) %>% 
  summarise(geometry = st_union(geometry), do_union = F) %>% 
  st_cast("MULTILINESTRING")

# combining the two
df <- rbind(df1, df2)

# trying to convert only the multilinestring to two linestrings not changing 
the already existing linestrings
df <- df %>% st_cast("LINESTRING")

# Warning message:
# In st_cast.MULTILINESTRING(X[[i]], ...) : keeping first linestring only

I can do it manually first converting everything to multilinestring, and after everything to linestring like in the following:

df <- df %>% st_cast("MULTILINESTRING") %>% st_cast("LINESTRING")

but is there maybe a better way of doing this?

  • 1
    Please check the code when creating a multilinestring the object df[1:2, ] should be df1[1:2, ]. – Guzmán Apr 25 '18 at 13:27
  • 1
    Also, try not to use library(tidyverse) - this example only needs (I think) library(dplyr) to work fine. – Spacedman Apr 25 '18 at 20:08
4

One alternative, to apply an st_cast to "LINESTRING" over each row:

> do.call(rbind,lapply(1:nrow(df),function(i){st_cast(df[i,],"LINESTRING")}))
Simple feature collection with 6 features and 1 field
geometry type:  LINESTRING
dimension:      XY
bbox:           xmin: 1 ymin: 1 xmax: 10 ymax: 10
epsg (SRID):    NA
proj4string:    NA
  var                   geometry
1   1 LINESTRING (1 1, 2 2, 3 3)
2   2 LINESTRING (4 4, 5 5, 6 6)
3   3      LINESTRING (7 7, 8 8)
4   4    LINESTRING (9 9, 10 10)
5   1 LINESTRING (1 1, 2 2, 3 3)
6   1 LINESTRING (4 4, 5 5, 6 6)

cant really be much better than:

> st_cast(st_cast(df, "MULTILINESTRING"),"LINESTRING")
Simple feature collection with 6 features and 1 field
geometry type:  LINESTRING
dimension:      XY
bbox:           xmin: 1 ymin: 1 xmax: 10 ymax: 10
epsg (SRID):    NA
proj4string:    NA
  var                   geometry
1   1 LINESTRING (1 1, 2 2, 3 3)
2   2 LINESTRING (4 4, 5 5, 6 6)
3   3      LINESTRING (7 7, 8 8)
4   4    LINESTRING (9 9, 10 10)
5   1 LINESTRING (1 1, 2 2, 3 3)
6   1 LINESTRING (4 4, 5 5, 6 6)

I assume that's what you mean in your last line, you don't give code. This is probably pretty close to optimal. library(microbenchmark) reckons the two-casts is about 10 times faster on your little example:

Unit: milliseconds
  expr      min       lq      mean    median       uq       max neval
 apply 9.087103 9.411445 10.056437 10.061594 10.50437 12.969576   100
 casts 1.737474 1.819215  2.000212  1.866471  1.92306  4.406047   100
  • yes, I thought there might be a simpler way than writing cast two times. Now it's clear. Many thanks! – adl Apr 25 '18 at 21:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.