#' Plot a time series as a horizon plot
#'
#' A horizon plot breaks the Y dimension down using colours. This is useful
#' when visualising y values spanning a vast range and / or trying to highlight
#' outliers without losing context of the rest of the data.\cr \cr Horizon
#' plots are best viewed in an apsect ratio of very low vertical length.
#'
#' @md
#' @section Aesthetics: `x`, `y`, `fill`. `fill` defaults to `..band..` which is
#' the band number the current data fill area belongs in.
#' @section Other parameters: `bandwidth`, to dictate the span of a band.
#' @export
geom_horizon <- function(mapping = NULL, data = NULL, show.legend = TRUE,
inherit.aes = TRUE, na.rm = TRUE, bandwidth = NULL, ...) {
list(
layer(
data = data,
mapping = mapping,
stat = "horizon",
geom = GeomHorizon,
position = 'identity',
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(bandwidth = bandwidth, na.rm = na.rm, ...)
)
)
}
#' @rdname geom_horizon
#' @keywords internal
#' @export
GeomHorizon <- ggproto("GeomHorizon", GeomArea,
required_aes = c("x", "y"),
default_aes = plyr::defaults(
aes(fill=NA, size = 0.15, linetype = 1, alpha = NA, colour = "gray20"),
ggplot2::GeomArea$default_aes
),
draw_key = ggplot2::draw_key_rect
)
#' Transforms data for a horizon plot
#' @rdname geom_horizon
#' @export
stat_horizon <- function(mapping = NULL, data = NULL, geom = "horizon", show.legend = TRUE,
inherit.aes = TRUE, na.rm = TRUE, bandwidth = NULL, ...) {
list(
layer(
stat = StatHorizon,
data = data,
mapping = mapping,
geom = geom,
position = 'identity',
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(bandwidth = bandwidth, na.rm = na.rm, ...)
)
)
}
#' @rdname geom_horizon
#' @keywords internal
#' @export
StatHorizon <- ggproto(
"StatHorizon",
Stat,
required_aes = c("x", "y"),
default_aes = aes(fill=..band..),
setup_params = function(data, params) {
# calculating a default bandwidth
if (is.null(params$bandwidth)) {
params$bandwidth <- diff(range(data$y)) / 4
message(sprintf("bandwidth not specified. Using computed bandwidth %s",
params$bandwidth))
}
params$n_min_y <- min(data$y, na.rm = TRUE)
params
},
compute_group = function(data, scales, bandwidth, n_min_y) {
# calculating the band in which the values fall
data$fillb <- ((data$y - n_min_y) %/% bandwidth) + 1
# calculating the banded y value
orig_y <- data$y
orig_fill_b <- data$fillb
data$y <- data$y - (bandwidth * (data$fillb - 1)) - n_min_y
fill_bands <- sort(unique(data$fillb))
# for each band, calculating value at a particular x
banded_data <- lapply(
fill_bands,
function(i_fill_band) {
df_banded_data <- data[data$fillb == i_fill_band,]
df_banded_data_high <- data[data$fillb > i_fill_band,]
if (nrow(df_banded_data_high) > 0) {
df_banded_data_high$y <- bandwidth
df_banded_data_high$fillb <- i_fill_band
}
df_banded_data_low <- data[data$fillb < i_fill_band,]
if (nrow(df_banded_data_low) > 0) {
df_banded_data_low$y <- 0
df_banded_data_low$fillb <- i_fill_band
}
data <- rbind(
rbind(df_banded_data, df_banded_data_low),
df_banded_data_high
)
data$fillb <- data$fillb * bandwidth
data$band <- i_fill_band
data$group <- i_fill_band
data
}
)
data <- do.call(rbind, banded_data)
data$band <- factor(data$band)
data
}
)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.