diff --git a/DESCRIPTION b/DESCRIPTION index a2f2dd7..6f103a2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -6,6 +6,7 @@ Authors@R: c(person("Olaf", "Mersmann", role=c("aut")), person("Claudia", "Beleites", role=c("ctb")), person("Rainer", "Hurling", role=c("ctb")), person("Ari", "Friedman", role=c("ctb")), + person("Grant", "McDermott", role=c("ctb")), person(given=c("Joshua","M."), family="Ulrich", role="cre", email="josh.m.ulrich@gmail.com")) URL: https://github.com/joshuaulrich/microbenchmark/ @@ -13,7 +14,9 @@ BugReports: https://github.com/joshuaulrich/microbenchmark/issues/ License: BSD_2_clause + file LICENSE Depends: R (>= 3.2.0) Imports: graphics, stats -Suggests: ggplot2, multcomp, RUnit +Suggests: ggplot2, multcomp, RUnit, tinyplot (>= 0.6.1) SystemRequirements: On a Unix-alike, one of the C functions mach_absolute_time (macOS), clock_gettime or gethrtime. If none of these is found, the obsolescent POSIX function gettimeofday will be tried. ByteCompile: yes -Version: 1.5.0 +Version: 1.5.0.99 +Encoding: UTF-8 +RoxygenNote: 7.3.3 diff --git a/R/microbenchmark.R b/R/microbenchmark.R index 81c8f2b..efa63ea 100644 --- a/R/microbenchmark.R +++ b/R/microbenchmark.R @@ -92,6 +92,7 @@ #' if (requireNamespace("ggplot2")) { #' ggplot2::autoplot(res) #' } +#' # See also ?tinyplot.microbenchmark #' #' ## Example check usage #' my_check <- function(values) { diff --git a/R/tinyplot.microbenchmark.R b/R/tinyplot.microbenchmark.R new file mode 100644 index 0000000..88812cd --- /dev/null +++ b/R/tinyplot.microbenchmark.R @@ -0,0 +1,118 @@ +#' Tinyplot method for microbenchmark objects +#' +#' @description Uses the `tinyplot` package to produce prettier base graphics +#' for microbenchmark timings. Note that `tinyplot` needs to be installed and +#' loaded separately. +#' +#' @param x A microbenchmark object. +#' @param type String giving the type of plot representation. One of `"violin"` +#' (the default), `"boxplot"`, or `"jitter"`. +#' @param unit Unit in which the results be plotted. +#' @param log Should times be plotted on a log scale? Default is \code{TRUE}. +#' @param order Names of output column(s) to order the results. +#' @param main,xlab,ylab Plot and axes titles. +#' @param flip Switch the X and Y axes? Default is \code{TRUE}. +#' @param trim Trim violin plots to data extent? Default is \code{TRUE}. +#' @param joint.bw Which (if any) joint smoothing bandwidth to use on violin +#' plots? Default is \code{"none"} to match +#' \code{\link[microbenchmark]{autoplot.microbenchmark}}. +#' @param ... Additional arguments passed to [`tinyplot`]. +#' @return No return value. Called for side effect of producing a plot. +#' +#' @examples +#' if (requireNamespace("tinyplot", quietly = TRUE)) { +#' library(tinyplot) +#' +#' tm <- microbenchmark(rchisq(100, 0), +#' rchisq(100, 1), +#' rchisq(100, 2), +#' rchisq(100, 3), +#' times=100L) +#' +#' # default plot +#' tinyplot(tm) +#' +#' # same, but with aesthetic tweaks +#' tinyplot(tm, +#' fill = "transparent", +#' theme = "classic", +#' main = "Impressive benchmarks", +#' sub = "Brought to you by tinyplot") +#' +#' # we can use tinyplot scaffolding to add layers to our plot +#' tinyplot_add(type = "jitter", cex = 0.5, alpha = 0.3) +#' } +#' @author Grant McDermott +#' @export +tinyplot.microbenchmark = function( + x, + type = c("violin", "boxplot", "jitter"), + log = TRUE, + unit = NULL, + order = NULL, + main = "microbenchmark timings", + xlab = NA, + ylab = NULL, + flip = TRUE, + trim = TRUE, + joint.bw = c("none", "mean", "full"), + ... +) { + + dots <- list(...) + + type <- match.arg(type) + joint.bw <- match.arg(joint.bw) + + unit <- determine_unit(x, unit) + x$ntime <- convert_to_unit(x, unit) + if (!is.null(order)) { + s <- summary(x) + x_colnames <- colnames(s) + order <- match.arg(order, x_colnames, several.ok=TRUE) + new_order <- do.call("order", c(s[, order, drop=FALSE], decreasing=TRUE)) + x$expr <- factor(x$expr, levels = levels(x$expr)[new_order]) + } + + if (is.null(ylab)) ylab <- sprintf( + "Time (%s) for neval = %d", + attr(x$ntime, "unit"), + nrow(x) / length(levels(x$expr)) + ) + + if (isTRUE(log)) { + log <- "y" + } else { + log <- NULL + } + + if (is.null(dots$ylim)) { + if (log == "y") { + y_min <- if (min(x$time) == 0) 1 else min(x$ntime) + } else { + y_min <- 0 + } + y_max <- max(x$ntime) + dots$ylim <- c(y_min, y_max) + } + + do.call( + tinyplot::tinyplot, + utils::modifyList( + list( + x = ntime ~ expr, + data = x, + type = type, + main = main, + ylab = ylab, + xlab = xlab, + log = log, + trim = trim, + flip = flip, + joint.bw = joint.bw + ), + dots + ) + ) + +} diff --git a/R/zzz.R b/R/zzz.R index 11d8fa6..43e6878 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -28,6 +28,10 @@ function(pkg, generic, class, fun = NULL) if (getRversion() < "3.6.0") { register_s3_method("ggplot2", "autoplot", "microbenchmark") } + + # Register tinyplot method if tinyplot is available + register_s3_method("tinyplot", "tinyplot", "microbenchmark") + invisible() } diff --git a/man/microbenchmark.Rd b/man/microbenchmark.Rd index 74bbc8e..f4ea589 100644 --- a/man/microbenchmark.Rd +++ b/man/microbenchmark.Rd @@ -113,6 +113,7 @@ boxplot(res) if (requireNamespace("ggplot2")) { ggplot2::autoplot(res) } +# See also ?tinyplot.microbenchmark ## Example check usage my_check <- function(values) { diff --git a/man/tinyplot.microbenchmark.Rd b/man/tinyplot.microbenchmark.Rd new file mode 100644 index 0000000..5991113 --- /dev/null +++ b/man/tinyplot.microbenchmark.Rd @@ -0,0 +1,80 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tinyplot.microbenchmark.R +\name{tinyplot.microbenchmark} +\alias{tinyplot.microbenchmark} +\title{Tinyplot method for microbenchmark objects} +\usage{ +tinyplot.microbenchmark( + x, + type = c("violin", "boxplot", "jitter"), + log = TRUE, + unit = NULL, + order = NULL, + main = "microbenchmark timings", + xlab = NA, + ylab = NULL, + flip = TRUE, + trim = TRUE, + joint.bw = c("none", "mean", "full"), + ... +) +} +\arguments{ +\item{x}{A microbenchmark object.} + +\item{type}{String giving the type of plot representation. One of `"violin"` +(the default), `"boxplot"`, or `"jitter"`.} + +\item{log}{Should times be plotted on a log scale? Default is \code{TRUE}.} + +\item{unit}{Unit in which the results be plotted.} + +\item{order}{Names of output column(s) to order the results.} + +\item{main, xlab, ylab}{Plot and axes titles.} + +\item{flip}{Switch the X and Y axes? Default is \code{TRUE}.} + +\item{trim}{Trim violin plots to data extent? Default is \code{TRUE}.} + +\item{joint.bw}{Which (if any) joint smoothing bandwidth to use on violin +plots? Default is \code{"none"} to match +\code{\link[microbenchmark]{autoplot.microbenchmark}}.} + +\item{...}{Additional arguments passed to [`tinyplot`].} +} +\value{ +No return value. Called for side effect of producing a plot. +} +\description{ +Uses the `tinyplot` package to produce prettier base graphics + for microbenchmark timings. Note that `tinyplot` needs to be installed and + loaded separately. +} +\examples{ +if (requireNamespace("tinyplot", quietly = TRUE)) { + library(tinyplot) + + tm <- microbenchmark(rchisq(100, 0), + rchisq(100, 1), + rchisq(100, 2), + rchisq(100, 3), + times=100L) + + # default plot + tinyplot(tm) + + # same, but with aesthetic tweaks + tinyplot(tm, + fill = "transparent", + theme = "classic", + main = "Impressive benchmarks", + sub = "Brought to you by tinyplot") + + # we can use tinyplot scaffolding to add layers to our plot + tinyplot_add(type = "jitter", cex = 0.5, alpha = 0.3) +} +} +\author{ +Grant McDermott +}