Nothing
#' Subset cells/rows/columns/geometries using their positions
#'
#' @description
#'
#' `slice()` methods lets you index cells/rows/columns/geometries by their
#' (integer) locations. It allows you to select, remove, and duplicate those
#' dimensions of a `Spat*` object.
#'
#' **If you want to slice your `SpatRaster` by geographic coordinates** use
#' [filter.SpatRaster()] method.
#'
#' It is accompanied by a number of helpers for common use cases:
#'
#' - `slice_head()` and `slice_tail()` select the first or last
#' cells/geometries.
#' - `slice_sample()` randomly selects cells/geometries.
#' - `slice_rows()` and `slice_cols()` allow to subset entire rows or columns,
#' of a `SpatRaster`.
#' - `slice_colrows()` subsets regions of the `SpatRaster` by row and column
#' position of a `SpatRaster`.
#'
#' You can get a skeleton of your `SpatRaster` with the cell, column and row
#' index with [as_coordinates()].
#'
#' See **Methods** for details.
#'
#' @export
#' @rdname slice.Spat
#' @name slice.Spat
#'
#' @seealso
#' [dplyr::slice()], [terra::spatSample()].
#'
#' You can get a skeleton of your `SpatRaster` with the cell, column and row
#' index with [as_coordinates()].
#'
#' If you want to slice by geographic coordinates use [filter.SpatRaster()].
#'
#' @family single table verbs
#' @family dplyr.rows
#' @family dplyr.methods
#'
#' @return A `Spat*` object of the same class than `.data`. See **Methods**.
#'
#' @importFrom dplyr slice
#'
#' @inheritParams mutate.Spat
#'
#' @param .preserve Ignored for `Spat*` objects.
#' @param .keep_extent Should the extent of the resulting `SpatRaster` be kept?
#' See also [terra::trim()], [terra::extend()].
#' @param ... <[`data-masking`][rlang::args_data_masking]> Integer row values.
#' Provide either positive values to keep, or negative values to drop.
#'
#' The values provided must be either all positive or all negative. Indices
#' beyond the number of rows in the input are silently ignored. See
#' **Methods**.
#'
#' @param cols,rows Integer col/row values of the `SpatRaster`
#' @param inverse If `TRUE`, `.data` is inverse-masked to the given selection.
#' See [terra::mask()].
#' @param na.rm Logical, should cells that present a value of `NA` removed when
#' computing `slice_min()/slice_max()`?. The default is `TRUE`.
#' @inheritParams dplyr::slice
#'
#' @section \CRANpkg{terra} equivalent:
#'
#' [terra::subset()], [terra::spatSample()]
#'
#' @section Methods:
#'
#' Implementation of the **generic** [dplyr::slice()] function.
#'
#' ## `SpatRaster`
#'
#' The result is a `SpatRaster` with the crs and resolution of the input and
#' where cell values of the selected cells/columns/rows are preserved.
#'
#' Use `.keep_extent = TRUE` to preserve the extent of `.data` on the output.
#' The non-selected cells would present a value of `NA`.
#'
#' ## `SpatVector`
#'
#' The result is a `SpatVector` where the attributes of the selected
#' geometries are preserved. If `.data` is a
#' [grouped][is_grouped_spatvector] `SpatVector`, the operation will be
#' performed on each group, so that (e.g.) `slice_head(df, n = 5)` will select
#' the first five rows in each group.
#'
#' @examples
#'
#'
#' library(terra)
#'
#' f <- system.file("extdata/cyl_temp.tif", package = "tidyterra")
#' r <- rast(f)
#'
#' # Slice first 100 cells
#' r %>%
#' slice(1:100) %>%
#' plot()
#'
#' # Rows
#' r %>%
#' slice_rows(1:30) %>%
#' plot()
#'
#' # Cols
#' r %>%
#' slice_cols(-(20:50)) %>%
#' plot()
#'
#' # Spatial sample
#' r %>%
#' slice_sample(prop = 0.2) %>%
#' plot()
#'
#'
#' # Slice regions
#' r %>%
#' slice_colrows(
#' cols = c(20:40, 60:80),
#' rows = -c(1:20, 30:50)
#' ) %>%
#' plot()
#'
#' # Group wise operation with SpatVectors--------------------------------------
#' v <- terra::vect(system.file("ex/lux.shp", package = "terra"))
#'
#' \donttest{
#' glimpse(v) %>% autoplot(aes(fill = NAME_1))
#'
#' gv <- v %>% group_by(NAME_1)
#' # All slice helpers operate per group, silently truncating to the group size
#' gv %>%
#' slice_head(n = 1) %>%
#' glimpse() %>%
#' autoplot(aes(fill = NAME_1))
#' gv %>%
#' slice_tail(n = 1) %>%
#' glimpse() %>%
#' autoplot(aes(fill = NAME_1))
#' gv %>%
#' slice_min(AREA, n = 1) %>%
#' glimpse() %>%
#' autoplot(aes(fill = NAME_1))
#' gv %>%
#' slice_max(AREA, n = 1) %>%
#' glimpse() %>%
#' autoplot(aes(fill = NAME_1))
#' }
slice.SpatRaster <- function(.data, ..., .preserve = FALSE,
.keep_extent = FALSE) {
# Create skeleton
skeleton <- as_coordinates(.data)
sliced <- dplyr::slice(skeleton, ...)
keepcells <- sliced$cellindex
# Make NA cells
# To NA
tonas <- setdiff(skeleton$cellindex, keepcells)
newrast <- .data
newrast[tonas] <- NA
# With keep_extent we just replaced the cells with NAs
if (.keep_extent) {
return(newrast)
}
# Crop to selected range
range <- range(keepcells)
keepindex <- seq(range[1], range[2], by = 1)
newrast <- newrast[keepindex, drop = FALSE]
return(newrast)
}
#' @export
#' @rdname slice.Spat
slice.SpatVector <- function(.data, ..., .preserve = FALSE) {
# Use own method
tbl <- as_tibble(.data)
ind <- make_safe_index("tterra_index", tbl)
tbl[[ind]] <- seq_len(nrow(tbl))
sliced <- dplyr::slice(tbl, ..., .preserve = .preserve)
# Regenerate
vend <- .data[as.integer(sliced[[ind]]), ]
vend <- group_prepare_spat(vend, sliced)
vend
}
#' @export
#' @rdname slice.Spat
#' @importFrom dplyr slice_head
slice_head.SpatRaster <- function(.data, ..., n, prop, .keep_extent = FALSE) {
# Create skeleton
skeleton <- as_coordinates(.data)
sliced <- dplyr::slice_head(skeleton, ..., n = n, prop = prop)
keepcells <- sliced$cellindex
# Make NA cells
# To NA
tonas <- setdiff(skeleton$cellindex, keepcells)
newrast <- .data
newrast[tonas] <- NA
# With keep_extent we just replaced the cells with NAs
if (.keep_extent) {
return(newrast)
}
newrast <- newrast[keepcells, drop = FALSE]
return(newrast)
}
#' @export
#' @rdname slice.Spat
slice_head.SpatVector <- function(.data, ..., n, prop) {
# Use own method
tbl <- as_tibble(.data)
ind <- make_safe_index("tterra_index", tbl)
tbl[[ind]] <- seq_len(nrow(tbl))
sliced <- dplyr::slice_head(tbl, ..., n = n, prop = prop)
# Regenerate
vend <- .data[as.integer(sliced[[ind]]), ]
vend <- group_prepare_spat(vend, sliced)
vend
}
#' @export
#' @rdname slice.Spat
#' @importFrom dplyr slice_tail
slice_tail.SpatRaster <- function(.data, ..., n, prop, .keep_extent = FALSE) {
# Create skeleton
skeleton <- as_coordinates(.data)
sliced <- dplyr::slice_tail(skeleton, ..., n = n, prop = prop)
keepcells <- sliced$cellindex
# Make NA cells
# To NA
tonas <- setdiff(skeleton$cellindex, keepcells)
newrast <- .data
newrast[tonas] <- NA
# With keep_extent we just replaced the cells with NAs
if (.keep_extent) {
return(newrast)
}
newrast <- newrast[keepcells, drop = FALSE]
return(newrast)
}
#' @export
#' @rdname slice.Spat
slice_tail.SpatVector <- function(.data, ..., n, prop) {
# Use own method
tbl <- as_tibble(.data)
ind <- make_safe_index("tterra_index", tbl)
tbl[[ind]] <- seq_len(nrow(tbl))
sliced <- dplyr::slice_tail(tbl, ..., n = n, prop = prop)
# Regenerate
vend <- .data[as.integer(sliced[[ind]]), ]
vend <- group_prepare_spat(vend, sliced)
vend
}
#' @export
#' @rdname slice.Spat
#' @importFrom dplyr slice_min
slice_min.SpatRaster <- function(.data, order_by, ..., n, prop,
with_ties = TRUE, .keep_extent = FALSE,
na.rm = TRUE) {
# Create skeleton
skeleton <- as_coordinates(.data)
values <- as_tibble(.data, na.rm = FALSE, xy = FALSE)
# Fix names just in case
names(skeleton) <- paste0(names(skeleton), ".tidyterra")
# Add values
skeleton <- dplyr::bind_cols(skeleton, values)
# Remove NAs
if (na.rm) skeleton <- tidyr::drop_na(skeleton)
sliced <- dplyr::slice_min(skeleton,
order_by = {{ order_by }},
..., n = n, prop = prop,
with_ties = with_ties
)
keepcells <- sliced$cellindex.tidyterra
# Make NA cells
# To NA
tonas <- setdiff(skeleton$cellindex.tidyterra, keepcells)
newrast <- .data
newrast[tonas] <- NA
# With keep_extent we just replaced the cells with NAs
if (.keep_extent) {
return(newrast)
}
# Crop to selected range
range <- range(keepcells)
keepindex <- seq(range[1], range[2], by = 1)
newrast <- newrast[keepindex, drop = FALSE]
return(newrast)
}
#' @export
#' @rdname slice.Spat
slice_min.SpatVector <- function(.data, order_by, ..., n, prop,
with_ties = TRUE, na_rm = FALSE) {
# Use own method
tbl <- as_tibble(.data)
ind <- make_safe_index("tterra_index", tbl)
tbl[[ind]] <- seq_len(nrow(tbl))
sliced <- dplyr::slice_min(tbl, ...,
order_by = {{ order_by }}, ..., n = n,
prop = prop, with_ties = with_ties, na_rm = na_rm
)
# Regenerate
vend <- .data[as.integer(sliced[[ind]]), ]
vend <- group_prepare_spat(vend, sliced)
vend
}
#' @export
#' @rdname slice.Spat
#' @importFrom dplyr slice_max
slice_max.SpatRaster <- function(.data, order_by, ..., n, prop,
with_ties = TRUE, .keep_extent = FALSE,
na.rm = TRUE) {
# Create skeleton
skeleton <- as_coordinates(.data)
values <- as_tibble(.data, na.rm = FALSE, xy = FALSE)
# Fix names just in case
names(skeleton) <- paste0(names(skeleton), ".tidyterra")
# Add values
skeleton <- dplyr::bind_cols(skeleton, values)
# Remove NAs
if (na.rm) skeleton <- tidyr::drop_na(skeleton)
sliced <- dplyr::slice_max(skeleton,
order_by = {{ order_by }},
..., n = n, prop = prop,
with_ties = with_ties
)
keepcells <- sliced$cellindex.tidyterra
# Make NA cells
# To NA
tonas <- setdiff(skeleton$cellindex.tidyterra, keepcells)
newrast <- .data
newrast[tonas] <- NA
# With keep_extent we just replaced the cells with NAs
if (.keep_extent) {
return(newrast)
}
# Crop to selected range
range <- range(keepcells)
keepindex <- seq(range[1], range[2], by = 1)
newrast <- newrast[keepindex, drop = FALSE]
return(newrast)
}
#' @export
#' @rdname slice.Spat
slice_max.SpatVector <- function(.data, order_by, ..., n, prop,
with_ties = TRUE, na_rm = FALSE) {
# Use own method
tbl <- as_tibble(.data)
ind <- make_safe_index("tterra_index", tbl)
tbl[[ind]] <- seq_len(nrow(tbl))
sliced <- dplyr::slice_max(tbl, ...,
order_by = {{ order_by }}, ..., n = n,
prop = prop, with_ties = with_ties, na_rm = na_rm
)
# Regenerate
vend <- .data[as.integer(sliced[[ind]]), ]
vend <- group_prepare_spat(vend, sliced)
vend
}
#' @export
#' @rdname slice.Spat
#' @importFrom dplyr slice_sample
slice_sample.SpatRaster <- function(.data, ..., n, prop,
weight_by = NULL, replace = FALSE,
.keep_extent = FALSE) {
# Create skeleton
skeleton <- as_coordinates(.data)
values <- as_tibble(.data, na.rm = FALSE, xy = FALSE)
# Fix names just in case
names(skeleton) <- paste0(names(skeleton), ".tidyterra")
# Add values
skeleton <- dplyr::bind_cols(skeleton, values)
sliced <- dplyr::slice_sample(skeleton, ...,
n = n,
prop = prop, weight_by = weight_by,
replace = replace
)
keepcells <- sliced$cellindex.tidyterra
# Make NA cells
# To NA
tonas <- setdiff(skeleton$cellindex.tidyterra, keepcells)
newrast <- .data
newrast[tonas] <- NA
# With keep_extent we just replaced the cells with NAs
if (.keep_extent) {
return(newrast)
}
# Crop to selected range
range <- range(keepcells)
keepindex <- seq(range[1], range[2], by = 1)
newrast <- newrast[keepindex, drop = FALSE]
return(newrast)
}
#' @export
#' @rdname slice.Spat
slice_sample.SpatVector <- function(.data, ..., n, prop,
weight_by = NULL, replace = FALSE) {
# Use own method
tbl <- as_tibble(.data)
ind <- make_safe_index("tterra_index", tbl)
tbl[[ind]] <- seq_len(nrow(tbl))
sliced <- dplyr::slice_sample(tbl, ..., n = n, prop = prop, replace = replace)
# Regenerate
vend <- .data[as.integer(sliced[[ind]]), ]
vend <- group_prepare_spat(vend, sliced)
vend
}
#' @export
#' @rdname slice.Spat
slice_rows <- function(.data, ...) {
UseMethod("slice_rows")
}
#' @export
#' @rdname slice.Spat
slice_rows.SpatRaster <- function(.data, ..., .keep_extent = FALSE) {
# Create skeleton
skeleton <- as_coordinates(.data)
index <- skeleton["rowindex"]
index$rowindex <- sort(index$rowindex)
index <- dplyr::distinct(index)
slice_dim <- dplyr::slice(index, ...)
# Get cells to make NA
sliced <- dplyr::inner_join(skeleton,
slice_dim,
by = "rowindex"
)
keepcells <- sliced$cellindex
# Make NA cells
# To NA
tonas <- setdiff(skeleton$cellindex, keepcells)
newrast <- .data
newrast[tonas] <- NA
# With keep_extent we just replaced the cells with NAs
if (.keep_extent) {
return(newrast)
}
# Crop to selected range
range <- range(slice_dim$rowindex)
keepindex <- seq(range[1], range[2], by = 1)
newrast <- newrast[keepindex, , drop = FALSE]
return(newrast)
}
#' @export
#' @rdname slice.Spat
slice_cols <- function(.data, ...) {
UseMethod("slice_cols")
}
#' @export
#' @rdname slice.Spat
slice_cols.SpatRaster <- function(.data, ..., .keep_extent = FALSE) {
# Create skeleton
skeleton <- as_coordinates(.data)
index <- skeleton["colindex"]
index$colindex <- sort(index$colindex)
index <- dplyr::distinct(index)
slice_dim <- dplyr::slice(index, ...)
# Get cells to make NA
sliced <- dplyr::inner_join(skeleton,
slice_dim,
by = "colindex"
)
keepcells <- sliced$cellindex
# Make NA cells
# To NA
tonas <- setdiff(skeleton$cellindex, keepcells)
newrast <- .data
newrast[tonas] <- NA
# With keep_extent we just replaced the cells with NAs
if (.keep_extent) {
return(newrast)
}
# Crop to selected range
range <- range(slice_dim$colindex)
keepindex <- seq(range[1], range[2], by = 1)
newrast <- newrast[, keepindex, drop = FALSE]
return(newrast)
}
#' @export
#' @rdname slice.Spat
slice_colrows <- function(.data, ...) {
UseMethod("slice_colrows")
}
#' @export
#' @rdname slice.Spat
slice_colrows.SpatRaster <- function(.data, ..., cols, rows,
.keep_extent = FALSE,
inverse = FALSE) {
# Create skeleton
skeleton <- as_coordinates(.data)
index <- skeleton["colindex"]
index$colindex <- sort(index$colindex)
index <- dplyr::distinct(index)
# Cols
col_index <- skeleton["colindex"]
col_index$colindex <- sort(col_index$colindex)
col_index <- dplyr::distinct(col_index)
slice_cols <- dplyr::slice(col_index, cols)
# Rows
row_index <- skeleton["rowindex"]
row_index$rowindex <- sort(row_index$rowindex)
row_index <- dplyr::distinct(row_index)
slice_rows <- dplyr::slice(row_index, rows)
# Get cells to make NA
sliced <- dplyr::inner_join(skeleton,
slice_cols,
by = "colindex"
)
sliced <- dplyr::inner_join(sliced,
slice_rows,
by = "rowindex"
)
keepcells <- sliced$cellindex
# Make NA cells
# To NA
tonas <- setdiff(skeleton$cellindex, keepcells)
newrast <- .data
newrast[tonas] <- NA
# With keep_extent we just replaced the cells with NAs
if (.keep_extent) {
return(newrast)
}
# Crop to selected range
# cols
range_col <- range(sliced$colindex)
keepindex_col <- seq(range_col[1], range_col[2], by = 1)
range_row <- range(sliced$rowindex)
keepindex_row <- seq(range_row[1], range_row[2], by = 1)
newrast <- newrast[keepindex_row, keepindex_col, drop = FALSE]
return(newrast)
}
#' @export
dplyr::slice
#' @export
dplyr::slice_head
#' @export
dplyr::slice_max
#' @export
dplyr::slice_min
#' @export
dplyr::slice_tail
#' @export
dplyr::slice_sample
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.