#' Geographic statistics for sets of cells with the same values
#'
#' @description This function calculates geographic statistics for each set of cells in an `integer` or `factor` `GRaster`. Statistics include:
#' * Area
#' * Perimeter length
#' * "Compact square" statistic: \eqn{4 \sqrt(area) / perimeter)}
#' * "Compact circle" statistic: \eqn{4 * P / ( 2 \sqrt(\pi * A))} where *P* is the perimeter length and *A* the area.
#' * fractal dimension: \eqn{2 ( log(P) / log(A + 0.001))} where *P* is perimeter length and *A* is area.
#' * The average x- and y-coordinates of each zone.
#'
#' @param x A `GRaster`.
#'
#' @param unit Character: Units of the output. Any of:
#' * `"meters"` (default)
#' * `"kilometers"` or `"km"`
#' * `"miles"` or `"mi"`
#' * `"yards"` or `"yd"`
#' * `"feet"` or `"ft"`: International foot; 1 foot exactly equal to 0.3048 meters
#' * `"cells"`: Number or cells
#'
#' Partial matching is used and case is ignored.
#'
#' @returns A list of `data.frame`s or a `data.table`s, one per layer in `x`. Only layers that are integers or factors have their geographies calculated. Other layers have `NULL` tables returned.
#'
#' @example man/examples/ex_zonalGeog.r
#'
#' @aliases zonalGeog
#' @rdname zonalGeog
#' @exportMethod zonalGeog
methods::setMethod(
f = "zonalGeog",
signature(x = "GRaster"),
function(x, unit = "meters") {
.locationRestore(x)
.region(x)
units <- c("m", "meters", "kilometers", "km", "miles", "feet", "ft", "yards", "yd", "cells")
unit <- omnibus::pmatchSafe(unit, units, useFirst = TRUE, nmax = 1L)
unit <- omnibus::expandUnits(unit)
flags <- if (unit != "cells") {
c(.quiet(), "m")
} else {
.quiet()
}
isFact <- is.factor(x)
isInt <- is.int(x)
nLayers <- nlyr(x)
out <- list()
for (i in seq_len(nLayers)) {
if (isInt[i] | isFact[i]) {
args <- list(
cmd = "r.object.geometry",
input = sources(x)[i],
intern = TRUE
)
if (!is.null(flags)) args$flags <- flags
info <- do.call(rgrass::execGRASS, args = args)
info <- strsplit(info, split = "\\|")
n <- length(info) - 1L
if (isFact[i]) {
xDrop <- x[[i]]
xDrop <- droplevels(xDrop)
labels <- levels(xDrop)[[1L]]
catName <- names(labels)[activeCat(xDrop) + 1L]
labels <- labels[[catName]]
thisOut <- data.table::data.table(
value = rep(NA_integer_, n),
label = labels,
area = rep(NA_real_, n),
perimeter = rep(NA_real_, n),
compactSquare = rep(NA_real_, n),
compactCircle = rep(NA_real_, n),
fractalDimension = rep(NA_real_, n),
meanX = rep(NA_real_, n),
meanY = rep(NA_real_, n)
)
# integer raster
} else {
thisOut <- data.table::data.table(
value = rep(NA_integer_, n),
area = rep(NA_real_, n),
perimeter = rep(NA_real_, n),
compactSquare = rep(NA_real_, n),
compactCircle = rep(NA_real_, n),
fractalDimension = rep(NA_real_, n),
meanX = rep(NA_real_, n),
meanY = rep(NA_real_, n)
)
} # pre-assign data table
for (j in 2L:length(info)) {
val <- info[[j]][1L]
val <- as.integer(val)
vals <- info[[j]]
vals <- as.numeric(vals)
index <- j - 1L
thisOut$value[index] <- val
thisOut$area[index] = vals[2L]
thisOut$perimeter[index] = vals[3L]
thisOut$compactSquare[index] = vals[4L]
thisOut$compactCircle[index] = vals[5L]
thisOut$fractalDimension[index] = vals[6L]
thisOut$meanX[index] = vals[7L]
thisOut$meanY[index] = vals[8L]
}
area <- perimeter <- NULL
if (unit == "kilometers") {
f <- omnibus::convertUnits(from = "meters2", to = "kilometers2")
thisOut[ , area := area * f]
f <- omnibus::convertUnits(from = "meters", to = "kilometers")
thisOut[ , perimeter := perimeter * f]
} else if (unit == "miles") {
f <- omnibus::convertUnits(from = "meters2", to = "miles2")
thisOut[ , area := area * f]
f <- omnibus::convertUnits(from = "meters", to = "miles")
thisOut[ , perimeter := perimeter * f]
} else if (unit == "feet") {
f <- omnibus::convertUnits(from = "meters2", to = "feet2")
thisOut[ , area := area * f]
f <- omnibus::convertUnits(from = "meters", to = "feet")
thisOut[ , perimeter := perimeter * f]
} else if (unit == "yards") {
f <- omnibus::convertUnits(from = "meters2", to = "yards2")
thisOut[ , area := area * f]
f <- omnibus::convertUnits(from = "meters", to = "yards")
thisOut[ , perimeter := perimeter * f]
}
# if raster is NOT integer or factor
} else {
thisOut <- data.table::data.table(NULL)
}
out[[i]] <- thisOut
} # next layer
names(out) <- names(x)
if (!faster("useDataTable")) {
for (i in seq_along(out)) out[[i]] <- as.data.frame(out)
}
out
} # EOF
)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.