#' Contours from a 2d density estimate.
#'
#' @inheritParams ggplot2::geom_point
#' @inheritParams ggplot2::geom_path
#' @export
#' @examples
#' m <- ggplot(faithful, aes(x = eruptions, y = waiting)) +
#' geom_point() +
#' xlim(0.5, 6) +
#' ylim(40, 110)
#'
#' m + geom_bkde2d(bandwidth=c(0.5, 4))
#'
#' m + stat_bkde2d(bandwidth=c(0.5, 4), aes(fill = ..level..), geom = "polygon")
#'
#' # If you map an aesthetic to a categorical variable, you will get a
#' # set of contours for each value of that variable
#' set.seed(4393)
#' dsmall <- diamonds[sample(nrow(diamonds), 1000), ]
#' d <- ggplot(dsmall, aes(x, y)) +
#' geom_bkde2d(bandwidth=c(0.5, 0.5), aes(colour = cut))
#' d
#'
#' # If we turn contouring off, we can use use geoms like tiles:
#' d + stat_bkde2d(bandwidth=c(0.5, 0.5), geom = "raster",
#' aes(fill = ..density..), contour = FALSE)
#'
#' # Or points:
#' d + stat_bkde2d(bandwidth=c(0.5, 0.5), geom = "point",
#' aes(size = ..density..), contour = FALSE)
geom_bkde2d <- function(mapping = NULL, data = NULL, stat = "bkde2d",
position = "identity", bandwidth=NULL, range.x=NULL,
lineend = "butt", contour=TRUE,
linejoin = "round", linemitre = 1,
na.rm = FALSE, show.legend = NA,
inherit.aes = TRUE, ...) {
layer(
data = data,
mapping = mapping,
stat = stat,
geom = GeomBkde2d,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
lineend = lineend,
linejoin = linejoin,
linemitre = linemitre,
bandwidth = bandwidth,
range.x = range.x,
na.rm = na.rm,
...
)
)
}
#' Geom Proto
#' @rdname ggalt-ggproto
#' @format NULL
#' @usage NULL
#' @keywords internal
#' @export
GeomBkde2d <- ggproto("GeomBkde2d", GeomPath,
default_aes = aes(colour = "#3366FF", size = 0.5, linetype = 1, alpha = NA)
)
#' Contours from a 2d density estimate.
#'
#' Perform a 2D kernel density estimation using \code{bkde2D} and display the
#' results with contours. This can be useful for dealing with overplotting
#'
#' \if{html}{
#' A sample of the output from \code{geom_bkde2d()}:
#'
#' \figure{geombkde2d01.png}{options: width="100\%" alt="Figure: geombkde2d01.png"}
#' }
#'
#' \if{latex}{
#' A sample of the output from \code{geom_bkde2d()}:
#'
#' \figure{geombkde2d01.png}{options: width=10cm}
#' }
#'
#' @param bandwidth the kernel bandwidth smoothing parameter. see
#' \code{\link[KernSmooth]{bkde2D}} for details. If \code{NULL},
#' it will be computed for you but will most likely not yield optimal
#' results. see \code{\link[KernSmooth]{bkde2D}} for details
#' @param grid_size vector containing the number of equally spaced points in each
#' direction over which the density is to be estimated. see
#' \code{\link[KernSmooth]{bkde2D}} for details
#' @param geom default geom to use with this stat
#' @param range.x a list containing two vectors, where each vector contains the
#' minimum and maximum values of x at which to compute the estimate for
#' each direction. see \code{\link[KernSmooth]{bkde2D}} for details
#' @param truncate logical flag: if TRUE, data with x values outside the range
#' specified by range.x are ignored. see \code{\link[KernSmooth]{bkde2D}}
#' for details
#' @param contour If \code{TRUE}, contour the results of the 2d density
#' estimation
#' @section Computed variables:
#' Same as \code{\link{stat_contour}}
#' @seealso \code{\link{geom_contour}} for contour drawing geom,
#' \code{\link{stat_sum}} for another way of dealing with overplotting
#' @rdname geom_bkde2d
#' @export
stat_bkde2d <- function(mapping = NULL, data = NULL, geom = "density2d",
position = "identity", contour = TRUE,
bandwidth=NULL, grid_size=c(51, 51), range.x=NULL,
truncate=TRUE, na.rm = FALSE, show.legend = NA,
inherit.aes = TRUE, ...) {
layer(
data = data,
mapping = mapping,
stat = StatBkde2d,
geom = geom,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(
bandwidth = bandwidth,
grid_size = grid_size,
range.x = range.x,
truncate = truncate,
contour = contour,
na.rm = na.rm,
...
)
)
}
#' @rdname ggalt-ggproto
#' @format NULL
#' @usage NULL
#' @export
StatBkde2d <- ggproto("StatBkde2d", Stat,
default_aes = aes(colour = "#3366FF", size = 0.5),
required_aes = c("x", "y"),
compute_group = function(data, scales, contour=TRUE, bandwidth=NULL,
grid_size=c(51, 51), range.x=NULL,
truncate=TRUE) {
# See geom_bkde/stat_bkde
if (is.null(bandwidth)) {
tmp <- tempfile()
on.exit(unlink(tmp))
save(".Random.seed", file=tmp)
set.seed(1492)
bandwidth <- c(KernSmooth::dpik(data$x),
KernSmooth::dpik(data$y))
message(
sprintf("Bandwidth not specified. Using ['%3.2f', '%3.2f'], via KernSmooth::dpik.",
bandwidth[1], bandwidth[2]))
load(tmp)
}
if (is.null(range.x)) {
x_range <- range(data$x)
y_range <- range(data$y)
x_range[1] <- x_range[1] - 1.75 * bandwidth[1]
x_range[2] <- x_range[2] + 1.75 * bandwidth[1]
y_range[1] <- y_range[1] - 1.75 * bandwidth[2]
y_range[2] <- y_range[2] + 1.75 * bandwidth[2]
range.x <- list(x_range, y_range)
}
dens <- KernSmooth::bkde2D(
as.matrix(data.frame(x=data$x, y=data$y)),
bandwidth,
grid_size,
range.x,
truncate
)
df <- data.frame(expand.grid(x=dens$x1,
y=dens$x2),
z=as.vector(dens$fhat))
df$group <- data$group[1]
if (contour) {
StatContour$compute_panel(df, scales)
} else {
names(df) <- c("x", "y", "density", "group")
df$level <- 1
df$piece <- 1
df
}
}
)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.