R/st_disaggregate.R
st_disaggregate.Rd
Disaggregate GEOMETRYCOLLECTION, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON into sub-geometries
st_disaggregate(
x,
only_geometrycollection = FALSE,
keep_empty = FALSE,
warn = TRUE
)
object of class sfg
, sfc
or sf
logical; if TRUE
only
GEOMETRYCOLLECTION
s are disaggregated into their components,
which can include MULTI
-part geometries. If FALSE
(default)
MULTI
-part geometries originating from GEOMETRYCOLLECTION
s or
included as such in x
are further disaggregated into their
sub-geometries.
logical; if TRUE
empty geometries are kept, if
FALSE
(default) they are dropped.
logical; if TRUE
, warn if attributes are assigned to sub-geometries
an object of class sf
, if the input x
itself is an
sf
-object, else a object of class sfc
, containing sub-geometries
of the disaggregated input geometries. The level of disaggregation is
determined by the argument only_geometrycollection
.
When GEOMETRYCOLLECTION
s, MULTIPOINT
s,
MULTILINESTRING
s or MULTIPOLYGON
s are combined in a geometry
set, possibly together with single part geometries, then disaggregating them
can be a cumbersome task. In most situations, some combination of filtering
by geometry type, st_collection_extract
and/or
st_cast
, will do the job. However, st_disaggregate
achieves that much more smoothly (for comparison s. examples below).
In particulate, extracting single and multi-part geometries as such when
contained in the very same GEOMETRYCOLLECTION
(i.e., without
disaggregating the multi-part geometries into their sub-geometries) can be
done with st_disaggregate
, but neither with
st_collection_extract
nor with st_cast
. Furthermore,
st_disaggregate
can dissolve a sfg
object consisting of
a multi-part geometry into all its sub-geometries, while st_cast
would
only return the first of the sub-geometry.
library(sf)
pt1 <- st_point(c(-10, -10))
pt2 <- st_point(c(10, -10))
pt3 <- st_point(c(10, 10))
pt4 <- st_point(c(-10, 10))
pt5 <- st_point(c(6, -5))
mpt <- st_multipoint(c(pt1, pt2, pt5))
ls1 <- st_linestring(c(pt1, pt2, pt3)) * 0.7 + c(1, 0)
ls2 <- st_linestring(c(pt1, pt4)) * 0.9 - c(1, 0)
ls3 <- st_linestring(c(pt1, pt3, pt4)) * 0.2 + c(-5, 6)
mls <- st_multilinestring(list(ls2, ls3))
pl1 <- st_polygon(list(rbind(pt1, pt3, pt4, pt1))) * 0.2 + c(-2, 3)
pl2 <- st_polygon(list(rbind(pt1, pt2, pt3, pt4, pt1) * 0.3,
rbind(pt1, pt2, pt3, pt1) * 0.1)) - c(2, 3)
pl3 <- st_polygon(list(rbind(pt1, pt5, pt3, pt4, pt1))) * 0.2 + c(3, 3)
mpl <- st_multipolygon(list(pl2, pl3))
gc1 <- st_geometrycollection(list(mpt, ls1, mpl))
gc2 <- st_geometrycollection(list()) # empty geometry
# function plotting sfc with distinct color for each geometry
plot_sfc <- function(sfc) {
sfc %>% plot(., col = seq_along(.), border = seq_along(.), lwd = 2, cex = 1.5)
}
plot(gc1)
st_disaggregate(gc1) %>% summary()
#> LINESTRING POINT POLYGON epsg:NA
#> 1 3 2 0
st_disaggregate(gc1) %>% plot_sfc()
st_disaggregate(gc1, only_geometrycollection = TRUE) %>% summary()
#> LINESTRING MULTIPOINT MULTIPOLYGON epsg:NA
#> 1 1 1 0
st_disaggregate(gc1, only_geometrycollection = TRUE) %>% plot_sfc()
mixed_bag <- st_sfc(pt3, pt4, mls, pl1, gc1, gc2)
mixed_bag %>% plot_sfc()
mixed_bag %>% summary()
#> GEOMETRYCOLLECTION MULTILINESTRING POINT POLYGON
#> 2 1 2 1
#> epsg:NA
#> 0
st_disaggregate(mixed_bag) %>% summary()
#> LINESTRING POINT POLYGON epsg:NA
#> 3 5 3 0
st_disaggregate(mixed_bag, only_geometrycollection = TRUE) %>% summary()
#> LINESTRING MULTILINESTRING MULTIPOINT MULTIPOLYGON POINT
#> 1 1 1 1 2
#> POLYGON epsg:NA
#> 1 0
st_disaggregate(mixed_bag, keep_empty = TRUE) %>% summary()
#> GEOMETRYCOLLECTION LINESTRING POINT POLYGON
#> 1 3 5 3
#> epsg:NA
#> 0
st_disaggregate(mixed_bag, keep_empty = TRUE) %>% st_is_empty() %>% summary()
#> Mode FALSE TRUE
#> logical 11 1
mixed_bag_without_gc <- st_sfc(pt3, pt4, mpt, ls1, mls, pl1, mpl)
mixed_bag_without_gc %>% plot_sfc()
mixed_bag_without_gc %>% summary()
#> LINESTRING MULTILINESTRING MULTIPOINT MULTIPOLYGON POINT
#> 1 1 1 1 2
#> POLYGON epsg:NA
#> 1 0
st_disaggregate(mixed_bag_without_gc) %>% summary()
#> LINESTRING POINT POLYGON epsg:NA
#> 3 5 3 0
# if no geometry collection is involved and only_geometrycollection = TRUE ...
# ... then no multi-part geometry is disaggregated:
all.equal(
mixed_bag_without_gc,
st_disaggregate(mixed_bag_without_gc, only_geometrycollection = TRUE)
)
#> [1] TRUE
# compare st_disaggregate() to st_cast() on mixed sets of single and multi-part-geometries:
mixed_ls_mls <- st_sfc(ls1, mls)
mixed_ls_mls %>% summary()
#> LINESTRING MULTILINESTRING epsg:NA
#> 1 1 0
st_disaggregate(mixed_ls_mls) %>% summary()
#> LINESTRING epsg:NA
#> 3 0
st_cast(mixed_ls_mls, "LINESTRING") %>% summary() # only 1st sub-geometry of each multi-part kept.
#> Warning: keeping first linestring only
#> LINESTRING epsg:NA
#> 2 0
st_cast(mixed_ls_mls, "MULTILINESTRING") %>% st_cast("LINESTRING") %>% summary() # this trick works!
#> LINESTRING epsg:NA
#> 3 0
# but st_disaggregate() is more elegant:
st_equals(
st_disaggregate(mixed_ls_mls),
st_cast(mixed_ls_mls, "MULTILINESTRING") %>% st_cast("LINESTRING")
)
#> Sparse geometry binary predicate list of length 3, where the predicate
#> was `equals'
#> 1: 1
#> 2: 2
#> 3: 3
# compare usage of st_disaggregate() and st_collection_extract() for extracting
# single geometries of the same dimension from a geometry collection containing
# single as well as multi-part geometries of that very dimension:
gc <- st_geometrycollection(list(pt1, pt2, ls1, mls))
st_disaggregate(gc) %>% summary()
#> LINESTRING POINT epsg:NA
#> 3 2 0
st_collection_extract(gc, "LINESTRING") %>% summary()
#> MULTILINESTRING epsg:NA
#> 2 0
st_disaggregate(gc) %>% .[st_dimension(.) == 1] %>% summary()
#> LINESTRING epsg:NA
#> 3 0
st_collection_extract(gc, "LINESTRING") %>% st_cast("LINESTRING") %>% summary()
#> LINESTRING epsg:NA
#> 3 0
st_equals(
st_disaggregate(gc) %>% .[st_dimension(.) == 1],
st_collection_extract(gc, "LINESTRING") %>% st_cast("LINESTRING")
)
#> Sparse geometry binary predicate list of length 3, where the predicate
#> was `equals'
#> 1: 2
#> 2: 3
#> 3: 1
# extracting single and multi-part geometries (of the same dimension) as such
# from a geometry collection only works with st_disaggregate():
st_disaggregate(gc, only_geometrycollection = TRUE) %>% .[st_dimension(.) == 1] %>% summary()
#> LINESTRING MULTILINESTRING epsg:NA
#> 1 1 0