Nothing
# Much of this code is copied from the labeling package.
# nolint start: object_name_linter
.simplicity <- function(q, Q, j, lmin, lmax, lstep) {
eps <- .Machine$double.eps * 100
n <- length(Q)
i <- match(q, Q)[1]
v <- ifelse(
(lmin %% lstep < eps ||
lstep - (lmin %% lstep) < eps) &&
lmin <= 0 &&
lmax >= 0,
1,
0
)
1 - (i - 1) / (n - 1) - j + v
}
.simplicity_max <- function(q, Q, j) {
n <- length(Q)
i <- match(q, Q)[1]
v <- 1
1 - (i - 1) / (n - 1) - j + v
}
.coverage <- function(dmin, dmax, lmin, lmax) {
range <- dmax - dmin
1 - 0.5 * ((dmax - lmax)^2 + (dmin - lmin)^2) / ((0.1 * range)^2)
}
.coverage_max <- function(dmin, dmax, span) {
range <- dmax - dmin
if (span > range) {
half <- (span - range) / 2
1 - 0.5 * (half^2 + half^2) / ((0.1 * range)^2)
} else {
1
}
}
.density <- function(k, m, dmin, dmax, lmin, lmax) {
r <- (k - 1) / (lmax - lmin)
rt <- (m - 1) / (max(lmax, dmax) - min(dmin, lmin))
2 - max(r / rt, rt / r)
}
.density_max <- function(k, m) {
if (k >= m) {
2 - (k - 1) / (m - 1)
} else {
1
}
}
.legibility <- function(lmin, lmax, lstep) {
1
}
#' Pretty axis breaks inclusive of extreme values
#'
#' This function returns pretty axis breaks that always include the extreme values of the data.
#' This works by calling the extended Wilkinson algorithm (Talbot et al., 2010), constrained to solutions
#' interior to the data range.
#' Then, the minimum and maximum labels are moved to the minimum and maximum of the data
#' range.
#'
#' \code{extended_range_breaks} implements the algorithm and returns the break values.
#' \code{scales_extended_range_breaks} uses the conventions of the \pkg{scales} package, and returns a function.
#'
#' @param dmin minimum of the data range
#' @param dmax maximum of the data range
#' @param n desired number of breaks
#' @param Q set of nice numbers
#' @param w weights applied to the four optimization components (simplicity, coverage, density, and legibility)
#' @return For \code{extended_range_breaks}, the vector of axis label locations.
#' For \code{scales_extended_range_breaks}, a function which takes a single argument, a vector of data, and returns
#' the vector of axis label locations.
#' @references
#' Talbot, J., Lin, S., Hanrahan, P. (2010) An Extension of Wilkinson's Algorithm
#' for Positioning Tick Labels on Axes, InfoVis 2010.
#' @author Justin Talbot \email{jtalbot@@stanford.edu}, Jeffrey B. Arnold, Baptiste Auguie
#' @rdname range_breaks
#' @export
extended_range_breaks_ <- function(
dmin,
dmax,
n = 5, # nolint: cyclocomp_linter
Q = c(1, 5, 2, 2.5, 4, 3), # nolint: object_name_linter
w = c(0.25, 0.2, 0.5, 0.05)
) {
eps <- .Machine$double.eps * 100
if (dmin > dmax) {
temp <- dmin
dmin <- dmax
dmax <- temp
}
if (dmax - dmin < eps) {
# if the range is near the floating point limit,
# let seq generate some equally spaced steps.
return(seq(from = dmin, to = dmax, length.out = n))
}
n <- length(Q)
best <- list()
best$score <- -2
j <- 1
while (j < Inf) {
for (q in Q) {
sm <- .simplicity_max(q, Q, j)
if ((w[1] * sm + w[2] + w[3] + w[4]) < best$score) {
j <- Inf
break
}
k <- 2
while (k < Inf) {
dm <- .density_max(k, n)
if ((w[1] * sm + w[2] + w[3] * dm + w[4]) < best$score) {
break
}
delta <- (dmax - dmin) / (k + 1) / j / q
z <- ceiling(log(delta, base = 10))
while (z < Inf) {
step <- j * q * 10^z
cm <- .coverage_max(dmin, dmax, step * (k - 1))
if ((w[1] * sm + w[2] * cm + w[3] * dm + w[4]) < best$score) {
break
}
min_start <- floor(dmax / (step)) * j - (k - 1) * j
max_start <- ceiling(dmin / (step)) * j
if (min_start > max_start) {
z <- z + 1
next
}
for (start in min_start:max_start) {
lmin <- start * (step / j)
lmax <- lmin + step * (k - 1)
lstep <- step
s <- .simplicity(q, Q, j, lmin, lmax, lstep)
c <- .coverage(dmin, dmax, lmin, lmax)
g <- .density(k, n, dmin, dmax, lmin, lmax)
l <- .legibility(lmin, lmax, lstep)
score <- w[1] * s + w[2] * c + w[3] * g + w[4] * l
if (
score > best$score &&
lmin >= dmin &&
lmax <= dmax
) {
best <- list(
lmin = lmin,
lmax = lmax,
lstep = lstep,
score = score
)
}
}
z <- z + 1
}
k <- k + 1
}
}
j <- j + 1
}
breaks <- seq(from = best$lmin, to = best$lmax, by = best$lstep)
if (length(breaks) >= 2) {
breaks[1] <- dmin
breaks[length(breaks)] <- dmax
}
breaks
}
#' @rdname range_breaks
#' @param ... other arguments passed to \code{extended_range_breaks_()}
#' @return A function which returns breaks given a vector.
#' @export
extended_range_breaks <- function(n = 5, ...) {
function(x) {
extended_range_breaks_(min(x), max(x), n, ...)
}
}
# from scales package
zero_range <- function(x, tol = 1000 * .Machine$double.eps) {
if (length(x) == 1) {
return(TRUE)
}
if (length(x) != 2) {
stop("x must be length 1 or 2")
}
if (any(is.na(x))) {
return(NA)
}
if (x[1] == x[2]) {
return(TRUE)
}
if (all(is.infinite(x))) {
return(FALSE)
}
m <- min(abs(x))
if (m == 0) {
return(FALSE)
}
abs((x[1] - x[2]) / m) < tol
}
# from scales package
precision <- function(x) {
rng <- range(x, na.rm = TRUE)
span <- if (zero_range(rng)) {
abs(rng[1])
} else {
diff(rng)
}
10^floor(log10(span))
}
# nolint start
#' Format numbers with automatic number of digits
#'
#' @param x A numeric vector to format
#' @param ... Parameters passed to \code{\link{format}()}
#'
#' @references Josh O'Brien,
#' \url{https://stackoverflow.com/questions/23169938/select-accuracy-to-display-additional-axis-breaks/23171858#23171858}.
#' @author Josh O'Brien, Baptise Auguie, Jeffrey B. Arnold
#' @return A character vector.
#' \code{smart_digits_format()} returns a function with a single argument
#' \code{x}, a numeric vector, that returns a character vector.
#'
#' @rdname smart_digits
#' @export
# nolint end
smart_digits <- function(x, ...) {
if (length(x) == 0) {
return(character())
}
accuracy <- precision(x)
x <- round(x / accuracy) * accuracy
format(x, ...)
}
#' @rdname smart_digits
#' @export
smart_digits_format <- function(x, ...) {
function(x) smart_digits(x, ...)
}
# nolint end: object_name_linter
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.