我正在尝试使用sf包和管道/ tidyverse工作流程来基于另一列中定义的组生成边界框。我认为它应该像下面那样工作,但是似乎st_bbox不尊重组。
我希望收到三个多边形记录,分别代表来自a,b和c的轮廓的边界框,但我收到三个多边形记录,它们代表所有点的边界框。
library(dplyr)
library(sf)
a <- data.frame(group=rep('a',100), lon=rnorm(100,11,.2), lat=rnorm(100,53,.2))
b <- data.frame(group=rep('b',100), lon=rnorm(100,11.5,.2), lat=rnorm(100,53.5,.2))
c <- data.frame(group=rep('c',100), lon=rnorm(100,12,.2), lat=rnorm(100,54,.2))
dat <- rbind(a,b,c)
pts <- dat %>% st_as_sf(coords=c('lon','lat'),crs=4326)
pts %>%
group_by(group) %>%
summarize(geometry = st_as_sfc(st_bbox(geometry)))
这将返回:
Simple feature collection with 3 features and 1 field
geometry type: POLYGON
dimension: XY
bbox: xmin: 10.34313 ymin: 52.43993 xmax: 12.54254 ymax: 54.54012
epsg (SRID): 4326
proj4string: +proj=longlat +datum=WGS84 +no_defs
# A tibble: 3 x 2
group geometry
<fct> <POLYGON [°]>
1 a ((10.34313 52.43993, 12.54254 52.43993, 12.54254 54.54012, 10.34313 54.54012, 10.34313 52...
2 b ((10.34313 52.43993, 12.54254 52.43993, 12.54254 54.54012, 10.34313 54.54012, 10.34313 52...
3 c ((10.34313 52.43993, 12.54254 52.43993, 12.54254 54.54012, 10.34313 54.54012, 10.34313 52...
答案 0 :(得分:3)
一种选择是先使用tidyr::nest
然后使用purrr::map
嵌套数据框。我还使用了包装函数来简化map
调用
library(tidyverse)
box_sf <- pts %>%
group_by(group) %>%
nest()
bbox_wrap <- function(x) st_as_sfc(st_bbox(x))
box_sf <- box_sf %>%
mutate(bbox = map(data, bbox_wrap))
这将为您提供边界框列表,作为数据框的一列。如果要转换回sf
对象,可以执行以下操作:
box_sf %>%
mutate(geometry = st_as_sfc(do.call(rbind, bbox))) %>%
select(-data, -bbox) %>%
st_as_sf()
似乎有点回旋处,我希望能按照您的原意使用group_by
来解决问题
答案 1 :(得分:0)
st_bbox()
函数似乎无法与group_by()
一起使用,因为它从sf_points
中提取了bbox属性,该属性并未为每个单独的组定义。
一种方法是使用类似以下内容的方法手动创建边界框:
library(dplyr)
library(sf)
library(ggplot2)
library(tidyr)
# function calculates angle with respect to polygon centroid.
# we need this to order the polygon correctly
calc_angle <- function(lon,lat) {
cent_lon <- mean(lon)
cent_lat <- mean(lat)
ang <- atan2(lat - cent_lat, lon - cent_lon)
return(ang)
}
bbox <-dat %>%
group_by(group) %>%
summarise(xmin = min(lon),ymin = min(lat), xmax=max(lon), ymax = max(lat)) %>%
gather(x,lon,c('xmin','xmax')) %>%
gather(y,lat,c('ymin','ymax')) %>%
st_as_sf(coords=c('lon','lat'),crs=4326,remove=F) %>%
group_by(group) %>%
mutate(angle = calc_angle(lon,lat)) %>%
arrange(angle) %>%
summarise(do_union=FALSE) %>%
st_cast('POLYGON')
基本上,我们通过获取每个组的xmin,xmax,ymin,ymax来计算自己的bbox。然后,我们进行汇总以保留x和y值,并在转换为polygon
之前按顺时针顺序对点进行排序。
看起来有些混乱,但这是使用group_by()
解决此问题的一种方法。
pts <- dat %>%
st_as_sf(coords=c('lon','lat'), crs=4326, remove=F)
ggplot(pts) + geom_sf(aes(col=group)) +
geom_sf(data=bbox, aes(col=group), fill=NA)