Sf: Apply st_bbox() for each feature

Created on 18 Oct 2019  路  10Comments  路  Source: r-spatial/sf

I have a set of polygons and i want to find the bbox for each polygon/ With st_bbox() i obtain the bbox for the whole set of features but i want to obtain bbox for each single feature. I try to use group_by() but the output is always the same.

g <- st_sfc(st_point(1:2), st_point(3:4)) %>% st_buffer(dist = 1)
s <- st_sf(a=3:4, g)
s %>% group_by(a) %>% st_bbox()%>% st_as_sfc

Most helpful comment

If you want to have it work with sf objects also (not only sfc geometry columns), you'd need to extract the geometries first:

library(sf)
library(mapview)

st_bbox_by_feature = function(x) {
  x = st_geometry(x)
  f <- function(y) st_as_sfc(st_bbox(y))
  do.call("c", lapply(x, f))
}

mapview(franconia) + st_bbox_by_feature(franconia)

Screenshot from 2019-10-18 10-58-07

As you see, there's many was to accomplish this...

Also, be aware of MULTI* geometries

All 10 comments

Tidyverse is confusing you:

library(sf)
g0 <- st_sfc(st_point(1:2), st_point(3:4))
g1 <- st_buffer(g0, dist=1)
is.list(g1)
f <- function(x) st_as_sfc(st_bbox(x))
bbs <- do.call("c", lapply(g1, f))
bbs

Note that ?st_bbox says "st_as_sfc has a methods for 'bbox' objects to generate a polygon around the four bounding box points", hence the apparent need to iterate over the list of "sfg" objects and then catenate the output "sfc" objects.

Or in another dialect:

bbs <- Reduce("c", Map(f, g1))
bbs

If you want to have it work with sf objects also (not only sfc geometry columns), you'd need to extract the geometries first:

library(sf)
library(mapview)

st_bbox_by_feature = function(x) {
  x = st_geometry(x)
  f <- function(y) st_as_sfc(st_bbox(y))
  do.call("c", lapply(x, f))
}

mapview(franconia) + st_bbox_by_feature(franconia)

Screenshot from 2019-10-18 10-58-07

As you see, there's many was to accomplish this...

Also, be aware of MULTI* geometries

Right, you need a list, and an "sfc" is a list column, so st_geometry() first. Do you have an example of MULTI-issues?

Not really an issue, just something to be aware of...

mapview(franconia[17, ]) + st_bbox_by_feature(franconia[17, ])

Screenshot from 2019-10-18 11-04-01

vs.

mapview(franconia[17, ]) + st_bbox_by_feature(st_cast(franconia[17, ], "POLYGON"))

Screenshot from 2019-10-18 11-04-23

when working with sf objects, there is a way to save data.frame obs?

You could just save it as a new column in the original df.

franconia$bbox = st_bbox_by_feature(franconia)
franconia

Simple feature collection with 37 features and 6 fields
Active geometry column: geometry
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: 8.975926 ymin: 48.8625 xmax: 12.27535 ymax: 50.56422
epsg (SRID):    4326
proj4string:    +proj=longlat +datum=WGS84 +no_defs
First 10 features:
   NUTS_ID  SHAPE_AREA SHAPE_LEN CNTR_CODE                  NAME_ASCI
1    DE241 0.006736012 0.3926225        DE  Bamberg, Kreisfreie Stadt
2    DE242 0.008424469 0.6247263        DE Bayreuth, Kreisfreie Stadt
3    DE243 0.005982341 0.5185471        DE   Coburg, Kreisfreie Stadt
4    DE244 0.007329480 0.4569815        DE      Hof, Kreisfreie Stadt
5    DE245 0.146698316 3.4819699        DE         Bamberg, Landkreis
6    DE246 0.159489736 3.6242023        DE        Bayreuth, Landkreis
7    DE247 0.074698748 2.6954234        DE          Coburg, Landkreis
8    DE248 0.079746707 1.7712298        DE                  Forchheim
9    DE249 0.112934151 2.7544708        DE             Hof, Landkreis
10   DE24A 0.081960299 1.9393830        DE                    Kronach
                         geometry    district                           bbox
1  MULTIPOLYGON (((10.92581 49... Oberfranken POLYGON ((10.83009 49.84247...
2  MULTIPOLYGON (((11.58157 49... Oberfranken POLYGON ((11.47477 49.88826...
3  MULTIPOLYGON (((10.95355 50... Oberfranken POLYGON ((10.88744 50.22205...
4  MULTIPOLYGON (((11.93067 50... Oberfranken POLYGON ((11.80842 50.26711...
5  MULTIPOLYGON (((10.87615 50... Oberfranken POLYGON ((10.43991 49.72112...
6  MULTIPOLYGON (((11.70657 50... Oberfranken POLYGON ((11.18432 49.61388...
7  MULTIPOLYGON (((10.88654 50... Oberfranken POLYGON ((10.71245 50.08796...
8  MULTIPOLYGON (((11.26376 49... Oberfranken POLYGON ((10.91986 49.58733...
9  MULTIPOLYGON (((11.91988 50... Oberfranken POLYGON ((11.5286 50.10325,...
10 MULTIPOLYGON (((11.36979 50... Oberfranken POLYGON ((11.16854 50.16031...

That works when the bbox is taken over a MULTI-object, but is there an st_join() variant for those st_cast() to multiple rows - how to preserve IDs?

@rsbivand if I understand you correctly, I guess you'd need to cast the original sf object to single features first, then calculate the bounding boxes. Then recast to MULTI* and append

fran = st_cast(franconia, "POLYGON")
bbox = st_bbox_by_feature(fran)

bbox_multi = st_cast(bbox, "MULTIPOLYGON", 
                     ids = as.integer(rownames(fran)), 
                     group_or_split = TRUE)

franconia$bbox = bbox_multi

mapview(franconia[17, ]) + franconia[17, ]$bbox

Screenshot from 2019-10-18 11-51-10

where the bbox is now a MULTIPOLYGON. There may be a more elegant way, but this seems to work...

Closing here. Feel free to reopen if necessary

Was this page helpful?
0 / 5 - 0 ratings