12

I have a list of sf objects that I would like to row bind to create a single sf object. I'm looking for a function similar to data.table::rbindlist, that would stack the individual objects in an efficient manner.

Data for reproducible example:

my_list <- structure(list(structure(list(idhex = 4L, geometry = structure(list(
            structure(c(664106.970004623, 6524137.38910266), class = c("XY", 
            "POINT", "sfg"))), class = c("sfc_POINT", "sfc"), precision = 0, bbox = structure(c(xmin = 664106.970004623, 
            ymin = 6524137.38910266, xmax = 664106.970004623, ymax = 6524137.38910266
            ), class = "bbox"), crs = structure(list(epsg = 32633L, proj4string = "+proj=utm +zone=33 +datum=WGS84 +units=m +no_defs"), class = "crs"), n_empty = 0L)), row.names = 1L, class = c("sf", 
            "data.frame"), sf_column = "geometry", agr = structure(c(idhex = NA_integer_), .Label = c("constant", 
            "aggregate", "identity"), class = "factor")), structure(list(
            idhex = 9, geometry = structure(list(structure(c(665491.220375992, 
            6525002.7560692), class = c("XY", "POINT", "sfg"))), class = c("sfc_POINT", 
            "sfc"), precision = 0, bbox = structure(c(xmin = 665491.220375992, 
            ymin = 6525002.7560692, xmax = 665491.220375992, ymax = 6525002.7560692
            ), class = "bbox"), crs = structure(list(epsg = 32633L, proj4string = "+proj=utm +zone=33 +datum=WGS84 +units=m +no_defs"), class = "crs"), n_empty = 0L)), row.names = 1L, class = c("sf", 
            "data.frame"), sf_column = "geometry", agr = structure(c(idhex = NA_integer_), .Label = c("constant", 
            "aggregate", "identity"), class = "factor"))), .Dim = 1:2, .Dimnames = list(
            ".", NULL))

Note that data.table and sf libraries are not entirely compatible yet. So the rbindlist function returns an object that is not recognized as an `sf object.

single_sf <- rbindlist(my_list)
class(single_sf)
Frank
  • 63,401
  • 8
  • 85
  • 161
rafa.pereira
  • 10,729
  • 4
  • 59
  • 88
  • 1
    Though you can easily convert to a sf (if the crs are equivalent) `sf::st_as_sf(data.table::rbindlist(my_list))` – TimSalabim Jul 13 '18 at 16:23
  • 1
    For completeness, @timelyportfolio also wrote `mapedit:::combine_list_of_sf` to achieve this. It may also be worth monitoring https://github.com/r-spatial/mapedit/issues/46 as a dedicated `bind_rows_sf` may be implemented in **sf** at some stage. – TimSalabim Jul 15 '18 at 09:28

2 Answers2

17
df <- do.call(rbind, my_list)

> class(df)
[1] "sf"         "data.frame"

It is worth noting that dplyr::bind_rows and purrr::map_dfr does not work with sf objects, and thus rbind is better in this case.

sebdalgarno
  • 2,351
  • 6
  • 23
1

This is an old question but it is worth to note that the recent version of dplyr (> 0.9) can bind rows of sf objects (in a list or not):

single_sf <- dplyr::bind_rows(my_list)
class(single_sf)
[1] "sf"         "data.frame"

Other packages also provide options that can be used for binding sf objects (e.g. mapedit:::combine_list_of_sf(), sf:::rbind.sf and data.table::rbindlist), besides the do.call() option mentioned above (see https://github.com/r-spatial/sf/issues/798# for a discussion and some benchmarking). But the dplyr option also works for sf objects with data frames containing different number of columns, somenthing that do.call(), sf:::rbind.sf(), and data.table::rbindlist() cannot do, and was important for me working with a list of sf objects with different number of columns.

R. Lima
  • 314
  • 1
  • 11