#' @title Emulates ggplot2 Default Color Palette
#'
#' @param n Integer: number of output colors
#' @return A character vector of HEX colors of length \code{n}
#' @examples
#' gg_color_hue(n = 3)
#' @export
gg_color_hue <- function(n) {
hues <- seq(15, 375, length = n + 1)
return(hcl(h = hues, l = 65, c = 100)[1:n])
}
#' @title Makes Color(s) Transparent
#'
#' @param color Color vector: vector of any of the three kinds of R color
#' specifications, i.e., either a color name (as listed by
#' \code{\link{colors}()}), a hexadecimal string of the form \code{"#rrggbb"}
#' or \code{"#rrggbbaa"} (see \code{\link{rgb}}), or a positive integer
#' \code{i} meaning \code{\link{palette}()[i]}.
#' @param alpha Numeric: amount of transparency in `[0, 1]`
#' @return A character vector of HEX colors of same length as \code{color}
#' @examples
#' add_alpha(c('red', 'blue'), alpha = 0.5)
#' @export
#' @seealso \code{\link[ggplot2]{scale_alpha}}
add_alpha <- function(color, alpha = 1) {
if(alpha < 0 | alpha > 1)
stop('alpha value must be in [0, 1]')
return(apply(unname(sapply(color, grDevices::col2rgb)) / 255, 2,
FUN = function(x) {grDevices::rgb(x[1], x[2], x[3],
alpha = alpha)}))
}
#' @title Compute Pretty Axis Ticks of Log-scale
#'
#' @description A wrapper function of \code{\link[grDevices]{axisTicks}} that
#' uses log scale.
#' @param n Integer: value indicating (approximately) the desired number of
#' intervals. See also \code{nint} in \code{\link[grDevices]{axisTicks}}
#' @return A function that taks a numeric vector and computes log-scale axis
#' tick locations
#' @examples
#' tick_func <- base_log_breaks(n = 10)
#' tick_func(runif(100, 0, 10))
#' @export
#' @seealso \code{\link[grDevices]{axisTicks}}
base_log_breaks <- function(n = 10){
function(x) {
grDevices::axisTicks(log10(range(x, na.rm = TRUE)), log = TRUE, n = n)
}
}
#' @title Create A Log-scale And Reverse Order Transformation Object
#'
#' @description A transformation created with \code{\link[scales]{trans_new}}
#' by setting \code{transform} to log-scale and \code{inverse} to
#' reverse-order function
#'
#' @param base Integer: the base with respect to which logarithms are computed
#' @return A transformation object
#' @examples
#' \dontrun{
#' revlog_trans <- reverselog_trans(base = 10)
#' }
#' @seealso \code{\link[scales]{trans_new}}
reverselog_trans <- function(base = 10) {
trans <- function(x) -log(x, base)
inv <- function(x) base^(-x)
scales::trans_new(paste0('reverselog-', format(base)), trans, inv,
breaks = base_log_breaks(),
domain = c(.Machine$double.xmin, Inf))
}
#' @title Check If Valid Color Representation
#'
#' @description A valid color representation is any of the three kinds of R
#' color specifications, i.e., either a color name (as listed by
#' \code{\link{colors}()}), a hexadecimal string of the form \code{"#rrggbb"}
#' or \code{"#rrggbbaa"} (see \code{\link{rgb}}), or a positive integer
#' \code{i} meaning \code{\link{palette}()[i]}.
#' @param obj Object: object to be tested
#' @return Logical: \code{TRUE} if the object is a valid color representation,
#' \code{FALSE} otherwise
#' @examples
#' is.color(c('red', 'blue'))
#' is.color(1)
#' is.color('abcd')
#' @export
#' @seealso \code{\link[grDevices]{col2rgb}}
is.color <- function(obj) {
sapply(obj, function(X) {
tryCatch(is.matrix(grDevices::col2rgb(X)),
error = function(e) FALSE)
})
}
#' @title ggplot position_jitter with random seed
gg_jitter <- function(x, width = NULL, randseed = NULL) {
if(!is.null(randseed)) set.seed(randseed)
if(is.null(width)) width <- ggplot2::resolution(x, zero = FALSE) * 0.4
trans_x <- base::jitter(x, amount = width)
return(trans_x)
}
#' @title imitate ggplot position_dodge
gg_dodge <- function(x, group, width = NULL) {
if(any(is.null(x), is.null(group)))
stop('both `x` and `group` must be present')
if(is.null(width)) width <- ggplot2::resolution(x, zero = FALSE) * 0.75
if(!is.factor(group)) group <- factor(group)
ngroups <- nlevels(group)
x <- x + (as.integer(group) - median(seq_len(ngroups))) / ngroups * width
return(x)
}
#' @title Set/Modify ggplot2 Components
#'
#' @description Helper function that allows the user to easily set/modify
#' ggplot2 object components, such as title, x-/y-axis log scale, grids and
#' etc..
gg_wrapper <- function(..., facet_r = NULL, facet_c = NULL,
facet_scale = 'fixed', facet_space = 'fixed',
is_x_continuous = TRUE, is_y_continuous = TRUE,
x_lab = NULL, y_lab = NULL, title = NULL,
x_limit = NULL, y_limit = NULL,
x_log = FALSE, y_log = FALSE,
x_reverse = FALSE, y_reverse = FALSE,
x_axis_breaks = NULL, y_axis_breaks = NULL,
x_tick_labels = x_axis_breaks,
y_tick_labels = y_axis_breaks,
x_tick_angle = 0, y_tick_angle = 0,
x_hjust = 0.5, y_hjust = 0.5,
add_legend = TRUE, legend_pos = 'bottom',
color_var = NULL, color_lab = color_var, all_colors = NULL,
fill_var = NULL, fill_lab = fill_var, all_fills = NULL,
size_var = NULL, size_lab = size_var, all_sizes = NULL,
shape_var = NULL, shape_lab = shape_var, all_shapes = NULL,
linetype_var = NULL, linetype_lab = linetype_var,
all_linetypes = NULL,
alpha_var = NULL, alpha_lab = alpha_var, all_alphas = NULL,
reference_hline = NULL, reference_vline = NULL,
grids = 'on', bw_theme = TRUE,
strip_background_color = NULL,
x_expand = NULL, y_expand = NULL) {
#---------------------------
# argument match
#---------------------------
is_x_continuous <- isTRUE(is_x_continuous)
is_y_continuous <- isTRUE(is_y_continuous)
x_log <- isTRUE(x_log)
y_log <- isTRUE(y_log)
x_reverse <- isTRUE(x_reverse)
y_reverse <- isTRUE(y_reverse)
bw_theme <- isTRUE(bw_theme)
add_legend <- isTRUE(add_legend)
legend_pos <- match.arg(tolower(legend_pos),
c('left', 'right', 'bottom', 'top'))
if(is.null(x_lab)) x_lab <- waiver()
if(is.null(y_lab)) y_lab <- waiver()
if(is_blank(x_limit)) x_limit <- NULL
if(is_blank(y_limit)) y_limit <- NULL
if(!grids %in% c('on', 'x', 'y', 'off')) {
stop('grids must be one of `c("on", "x", "y", "off")`')
}
# `environment = parent.frame()` sets the environment to the calling env
# so that ggplot is able to access the local variable defined in the
# function that calls `gg_wrapper`
base_plot <- ggplot2::ggplot(..., environment = parent.frame())
if(bw_theme) base_plot <- base_plot + theme_bw()
# add aesthetics - color
if(!is_blank(color_var)) {
base_plot <- base_plot + aes_string(colour = paste0('`', color_var, '`'))
if(!is_blank(all_colors)) {
if(!all(is.color(all_colors)))
stop('all_colors must be valid color representation')
base_plot <- base_plot + scale_colour_manual(values = all_colors)
}
} else {
if(!is_blank(all_colors)) {
if(!all(is.color(all_colors)))
stop('all_colors must be valid color representation')
base_plot <- base_plot + aes(colour = factor(1)) +
scale_colour_manual(values = all_colors, guide = FALSE)
}
}
# add aesthetics - fill
if(!is_blank(fill_var)) {
base_plot <- base_plot + aes_string(fill = paste0('`', fill_var, '`'))
if(!is_blank(all_fills)) {
if(!all(is.color(all_fills)))
stop('all_fills must be valid color representation')
base_plot <- base_plot + scale_fill_manual(values = all_fills)
}
} else {
if(!is_blank(all_fills)) {
if(!all(is.color(all_fills)))
stop('all_fills must be valid color representation')
base_plot <- base_plot + aes(fill = factor(1)) +
scale_fill_manual(values = all_fills, guide = FALSE)
}
}
# add aesthetics - size
if(!is_blank(size_var)) {
base_plot <- base_plot + aes_string(size = paste0('`', size_var, '`'))
if(!is_blank(all_sizes)) {
if(!all(all_sizes >= 0))
stop('all_sizes must be >= 0')
base_plot <- base_plot + scale_size_manual(values = all_sizes)
}
} else {
if(!is_blank(all_sizes)) {
if(!all(all_sizes >= 0))
stop('all_sizes must be >= 0')
base_plot <- base_plot + aes(size = factor(1)) +
scale_size_manual(values = all_sizes, guide = FALSE)
}
}
# add aesthetics - shape
if(!is_blank(shape_var)) {
base_plot <- base_plot + aes_string(shape = paste0('`', shape_var, '`'))
if(!is_blank(all_shapes)) {
if(!(all(all_shapes %% 1 == 0 & all_shapes >= 0)))
stop('all_shapes must be an integer >= 0')
base_plot <- base_plot + scale_shape_manual(values = all_shapes)
}
} else {
if(!is_blank(all_shapes)) {
if(!(all(all_shapes %% 1 == 0 & all_shapes >= 0)))
stop('all_shapes must be an integer >= 0')
base_plot <- base_plot + aes(shape = factor(1)) +
scale_shape_manual(values = all_shapes, guide = FALSE)
}
}
# add aesthetics - linetype
if(!is_blank(linetype_var)) {
base_plot <- base_plot +
aes_string(linetype = paste0('`', linetype_var, '`'))
if(!is_blank(all_linetypes)) {
valid_linetypes <- c(
'blank' = 0, 'solid' = 1, 'dashed' = 2,
'dotted' = 3, 'dotdash' = 4, 'longdash' = 5,
'twodash' = 6
)
if(!(all(all_linetypes %in% names(valid_linetypes)) |
all(all_linetypes %in% valid_linetypes)))
stop('all_linetypes must be valid linetype value')
base_plot <- base_plot + scale_linetype_manual(values = all_linetypes)
}
} else {
if(!is_blank(all_linetypes)) {
valid_linetypes <- c(
'blank' = 0, 'solid' = 1, 'dashed' = 2,
'dotted' = 3, 'dotdash' = 4, 'longdash' = 5,
'twodash' = 6
)
if(!(all(all_linetypes %in% names(valid_linetypes)) |
all(all_linetypes %in% valid_linetypes)))
stop('all_linetypes must be valid linetype value')
base_plot <- base_plot + aes(linetype = factor(1)) +
scale_linetype_manual(values = all_linetypes, guide = FALSE)
}
}
# add aesthetics - alpha
if(!is_blank(alpha_var)) {
base_plot <- base_plot + aes_string(alpha = paste0('`', alpha_var, '`'))
if(!is_blank(all_alphas)) {
if(!(all(all_alphas >= 0 & all_alphas <= 1)))
stop('all_alphas must be a number in [0, 1]')
base_plot <- base_plot + scale_alpha_manual(values = all_alphas)
}
} else {
if(!is_blank(all_alphas)) {
if(!(all(all_alphas >= 0 & all_alphas <= 1)))
stop('all_alphas must be a number in [0, 1]')
base_plot <- base_plot + aes(alpha = factor(1)) +
scale_alpha_manual(values = all_alphas, guide = FALSE)
}
}
# add faceting
if(!is_blank(facet_r) | !is_blank(facet_c)) {
facets <- paste(ternary(is_blank(facet_r), '.', facet_r), '~',
ternary(is_blank(facet_c), '.', facet_c))
base_plot <- base_plot +
facet_grid(facets, scales = facet_scale, space = facet_space)
}
# draw x-/y-axis
if(!is_x_continuous && x_log) {
stop('discrete x-axis does not take log scale')
}
if(!is_x_continuous && x_reverse) {
stop('discrete x-axis does not take descending order')
}
if(!is_y_continuous && y_log) {
stop('discrete y-axis does not take log scale')
}
if(!is_y_continuous && y_reverse) {
stop('discrete y-axis does not take descending order')
}
if(!x_log) {
if(any(!is_blank(x_axis_breaks), !is.null(x_tick_labels))) {
if(is_blank(x_axis_breaks)) x_axis_breaks <- waiver()
if(is.null(x_tick_labels)) x_tick_labels <- waiver()
x_axis_draw <- ternary(
x_reverse, scale_x_reverse,
ternary(is_x_continuous, scale_x_continuous, scale_x_discrete)
)
if(is_blank(x_expand)) {
x_expand <- ternary(is_x_continuous, c(0.017, 0), c(0, 0.6))
}
base_plot <- base_plot +
x_axis_draw(name = x_lab, breaks = x_axis_breaks,
labels = x_tick_labels, expand = x_expand)
}
} else {
force(x_tick_labels)
trans <- ternary(x_reverse, reverselog_trans(10), 'log10')
if(is.null(x_axis_breaks)) {
x_axis_breaks <- ternary(x_reverse, waiver(), base_log_breaks())
}
if(is.null(x_tick_labels)) x_tick_labels <- base::prettyNum
if(is_blank(x_expand)) x_expand <- c(0.017, 0)
base_plot <- base_plot +
scale_x_continuous(name = x_lab, breaks = x_axis_breaks,
labels = x_tick_labels, trans = trans,
expand = x_expand)
}
if(!y_log) {
if(any(!is_blank(y_axis_breaks), !is.null(y_tick_labels))) {
if(is_blank(y_axis_breaks)) y_axis_breaks <- waiver()
if(is.null(y_tick_labels)) y_tick_labels <- waiver()
y_axis_draw <- ternary(
y_reverse, scale_y_reverse,
ternary(is_y_continuous, scale_y_continuous, scale_y_discrete)
)
if(is_blank(y_expand)) {
y_expand <- ternary(is_y_continuous, c(0.025, 0), c(0, 0.6))
}
base_plot <- base_plot +
y_axis_draw(name = y_lab, breaks = y_axis_breaks,
labels = y_tick_labels, expand = y_expand)
}
} else {
force(y_tick_labels)
trans <- ternary(y_reverse, reverselog_trans(10), 'log10')
if(is.null(y_axis_breaks)) {
y_axis_breaks <- ternary(y_reverse, waiver(), base_log_breaks())
}
if(is.null(y_tick_labels)) {
y_tick_labels <- base::prettyNum
}
if(is_blank(y_expand)) y_expand <- c(0.025, 0)
base_plot <- base_plot +
scale_y_continuous(name = y_lab, breaks = y_axis_breaks,
labels = y_tick_labels, trans = trans,
expand = y_expand)
}
# add horizontal reference line
if(!is_blank(reference_hline)) {
if(is.numeric(reference_hline)) {
base_plot <- base_plot +
geom_hline(yintercept = reference_hline, linetype = 'dashed')
}
if(isTRUE(reference_hline)) {
base_plot <- base_plot +
geom_hline(yintercept = 0, linetype = 'dashed')
}
}
# add vertical reference line
if(!is_blank(reference_vline)) {
if(is.numeric(reference_vline)) {
base_plot <- base_plot +
geom_vline(xintercept = reference_vline, linetype = 'dashed')
}
if(isTRUE(reference_vline)) {
base_plot <- base_plot +
geom_hline(xintercept = 0, linetype = 'dashed')
}
}
# add title
if(!is.null(title)) base_plot <- base_plot + labs(title = title)
if(!is.null(x_lab)) base_plot <- base_plot + labs(x = x_lab)
if(!is.null(y_lab)) base_plot <- base_plot + labs(y = y_lab)
if(!is_blank(color_var)) base_plot <- base_plot + labs(colour = color_lab)
if(!is_blank(fill_var)) base_plot <- base_plot + labs(fill = fill_lab)
if(!is_blank(size_var)) base_plot <- base_plot + labs(size = size_lab)
if(!is_blank(shape_var)) base_plot <- base_plot + labs(shape = shape_lab)
if(!is_blank(linetype_var))
base_plot <- base_plot + labs(linetype = linetype_lab)
if(!is_blank(alpha_var)) base_plot <- base_plot + labs(alpha = alpha_lab)
# specify theme elements
if(grids == 'on') {
panel.grid.major.x = element_line()
panel.grid.major.y = element_line()
panel.grid.minor = element_blank()
} else if(grids == 'x') {
panel.grid.major.x = element_line()
panel.grid.major.y = element_blank()
panel.grid.minor = element_blank()
} else if(grids == 'y') {
panel.grid.major.x = element_blank()
panel.grid.major.y = element_line()
panel.grid.minor = element_blank()
} else {
panel.grid.major.x = element_blank()
panel.grid.major.y = element_blank()
panel.grid.minor = element_blank()
}
base_plot <- base_plot +
theme(axis.text.x = element_text(angle = x_tick_angle,
hjust = x_hjust, vjust = 0.5),
axis.text.y = element_text(angle = y_tick_angle,
hjust = y_hjust, vjust = 0.5),
panel.grid.major.x = panel.grid.major.x,
panel.grid.major.y = panel.grid.major.y,
panel.grid.minor = panel.grid.minor,
legend.position = legend_pos,
plot.title = element_text(hjust = 0.5))
if(!add_legend) base_plot <- base_plot + theme(legend.position = 'none')
if(all(is.color(strip_background_color))) {
base_plot <- base_plot +
theme(strip.background = element_rect(fill = strip_background_color))
}
if(!is.null(x_limit)) base_plot <- base_plot + coord_cartesian(xlim = x_limit)
if(!is.null(y_limit)) base_plot <- base_plot + coord_cartesian(ylim = y_limit)
return(base_plot)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.