scales/0000755000176200001440000000000015002414662011524 5ustar liggesusersscales/tests/0000755000176200001440000000000014672302067012675 5ustar liggesusersscales/tests/testthat/0000755000176200001440000000000015002414662014526 5ustar liggesusersscales/tests/testthat/test-label-expression.R0000644000176200001440000000072214672302077021113 0ustar liggesuserstest_that("parse_format() returns an expression object", { expect_equal( parse_format()(c("alpha", "beta", "gamma")), expression(alpha, beta, gamma) ) expect_equal( parse_format()(1:5), expression(1, 2, 3, 4, 5) ) expect_identical(label_math()(character()), expression()) expect_identical(label_parse()(character()), expression()) }) test_that("math_format() returns expression", { expect_equal(label_math()(1), expression(10^1)) }) scales/tests/testthat/test-utils.R0000644000176200001440000000041414706713207016774 0ustar liggesuserstest_that("recycle_common throws appropriate errors", { expect_snapshot(recycle_common(a = 1:2, size = 3), error = TRUE) expect_snapshot(recycle_common(a = 1:2, b = 1:3), error = TRUE) expect_snapshot(recycle_common(a = 1:2, b = 1:3, size = 3), error = TRUE) }) scales/tests/testthat/test-round-any.R0000644000176200001440000000164014672302077017553 0ustar liggesuserstest_that("round_any function rounds numeric", { expect_equal(round_any(135, 10), 140) expect_equal(round_any(135, 100), 100) expect_equal(round_any(135, 25), 125) expect_equal(round_any(135, 10, floor), 130) expect_equal(round_any(135, 100, floor), 100) expect_equal(round_any(135, 25, floor), 125) expect_equal(round_any(135, 10, ceiling), 140) expect_equal(round_any(135, 100, ceiling), 200) expect_equal(round_any(135, 25, ceiling), 150) }) test_that("round_any() function rounds POSIXct", { expect_equal( round_any(as.POSIXct("2000-01-01 11:00:00", tz = "UTC"), 86400), as.POSIXct("2000-01-01", tz = "UTC") ) expect_equal( round_any(as.POSIXct("2000-01-01 11:11:11", tz = "UTC"), 3600), as.POSIXct("2000-01-01 11:00", tz = "UTC") ) expect_equal( round_any(as.POSIXct("2000-01-01 11:11:11", tz = "UTC"), 10, ceiling), as.POSIXct("2000-01-01 11:11:20", tz = "UTC") ) }) scales/tests/testthat/test-breaks-log.R0000644000176200001440000000604315002117500017646 0ustar liggesuserstest_that("Five ticks over 10^4 range work", { expect_equal(breaks_log()(10^(1:5)), 10^(1:5)) }) test_that("behaves nicely when inputs are wacky", { expect_equal(breaks_log()(c(0, NA)), 0) expect_equal(breaks_log()(c(0, Inf)), numeric()) expect_equal(breaks_log()(c(NA, NA)), numeric()) expect_equal(breaks_log()(c(-Inf, Inf)), numeric()) expect_equal(breaks_log()(numeric(0)), numeric()) }) test_that("use integer base powers when at least 3 breaks are within range", { base <- 10 expect_equal( breaks_log(base = base)(base^c(0, 2)), base^(0:2) ) base <- 4 expect_equal( breaks_log(base = base)(base^c(0, 2)), base^(0:2) ) base <- 2 expect_equal( breaks_log(base = base)(base^c(0, 2)), base^(0:2) ) }) test_that("add intermediate breaks when more breaks are needed", { base <- 10 expect_equal( breaks_log(base = base)(base^c(2, 4) + c(1, -1)), c(100, 300, 1000, 3000, 10000) ) expect_equal( breaks_log(base = base)(base^c(2, 3) + c(1, -1)), c(100, 200, 300, 500, 1000) ) base <- 4 expect_equal( breaks_log(base = base)(base^c(2, 4) + c(1, -1)), c(16, 32, 64, 128, 256) ) base <- 3 expect_equal( breaks_log(base = base)(base^c(2, 4) + c(1, -1)), c(9, 18, 27, 54, 81) ) base <- 2 expect_equal( breaks_log(n = 5, base = 2)(c(3, 100)), c(2, 4, 8, 16, 32, 64, 128) ) }) test_that("breaks_log arguments are forcely evaluated on each call #81", { subfun1 <- breaks_log(n = 5, base = 10) subfun2 <- breaks_log(n = 20, base = 5) subfuns <- list() cases_n <- c(5, 20) cases_base <- c(10, 5) for (i in 1:2) { subfuns[[i]] <- breaks_log(n = cases_n[i], base = cases_base[i]) } expect_equal(subfun1(1:1000), subfuns[[1]](1:1000)) expect_equal(subfun2(1:1000), subfuns[[2]](1:1000)) }) test_that("breaks_log with very small ranges fall back to extended_breaks", { expect_equal( breaks_log(n = 5, base = 10)(c(2.001, 2.002)), extended_breaks(n = 5)(c(2.001, 2.002)) ) expect_equal( breaks_log(n = 5, base = 10)(c(0.95, 1.1)), extended_breaks(n = 5)(c(0.95, 1.1)) ) # The switch to extended_breaks occurs at approximately the half-log point expect_equal( breaks_log(n = 5, base = 10)(c(0.95, 2.9)), extended_breaks(n = 5)(c(0.95, 2.9)) ) expect_false(identical( breaks_log(n = 5, base = 10)(c(0.95, 3)), extended_breaks(n = 5)(c(0.95, 3)) )) }) test_that("minor_breaks_log has correct amount of detail", { range <- c(1, 10) test <- minor_breaks_log(detail = 1)(range) expect_true(all(1:10 %in% test)) test <- minor_breaks_log(detail = 5)(range) expect_false(all(1:10 %in% test)) expect_true(all(c(1, 5, 10) %in% test)) test <- minor_breaks_log(detail = 10)(range) expect_true(all(c(1, 10) %in% test)) expect_false(5 %in% test) test <- minor_breaks_log(detail = 1)(c(-10, 10)) expect_true(all(-10:10 %in% test)) }) test_that("minor_breaks_log rejects invalid arguments", { expect_snapshot(minor_breaks_log(7), error = TRUE) expect_snapshot(minor_breaks_log(smallest = 0), error = TRUE) }) scales/tests/testthat/test-labels-retired.R0000644000176200001440000000064714672302077020543 0ustar liggesuserstest_that("unit format", { expect_equal( unit_format(unit = "km", scale = 1e-3)(c(1e3, NA, 2e3)), c("1 km", NA, "2 km") ) expect_equal( unit_format(unit = "ha", scale = 1e-4, accuracy = .1)(c(1e3, 2e3)), c("0.1 ha", "0.2 ha") ) expect_equal( unit_format()(c(1e2, 2e2)), c("100 m", "200 m") ) }) test_that("unit_format preserves names", { expect_named(unit_format()(c(a = 1)), "a") }) scales/tests/testthat/test-scale-continuous.R0000644000176200001440000000233715001712000021110 0ustar liggesuserstest_that("NA.value works for continuous scales", { x <- c(NA, seq(0, 1, length.out = 10), NA) pal <- rescale_pal() expect_equal(cscale(x, pal)[1], NA_real_) expect_equal(cscale(x, pal)[12], NA_real_) expect_equal(cscale(x, pal, 5)[1], 5) expect_equal(cscale(x, pal, 5)[12], 5) }) test_that("train_continuous stops on discrete values", { expect_snapshot(train_continuous(LETTERS[1:5]), error = TRUE) }) test_that("train_continuous strips attributes", { expect_equal(train_continuous(1:5), c(1, 5)) x <- as.Date("1970-01-01") + c(1, 5) expect_equal(train_continuous(x), c(1, 5)) }) test_that("train_continuous with new=NULL maintains existing range.", { expect_equal( train_continuous(NULL, existing = c(1, 5)), c(1, 5) ) }) test_that("train_continuous works with integer64", { skip_if_not_installed("bit64") new <- bit64::as.integer64(1:10) expect_identical( train_continuous(new), c(1, 10) ) }) test_that("train_continuous can train on S3 classes", { my_obj <- structure(c("IX", "CM", "X", "IV"), class = "bar") range.bar <- function(x, ...) range(.romans[x], ...) registerS3method("range", "bar", method = range.bar) expect_equal( train_continuous(my_obj), c(4, 900) ) }) scales/tests/testthat/test-range.R0000644000176200001440000000366715002117500016725 0ustar liggesuserstest_that("R6 inheritance works", { expect_no_error(ContinuousRange$new()) expect_no_error(DiscreteRange$new()) expect_true(R6::is.R6(ContinuousRange$new())) expect_true(R6::is.R6(DiscreteRange$new())) }) test_that("Mutable ranges work", { x <- ContinuousRange$new() x$train(c(-1, 45, 10)) expect_equal(x$range, c(-1, 45)) x$train(c(1000)) expect_equal(x$range, c(-1, 1000)) x$reset() expect_equal(x$range, NULL) x <- DiscreteRange$new() x$train(factor(letters[1:3])) expect_equal(x$range, c("a", "b", "c")) x$train(factor(c("a", "h"))) expect_equal(x$range, c("a", "b", "c", "h")) x$reset() expect_equal(x$range, NULL) }) test_that("starting with NULL always returns new", { expect_equal(discrete_range(NULL, 1:3), 1:3) expect_equal(discrete_range(NULL, 3:1), 1:3) expect_equal(discrete_range(NULL, c("a", "b", "c")), c("a", "b", "c")) expect_equal(discrete_range(NULL, c("c", "b", "a")), c("a", "b", "c")) f1 <- factor(letters[1:3], levels = letters[1:4]) expect_equal(discrete_range(NULL, f1, drop = FALSE), letters[1:4]) expect_equal(discrete_range(NULL, f1, drop = TRUE), letters[1:3]) f2 <- factor(letters[1:3], levels = letters[4:1]) expect_equal(discrete_range(NULL, f2, drop = FALSE), letters[4:1]) expect_equal(discrete_range(NULL, f2, drop = TRUE), letters[3:1]) }) test_that("factor discrete ranges stay in order", { f <- factor(letters[1:3], levels = letters[3:1]) expect_equal(discrete_range(f, f), letters[3:1]) expect_equal(discrete_range(f, "c"), letters[3:1]) expect_equal(discrete_range(f, c("a", "b", "c")), letters[3:1]) expect_equal( discrete_range(f, c("a", "b", "c", NA), na.rm = FALSE), c(letters[3:1], NA) ) }) test_that("factor discrete ranges take precedence over character", { f <- factor(letters[1:3], levels = letters[3:1]) expect_equal(discrete_range(letters[1:3], f), letters[3:1]) expect_equal(discrete_range(letters[1:4], f), letters[c(3:1, 4)]) }) scales/tests/testthat/test-label-ordinal.R0000644000176200001440000000116115002117500020321 0ustar liggesuserstest_that("ordinal format in English", { expect_snapshot({ ordinal(c(1:4, 11:21, 101, NA)) ordinal(c(1, 2, 10, 11, NA), rules = ordinal_french()) ordinal(c(1, 2, 10, 11, NA), rules = ordinal_french("f", TRUE)) }) }) test_that("ordinal match rules in order", { custom <- list( a = "^1", b = ".", c = "^3" ) expect_equal( ordinal(1:3, rules = custom), c("1a", "2b", "3b") ) }) test_that("ordinal format maintains order", { expect_equal(ordinal(c(21, 1, NA, 11)), c("21st", "1st", NA, "11th")) }) test_that("ordinal preserves names", { expect_named(ordinal(c(a = 1)), "a") }) scales/tests/testthat/test-label-percent.R0000644000176200001440000000127315002117500020335 0ustar liggesuserstest_that("negative percents work", { expect_equal(percent(-0.6, accuracy = 1), "-60%") }) test_that("Single 0 gives 0%", { expect_equal(percent(0), "0%") }) test_that("preserves NAs", { expect_equal(percent(c(NA, 1, 2, 3)), c(NA, "100%", "200%", "300%")) expect_equal(percent(NA_real_), NA_character_) }) test_that("preserves names", { expect_named(percent(c(a = 1)), "a") }) test_that("default accuracy works for range of inputs", { x <- c(0.1, 0.2, 0.5) expect_equal(percent(x / 100), c("0.1%", "0.2%", "0.5%")) expect_equal(percent(x / 10), c("1%", "2%", "5%")) expect_equal(percent(x), c("10%", "20%", "50%")) expect_equal(percent(x * 10), c("100%", "200%", "500%")) }) scales/tests/testthat/test-bounds.R0000644000176200001440000001353715002117500017120 0ustar liggesuserstest_that("rescale_mid returns correct results", { x <- c(-1, 0, 1) expect_equal(rescale_mid(x), c(0, 0.5, 1)) expect_equal(rescale_mid(x, mid = -1), c(0.5, 0.75, 1)) expect_equal(rescale_mid(x, mid = 1), c(0, 0.25, 0.5)) expect_equal(rescale_mid(x, mid = 1, to = c(0, 10)), c(0, 2.5, 5)) expect_equal(rescale_mid(x, mid = 1, to = c(8, 10)), c(8, 8.5, 9)) expect_equal(rescale_mid(c(1, NA, 1)), c(0.5, NA, 0.5)) }) test_that("rescale_max returns correct results", { expect_equal(rescale_max(0), NaN) expect_equal(rescale_max(1), 1) expect_equal(rescale_max(.3), 1) expect_equal(rescale_max(c(4, 5)), c(0.8, 1.0)) expect_equal(rescale_max(c(-3, 0, -1, 2)), c(-1.5, 0, -0.5, 1)) expect_equal(rescale_max(c(-3, 0, -1, 2)), c(-1.5, 0, -0.5, 1)) }) test_that("rescale functions handle NAs consistently", { expect_equal(rescale(c(2, NA, 0, -2)), c(1, NA, 0.5, 0)) expect_equal(rescale(c(-2, NA, -2)), c(.5, NA, .5)) expect_equal(rescale_mid(c(NA, 1, 2)), c(NA, 0.75, 1)) expect_equal(rescale_mid(c(2, NA, 0, -2), mid = .5), c(0.8, NA, 0.4, 0)) expect_equal(rescale_mid(c(-2, NA, -2)), c(.5, NA, .5)) expect_equal(rescale_max(c(1, NA)), c(1, NA)) expect_equal(rescale_max(c(2, NA, 0, -2)), c(1, NA, 0, -1)) expect_equal(rescale_max(c(-2, NA, -2)), c(1, NA, 1)) }) test_that("rescale preserves NAs even when x has zero range", { expect_equal(rescale(c(1, NA)), c(0.5, NA)) }) test_that("zero range inputs return mid range", { expect_equal(rescale(0), 0.5) expect_equal(rescale(c(0, 0)), c(0.5, 0.5)) }) test_that("scaling is possible with dates and times", { dates <- as.Date(c("2010-01-01", "2010-01-03", "2010-01-05", "2010-01-07")) expect_equal(rescale(dates, from = c(dates[1], dates[4])), seq(0, 1, 1 / 3)) expect_equal(rescale_mid(dates, mid = dates[3])[3], 0.5) dates <- as.POSIXct(c( "2010-01-01 01:40:40", "2010-01-01 03:40:40", "2010-01-01 05:40:40", "2010-01-01 07:40:40" )) expect_equal(rescale(dates, from = c(dates[1], dates[4])), seq(0, 1, 1 / 3)) expect_equal(rescale_mid(dates, mid = dates[3])[3], 0.5) }) test_that("scaling is possible with integer64 data", { skip_if_not_installed("bit64") x <- bit64::as.integer64(2^60) + c(0:3) expect_equal( rescale_mid(x, mid = bit64::as.integer64(2^60) + 1), c(0.25, 0.5, 0.75, 1) ) }) test_that("scaling is possible with NULL values", { expect_null(rescale(NULL)) expect_null(rescale_mid(NULL)) }) test_that("rescaling does not alter AsIs objects", { expect_identical(I(1:3), rescale(I(1:3), from = c(0, 4))) expect_identical(I(1:3), rescale_mid(I(1:3), from = c(0, 4), mid = 1)) }) test_that("scaling is possible with logical values", { expect_equal(rescale(c(FALSE, TRUE)), c(0, 1)) expect_equal(rescale_mid(c(FALSE, TRUE), mid = 0.5), c(0, 1)) }) test_that("expand_range respects mul and add values", { expect_equal(expand_range(c(1, 1), mul = 0, add = 0.6), c(0.4, 1.6)) expect_equal(expand_range(c(1, 1), mul = 1, add = 0.6), c(-0.6, 2.6)) expect_equal(expand_range(c(1, 9), mul = 0, add = 2), c(-1, 11)) }) test_that("out of bounds functions return correct values", { x <- c(-Inf, -1, 0.5, 1, 2, NA, Inf) expect_equal(oob_censor(x), c(-Inf, NA, 0.5, 1, NA, NA, Inf)) expect_equal(oob_censor_any(x), c(NA, NA, 0.5, 1, NA, NA, NA)) expect_equal(oob_censor(x), censor(x)) expect_equal(oob_squish(x), c(-Inf, 0, 0.5, 1, 1, NA, Inf)) expect_equal(oob_squish_any(x), c(0, 0, 0.5, 1, 1, NA, 1)) expect_equal(oob_squish_infinite(x), c(0, -1, 0.5, 1, 2, NA, 1)) expect_equal(oob_squish(x), squish(x)) expect_equal(oob_discard(x), c(0.5, 1, NA)) expect_equal(oob_discard(x), discard(x)) expect_equal(oob_keep(x), x) }) # zero_range -------------------------------------------------------------- test_that("large numbers with small differences", { expect_false(zero_range(c(1330020857.8787, 1330020866.8787))) expect_true(zero_range(c(1330020857.8787, 1330020857.8787))) }) test_that("small numbers with differences on order of values", { expect_false(zero_range(c(5.63e-147, 5.93e-123))) expect_false(zero_range(c(-7.254574e-11, 6.035387e-11))) expect_false(zero_range(c(-7.254574e-11, -6.035387e-11))) }) test_that("ranges with 0 endpoint(s)", { expect_false(zero_range(c(0, 10))) expect_true(zero_range(c(0, 0))) expect_false(zero_range(c(-10, 0))) expect_false(zero_range(c(0, 1) * 1e-100)) expect_false(zero_range(c(0, 1) * 1e+100)) }) test_that("symmetric ranges", { expect_false(zero_range(c(-1, 1))) expect_false(zero_range(c(-1, 1 * (1 + 1e-20)))) expect_false(zero_range(c(-1, 1) * 1e-100)) }) test_that("length 1 ranges", { expect_true(zero_range(c(1))) expect_true(zero_range(c(0))) expect_true(zero_range(c(1e100))) expect_true(zero_range(c(1e-100))) }) test_that("NA and Inf", { # Should return NA expect_true(is.na(zero_range(c(NA, NA)))) expect_true(is.na(zero_range(c(1, NA)))) expect_true(is.na(zero_range(c(1, NaN)))) # Not zero range expect_false(zero_range(c(1, Inf))) expect_false(zero_range(c(-Inf, Inf))) # Can't know if these are truly zero range expect_true(zero_range(c(Inf, Inf))) expect_true(zero_range(c(-Inf, -Inf))) }) test_that("Tolerance", { # By default, tolerance is 1000 times this eps <- .Machine$double.eps expect_true(zero_range(c(1, 1 + eps))) expect_true(zero_range(c(1, 1 + 99 * eps))) # Cross the threshold expect_false(zero_range(c(1, 1 + 1001 * eps))) expect_false(zero_range(c(1, 1 + 2 * eps), tol = eps)) # Scaling up or down all the values has no effect since the values # are rescaled to 1 before checking against tol expect_true(zero_range(100000 * c(1, 1 + eps))) expect_true(zero_range(.00001 * c(1, 1 + eps))) expect_true(zero_range(100000 * c(1, 1 + 99 * eps))) expect_true(zero_range(.00001 * c(1, 1 + 99 * eps))) expect_false(zero_range(100000 * c(1, 1 + 1001 * eps))) expect_false(zero_range(.00001 * c(1, 1 + 1001 * eps))) }) scales/tests/testthat/test-pal-.R0000644000176200001440000000247215002117500016453 0ustar liggesuserstest_that("continuous palettes can be created, tested and coerced", { pal <- new_continuous_palette( function(x) ((x - 0.5) * 4)^2, "numeric", na_safe = FALSE ) expect_equal(pal(seq(0, 1, by = 0.25)), c(4, 1, 0, 1, 4)) expect_true(is_pal(pal)) expect_true(is_continuous_pal(pal)) expect_false(is_discrete_pal(pal)) expect_false(is_colour_pal(pal)) expect_true(is_numeric_pal(pal)) expect_equal(palette_type(pal), "numeric") expect_equal(palette_na_safe(pal), FALSE) expect_equal(palette_nlevels(pal), NA_integer_) new <- as_discrete_pal(pal) expect_true(is_discrete_pal(new)) expect_equal(new(5), c(4, 1, 0, 1, 4)) }) test_that("discrete palettes can be created, tested and coerced", { pal <- new_discrete_palette( function(n) c("red", "green", "blue")[seq_len(n)], "colour", nlevels = 3 ) expect_equal(pal(2), c("red", "green")) expect_true(is_pal(pal)) expect_true(is_discrete_pal(pal)) expect_false(is_continuous_pal(pal)) expect_true(is_colour_pal(pal)) expect_false(is_numeric_pal(pal)) expect_equal(palette_type(pal), "colour") expect_equal(palette_na_safe(pal), FALSE) expect_equal(palette_nlevels(pal), 3) new <- as_continuous_pal(pal) expect_true(is_continuous_pal(new)) expect_equal(new(c(0, 0.5, 1)), c("#FF0000", "#00FF00", "#0000FF")) }) scales/tests/testthat/test-label-wrap.R0000644000176200001440000000102214672302077017657 0ustar liggesuserstest_that("wrap correctly wraps long lines", { expect_equal( label_wrap(10)("this is a long line"), "this is a\nlong line" ) expect_equal( label_wrap(10)(c("this is a long line", "this is another long line")), c("this is a\nlong line", "this is\nanother\nlong line") ) expect_equal( label_wrap(10)("a_very_long_word_without_spaces"), "a_very_long_word_without_spaces" ) expect_equal(wrap_format(10)("short line"), "short\nline") expect_equal(wrap_format(15)("short line"), "short line") }) scales/tests/testthat/test-minor_breaks.R0000644000176200001440000000072114672302077020311 0ustar liggesuserstest_that("minor breaks are calculated correctly", { l1 <- c(0, 9) b1 <- extended_breaks()(l1) m1 <- regular_minor_breaks()(b1, l1, n = 2) expect_equal(m1, c(0, 1.25, 2.5, 3.75, 5, 6.25, 7.5, 8.75, 10)) }) test_that("minor breaks for reversed scales are comparable to non-reversed", { l2 <- c(0, -9) b2 <- extended_breaks()(l2) m2 <- regular_minor_breaks()(b2, l2, n = 2) expect_equal(m2, c(-10, -8.75, -7.5, -6.25, -5, -3.75, -2.5, -1.25, 0)) }) scales/tests/testthat/test-colour-manip.R0000644000176200001440000000550715002117500020231 0ustar liggesusers# hcl --------------------------------------------------------------------- test_that("can modify each hcl component", { expect_equal(col2hcl("red", h = 180), "#00B793") expect_equal(col2hcl("red", l = 50), "#F40000") expect_equal(col2hcl("red", c = 50), "#B36B6B") expect_equal(col2hcl("red", alpha = 0.5), "#FF000080") }) # alpha ------------------------------------------------------------------- test_that("missing alpha preserves existing", { rgb <- farver::decode_colour(rep("red", 5), to = "rgb") alpha <- seq(0, 1, length.out = nrow(rgb)) reds <- farver::encode_colour(rgb, alpha) expect_equal(reds, alpha(reds, NA)) expect_equal(reds, alpha(reds, rep(NA, 5))) }) test_that("alpha values recycled to match colour", { cols <- farver::encode_colour(farver::decode_colour(c( "red", "green", "blue", "pink" ))) expect_equal(cols, alpha(cols, NA)) expect_equal(cols, alpha(cols, 1)) }) test_that("col values recycled to match alpha", { alphas <- round(seq(0, 1, length.out = 3)) reds <- alpha("red", alphas) reds_alpha <- farver::decode_colour(reds, TRUE)[, 4] expect_equal(alphas, reds_alpha) }) test_that("preserves names", { x <- c("deeppink", "hotpink", "lightpink") expect_named(alpha(x, 0.5), NULL) names(x) <- x expect_named(alpha(x, 0.5), names(x)) }) # col_mix ----------------------------------------------------------------- test_that("col_mix interpolates colours", { x <- col_mix("red", c("blue", "green")) y <- col_mix(c("blue", "green"), "red") expect_equal(x, y) expect_equal(x, c("#800080", "#808000")) x <- col_mix("red", "blue", amount = 0.75) expect_equal(x, "#4000BFFF") }) test_that("col_shift shifts colours correctly", { x <- c("#FF0000", "#00FF00", "#0000FF") expect_equal(col_shift(x, 360), x) expect_equal(col_shift(x, 180), c("#00B8B8", "#FF92FF", "#535300")) }) test_that("col_lighter and col_darker adjust lightness correctly", { x <- c("#FF0000", "#00FF00", "#0000FF") expect_equal(col_lighter(x, 30), c("#FF9999", "#99FF99", "#9999FF")) expect_equal(col_darker(x, 30), c("#660000", "#006600", "#000066")) }) test_that("col_saturate can (de)saturate colours", { x <- c("#BF4040", "#40BF40", "#4040BF") expect_equal(col_saturate(x, 30), c("#E51A1A", "#1AE51A", "#1A1AE5")) expect_equal(col_saturate(x, -30), c("#996666", "#669966", "#666699")) }) test_that("colour manipulation functions work on palettes", { pal <- pal_manual(c("#FF0000", "#00FF00", "#0000FF")) expect_equal(col_shift(pal, 180)(3), c("#00B8B8", "#FF92FF", "#535300")) expect_equal(col_darker(pal, 30)(3), c("#660000", "#006600", "#000066")) expect_equal(col_lighter(pal, 30)(3), c("#FF9999", "#99FF99", "#9999FF")) expect_equal(col_saturate(pal, -50)(3), c("#BF4040", "#40BF40", "#4040BF")) expect_equal(col_mix(pal, "white")(3), c("#FF8080", "#80FF80", "#8080FF")) }) scales/tests/testthat/test-pal-hue.R0000644000176200001440000000152014672302077017167 0ustar liggesuserstest_that("pal_hue arguments are forcely evaluated on each call #81", { col1 <- pal_hue(h.start = 0) col2 <- pal_hue(h.start = 90) colours <- list() hues <- c(0, 90) for (i in 1:2) { colours[[i]] <- pal_hue(h.start = hues[i]) } expect_equal(col1(1), colours[[1]](1)) expect_equal(col2(1), colours[[2]](1)) }) test_that("hue_pal respects direction argument #252", { col1 <- pal_hue() col2 <- pal_hue(direction = -1) expect_equal(col1(3), rev(col2(3))) expect_equal(col1(9), rev(col2(9))) }) test_that("hue_pal respects h.start", { hue <- function(...) { farver::decode_colour(pal_hue(...)(2), to = "hcl")[, "h"] } # Have to use large tolerance since we're generating out of gamut colours. expect_equal(hue(), c(15, 195), tolerance = 0.1) expect_equal(hue(h.start = 30), c(45, 235), tolerance = 0.1) }) scales/tests/testthat/test-label-bytes.R0000644000176200001440000000551614706713207020047 0ustar liggesuserstest_that("auto units always rounds down", { expect_equal(label_bytes()(1000^(1:3)), c("1 kB", "1 MB", "1 GB")) }) test_that("auto units handles 0 and other special values", { expect_equal(label_bytes()(NA_real_), NA_character_) expect_equal(label_bytes()(0), "0 B") expect_equal(label_bytes()(-1), "-1 B") expect_equal(label_bytes()(Inf), "Inf") }) test_that("can use either binary or si units", { expect_equal(label_bytes("kB")(1000), "1 kB") expect_equal(label_bytes("kiB")(1024), "1 kiB") }) test_that("compatible with scale argument", { expect_equal(label_bytes("auto_si", scale = 2)(500), "1 kB") expect_equal(label_bytes("auto_binary", scale = 2)(512), "1 kiB") }) test_that("errors if unknown unit", { expect_snapshot(label_bytes("unit")(0), error = TRUE) }) # deprecated interface ---------------------------------------------------- test_that("Byte formatter can take a symbol designator", { expect_equal( number_bytes(c(50, 400, 502, NA), symbol = "B"), c("50 B", "400 B", "502 B", NA) ) expect_equal( number_bytes(3:5 * 1024^2, symbol = "MiB"), c("3 MiB", "4 MiB", "5 MiB") ) expect_equal( number_bytes(1000^(1:3), symbol = "kB", units = "si"), c("1 kB", "1 000 kB", "1 000 000 kB") ) # informative warning for incorrect spelling expect_snapshot(number_bytes(c(50, 400, 502, NA), symbol = "k")) # respects unit designation expect_equal(number_bytes(1024, accuracy = .01), c("1.00 KiB")) expect_equal(number_bytes(1024, units = "si", accuracy = .01), c("1.02 kB")) expect_equal(number_bytes(1000, units = "si", accuracy = .01), c("1.00 kB")) # takes parameters from number() expect_equal( number_bytes(c(3e6, 4e6, 5e6), accuracy = .001), c("2.861 MiB", "3.815 MiB", "4.768 MiB") ) expect_equal( number_bytes(c(3e6, 4e6, 5e6), units = "si", accuracy = .1), c("3.0 MB", "4.0 MB", "5.0 MB") ) # unit system is enforced expect_snapshot(number_bytes(1024^(1:2), "kB", units = "binary")) expect_snapshot(number_bytes(1024^(1:2), "KiB", units = "si")) }) test_that("Byte formatter handles zero values", { expect_equal(number_bytes(0), "0 B") }) test_that("Byte formatter handles large values", { expect_equal(number_bytes(1024^11), "1 073 741 824 YiB") expect_equal(number_bytes(1000^9, units = "si"), "1 000 YB") }) test_that("Byte formatter handles negative values", { expect_equal(number_bytes(-1024^2), "-1 MiB") }) test_that('Byte formatter symbol = "auto" can show variable multiples', { expect_equal(number_bytes(1024^(1:3)), c("1 KiB", "1 MiB", "1 GiB")) }) test_that("Byte formatter throws informative error for wrong length symbol", { expect_snapshot(number_bytes(symbol = character()), error = TRUE) expect_snapshot(number_bytes(symbol = c("kB", "MB")), error = TRUE) }) test_that("preserves names", { expect_named(number_bytes(c(a = 1)), "a") }) scales/tests/testthat/test-scale-discrete.R0000644000176200001440000000217115001712000020500 0ustar liggesuserstest_that("NA.value works for discrete", { x <- c(NA, "a", "b", "c", NA) pal <- brewer_pal() expect_equal(dscale(x, pal)[1], NA_character_) expect_equal(dscale(x, pal)[5], NA_character_) expect_equal(dscale(x, pal, "grey50")[1], "grey50") expect_equal(dscale(x, pal, "grey50")[5], "grey50") }) test_that("na.rm = FALSE keeps NA", { x1 <- c("a", NA) x2 <- factor(x1) x3 <- addNA(x2) expect_equal(train_discrete(x1, na.rm = FALSE), c("a", NA)) expect_equal(train_discrete(x2, na.rm = FALSE), c("a", NA)) expect_equal(train_discrete(x3, na.rm = FALSE), c("a", NA)) }) test_that("na.rm = TRUE drops NA", { x1 <- c("a", NA) x2 <- factor(x1) x3 <- addNA(x2) expect_equal(train_discrete(x1, na.rm = TRUE), "a") expect_equal(train_discrete(x2, na.rm = TRUE), "a") expect_equal(train_discrete(x3, na.rm = TRUE), "a") }) test_that("discrete ranges can be trained on S3 classes", { my_obj <- structure(list("A", c("B", "C")), class = "foo") levels.foo <- function(x) unique(unlist(x)) registerS3method("levels", "foo", method = levels.foo) expect_equal( train_discrete(my_obj), LETTERS[1:3] ) }) scales/tests/testthat/test-full-seq.R0000644000176200001440000000240315002117500017344 0ustar liggesuserstest_that("works with numeric", { x <- c(0, 100) expected <- c(0, 50, 100) expect_equal(fullseq(x, 50), expected) expect_equal(fullseq(rev(x), 50), expected) }) test_that("works with POSIXct", { x <- as.POSIXct(c("2000-01-01 08:29:58", "2000-01-01 08:30:10"), tz = "UTC") expected <- as.POSIXct( c("2000-01-01 8:00:00 UTC", "2000-01-01 9:00:00 UTC"), tz = "UTC" ) expect_equal(fullseq(x, "1 hour"), expected) expect_equal(fullseq(rev(x), "1 hour"), expected) expect_equal( fullseq(x, ".5 secs")[1:2], as.POSIXct( c("2000-01-01 08:29:58.0 UTC", "2000-01-01 08:29:58.5 UTC"), tz = "UTC" ) ) }) test_that("works with Date", { x <- as.Date("2012-01-01") + c(1, 30) expected <- as.Date(c("2012-01-01", "2012-02-01", "2012-03-01")) expect_equal(fullseq(x, "1 month"), expected) expect_equal(fullseq(rev(x), "1 month"), expected) }) test_that("works with hms/difftime", { x <- hms::hms(hours = 0:1) y <- as.difftime(c(0, 1800, 3600), units = "secs") expect_equal(fullseq(x, 1800), y) expect_equal(fullseq(x, "30 mins"), y) expect_equal(fullseq(rev(x), "30 mins"), y) # Preserves units x <- as.difftime(c(0, 1), units = "hours") expect_equal(fullseq(x, 1800), as.difftime(c(0, 0.5, 1), units = "hours")) }) scales/tests/testthat/test-label-number-auto.R0000644000176200001440000000207314672302077021153 0ustar liggesuserstest_that("gracefully handles bad input works", { number_auto <- label_number_auto() expect_equal(number_auto(NULL), character()) expect_equal(number_auto(numeric()), character()) expect_equal(number_auto(NA), "NA") expect_equal(number_auto(Inf), "Inf") }) test_that("tricky breaks don't change unexpectedly", { expect_snapshot({ number_auto <- label_number_auto() number_auto(c(0, 0.000001)) number_auto(c(0.0009, 0.0010, 0.0011)) number_auto(c(0.00009, 0.00010, 0.00011)) number_auto(c(0.000009, 0.000010, 0.000011)) number_auto(c(999, 1000, 1001)) number_auto(c(999999, 1000000, 1000001)) number_auto(c(9999999, 10000000, 10000001)) number_auto(c(99999999, 100000000, 100000001)) number_auto(c(0.0000009, 0.0000010, 0.0000011)) "Years shouldn't get commas" number_auto(c(2010, 2013, 2020)) number_auto(c(-2010, -2013, -2020)) "Pick shortest individually" number_auto(10^(1:7)) }) }) test_that("single values > 1e+06 don't throw error", { expect_equal(label_number_auto()(30925005), "30 925 005") }) scales/tests/testthat/test-label-date.R0000644000176200001440000000361415002117500017613 0ustar liggesuserstest_that("date_format works correctly", { a_date <- ISOdate(2012, 1, 1, 11, tz = "UTC") na_date <- ISOdate(NA, 1, 1) # date of value NA expect_equal(date_format()(a_date), "2012-01-01") expect_equal(date_format(format = "%m/%d/%Y")(a_date), "01/01/2012") expect_equal( date_format(format = "%m/%d/%Y", tz = "Etc/GMT+12")(a_date), "12/31/2011" ) expect_equal(date_format()(na_date), NA_character_) }) test_that("time_format works correctly", { a_time <- ISOdatetime(2012, 1, 1, 11, 30, 0, tz = "UTC") na_time <- ISOdatetime(NA, 1, 1, 1, 1, 0) # time of value NA expect_equal(time_format()(a_time), "11:30:00") expect_equal(time_format()(hms::as_hms(a_time)), "11:30:00") expect_equal(time_format(format = "%H")(hms::as_hms(a_time)), "11") expect_equal(time_format()(na_time), NA_character_) }) test_that("can set locale", { x <- ISOdate(2012, 1, 1, 11, tz = "UTC") expect_equal(date_format("%B", locale = "fr")(x), "janvier") expect_equal(time_format("%B", locale = "fr")(x), "janvier") }) test_that("label_date_short can replace leading zeroes", { x <- seq(as.Date("2024-01-01"), as.Date("2025-01-01"), by = "1 month") labels <- label_date_short( format = c("%Y", "%m", "%d"), sep = "-", leading = "x" )(x) expect_equal(labels, c("x1-2024", paste0("x", 2:9), c(10:12), "x1-2025")) }) test_that("date_short doesn't change unexpectedly", { expect_snapshot({ dformat <- label_date_short() "dates" jan1 <- as.Date("2010-01-01") dformat(seq(jan1, length = 8, by = "7 day")) dformat(seq(jan1, length = 8, by = "3 month")) dformat(seq(jan1, length = 8, by = "1 year")) "date-times" jan1 <- as.POSIXct("2010-01-01", tz = "UTC") dformat(seq(jan1, length = 6, by = "3 hours")) dformat(seq(jan1, length = 6, by = "7 day")) dformat(seq(jan1, length = 6, by = "3 month")) dformat(seq(jan1, length = 6, by = "1 year")) }) }) scales/tests/testthat/test-label-scientific.R0000644000176200001440000000213415002117500021012 0ustar liggesuserstest_that("scientific format shows specific sig figs", { expect_equal(label_scientific(digits = 1)(123456), "1e+05") expect_equal(label_scientific(digits = 2)(123456), "1.2e+05") expect_equal(label_scientific(digits = 3)(123456), "1.23e+05") expect_equal(label_scientific(digits = 1)(0.123456), "1e-01") expect_equal(label_scientific(digits = 2)(0.123456), "1.2e-01") expect_equal(label_scientific(digits = 3)(0.123456), "1.23e-01") }) test_that("prefix and suffix works with scientific format", { expect_equal(scientific(123456, digits = 2, prefix = "V="), "V=1.2e+05") expect_equal(scientific(123456, digits = 2, suffix = " km"), "1.2e+05 km") }) test_that("scale works with scientific format", { expect_equal(scientific(123456, digits = 2, scale = 1000), "1.2e+08") }) test_that("decimal.mark works with scientific format", { expect_equal(scientific(123456, digits = 2, decimal.mark = ","), "1,2e+05") }) test_that("scientific format respects NAs", { expect_equal(scientific(NA), NA_character_) }) test_that("scientific preserves names", { expect_named(scientific(c(a = 1)), "a") }) scales/tests/testthat/test-pal-manual.R0000644000176200001440000000042614706713207017666 0ustar liggesuserstest_that("pal_manual gives warning if n greater than the number of values", { expect_snapshot(pal_manual(c("red", "blue", "green"))(4)) }) test_that("pal_manual returns an unnamed vector", { x <- c(foo = "red", bar = "blue") expect_equal(pal_manual(x)(2), unname(x)) }) scales/tests/testthat/test-trans-date.R0000644000176200001440000000342615002117500017664 0ustar liggesusersa_time <- ISOdatetime(2012, 1, 1, 11, 30, 0, tz = "UTC") a_date <- as.Date(a_time) tz <- function(x) attr(as.POSIXlt(x), "tzone")[1] tz2 <- function(x) format(x, "%Z") with_tz <- function(x, value) { as.POSIXct(format(x, tz = value, usetz = TRUE), tz = value) } test_that("date/time scales raise error on incorrect inputs", { time <- transform_time() expect_snapshot_error(time$transform(a_date)) date <- transform_date() expect_snapshot_error(date$transform(a_time)) }) test_that("time scales learn timezones", { skip_if_not(getRversion() > "3.3.3") time <- transform_time() x <- time$inverse(time$transform(a_time)) expect_equal(tz(x), "UTC") expect_equal(tz2(x), "UTC") time <- transform_time() x <- time$inverse(time$transform(with_tz(a_time, "GMT"))) expect_equal(tz(x), "GMT") expect_equal(tz2(x), "GMT") }) test_that("tz arugment overrules default time zone", { time <- transform_time("GMT") x <- time$inverse(time$transform(a_time)) expect_equal(tz(x), "GMT") expect_equal(tz2(x), "GMT") }) test_that("date_breaks() works", { times <- as.POSIXct( c("2000-01-01 08:29:58", "2000-01-01 08:30:10"), tz = "UTC" ) expect_equal( date_breaks("1 hour")(times), as.POSIXct( c("2000-01-01 8:00:00 UTC", "2000-01-01 9:00:00 UTC"), tz = "UTC" ) ) expect_equal( date_breaks(".5 secs")(times)[1:2], as.POSIXct( c("2000-01-01 08:29:58.0 UTC", "2000-01-01 08:29:58.5 UTC"), tz = "UTC" ) ) dates <- a_date + 1:30 expect_equal( date_breaks("1 month")(dates), as.Date(c("2012-01-01", "2012-02-01")) ) }) test_that("can invert domain", { t <- transform_date() expect_equal(t$transform(t$domain), c(-Inf, Inf)) t <- transform_time() expect_equal(t$transform(t$domain), c(-Inf, Inf)) }) scales/tests/testthat/test-palette-registry.R0000644000176200001440000000210415002117500021116 0ustar liggesuserstest_that("palette getters and setters work as intended", { # Test that palettes have been populated in .onLoad expect_in(c("hue", "grey"), palette_names()) # We cannot get unknown palettes expect_snapshot(get_palette("rgb"), error = TRUE) # We cannot set nonsense palettes expect_snapshot(set_palette("foobar", list(a = 1:2, b = "A")), error = TRUE) # Test we can set custom palettes colours <- c("red", "green", 'blue') set_palette("rgb", palette = colours) expect_in("rgb", palette_names()) # Test we can get custom palettes pal <- get_palette("rgb") expect_equal(pal(length(colours)), colours) # Test we can reset palettes reset_palettes() expect_false("rgb" %in% palette_names()) }) test_that("as_continuous_pal and as_discrete_pal can retrieve known palettes", { colours <- c("#FF0000", "#00FF00", '#0000FF') set_palette("rgb", colours) pal <- as_discrete_pal("rgb") expect_equal(pal(length(colours)), colours) pal <- as_continuous_pal("rgb") expect_equal(pal(seq(0, 1, length.out = length(colours))), colours) reset_palettes() }) scales/tests/testthat/test-breaks.R0000644000176200001440000000252614705655135017115 0ustar liggesuserstest_that("extended breaks returns no breaks for bad inputs", { breaks <- extended_breaks() expect_equal(breaks(NA), numeric()) expect_equal(breaks(Inf), numeric()) expect_equal(breaks(NaN), numeric()) }) test_that("breaks_pretty() arguments are forcely evaluated on each call #81", { subfun1 <- breaks_pretty(n = 5) subfun2 <- breaks_pretty(n = 10) subfuns <- list() cases <- c(5, 10) for (i in 1:2) { subfuns[[i]] <- breaks_pretty(n = cases[i]) } expect_equal(subfun1(1), subfuns[[1]](1)) expect_equal(subfun2(1), subfuns[[2]](1)) # A ... argument: subfun1 <- breaks_pretty(n = 10, min.n = 2) subfun2 <- breaks_pretty(n = 10, min.n = 5) subfuns <- list() cases <- c(2, 5) for (i in 1:2) { subfuns[[i]] <- breaks_pretty(n = 10, min.n = cases[i]) } expect_equal(subfun1(1), subfuns[[1]](1)) expect_equal(subfun2(1), subfuns[[2]](1)) }) test_that("breaks_pretty() returns input when given zero-width range (#446)", { expect_equal(breaks_pretty()(c(1, 1)), 1) }) test_that("exponential breaks give sensible values", { x <- breaks_exp()(c(0, 2)) expect_equal(x, c(0, 0.5, 1, 1.5, 2)) x <- breaks_exp()(c(0, 5)) expect_equal(x, c(5, 4, 3, 2, 0)) x <- breaks_exp()(c(100, 102)) expect_equal(x, c(0, 0.5, 1, 1.5, 2) + 100) x <- breaks_exp()(c(0, 100)) expect_equal(x, c(100, 99, 98, 97, 0)) }) scales/tests/testthat/test-label-pvalue.R0000644000176200001440000000136615002117500020174 0ustar liggesuserstest_that("arguments passed onto number()", { expect_equal(label_pvalue()(c(.5, NA)), c("0.500", NA)) expect_equal(label_pvalue(0.1)(c(.5, NA)), c("0.5", NA)) expect_equal(label_pvalue(decimal.mark = ",")(c(.5, NA)), c("0,500", NA)) }) test_that("preserves names", { expect_named(label_pvalue()(c(a = 1)), "a") }) test_that("values close to 0 and 1 get special treamtent", { expect_equal(label_pvalue(0.1)(0.001), "<0.1") expect_equal(label_pvalue(0.1)(0.999), ">0.9") }) test_that("can control prefixes", { x <- c(0.001, 0.5, 0.999) expect_equal( label_pvalue(0.01, add_p = TRUE)(x), c("p<0.01", "p=0.50", "p>0.99") ) expect_equal( label_pvalue(0.01, prefix = c("a", "b", "c"))(x), c("a0.01", "b0.50", "c0.99") ) }) scales/tests/testthat/test-trans-compose.R0000644000176200001440000000255415002117500020415 0ustar liggesuserstest_that("composes transforms correctly", { t <- transform_compose("log10", "reverse") expect_equal(t$transform(100), -2) expect_equal(t$inverse(-2), 100) }) test_that("composes derivatives correctly", { t <- transform_compose("sqrt", "reciprocal", "reverse") expect_equal(t$d_transform(0.25), 4) expect_equal(t$d_inverse(-2), 0.25) }) test_that("produces NULL derivatives if not all transforms have derivatives", { t <- transform_compose("sqrt", new_transform("no_deriv", identity, identity)) expect_null(t$d_transform) expect_null(t$d_inverse) }) test_that("uses breaks from first transformer", { t <- transform_compose("log10", "reverse") expect_equal(t$breaks(c(1, 1000)), log_breaks()(c(1, 1000))) }) test_that("produces informative errors", { expect_snapshot(error = TRUE, { transform_compose() transform_compose("sqrt", "reverse", "log10") }) }) test_that("produces correct domains", { expect_equal(transform_compose("sqrt", "reverse")$domain, c(0, Inf)) expect_equal(transform_compose("sqrt", "log")$domain, c(0, Inf)) expect_equal(transform_compose("log", "log")$domain, c(1, Inf)) expect_equal(transform_compose("reverse", "log")$domain, c(-Inf, 0)) expect_equal(transform_compose("reverse", "logit", "log")$domain, c(-1, -0.5)) expect_snapshot( transform_compose("sqrt", "reverse", "log")$domain, error = TRUE ) }) scales/tests/testthat/test-label-dictionary.R0000644000176200001440000000050315002117500021035 0ustar liggesuserstest_that("label_dictionary gives correct answers", { short <- c("A", "B", "C") lut <- c("A" = "Apple", "C" = "Cherry", "D" = "Date") expect_equal(label_dictionary(lut)(short), c("Apple", "B", "Cherry")) expect_equal( label_dictionary(lut, nomatch = "Banana")(short), c("Apple", "Banana", "Cherry") ) }) scales/tests/testthat/test-label-log.R0000644000176200001440000000066614705443562017506 0ustar liggesuserstest_that("label_log() returns expression", { expect_identical(label_log()(numeric()), expression()) expect_identical(label_log()(NA_real_), expression(NA)) expect_equal(label_log()(c(0.1, 10)), expression(10^-1, 10^1)) expect_equal(label_log(base = 2)(8), expression(2^3)) expect_equal(label_log(base = 2, digits = 3)(7), expression(2^2.81)) expect_equal(label_log(signed = TRUE)(c(-100, 100)), expression(-10^2, +10^2)) }) scales/tests/testthat/test-colour-ramp.R0000644000176200001440000000214114672302077020074 0ustar liggesuserstest_that("Special values yield NAs", { pal <- seq_gradient_pal() expect_equal(pal(NA), NA_character_) expect_equal(pal(NaN), NA_character_) expect_equal(pal(Inf), NA_character_) expect_equal(pal(-Inf), NA_character_) }) test_that("can make ramp with single color", { expect_equal(colour_ramp("black")(0.5), "black") expect_equal(colour_ramp("black", na.color = "red")(NA), "red") }) test_that("Fully opaque colors are returned without alpha", { expect_equal( colour_ramp(c("#1234AB", "#BA4321"))(0:1), c("#1234AB", "#BA4321") ) }) test_that("Partially transparent colors are returned with alpha", { expect_equal( colour_ramp(c("#1234AB20", "#BA43218F"))(0:1), c("#1234AB20", "#BA43218F") ) }) test_that("Partially transparent colors are returned without alpha when `alpha = FALSE`", { expect_equal( colour_ramp(c("#1234AB20", "#BA43218F"), alpha = FALSE)(0:1), c("#1234AB", "#BA4321") ) }) test_that("Interpolation works from color without to color with alpha channel", { expect_identical( colour_ramp(c("#1234AB", "#1234AB00"))(0.5), "#1234AB80" ) }) scales/tests/testthat/test-label-number.R0000644000176200001440000001607615002117500020174 0ustar liggesusers# Number formatter -------------------------------------------------------- test_that("number format works correctly", { expect_equal(number(123.45, accuracy = 1), "123") expect_equal(number(123.45, accuracy = 10), "120") expect_equal(number(123.45, accuracy = .25), "123.5") expect_equal( number(12345, big.mark = ","), "12,345" ) expect_equal( number(12.3, decimal.mark = ",", accuracy = .1), "12,3" ) expect_equal( number(1.234, scale = 100), "123" ) expect_equal( number(123, prefix = "pre", suffix = "post"), "pre123post" ) expect_equal(number(c(1, 23)), c("1", "23")) expect_equal(number(c(1, 23), trim = FALSE), c(" 1", "23")) }) test_that("number_format works with Inf", { cust <- number_format(suffix = "suff", accuracy = NULL) expect_equal(cust(c(Inf, -Inf)), c("Inf", "-Inf")) }) test_that("number preserves names", { expect_named(number(c(a = 1)), "a") }) test_that("can control positive and negative styles", { expect_equal(number(1, style_positive = "none"), "1") expect_equal(number(1, style_positive = "plus"), "+1") expect_equal(number(-1, style_negative = "hyphen"), "-1") expect_equal(number(-1, style_negative = "minus"), "\u22121") expect_equal(number(-1, style_negative = "parens"), "(1)") }) test_that("prefix applied before negative format", { expect_equal(number(-1, prefix = "$"), "-$1") expect_equal(number(-1, prefix = "$", style_negative = "parens"), "($1)") }) test_that("accuracy is vectorised", { expect_equal( number(rep(0.1234, 4), accuracy = 10^(0:-3)), c("0", "0.1", "0.12", "0.123") ) }) # Comma formatter -------------------------------------------------------- test_that("comma format always adds commas", { expect_equal(comma(1e3), "1,000") expect_equal(comma(1e6), "1,000,000") expect_equal(comma(1e9), "1,000,000,000") }) test_that("comma preserves names", { expect_named(comma(c(a = 1)), "a") }) # Common tests -------------------------------------------------------- test_that("formatters don't add extra spaces", { has_space <- function(x) any(grepl("\\s", x)) x <- 10^c(-1, 0, 1, 3, 6, 9) expect_false(has_space(number(x, big.mark = ","))) expect_false(has_space(comma(x))) expect_false(has_space(dollar(x))) expect_false(has_space(percent(x, big.mark = ","))) expect_false(has_space(scientific(x))) }) test_that("formats work with 0 length input", { x <- numeric() expected <- character() expect_identical(number(x), expected) expect_identical(comma(x), expected) expect_identical(dollar(x), expected) expect_identical(percent(x), expected) expect_identical(scientific(x), expected) expect_identical(comma_format()(x), expected) expect_identical(date_format()(as.Date(character(0))), expected) expect_identical(dollar_format()(x), expected) expect_identical(parse_format()(x), expression()) expect_identical(parse_format()(character()), expression()) expect_identical(percent_format()(x), expected) expect_identical(scientific_format()(x), expected) expect_identical(trans_format(identity)(x), expected) }) # precision --------------------------------------------------------------- test_that("precision rounds large numbers appropriately", { x <- c(0, 0.025) expect_equal(precision(x), 0.001) expect_equal(precision(x * 10), 0.01) expect_equal(precision(x * 100), 0.1) expect_equal(precision(x * 1000), 1) expect_equal(precision(x * 10000), 1) }) test_that("precision is reduced when possible", { expect_equal(precision(c(0, 0.01)), 0.01) expect_equal(precision(c(0, 0.011)), 0.001) expect_equal(precision(c(0, 0.0101)), 0.01) expect_equal(precision(c(0, 0.0109)), 0.001) expect_equal(precision(c(0.251, 0.351)), 0.01) }) test_that("precision handles duplicate values", { expect_equal(precision(c(0, 0, 0.025)), 0.001) expect_equal(precision(c(Inf, 0.1, 0.2, Inf)), 0.1) }) test_that("precision ignores Inf and NA", { expect_equal(precision(c(NA, Inf, -Inf)), 1) expect_equal(precision(c(1, NA)), 1) }) # scale_cut --------------------------------------------------------------- test_that("accuracy computed on individual scales", { x <- c(0, 250, 500, 750, 1250, 1500) * 1e3 expect_equal( number(x, scale_cut = cut_short_scale()), c("0", "250K", "500K", "750K", "1.25M", "1.50M") ) }) test_that("zero and special values don't get units", { x <- c(0, NA, Inf, -Inf) expect_equal( number(x, scale_cut = cut_short_scale()), c("0", NA, "Inf", "-Inf") ) }) test_that("scale applied before scale_cut", { expect_equal(number(500, scale = 2, scale_cut = cut_short_scale()), "1K") expect_equal( number(c(0, 5e5, 1.2e6), scale = 1 / 1000, scale_cut = cut_short_scale()), c("0", "500", "1K") ) }) test_that("cut_si() adds space before unit", { skip_if_not(getRversion() >= "3.5") expect_equal( number(c(0, 1, 1000), scale_cut = cut_si("m")), c("0 m", "1 m", "1 km") ) }) test_that("handles out-of-range inputs", { expect_equal(number(1e15, scale_cut = cut_short_scale()), "1 000T") }) test_that("short and long scale can add spaces", { expect_equal(number(1000, scale_cut = cut_short_scale(TRUE)), "1 K") expect_equal(number(1000, scale_cut = cut_long_scale(TRUE)), "1 K") }) test_that("scale_cut checks its inputs", { expect_snapshot(error = TRUE, { number(1, scale_cut = 0) number(1, scale_cut = "x") number(1, scale_cut = c(x = 0, NA)) }) }) test_that("scale_cut prefers clean cuts", { x <- c(518400, 691200) # prefers days over week in second element expect_equal(number(x, scale_cut = cut_time_scale()), c("6d", "8d")) # do not select off-scale breaks x <- c(0, 500, 1500, 2000, 2500) expect_equal( number(x, scale_cut = cut_short_scale()), c("0", "500", "1.5K", "2.0K", "2.5K") ) }) test_that("built-in functions return expected values", { skip_if_not(getRversion() >= "3.5") expect_equal(number(1e9, scale_cut = cut_short_scale()), "1B") expect_equal(number(1e9, scale_cut = cut_long_scale()), "1 000M") expect_equal(number(1e9, scale_cut = cut_si("m")), "1 Gm") }) # options ----------------------------------------------------------------- test_that("number_options are observed", { number_options(decimal.mark = ",", big.mark = ".") expect_equal( label_number()(c(0.1, 10, 1e6)), c("0,1", "10,0", "1.000.000,0") ) number_options(style_positive = "plus", style_negative = "parens") expect_equal( label_number()(c(-0.1, 0, 1)), c("(0.1)", "0.0", "+1.0") ) number_options( currency.prefix = "", currency.suffix = " GBP", currency.decimal.mark = ",", currency.big.mark = "." ) # Regular number are not affected expect_equal( label_number()(c(0.1, 10, 1e6)), c("0.1", "10.0", "1 000 000.0") ) # But currency is affected expect_equal( label_currency(accuracy = 0.1)(c(0.1, 10, 1e6)), c("0,1 GBP", "10,0 GBP", "1.000.000,0 GBP") ) number_options(ordinal.rules = ordinal_french(plural = TRUE)) expect_equal( label_ordinal()(1:4), c("1ers", "2es", "3es", "4es") ) # Can be reset number_options() expect_equal( label_ordinal()(1:4), c("1st", "2nd", "3rd", "4th") ) }) scales/tests/testthat/_snaps/0000755000176200001440000000000015001712000015773 5ustar liggesusersscales/tests/testthat/_snaps/pal-manual.md0000644000176200001440000000043615002115116020355 0ustar liggesusers# pal_manual gives warning if n greater than the number of values Code pal_manual(c("red", "blue", "green"))(4) Condition Warning: This manual palette can handle a maximum of 3 values. You have supplied 4 Output [1] "red" "blue" "green" NA scales/tests/testthat/_snaps/trans-numeric.md0000644000176200001440000000067715002115117021125 0ustar liggesusers# Boxcox gives error for negative values Code trans$trans(-10:10) Condition Error in `trans$trans()`: ! `transform_boxcox()` must be given only positive values i Consider using `transform_modulus()` instead? --- Code trans$trans(-10:10) Condition Error in `trans$trans()`: ! `transform_boxcox()` must be given only positive values i Consider using `transform_modulus()` instead? scales/tests/testthat/_snaps/scale-continuous.md0000644000176200001440000000032315002115116021614 0ustar liggesusers# train_continuous stops on discrete values Code train_continuous(LETTERS[1:5]) Condition Error: ! Discrete value supplied to a continuous scale. i Example values: "A" and "E". scales/tests/testthat/_snaps/label-ordinal.md0000644000176200001440000000076615002115115021040 0ustar liggesusers# ordinal format in English Code ordinal(c(1:4, 11:21, 101, NA)) Output [1] "1st" "2nd" "3rd" "4th" "11th" "12th" "13th" "14th" "15th" [10] "16th" "17th" "18th" "19th" "20th" "21st" "101st" NA Code ordinal(c(1, 2, 10, 11, NA), rules = ordinal_french()) Output [1] "1er" "2e" "10e" "11e" NA Code ordinal(c(1, 2, 10, 11, NA), rules = ordinal_french("f", TRUE)) Output [1] "1res" "2es" "10es" "11es" NA scales/tests/testthat/_snaps/trans.md0000644000176200001440000000100215002115117017444 0ustar liggesusers# as.transform generates informative error Code as.transform(1) Condition Error in `as.transform()`: ! `x` must be a character vector or transform object, not the number 1. Code as.transform("x") Condition Error in `as.transform()`: ! Could not find any function named `transform_x()` or `x_trans()` # trans has useful print method Code new_transform("test", transform = identity, inverse = identity) Output Transformer: test [-Inf, Inf] scales/tests/testthat/_snaps/breaks-log.md0000644000176200001440000000056215002115114020352 0ustar liggesusers# minor_breaks_log rejects invalid arguments Code minor_breaks_log(7) Condition Error in `minor_breaks_log()`: ! The `detail` argument must be one of 1, 5 or 10. --- Code minor_breaks_log(smallest = 0) Condition Error in `minor_breaks_log()`: ! The `smallest` argument must be a finite, positive, non-zero number. scales/tests/testthat/_snaps/label-date.md0000644000176200001440000000264215002115115020320 0ustar liggesusers# date_short doesn't change unexpectedly Code dformat <- label_date_short() # dates jan1 <- as.Date("2010-01-01") dformat(seq(jan1, length = 8, by = "7 day")) Output [1] "01\nJan\n2010" "08" "15" "22" [5] "29" "05\nFeb" "12" "19" Code dformat(seq(jan1, length = 8, by = "3 month")) Output [1] "Jan\n2010" "Apr" "Jul" "Oct" "Jan\n2011" "Apr" [7] "Jul" "Oct" Code dformat(seq(jan1, length = 8, by = "1 year")) Output [1] "2010" "2011" "2012" "2013" "2014" "2015" "2016" "2017" Code # date-times jan1 <- as.POSIXct("2010-01-01", tz = "UTC") dformat(seq(jan1, length = 6, by = "3 hours")) Output [1] "00:00\n01\nJan\n2010" "03:00" "06:00" [4] "09:00" "12:00" "15:00" Code dformat(seq(jan1, length = 6, by = "7 day")) Output [1] "01\nJan\n2010" "08" "15" "22" [5] "29" "05\nFeb" Code dformat(seq(jan1, length = 6, by = "3 month")) Output [1] "Jan\n2010" "Apr" "Jul" "Oct" "Jan\n2011" "Apr" Code dformat(seq(jan1, length = 6, by = "1 year")) Output [1] "2010" "2011" "2012" "2013" "2014" "2015" scales/tests/testthat/_snaps/trans-compose.md0000755000176200001440000000107415002115116021122 0ustar liggesusers# produces informative errors Code transform_compose() Condition Error in `transform_compose()`: ! `transform_compose()` must include at least 1 transformer to compose Code transform_compose("sqrt", "reverse", "log10") Condition Error in `transform_compose()`: ! Sequence of transformations yields invalid domain # produces correct domains Code transform_compose("sqrt", "reverse", "log")$domain Condition Error in `transform_compose()`: ! Sequence of transformations yields invalid domain scales/tests/testthat/_snaps/label-number-auto.md0000644000176200001440000000253115002115115021636 0ustar liggesusers# tricky breaks don't change unexpectedly Code number_auto <- label_number_auto() number_auto(c(0, 1e-06)) Output [1] "0e+00" "1e-06" Code number_auto(c(9e-04, 0.001, 0.0011)) Output [1] "0.0009" "0.0010" "0.0011" Code number_auto(c(9e-05, 1e-04, 0.00011)) Output [1] "0.00009" "0.00010" "0.00011" Code number_auto(c(9e-06, 1e-05, 1.1e-05)) Output [1] "9.0e-06" "1.0e-05" "1.1e-05" Code number_auto(c(999, 1000, 1001)) Output [1] "999" "1 000" "1 001" Code number_auto(c(999999, 1e+06, 1000001)) Output [1] "999 999" "1 000 000" "1 000 001" Code number_auto(c(9999999, 1e+07, 10000001)) Output [1] "9 999 999" "10 000 000" "10 000 001" Code number_auto(c(99999999, 1e+08, 100000001)) Output [1] "1e+08" "1e+08" "1e+08" Code number_auto(c(9e-07, 1e-06, 1.1e-06)) Output [1] "9.0e-07" "1.0e-06" "1.1e-06" Code # Years shouldn't get commas number_auto(c(2010, 2013, 2020)) Output [1] "2010" "2013" "2020" Code number_auto(c(-2010, -2013, -2020)) Output [1] "-2 010" "-2 013" "-2 020" Code # Pick shortest individually number_auto(10^(1:7)) Output [1] "10" "100" "1 000" "1e+04" "1e+05" "1e+06" "1e+07" scales/tests/testthat/_snaps/trans-date.md0000644000176200001440000000027415002115116020370 0ustar liggesusers# date/time scales raise error on incorrect inputs `transform_time()` works with objects of class only --- `transform_date()` works with objects of class only scales/tests/testthat/_snaps/label-bytes.md0000644000176200001440000000301115002115115020520 0ustar liggesusers# errors if unknown unit Code label_bytes("unit")(0) Condition Error: ! `units` must be one of "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", or "YiB", not "unit". # Byte formatter can take a symbol designator Code number_bytes(c(50, 400, 502, NA), symbol = "k") Condition Warning: `symbol` must be one of auto, B, KiB, MiB, GiB, TiB, PiB, EiB, ZiB, or YiB i The provided value ("k") will be changed to the default ("auto") Output [1] "50 B" "400 B" "502 B" NA --- Code number_bytes(1024^(1:2), "kB", units = "binary") Condition Warning: `symbol` must be one of auto, B, KiB, MiB, GiB, TiB, PiB, EiB, ZiB, or YiB i The provided value ("kB") will be changed to the default ("auto") Output [1] "1 KiB" "1 MiB" --- Code number_bytes(1024^(1:2), "KiB", units = "si") Condition Warning: `symbol` must be one of auto, B, kB, MB, GB, TB, PB, EB, ZB, or YB i The provided value ("KiB") will be changed to the default ("auto") Output [1] "1 kB" "1 MB" # Byte formatter throws informative error for wrong length symbol Code number_bytes(symbol = character()) Condition Error in `validate_byte_symbol()`: ! `symbol` must have length 1, not length 0 --- Code number_bytes(symbol = c("kB", "MB")) Condition Error in `validate_byte_symbol()`: ! `symbol` must have length 1, not length 2 scales/tests/testthat/_snaps/label-number.md0000644000176200001440000000067615002115115020700 0ustar liggesusers# scale_cut checks its inputs Code number(1, scale_cut = 0) Condition Error in `scale_cut()`: ! `scale_cut` must have names Code number(1, scale_cut = "x") Condition Error in `scale_cut()`: ! `scale_cut` must be a numeric vector, not the string "x". Code number(1, scale_cut = c(x = 0, NA)) Condition Error in `scale_cut()`: ! `scale_cut` values must not be missing scales/tests/testthat/_snaps/utils.md0000644000176200001440000000065215002115117017467 0ustar liggesusers# recycle_common throws appropriate errors Code recycle_common(a = 1:2, size = 3) Condition Error: ! Cannot recycle `a` to length 3. --- Code recycle_common(a = 1:2, b = 1:3) Condition Error: ! Cannot recycle `a` and `b` to a common size. --- Code recycle_common(a = 1:2, b = 1:3, size = 3) Condition Error: ! Cannot recycle `a` to length 3. scales/tests/testthat/_snaps/palette-registry.md0000644000176200001440000000053215002115116021627 0ustar liggesusers# palette getters and setters work as intended Code get_palette("rgb") Condition Error in `get_palette()`: ! Unknown palette: rgb --- Code set_palette("foobar", list(a = 1:2, b = "A")) Condition Error in `set_palette()`: ! The `palette` argument must be a or vector. scales/tests/testthat/_snaps/colour-mapping.md0000644000176200001440000000403015002115115021253 0ustar liggesusers# Outside of domain returns na.color Code col_factor(bw, letters, na.color = NA)("foo") Condition Warning: Some values were outside the color scale and will be treated as NA Output [1] NA --- Code col_quantile(bw, 0:1, na.color = NA)(-1) Condition Warning: Some values were outside the color scale and will be treated as NA Output [1] NA --- Code col_quantile(bw, 0:1, na.color = NA)(2) Condition Warning: Some values were outside the color scale and will be treated as NA Output [1] NA --- Code col_numeric(bw, c(0, 1), na.color = NA)(-1) Condition Warning: Some values were outside the color scale and will be treated as NA Output [1] NA --- Code col_numeric(bw, c(0, 1), na.color = NA)(2) Condition Warning: Some values were outside the color scale and will be treated as NA Output [1] NA # factors match by name, not position Code col <- pal(letters[10:20]) Condition Warning: Some values were outside the color scale and will be treated as NA # qualitative palettes don't interpolate Code pal(letters[6]) Condition Warning: Some values were outside the color scale and will be treated as NA Output [1] NA # OK, qualitative palettes sometimes interpolate Code result <- pal(letters[1:20]) Condition Warning in `RColorBrewer::brewer.pal()`: n too large, allowed maximum for palette Accent is 8 Returning the palette you asked for with that many colors # col_quantile handles skewed data Code x <- c(1:5, rep(10, 10)) col <- col_quantile("RdYlBu", domain = x, n = 7)(x) Condition Warning: Skewed data means we can only allocate 4 unique colours not the 7 requested Code col <- col_quantile("RdYlBu", domain = NULL, n = 7)(x) Condition Warning: Skewed data means we can only allocate 4 unique colours not the 7 requested scales/tests/testthat/test-label-compose.R0000644000176200001440000000037715002117500020346 0ustar liggesuserstest_that("compose_labels can chain together functions", { labeller <- compose_label(`-`, label_number(suffix = " foo"), toupper) expect_equal( labeller(c(0.1, 1.0, 10.0)), c("-0.1 FOO", "-1.0 FOO", "-10.0 FOO"), ignore_attr = TRUE ) }) scales/tests/testthat/test-offset-by.R0000644000176200001440000000405215002117500017514 0ustar liggesuserstest_that("breaks_width() offset supports numeric units", { scale_range <- 0:1 breaks <- breaks_width(1, offset = 0.5) expect_equal(breaks(scale_range), c(0.5, 1.5)) }) test_that("breaks_width() with offset supports Date and POSIXt units #247 #269", { breaks <- breaks_width("1 year", offset = "3 months") compound_breaks <- breaks_width("1 year", offset = c("3 months", "5 days")) Date_range <- as.Date(c("2020-01-01", "2020-01-02")) POSIXt_range <- as.POSIXct(c("2020-01-01", "2020-01-02"), tz = "UTC") # Date expect_equal( breaks(Date_range), as.Date(c("2020-04-01", "2021-04-01")) ) expect_equal( compound_breaks(Date_range), as.Date(c("2020-04-06", "2021-04-06")) ) # POSIXt expect_equal( breaks(POSIXt_range), as.POSIXct(c("2020-04-01", "2021-04-01"), tz = "UTC") ) expect_equal( compound_breaks(POSIXt_range), as.POSIXct(c("2020-04-06", "2021-04-06"), tz = "UTC") ) # Fractional seconds fractional_seconds <- breaks_width("1 sec", offset = "0.5 secs") sec_range <- as.POSIXct( c("2020-01-01 00:00:00", "2020-01-01 00:00:01"), tz = "UTC" ) expected <- .POSIXct(c(1577836800.5, 1577836801.5, 1577836802.5), tz = "UTC") expect_equal(fractional_seconds(sec_range), expected) }) test_that("breaks_width() with offset supports difftime units #247 #269", { secs <- breaks_width("3 mins", offset = "1 sec") mins <- breaks_width("3 mins", offset = "1 min") hours <- breaks_width("3 hours", offset = "1 hour") days <- breaks_width("3 days", offset = "1 day") scale_range <- as.difftime(0:1, units = "secs") expect_equal(secs(scale_range), as.difftime(c(1, 181), units = "secs")) expect_equal(mins(scale_range), as.difftime(c(60, 240), units = "secs")) expect_equal(hours(scale_range), as.difftime(c(3600, 14400), units = "secs")) expect_equal(days(scale_range), as.difftime(c(86400, 345600), units = "secs")) # Compound units mins_secs <- breaks_width("1 hour", offset = c("1 min", "1 sec")) expect_equal(mins_secs(scale_range), as.difftime(c(61, 3661), units = "secs")) }) scales/tests/testthat/test-label-number-si.R0000644000176200001440000000022614672302077020614 0ustar liggesuserstest_that("label_number_si() is deprecated", { lifecycle::expect_defunct(label_number_si("")) lifecycle::expect_defunct(label_number_si("m")) }) scales/tests/testthat/test-colour-mapping.R0000644000176200001440000002262015002117500020553 0ustar liggesusersbw <- c("black", "white") test_that("Edgy col_bin scenarios", { # Do these cases make sense? expect_equal(col_bin(bw, NULL)(1), "#777777") expect_equal(col_bin(bw, 1)(1), "#FFFFFF") }) test_that("Outside of domain returns na.color", { suppressWarnings({ expect_identical("#808080", col_factor(bw, letters)("foo")) expect_identical("#808080", col_quantile(bw, 0:1)(-1)) expect_identical("#808080", col_quantile(bw, 0:1)(2)) expect_identical("#808080", col_numeric(bw, c(0, 1))(-1)) expect_identical("#808080", col_numeric(bw, c(0, 1))(2)) expect_true(is.na(col_factor(bw, letters, na.color = NA)("foo"))) expect_true(is.na(col_quantile(bw, 0:1, na.color = NA)(-1))) expect_true(is.na(col_quantile(bw, 0:1, na.color = NA)(2))) expect_true(is.na(col_numeric(bw, c(0, 1), na.color = NA)(-1))) expect_true(is.na(col_numeric(bw, c(0, 1), na.color = NA)(2))) }) expect_snapshot(col_factor(bw, letters, na.color = NA)("foo")) expect_snapshot(col_quantile(bw, 0:1, na.color = NA)(-1)) expect_snapshot(col_quantile(bw, 0:1, na.color = NA)(2)) expect_snapshot(col_numeric(bw, c(0, 1), na.color = NA)(-1)) expect_snapshot(col_numeric(bw, c(0, 1), na.color = NA)(2)) }) test_that("Basic color accuracy", { expect_identical( c("#000000", "#808080", "#FFFFFF"), col_numeric(colorRamp(bw), NULL)(c(0, 0.5, 1)) ) expect_identical(c("#000000", "#FFFFFF"), col_bin(bw, NULL)(c(1, 2))) expect_identical(c("#000000", "#FFFFFF"), col_bin(bw, c(1, 2))(c(1, 2))) expect_identical(c("#000000", "#FFFFFF"), col_bin(bw, c(1, 2), 2)(c(1, 2))) expect_identical( c("#000000", "#FFFFFF"), col_bin(bw, NULL, bins = c(1, 1.5, 2))(c(1, 2)) ) expect_identical( c("#000000", "#FFFFFF"), col_bin(bw, c(1, 2), bins = c(1, 1.5, 2))(c(1, 2)) ) expect_identical( c("#000000", "#777777", "#FFFFFF"), col_numeric(bw, NULL)(1:3) ) expect_identical( c("#000000", "#777777", "#FFFFFF"), col_numeric(bw, c(1:3))(1:3) ) expect_identical( rev(c("#000000", "#777777", "#FFFFFF")), col_numeric(rev(bw), c(1:3))(1:3) ) # domain != unique(x) expect_identical( c("#000000", "#0E0E0E", "#181818"), col_factor(bw, LETTERS)(LETTERS[1:3]) ) # domain == unique(x) expect_identical( c("#000000", "#777777", "#FFFFFF"), col_factor(bw, LETTERS[1:3])(LETTERS[1:3]) ) # no domain expect_identical( c("#000000", "#777777", "#FFFFFF"), col_factor(bw, NULL)(LETTERS[1:3]) ) # Non-factor domains are sorted unless instructed otherwise expect_identical( c("#000000", "#777777", "#FFFFFF"), col_factor(bw, rev(LETTERS[1:3]))(LETTERS[1:3]) ) expect_identical( rev(c("#000000", "#777777", "#FFFFFF")), col_factor(bw, rev(LETTERS[1:3]), ordered = TRUE)(LETTERS[1:3]) ) }) test_that("col_numeric respects alpha", { expect_equal( col_numeric(c("#FF000000", "#FF0000FF"), c(0, 1), alpha = TRUE)(0.5), "#FF000080" ) }) test_that("CIELab overflow", { expect_identical( c("#FFFFFF", "#CFB1FF", "#9265FF", "#0000FF"), colour_ramp(c("white", "blue"))(0:3 / 3) ) }) test_that("factors match by name, not position", { full <- factor(letters[1:5]) pal <- col_factor("magma", na.color = NA, levels = full) partial <- full[2:4] expect_identical(pal(partial), pal(droplevels(partial))) # Sending in values outside of the color scale should result in a warning and na.color expect_snapshot(col <- pal(letters[10:20])) expect_true(all(is.na(col))) }) test_that("qualitative palettes don't interpolate", { pal <- col_factor("Accent", na.color = NA, levels = letters[1:5]) allColors <- RColorBrewer::brewer.pal( n = RColorBrewer::brewer.pal.info["Accent", "maxcolors"], name = "Accent" ) # If we're not interpolating, then the colors for each level should match # exactly with the color in the corresponding position in the palette. expect_identical(pal(letters[1:5]), allColors[1:5]) # Same behavior when domain is provided initially expect_identical( col_factor("Accent", domain = rep(letters[1:5], 2))(letters[1:5]), allColors[1:5] ) # Same behavior when domain is provided initially, and is a factor expect_identical( col_factor("Accent", domain = factor(rep(letters[5:1], 2)))(letters[1:5]), allColors[1:5] ) # Same behavior when domain is provided initially, and is not a factor expect_identical( col_factor("Accent", domain = rep(letters[5:1], 2), ordered = TRUE)(letters[ 5:1 ]), allColors[1:5] ) # Same behavior when no domain or level is provided initially expect_identical( col_factor("Accent", NULL)(letters[1:5]), allColors[1:5] ) # Values outside of the originally provided levels should be NA with warning expect_snapshot(pal(letters[6])) expect_true(suppressWarnings(is.na(pal(letters[6])))) }) test_that("OK, qualitative palettes sometimes interpolate", { pal <- col_factor("Accent", na.color = NA, levels = letters[1:20]) allColors <- RColorBrewer::brewer.pal( n = RColorBrewer::brewer.pal.info["Accent", "maxcolors"], name = "Accent" ) expect_snapshot(result <- pal(letters[1:20])) # The first and last levels are the first and last palette colors expect_true(all(result[c(1, 20)] %in% allColors)) # All the rest are interpolated though expect_true(!any(result[-c(1, 20)] %in% allColors)) }) verifyReversal <- function(colorFunc, values, ..., filter = identity) { f1 <- filter(colorFunc("Blues", domain = values, ...)(values)) f2 <- filter(colorFunc("Blues", domain = NULL, ...)(values)) f3 <- filter(colorFunc("Blues", domain = values, reverse = FALSE, ...)( values )) f4 <- filter(colorFunc("Blues", domain = NULL, reverse = FALSE, ...)(values)) r1 <- filter(colorFunc("Blues", domain = values, reverse = TRUE, ...)(values)) r2 <- filter(colorFunc("Blues", domain = NULL, reverse = TRUE, ...)(values)) expect_identical(f1, f2) expect_identical(f1, f3) expect_identical(f1, f4) expect_identical(r1, r2) expect_identical(f1, rev(r1)) } test_that("col_numeric can be reversed", { verifyReversal(col_numeric, 1:10) }) test_that("col_bin can be reversed", { # col_bin needs to filter because with 10 values and 7 bins, there is some # repetition that occurs in the results. Hard to explain but easy to see: # scales::show_col(col_bin("Blues", NULL)(1:8)) # scales::show_col(col_bin("Blues", NULL, reverse = TRUE)(1:8)) verifyReversal(col_bin, 1:10, filter = unique) }) test_that("col_quantile can be reversed", { verifyReversal(col_quantile, 1:10, n = 7) }) test_that("col_factor can be reversed", { # With interpolation verifyReversal(col_factor, letters[1:8]) # Without interpolation accent <- suppressWarnings(RColorBrewer::brewer.pal(Inf, "Accent")) result1 <- col_factor("Accent", NULL)(letters[1:5]) expect_identical(result1, head(accent, 5)) # Reversing a qualitative palette means we should pull the same colors, but # apply them in reverse order result2 <- col_factor("Accent", NULL, reverse = TRUE)(letters[1:5]) expect_identical(result2, rev(head(accent, 5))) }) test_that("Palettes with ncolor < 3 work properly", { test_palette <- function(palette) { colors <- col_factor(palette, letters[1:2])(letters[1:2]) # brewer.pal returns minimum 3 colors, and warns if you request less than 3. expected_colors <- suppressWarnings(RColorBrewer::brewer.pal(2, palette))[ 1:2 ] # The expected behavior is that the first two colors in the palette are returned. # This is different than the behavior in Leaflet color* functions; in those # functions, when 2 colors are needed from an RColorBrewer palette, the first and # third colors are used. Using the first and third is arguably a better choice # for sequential and diverging palettes, and very arguably worse for qualitative. # The scales' col_* functions use the first 2 colors for consistency with # scales::brewer_pal. expect_identical(colors, expected_colors) colors <- col_bin(palette, 1:2, bins = 2)(1:2) expect_identical(colors, expected_colors) } # Qualitative palette test_palette("Accent") # Sequential palette test_palette("Blues") # Diverging palette test_palette("Spectral") }) test_that("col_quantile handles skewed data", { expect_snapshot({ x <- c(1:5, rep(10, 10)) col <- col_quantile("RdYlBu", domain = x, n = 7)(x) col <- col_quantile("RdYlBu", domain = NULL, n = 7)(x) }) }) test_that("Arguments to `cut` are respected", { colors1 <- col_bin("Greens", 1:3, 1:3)(1:3) # Intervals are [1,2) and [2,3], so 2 and 3 are the same expect_identical(colors1, c("#E5F5E0", "#A1D99B", "#A1D99B")) colors2 <- col_bin("Blues", 1:3, 1:3, right = TRUE)(1:3) # Intervals are [1,2] and (2,3], so 1 and 2 are the same expect_identical(colors2, c("#DEEBF7", "#DEEBF7", "#9ECAE1")) # Shows that you can use cut + col_factor to achieve finer grained # control than with col_bin pal <- col_factor("Reds", domain = NULL, na.color = NA) colorsTT <- pal(cut(1:3, 1:3, include.lowest = TRUE, right = TRUE)) expect_identical(colorsTT, c("#FEE0D2", "#FEE0D2", "#FC9272")) colorsTF <- pal(cut(1:3, 1:3, include.lowest = TRUE, right = FALSE)) expect_identical(colorsTF, c("#FEE0D2", "#FC9272", "#FC9272")) colorsFT <- pal(cut(1:3, 1:3, include.lowest = FALSE, right = TRUE)) expect_identical(colorsFT, c(NA, "#FEE0D2", "#FC9272")) colorsFF <- pal(cut(1:3, 1:3, include.lowest = FALSE, right = FALSE)) expect_identical(colorsFF, c("#FEE0D2", "#FC9272", NA)) }) scales/tests/testthat/test-trans-numeric.R0000644000176200001440000002615015002117500020410 0ustar liggesuserstest_that("Pseudo-log is invertible", { trans <- transform_pseudo_log() expect_equal( trans$inverse(trans$transform(-10:10)), -10:10 ) }) test_that("Modulus is invertible for negative and positive numbers", { trans <- transform_modulus(p = .1) expect_equal(trans$inv(trans$trans(-10:10)), -10:10) trans <- transform_modulus(p = -2) expect_equal(trans$inv(trans$trans(-10:10)), -10:10) trans <- transform_modulus(p = 1) expect_equal(trans$inv(trans$trans(-10:10)), -10:10) }) test_that("Boxcox gives error for negative values", { trans <- transform_boxcox(p = .1) expect_snapshot(trans$trans(-10:10), error = TRUE) trans <- transform_boxcox(p = -2) expect_snapshot(trans$trans(-10:10), error = TRUE) }) test_that("Boxcox can handle NA values", { trans <- transform_boxcox(p = 0) expect_equal(trans$trans(c(1, NA_real_)), c(0, NA_real_)) }) test_that("Boxcox is invertible", { trans <- transform_boxcox(p = .1) expect_equal(trans$inv(trans$trans(0:10)), 0:10) trans <- transform_boxcox(p = -2) expect_equal(trans$inv(trans$trans(0:10)), 0:10) trans <- transform_boxcox(p = 1) expect_equal(trans$inv(trans$trans(0:10)), 0:10) }) test_that("Yeo-Johnson is invertible", { x <- c(-12345, 12345, -0.12345, 0.12345, -10:10) trans <- transform_yj(p = -1.5) expect_equal(trans$inverse(trans$transform(x)), x) trans <- transform_yj(p = 0) expect_equal(trans$inverse(trans$transform(x)), x) trans <- transform_yj(p = 0.7) expect_equal(trans$inverse(trans$transform(x)), x) trans <- transform_yj(p = 1.5) expect_equal(trans$inverse(trans$transform(x)), x) trans <- transform_yj(p = 2) expect_equal(trans$inverse(trans$transform(x)), x) }) test_that("Yeo-Johnson is identity function for p = 1", { x <- c(-12345, 12345, -0.12345, 0.12345, -10:10) trans <- transform_yj(p = 1) expect_equal(trans$transform(x), x) }) test_that("Yeo-Johnson transforms NAs to NAs without error", { x <- c(1, 2, NA, 4) trans <- transform_yj(p = 1) expect_equal(trans$transform(x), x) }) test_that("Yeo-Johnson transform works", { # example data adpated from recipes package # https://github.com/tidymodels/recipes/blob/master/tests/testthat/test_YeoJohnson.R n <- 20 set.seed(1) x <- data.frame( x1 = exp(rnorm(n, mean = .1)), x2 = 1 / rnorm(n), x3 = rexp(n) ) lambdas <- c( x1 = -0.2727204451, x2 = 1.139292543, x3 = -1.012702061 ) expected_data <- data.frame( x1 = c( 0.435993557749438, 0.754696454247318, 0.371327932207827, 1.46113017436327, 0.82204097731098, 0.375761562702297, 0.89751975937422, 1.02175936118846, 0.940739811377902, 0.54984302797741, 1.41856737837093, 0.850587387615876, 0.437701618670981, 0.112174615510591, 1.21942112715274, 0.654589551748501, 0.666780580127795, 1.12625135443351, 1.0636850911955, 0.949680956411546 ), x2 = c( 1.15307873387121, 1.36532999080347, 17.4648439780388, -0.487746797875704, 1.74452440065935, -13.3640721541574, -5.35805967319061, -0.653901985285932, -1.90735599477338, 2.65253432454371, 0.76771137336975, -7.79484535687973, 2.87484976680907, -13.8738947581599, -0.696856395842167, -2.17745353101028, -2.28384276604207, -12.7261652971783, 0.95585544349634, 1.40099012093008 ), x3 = c( 0.49061104973894, 0.49670370366879, 0.338742419511653, 0.663722100577351, 0.296260662322359, 0.681346128666408, 0.757581280603711, 0.357148961119583, 0.371872889850153, 0.49239057672598, 0.173259524331095, 0.235933290139909, 0.52297977893566, 0.434927187456966, 0.0822501770191215, 0.523479652016858, 0.197977570919824, 0.608108816144845, 0.821913792446345, 0.300608495427594 ) ) expect_equal(transform_yj(lambdas[1])$transform(x[[1]]), expected_data[[1]]) expect_equal(transform_yj(lambdas[2])$transform(x[[2]]), expected_data[[2]]) expect_equal(transform_yj(lambdas[3])$transform(x[[3]]), expected_data[[3]]) }) test_that("probability transforms have domain (0,1)", { expect_equal(transform_logit()$domain, c(0, 1)) expect_equal(transform_probit()$domain, c(0, 1)) }) # Derivatives ------------------------------------------------------------- test_that("transform_asn derivatives work", { trans <- transform_asn() expect_equal(trans$d_transform(c(0, 0.5, 1)), c(Inf, 2, Inf)) expect_equal(trans$d_inverse(c(0, pi / 2, pi)), c(0, 0.5, 0)) x <- seq(0.1, 0.9, length.out = 10) expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_atanh derivatives work", { trans <- transform_atanh() expect_equal(trans$d_transform(c(-1, 0, 1)), c(Inf, 1, Inf)) expect_equal(trans$d_inverse(c(-log(2), 0, log(2))), c(0.64, 1, 0.64)) x <- seq(-0.9, 0.9, length.out = 10) expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_asinh derivatives work", { trans <- transform_asinh() expect_equal(trans$d_transform(c(-1, 0, 1)), c(sqrt(2) / 2, 1, sqrt(2) / 2)) expect_equal(trans$d_inverse(c(-log(2), 0, log(2))), c(1.25, 1, 1.25)) x <- seq(-0.9, 0.9, length.out = 10) expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_boxcox derivatives work", { trans <- transform_boxcox(p = 0, offset = 1) expect_equal(trans$d_transform(c(0, 1, 2)), c(1, 1 / 2, 1 / 3)) expect_equal(trans$d_inverse(c(0, 1, 2)), exp(c(0, 1, 2))) x <- 0:10 expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) trans <- transform_boxcox(p = 2, offset = 2) expect_equal(trans$d_transform(c(0, 1, 2)), c(2, 3, 4)) expect_equal(trans$d_inverse(c(0, 0.5, 4)), c(1, sqrt(2) / 2, 1 / 3)) expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_modulus derivatives work", { trans <- transform_modulus(p = 0, offset = 1) expect_equal( trans$d_transform(c(-2, -1, 1, 2)), c(1 / 3, 1 / 2, 1 / 2, 1 / 3) ) expect_equal(trans$d_inverse(c(-2, -1, 1, 2)), exp(c(2, 1, 1, 2))) x <- c(-10:-2, 2:10) expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) trans <- transform_modulus(p = 2, offset = 2) expect_equal(trans$d_transform(c(-2, -1, 1, 2)), c(4, 3, 3, 4)) expect_equal( trans$d_inverse(c(-4, -0.5, 0.5, 4)), c(1 / 3, sqrt(2) / 2, sqrt(2) / 2, 1 / 3) ) expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_yj derivatives work", { trans <- transform_yj(p = 0) expect_equal(trans$d_transform(c(-2, -1, 1, 2)), c(3, 2, 0.5, 1 / 3)) expect_equal(trans$d_inverse(c(-1 / 2, 1, 2)), c(sqrt(2) / 2, exp(1), exp(2))) x <- c(-10:10) expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) trans <- transform_yj(p = 3) expect_equal(trans$d_transform(c(-2, -1, 1, 2)), c(1 / 9, 1 / 4, 4, 9)) expect_equal(trans$d_inverse(c(-4, -0.5, 1)), c(1 / 9, 4, (1 / 16)^(1 / 3))) expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal( trans$d_inverse(0:10), 1 / trans$d_transform(trans$inverse(0:10)) ) }) test_that("transform_exp derivatives work", { trans <- transform_exp(10) expect_equal(trans$d_transform(c(0, 1, 2)), c(1, 10, 100) * log(10)) expect_equal(trans$d_inverse(c(0.1, 1, 10) / log(10)), c(10, 1, 0.1)) x <- 1:10 expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_identity derivatives work", { trans <- transform_identity() expect_equal(trans$d_transform(numeric(0)), numeric(0)) expect_equal(trans$d_transform(c(0, 1, 2)), c(1, 1, 1)) expect_equal(trans$d_inverse(numeric(0)), numeric(0)) expect_equal(trans$d_inverse(c(0, 1, 2)), c(1, 1, 1)) }) test_that("transform_log derivatives work", { trans <- transform_log(10) expect_equal(trans$d_transform(c(0.1, 1, 10) / log(10)), c(10, 1, 0.1)) expect_equal(trans$d_inverse(c(0, 1, 2)), c(1, 10, 100) * log(10)) x <- 1:10 expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_log1p derivatives work", { trans <- transform_log1p() expect_equal(trans$d_transform(c(0, 1, 2)), c(1, 1 / 2, 1 / 3)) expect_equal(trans$d_inverse(c(0, 1, 2)), exp(c(0, 1, 2))) x <- 0:10 expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_pseudo_log derivatives work", { trans <- transform_pseudo_log(0.5) expect_equal(trans$d_transform(c(0, 1)), c(1, sqrt(2) / 2)) expect_equal(trans$d_inverse(c(0, 1)), c(1, cosh(1))) x <- 1:10 expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_logit derivatives work", { trans <- transform_logit() expect_equal(trans$d_transform(c(0.1, 0.5, 0.8)), c(100 / 9, 4, 6.25)) expect_equal(trans$d_inverse(c(0, 1, 2)), dlogis(c(0, 1, 2))) x <- seq(0.1, 0.9, length.out = 10) expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_reciprocal derivatives work", { trans <- transform_reciprocal() expect_equal(trans$d_transform(c(0.1, 1, 10)), c(-100, -1, -0.01)) expect_equal(trans$d_inverse(c(0.1, 1, 10)), c(-100, -1, -0.01)) x <- (1:20) / 10 expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) test_that("transform_reverse derivatives work", { trans <- transform_reverse() expect_equal(trans$d_transform(numeric(0)), numeric(0)) expect_equal(trans$d_transform(c(-1, 1, 2)), c(-1, -1, -1)) expect_equal(trans$d_inverse(numeric(0)), numeric(0)) expect_equal(trans$d_inverse(c(-1, 1, 2)), c(-1, -1, -1)) }) test_that("transform_sqrt derivatives work", { trans <- transform_sqrt() expect_equal(trans$d_transform(c(1, 4, 9)), c(1 / 2, 1 / 4, 1 / 6)) expect_equal(trans$d_inverse(c(1, 2, 3)), c(2, 4, 6)) x <- 1:10 expect_equal(trans$d_transform(x), 1 / trans$d_inverse(trans$transform(x))) expect_equal(trans$d_inverse(x), 1 / trans$d_transform(trans$inverse(x))) }) scales/tests/testthat/test-label-glue.R0000644000176200001440000000040515002117500017625 0ustar liggesuserstest_that("label_glue environments work out as intended", { x <- LETTERS[1:3] y <- "foo" # Note `{x}` should mask the `x <- LETTERS[1:3]` above f <- label_glue("{x} and {y}") expect_equal(f(letters[1:3]), c("a and foo", "b and foo", "c and foo")) }) scales/tests/testthat/test-label-currency.R0000644000176200001440000000150115002117500020521 0ustar liggesuserstest_that("negative comes before prefix", { expect_equal(label_currency()(-1), "-$1") }) test_that("negative_parens is deprecated", { lifecycle::expect_defunct(label_dollar(negative_parens = TRUE)(1)) }) test_that("preserves NAs", { expect_equal(label_currency()(NA_real_), NA_character_) }) test_that("preserves names", { expect_named(label_currency()(c(a = 1)), "a") }) test_that("decimal.mark could be modified", { expect_equal(label_currency(decimal.mark = ",")(123.45), "$123,45") }) test_that("can rescale with scale_cut", { lab <- label_currency(scale_cut = cut_short_scale()) expect_equal(lab(c(1, 1e3, 1e6)), c("$1", "$1K", "$1M")) lab <- label_currency( scale_cut = cut_short_scale(), prefix = "", suffix = " USD" ) expect_equal(lab(c(1, 1e3, 1e6)), c("1 USD", "1K USD", "1M USD")) }) scales/tests/testthat/test-trans.R0000644000176200001440000000160014672302077016762 0ustar liggesuserstest_that("Transformed ranges silently drop out-of-domain values", { r1 <- trim_to_domain(transform_log(), -1:10) expect_equal(r1, log(c(1e-100, 10))) r2 <- trim_to_domain(transform_sqrt(), -1:10) expect_equal(r2, sqrt(c(0, 10))) }) test_that("as.transform handles character inputs", { expect_equal(as.trans("log10"), transform_log10()) expect_equal( as.transform(c("log10", "reverse")), transform_compose(transform_log10(), transform_reverse()) ) }) test_that("as.transform generates informative error", { expect_snapshot(error = TRUE, { as.transform(1) as.transform("x") }) }) test_that("trans has useful print method", { expect_snapshot({ new_transform("test", transform = identity, inverse = identity) }) }) test_that("inverse of trans_sqrt() returns NA for values outside of range", { expect_equal(transform_sqrt()$inverse(-2), NA_real_) }) scales/tests/testthat.R0000644000176200001440000000007014672302077014656 0ustar liggesuserslibrary(testthat) library(scales) test_check("scales") scales/MD50000644000176200001440000003232415002414662012040 0ustar liggesusersf140d33fd240292b9665f233a164d0f1 *DESCRIPTION bdce44acd8616297008fd177df3e717b *LICENSE 68001309f8e2080f0b75d16a7bab04b2 *NAMESPACE e86b2e9000a18d5ca0de079ba20760ac *NEWS.md 619faaacb56b0584d1c6f3df8bb47a84 *R/bounds.R 2b031b7904d5976b3e9ad38c09bd188b *R/breaks-log.R 83a2b67a7fae51e72b1a04addcd3819e *R/breaks-retired.R 2696789d2c0eb475cc245f4810c46235 *R/breaks.R 8c94d2d974f28fb5d155d58f3ed641cf *R/colour-manip.R 7b50f0d67425bf1b3c0a901275415ea8 *R/colour-mapping.R 106d7fd5da15b4feacc9127ca95e4b40 *R/colour-ramp.R 0369d428e5583c741ea919ba887d23a1 *R/date-time.R 1766434b368c5b53280110fb4e93da1f *R/documentation.R e7198f6eb64fab73fce41920393ff125 *R/full-seq.R 799bdb3344a8c0c98ff29fa5f7055f01 *R/import-standalone-obj-type.R 62545d8f97ad53b42ec2efcbde7de6bc *R/import-standalone-types-check.R 9bfd6e86b7223653f0e59d237476b63b *R/label-bytes.R a7521f3027c97e0404144fbf377154ee *R/label-compose.R 6ea0a3140973156e071a2898401d7e00 *R/label-currency.R 5a63ffdf5606b8b67c24191496e9904c *R/label-date.R d98cf483924c2e30b314800dd6cc5ac6 *R/label-dictionary.R a457012db694d859ebf670a7bbc572c4 *R/label-expression.R 3a2e6a73561f60c8899bb28b478bc32c *R/label-glue.R cea41ed678b03cfa8d27c3d40335be7a *R/label-log.R 89d270829ca52175aa311ed845ff3bb9 *R/label-number-auto.R aeb4bcb15681693adbbab638b93e6be2 *R/label-number-si.R 380569307d84826a2b4ef48cf40953d0 *R/label-number.R a1fead8837f8750a22b8dd673543c777 *R/label-ordinal.R 461e7ff0e5dcb49a4558dc024662ad56 *R/label-percent.R 95c376d1a438da471278d4ede0e51462 *R/label-pvalue.R 3d8491859c4cd04b9784be03eb1516ca *R/label-scientific.R 90f415d5068d0bfc7f87fc4a6f351c19 *R/label-wrap.R 9fb7b92a4af1bdd803a2891008e7d46b *R/labels-retired.R b8852b7e92b0f2ace954538e0f2dd09b *R/minor_breaks.R 37f738b5dc4c092541ccbec3f4454812 *R/offset-by.R 015514b97741e5100d578ba1bfb095cf *R/pal-.R 8c4024d13f6222358b81cb5b96952f5a *R/pal-area.R 2dc5fb8cc0e879f214179f4415cca516 *R/pal-brewer.R c50ed9303faba5d386960e31b0f88337 *R/pal-dichromat.R 53a3934daaf9a87567af61420489e3e6 *R/pal-gradient.R a2fbe674eb0d3b08e7249854f1460b5e *R/pal-grey.R ab91d826ae784003efa0068bb7805993 *R/pal-hue.R 131c533bf8754a8c722b34520c6e3faa *R/pal-identity.R dd1b4841929e057e1f64168e345cfdaf *R/pal-linetype.R 290955d00e17c964fd059aaee5e76614 *R/pal-manual.R ce6cb1832469fae5915d5c0f3f203473 *R/pal-rescale.R 615357e4a428b18eb696fbeda545d9a5 *R/pal-shape.r 292b36b1db0d664b35f43d265464f22b *R/pal-viridis.R 11f6a97230a6da3107d6ec8dc4f97b81 *R/palette-registry.R f3e118c4deab62fa95c385c1be48c546 *R/range.R 5d3dad6c4f5c87a4e745ff798e100a26 *R/round-any.R 2e5a41f8d72ce620b1e10552aef16be0 *R/scale-continuous.R 7b4922fb4575004446861a73423eb52a *R/scale-discrete.R 64a7c51ef8780793a101a0049aec558f *R/scales-package.R ed75077b26e1aa1331e0bc32458130e3 *R/transform-compose.R 4ff9ebf8ef8cbc0d51e795cea81043f1 *R/transform-date.R 7042049d892c8196faa1d422b0d0b1b5 *R/transform-numeric.R 8bdb4bde78e17b8369a6a8433a9d973a *R/transform.R 39356cbfd10794699a17e327c340d9bc *R/utils.R 76f572b7826f041680f84d04916d1b3e *README.md 7147a19b86c572023c08aa7a24adee38 *build/partial.rdb 8df734d2f10b99e178943aaeb6ae818b *man/Range.Rd b4d2e009965530bdcf0844acd98cfe94 *man/alpha.Rd 4d0c3c2da7014098d17dc72bea612980 *man/breaks_exp.Rd a88de55405d2b40c464d0c02a60481ba *man/breaks_extended.Rd e76b9bb68106bbf1ec47b6eb44c6153a *man/breaks_log.Rd 1dd405958f8940af7b9ce62569fa912f *man/breaks_pretty.Rd 1ce112b459e239a1b8869218a90dff76 *man/breaks_timespan.Rd 67e6fd149bd5c8d80b19405685430b9e *man/breaks_width.Rd 450975074ff4d8e11d42a645e3340f9e *man/cbreaks.Rd b9d53ecc106b2ec979d2e3517910bde8 *man/col2hcl.Rd 705266c3d53833bef005b04b3dd5d1af *man/col_mix.Rd bbeee98ad38c4cbd048f49fe0ba0f0f1 *man/col_numeric.Rd e8d725a3e0d84181a65311fae2f3ccae *man/colour_manip.Rd 1d322bd9d68d9149f99ac63ee127067e *man/colour_ramp.Rd 7bc017bd4471d037f65ab7cc60e76cba *man/comma.Rd d71d3e922be6245e40bc5cddc0304171 *man/compose_label.Rd 52de21dd7e11fce200446530cb8ad926 *man/cscale.Rd f572db11afa4399b9e178122f4f38660 *man/date_breaks.Rd 926a408d4295a861fcf989690b36dbfa *man/date_format.Rd cf8a90e0bb0279556017a2678ce1fba4 *man/demo_continuous.Rd e385c10f35e2d3e5a649e1e13f2d0a3c *man/dollar_format.Rd 54301fe14acecea257b700c4c1c61a08 *man/dscale.Rd a4fc7c27dde4719bfa681d779bd2e0a5 *man/expand_range.Rd 2f29cb23984bdfe8c6cb89ae5976aa2d *man/figures/README-labels-1.png 73e83a7499ef80323378a96413686c79 *man/figures/README-labels-2.png 711b0e907d5c8589847635da67baed0b *man/figures/README-palettes-1.png abb3c8548757ba624ab20378677e6676 *man/figures/README-transforms-1.png 73e83a7499ef80323378a96413686c79 *man/figures/README-unnamed-chunk-3-1.png 73e83a7499ef80323378a96413686c79 *man/figures/README-unnamed-chunk-4-1.png a1cbaf3f328e8d74e747faacf640c7fc *man/figures/lifecycle-archived.svg 6f521fb1819410630e279d1abf88685a *man/figures/lifecycle-defunct.svg 391f696f961e28914508628a7af31b74 *man/figures/lifecycle-deprecated.svg 691b1eb2aec9e1bec96b79d11ba5e631 *man/figures/lifecycle-experimental.svg 405e252e54a79b33522e9699e4e9051c *man/figures/lifecycle-maturing.svg f41ed996be135fb35afe00641621da61 *man/figures/lifecycle-questioning.svg 306bef67d1c636f209024cf2403846fd *man/figures/lifecycle-soft-deprecated.svg ed42e3fbd7cc30bc6ca8fa9b658e24a8 *man/figures/lifecycle-stable.svg bf2f1ad432ecccee3400afe533404113 *man/figures/lifecycle-superseded.svg 60807ec2287388bdc448a0755c667cc8 *man/figures/logo.png 90dde0bc6fdfadcb4d25ff3b9b96c020 *man/figures/logo.svg cae727a9c3f1be007d2efc7576006380 *man/format_format.Rd 517737ee0f3e8917ebb550f4b9e8948c *man/fullseq.Rd a73fd971cae6035fe540a3037b8a3b5d *man/label_bytes.Rd fb2270c37fb13e4ff7f32a082c9ca641 *man/label_currency.Rd 407ae38da0d6cb8c343560fa1dc83b94 *man/label_date.Rd 0ece4bde47fc428bfd21de182caf4326 *man/label_dictionary.Rd 5d3a9f637f3a2b190ae9107fc1fd67d4 *man/label_glue.Rd a26ba68b39d161b4990f4e6438ee823e *man/label_log.Rd 903c31edbda385127be285f2cb333cc7 *man/label_number.Rd ca86f06e64ecdd02c76ef0c587de6d7e *man/label_number_auto.Rd e71d67947393ab05b89dd4419aa04a86 *man/label_number_si.Rd 02bdc39821ef54ba7c4c65fa46eef00a *man/label_ordinal.Rd 779c5159bdd138c340cc090ff7346db8 *man/label_parse.Rd 3ee105f573b9048ed3ccb467e991e65b *man/label_percent.Rd 259830516c9883a0d4ab1dfe91e108e6 *man/label_pvalue.Rd f9a506b4ebd5f0fc70e214284925829d *man/label_scientific.Rd 9b9272b9392932ae08e0e52af96260a0 *man/label_wrap.Rd 3d71b71214f6d4036dfd87643dc94d3a *man/minor_breaks_log.Rd d0ef33ad152a289c21404c4907af50af *man/minor_breaks_width.Rd acdf14966f8157b6bf4ea59d33dbff0e *man/muted.Rd 7245a1eddab9c25ad3555b94f7c893bd *man/new_continuous_palette.Rd c30b8a331403fe978fb46b71714065dd *man/new_transform.Rd 10e8d49e4e04d31f907c1128c1ca3734 *man/number.Rd 46b378fd9a11b2c7a0a1d0ffda3b7c6e *man/number_bytes_format.Rd c884656292197a58a1a7ef0909c27d5f *man/number_options.Rd 1f4a10b947cc61cf87707d7ef383791f *man/oob.Rd 096a2c6b652ac775ef6e516442fe9321 *man/ordinal_format.Rd fc4f8b22fef43b15f8683b489d08ed1b *man/pal_area.Rd 3c2828f6882e4bd3e932e1fa8f2929e4 *man/pal_brewer.Rd cfee9abba16575b2a81e538b1f1d608b *man/pal_dichromat.Rd 7ee7bb0f120922dfe98d34a2725952ec *man/pal_div_gradient.Rd 643eb1d9a43297a41a3c20c845a15277 *man/pal_gradient_n.Rd 05a6f85a448d29d15e6f0861a53a9d57 *man/pal_grey.Rd 2bb08d9ee59321f0347b7b87af2244c0 *man/pal_hue.Rd e5a897d82dd57afb18826adc8fd9fdb9 *man/pal_identity.Rd ca30b5e18a9044525460f83e474b829b *man/pal_linetype.Rd 018899a094c86bac3192da394b3f33cc *man/pal_manual.Rd b7851f4428bb6635d0a5658c712af7d6 *man/pal_rescale.Rd 90686f19580fe35a23c7e9c739db4b3c *man/pal_seq_gradient.Rd 681cb71c0a4cc9c5cdea6b39e550f66d *man/pal_shape.Rd 5b5784eb4b6c52017c396c47378121eb *man/pal_viridis.Rd 7315b2bc5265ff9567a33fc2dfdec2f8 *man/palette-recommendations.Rd 87023e6af5509b7872d1a8b42ccc9900 *man/parse_format.Rd 84d3d6cfab3118932d3d871c920a8ee5 *man/percent_format.Rd 7dfe8ee853c8e8ab811f693e62028dd6 *man/pretty_breaks.Rd 9beb3b7cdd306169037c44a52408a933 *man/pvalue_format.Rd 956c832f6b8d1bf786f24386032b6358 *man/regular_minor_breaks.Rd 1b6440e79c4de593e66aacb0ab93bdc9 *man/rescale.Rd d9672e336aae3f32b849680b8546b7a7 *man/rescale_max.Rd 28da7460e95f91718a7fcadd471b8601 *man/rescale_mid.Rd 62846324d590864f54033f96cd4f9a68 *man/rescale_none.Rd 3150e205364bf9f5b25c56a10a592e9a *man/scales-package.Rd dc0b50a9d7d8d93b36e620856de2831c *man/scientific_format.Rd 3efe8c7d6c26c934ffe7d132017d5b25 *man/show_col.Rd d4d65566ed53561e97a4871b031651f1 *man/train_continuous.Rd a407913a2a4a837117f54c8b6aba0fbb *man/train_discrete.Rd 622fb57a93a119eb9899433b24413053 *man/trans_breaks.Rd f3d5ae917c55ae3f838455a292f6f0f4 *man/trans_format.Rd 91f6d4e5998e5d2a8c6f7bf717b30f1e *man/transform_asinh.Rd 49e4ba2eed6226abfec4c19bb2f9dab9 *man/transform_asn.Rd f47a15f4270cdfb969dd3e7ef4e2416b *man/transform_atanh.Rd ffcbade741f68f9a789db065ff3e2aca *man/transform_boxcox.Rd 81941b145e34ab66335b41bec6dde403 *man/transform_compose.Rd edefd6f3ef1b0f1969f73390b95b1e78 *man/transform_date.Rd c77039efed9e86f4322000de32642f38 *man/transform_exp.Rd 341a86fa7f35a9bf0f6b1531f635401b *man/transform_identity.Rd edbd21258d9f851cb1eaf6887ff8f86f *man/transform_log.Rd 46637248085504319e4c66f7ede49628 *man/transform_probability.Rd e688538ea74215c3735fd4f3f00873bd *man/transform_reciprocal.Rd 842ad1ca31fc2388692b57a1b64d5897 *man/transform_reverse.Rd c3e388b2a4cc86c5aa50baa467e44b77 *man/transform_sqrt.Rd 213ddba1e9709c75b1fdca751b08f20e *man/transform_time.Rd 222b87074dfae85e586577dcf65036a0 *man/transform_timespan.Rd e03867278737dfd633160611211d44fa *man/transform_yj.Rd fa19639cc4e8b00e22d49e439ab45b2e *man/trim_to_domain.Rd 65d3824711d3cf431ec92a7822e2ab71 *man/unit_format.Rd 6ddec2147e677e82a5454d0eb453b3e0 *man/wrap_format.Rd 8f227fefe98a7ea2a5fe92c7263c7a9c *man/zero_range.Rd 1bc97669868c55fc86b10bffb2010b63 *tests/testthat.R d1cdf331ba0ff525eaf9abd3313094da *tests/testthat/_snaps/breaks-log.md 880fb5fac562e028c4be875e802dffe1 *tests/testthat/_snaps/colour-mapping.md fa7e83fc1855442600e9c918da645352 *tests/testthat/_snaps/label-bytes.md a4538e6ace0483294af592e17ae1d529 *tests/testthat/_snaps/label-date.md 202b124010f867b79f74c0a7e3c9f88f *tests/testthat/_snaps/label-number-auto.md 5ac8dd2fcc2fd6fda77e51ebeb3990f7 *tests/testthat/_snaps/label-number.md 5df8b93419757304abaece7ff6a6bdbd *tests/testthat/_snaps/label-ordinal.md 8140f25346a20f925dabc28d20b7b8a4 *tests/testthat/_snaps/pal-manual.md f1840499a1e735d444ae58729ccdc836 *tests/testthat/_snaps/palette-registry.md 52dc793ada8639ea63a18ae3c1b97ba4 *tests/testthat/_snaps/scale-continuous.md 3dec94b41e068c5304ad74ce75c780e3 *tests/testthat/_snaps/trans-compose.md c70ecef7db96ebc8085d934b08a911c2 *tests/testthat/_snaps/trans-date.md 1994fc4be9c22dfb64938f368477f66e *tests/testthat/_snaps/trans-numeric.md 7c0f5f8c4f7a3f084d2f52715017bd31 *tests/testthat/_snaps/trans.md a5d38897e8eaef299c83fc990377f48d *tests/testthat/_snaps/utils.md 7fc7689dab736212dfef6eabc2d18c3f *tests/testthat/test-bounds.R 5f7a93af71927cdf305ba42b7fbe84c5 *tests/testthat/test-breaks-log.R 579000a6d52fb5190e5239b195594207 *tests/testthat/test-breaks.R 7676024754db716a77be0ab8d0156d21 *tests/testthat/test-colour-manip.R 49bd1e0950aa8efa6d4e86919c3e3169 *tests/testthat/test-colour-mapping.R 4fb53fa4b105c924d33c0e03301b666c *tests/testthat/test-colour-ramp.R 102bb4d768242857cf7f79ce454a87ff *tests/testthat/test-full-seq.R aa144c93351ac3c3303f9e7ca71dc9a9 *tests/testthat/test-label-bytes.R 0bfdd725e7f88b8232b2fad7a6851ca3 *tests/testthat/test-label-compose.R 8d4aeab0968025b32b64d4962bc7b9d2 *tests/testthat/test-label-currency.R 84b02f82818702e1f3cd89994c1e0ed4 *tests/testthat/test-label-date.R e9270016e9767d9586b8c30c573fe053 *tests/testthat/test-label-dictionary.R 9f0dfffab9f421258ad6f183602e5797 *tests/testthat/test-label-expression.R bc4f97135e4eb8e0456898bbb1c23e3c *tests/testthat/test-label-glue.R 9f9b0e2258dad64a8d709ddcbab17f25 *tests/testthat/test-label-log.R 3b056db9a1f8b2da54ad0adfddaec45e *tests/testthat/test-label-number-auto.R 11ae0d053d143a4f1a72c52995617456 *tests/testthat/test-label-number-si.R 15a8cac9258cd1473dba7ff6b4896ace *tests/testthat/test-label-number.R 865e7a64f3f82d63e6427ddbbe80ba1f *tests/testthat/test-label-ordinal.R 97456b3a7406696ac617dedcc0131458 *tests/testthat/test-label-percent.R a0017b5fb85a5a9901ee3cd2e09681a8 *tests/testthat/test-label-pvalue.R 7ca43335525199f603adcb1851181217 *tests/testthat/test-label-scientific.R 9edaadb50a932261843dfbfa4718805d *tests/testthat/test-label-wrap.R 258114b488527ed2037ef2773f05bfc0 *tests/testthat/test-labels-retired.R 6106647ac1b736b9242e8ff3a433de06 *tests/testthat/test-minor_breaks.R 5101acfc0c80c0baffaec439708a189d *tests/testthat/test-offset-by.R c0643d986a5233eb5f49334439015b8c *tests/testthat/test-pal-.R dcfdda37753a92d04d9288701aefa146 *tests/testthat/test-pal-hue.R 43d4b9ab1b032ae0b1ec447753c7f0a4 *tests/testthat/test-pal-manual.R c3a9fb608ea6cc1cc6023803e97e4320 *tests/testthat/test-palette-registry.R 7c130f5d2ee8626cab1b7e9ca0e47aa4 *tests/testthat/test-range.R a1e372a8010cfd235ed2598f7f0995c4 *tests/testthat/test-round-any.R ee02bde9ca2153a9671c4c10828b7ca9 *tests/testthat/test-scale-continuous.R 950a4f299e7ab520451a6bf2df28c1bf *tests/testthat/test-scale-discrete.R 6d7f14a78877e887f1384a7c2f3a803d *tests/testthat/test-trans-compose.R 4b4a00ee1bc4979945a3b07f5a10a343 *tests/testthat/test-trans-date.R f92a19558383bc0c4e20efcac8df792c *tests/testthat/test-trans-numeric.R 5e8e2c6f5807938656527f0b9f1a46c1 *tests/testthat/test-trans.R 184165c5045e7ef7bff02f2b8571e0dd *tests/testthat/test-utils.R scales/R/0000755000176200001440000000000015002146671011727 5ustar liggesusersscales/R/offset-by.R0000644000176200001440000000205114672302077013754 0ustar liggesusersoffset_by <- function(x, size) { UseMethod("offset_by") } #' @export offset_by.numeric <- function(x, size) { x + size } #' @export offset_by.Date <- function(x, size) { fun <- function(x) seq(x, length.out = 2, by = size)[2] out <- lapply(x, fun) do.call(c, out) } #' @export offset_by.POSIXt <- function(x, size) { # for subsecond interval support # seq() does not support partial secs in character strings if (is.character(size) && (parsed <- parse_unit_spec(size))$unit == "sec") { fun <- function(x) seq(x, length.out = 2, by = parsed$mult)[2] } else { fun <- function(x) seq(x, length.out = 2, by = size)[2] } out <- lapply(x, fun) out <- do.call(c, out) attr(out, "tzone") <- attr(x, "tzone") out } #' @export offset_by.difftime <- function(x, size) { if (is.numeric(size)) { size_seconds <- size } else { size_seconds <- unit_seconds(size) } input_units <- units(x) x <- as.numeric(x, units = "secs") x <- x + size_seconds x <- as.difftime(x, units = "secs") units(x) <- input_units x } scales/R/label-percent.R0000644000176200001440000000275715002117500014567 0ustar liggesusers#' Label percentages (2.5%, 50%, etc) #' #' @inherit label_number return params #' @inheritDotParams label_number #' @export #' @family labels for continuous scales #' @examples #' demo_continuous(c(0, 1)) #' demo_continuous(c(0, 1), labels = label_percent()) #' #' # Use prefix and suffix to create your own variants #' french_percent <- label_percent( #' decimal.mark = ",", #' suffix = " %" #' ) #' demo_continuous(c(0, .01), labels = french_percent) label_percent <- function( accuracy = NULL, scale = 100, prefix = "", suffix = "%", big.mark = NULL, decimal.mark = NULL, trim = TRUE, ... ) { number_format( accuracy = accuracy, scale = scale, prefix = prefix, suffix = suffix, big.mark = big.mark, decimal.mark = decimal.mark, trim = trim, ... ) } #' Superseded interface to `label_percent()` #' #' @description #' `r lifecycle::badge("superseded")` #' #' These functions are kept for backward compatibility; you should switch #' to [label_percent()] for new code. #' #' @keywords internal #' @export #' @inheritParams label_percent percent_format <- label_percent #' @export #' @rdname percent_format percent <- function( x, accuracy = NULL, scale = 100, prefix = "", suffix = "%", big.mark = NULL, decimal.mark = NULL, trim = TRUE, ... ) { number( x = x, accuracy = accuracy, scale = scale, prefix = prefix, suffix = suffix, big.mark = big.mark, decimal.mark = decimal.mark, trim = trim, ... ) } scales/R/label-pvalue.R0000644000176200001440000000447715002117500014424 0ustar liggesusers#' Label p-values (e.g. <0.001, 0.25, p >= 0.99) #' #' Formatter for p-values, using "<" and ">" for p-values close to 0 and 1. #' #' @inherit label_number return params #' @param prefix A character vector of length 3 giving the prefixes to #' put in front of numbers. The default values are `c("p<", "p=", "p>")` #' if `add_p` is `TRUE` and `c("<", "", ">")` if `FALSE`. #' @param add_p Add "p=" before the value? #' @export #' @family labels for continuous scales #' @examples #' demo_continuous(c(0, 1)) #' demo_continuous(c(0, 1), labels = label_pvalue()) #' demo_continuous(c(0, 1), labels = label_pvalue(accuracy = 0.1)) #' demo_continuous(c(0, 1), labels = label_pvalue(add_p = TRUE)) #' #' # Or provide your own prefixes #' prefix <- c("p < ", "p = ", "p > ") #' demo_continuous(c(0, 1), labels = label_pvalue(prefix = prefix)) label_pvalue <- function( accuracy = .001, decimal.mark = NULL, prefix = NULL, add_p = FALSE ) { force_all(accuracy, decimal.mark, add_p) function(x) { pvalue( x, accuracy = accuracy, decimal.mark = decimal.mark, prefix = prefix, add_p = add_p ) } } #' Superseded interface to `label_pvalue()` #' #' @description #' `r lifecycle::badge("superseded")` #' #' These functions are kept for backward compatibility; you should switch #' to [label_pvalue()] for new code. #' #' @keywords internal #' @export #' @inheritParams label_pvalue #' @export pvalue_format <- label_pvalue #' @rdname pvalue_format #' @export pvalue <- function( x, accuracy = .001, decimal.mark = NULL, prefix = NULL, add_p = FALSE ) { decimal.mark <- decimal.mark %||% getOption("scales.decimal.mark", default = ".") out <- number(x, accuracy, decimal.mark = decimal.mark) below <- number(accuracy, accuracy, decimal.mark = decimal.mark) above <- number(1 - accuracy, accuracy, decimal.mark = decimal.mark) if (is.null(prefix)) { if (add_p) { prefix <- c("p<", "p=", "p>") } else { prefix <- c("<", "", ">") } } else { if (!is.character(prefix) || length(prefix) != 3) { cli::cli_abort("{.arg prefix} must be a length 3 character vector") } } out <- paste0(prefix[[2]], out) out[x < accuracy] <- paste0(prefix[[1]], below) out[x > 1 - accuracy] <- paste0(prefix[[3]], above) out[is.na(x)] <- NA names(out) <- names(x) out } scales/R/label-bytes.R0000644000176200001440000000523714706713437014276 0ustar liggesusers#' Label bytes (1 kB, 2 MB, etc) #' #' Scale bytes into human friendly units. Can use either SI units (e.g. #' kB = 1000 bytes) or binary units (e.g. kiB = 1024 bytes). See #' [Units of Information](https://en.wikipedia.org/wiki/Units_of_information) #' on Wikipedia for more details. #' #' @inherit label_number return #' @param units Unit to use. Should either one of: #' * "kB", "MB", "GB", "TB", "PB", "EB", "ZB", and "YB" for #' SI units (base 1000). #' * "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", and "YiB" for #' binary units (base 1024). #' * `auto_si` or `auto_binary` to automatically pick the most appropriate #' unit for each value. #' @inheritParams number_format #' @inheritDotParams number #' #' @export #' @family labels for continuous scales #' @family labels for log scales #' @examples #' demo_continuous(c(1, 1e6)) #' demo_continuous(c(1, 1e6), labels = label_bytes()) #' #' # Auto units are particularly nice on log scales #' demo_log10(c(1, 1e7), labels = label_bytes()) #' #' # You can also set the units #' demo_continuous(c(1, 1e6), labels = label_bytes("kB")) #' #' # You can also use binary units where a megabyte is defined as #' # (1024) ^ 2 bytes rather than (1000) ^ 2. You'll need to override #' # the default breaks to make this more informative. #' demo_continuous(c(1, 1024^2), #' breaks = breaks_width(250 * 1024), #' labels = label_bytes("auto_binary") #' ) label_bytes <- function(units = "auto_si", accuracy = 1, scale = 1, ...) { check_string(units) force_all(accuracy, ...) function(x) { if (units %in% c("auto_si", "auto_binary")) { scale_cut <- cut_bytes(if (units == "auto_binary") "binary" else "si") suffix <- "" } else { powers <- si_powers[si_powers >= 3] / 3 # powers of 1000 si_units <- paste0(names(powers), "B") bin_units <- paste0(names(powers), "iB") arg_match0(units, c(si_units, bin_units)) if (units %in% si_units) { base <- 1000 power <- powers[[match(units, si_units)]] } else { base <- 1024 power <- powers[[match(units, bin_units)]] } suffix <- paste0(" ", units) scale <- scale / base^power scale_cut <- NULL } number( x, accuracy = accuracy, scale = scale, suffix = suffix, scale_cut = scale_cut, ... ) } } cut_bytes <- function(units = c("si", "binary")) { units <- arg_match(units) powers <- si_powers[si_powers >= 3] / 3 # powers of 1000 base <- if (units == "binary") 1024 else 1000 suffix <- if (units == "binary") "iB" else "B" out <- c(0, base^powers) names(out) <- c(paste0(" ", suffix), paste0(" ", names(powers), suffix)) out } scales/R/import-standalone-types-check.R0000644000176200001440000003047414705661306017745 0ustar liggesusers# Standalone file: do not edit by hand # Source: https://github.com/r-lib/rlang/blob/HEAD/R/standalone-types-check.R # Generated by: usethis::use_standalone("r-lib/rlang", "types-check") # ---------------------------------------------------------------------- # # --- # repo: r-lib/rlang # file: standalone-types-check.R # last-updated: 2023-03-13 # license: https://unlicense.org # dependencies: standalone-obj-type.R # imports: rlang (>= 1.1.0) # --- # # ## Changelog # # 2024-08-15: # - `check_character()` gains an `allow_na` argument (@martaalcalde, #1724) # # 2023-03-13: # - Improved error messages of number checkers (@teunbrand) # - Added `allow_infinite` argument to `check_number_whole()` (@mgirlich). # - Added `check_data_frame()` (@mgirlich). # # 2023-03-07: # - Added dependency on rlang (>= 1.1.0). # # 2023-02-15: # - Added `check_logical()`. # # - `check_bool()`, `check_number_whole()`, and # `check_number_decimal()` are now implemented in C. # # - For efficiency, `check_number_whole()` and # `check_number_decimal()` now take a `NULL` default for `min` and # `max`. This makes it possible to bypass unnecessary type-checking # and comparisons in the default case of no bounds checks. # # 2022-10-07: # - `check_number_whole()` and `_decimal()` no longer treat # non-numeric types such as factors or dates as numbers. Numeric # types are detected with `is.numeric()`. # # 2022-10-04: # - Added `check_name()` that forbids the empty string. # `check_string()` allows the empty string by default. # # 2022-09-28: # - Removed `what` arguments. # - Added `allow_na` and `allow_null` arguments. # - Added `allow_decimal` and `allow_infinite` arguments. # - Improved errors with absent arguments. # # # 2022-09-16: # - Unprefixed usage of rlang functions with `rlang::` to # avoid onLoad issues when called from rlang (#1482). # # 2022-08-11: # - Added changelog. # # nocov start # Scalars ----------------------------------------------------------------- .standalone_types_check_dot_call <- .Call check_bool <- function(x, ..., allow_na = FALSE, allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x) && .standalone_types_check_dot_call(ffi_standalone_is_bool_1.0.7, x, allow_na, allow_null)) { return(invisible(NULL)) } stop_input_type( x, c("`TRUE`", "`FALSE`"), ..., allow_na = allow_na, allow_null = allow_null, arg = arg, call = call ) } check_string <- function(x, ..., allow_empty = TRUE, allow_na = FALSE, allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { is_string <- .rlang_check_is_string( x, allow_empty = allow_empty, allow_na = allow_na, allow_null = allow_null ) if (is_string) { return(invisible(NULL)) } } stop_input_type( x, "a single string", ..., allow_na = allow_na, allow_null = allow_null, arg = arg, call = call ) } .rlang_check_is_string <- function(x, allow_empty, allow_na, allow_null) { if (is_string(x)) { if (allow_empty || !is_string(x, "")) { return(TRUE) } } if (allow_null && is_null(x)) { return(TRUE) } if (allow_na && (identical(x, NA) || identical(x, na_chr))) { return(TRUE) } FALSE } check_name <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { is_string <- .rlang_check_is_string( x, allow_empty = FALSE, allow_na = FALSE, allow_null = allow_null ) if (is_string) { return(invisible(NULL)) } } stop_input_type( x, "a valid name", ..., allow_na = FALSE, allow_null = allow_null, arg = arg, call = call ) } IS_NUMBER_true <- 0 IS_NUMBER_false <- 1 IS_NUMBER_oob <- 2 check_number_decimal <- function(x, ..., min = NULL, max = NULL, allow_infinite = TRUE, allow_na = FALSE, allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (missing(x)) { exit_code <- IS_NUMBER_false } else if (0 == (exit_code <- .standalone_types_check_dot_call( ffi_standalone_check_number_1.0.7, x, allow_decimal = TRUE, min, max, allow_infinite, allow_na, allow_null ))) { return(invisible(NULL)) } .stop_not_number( x, ..., exit_code = exit_code, allow_decimal = TRUE, min = min, max = max, allow_na = allow_na, allow_null = allow_null, arg = arg, call = call ) } check_number_whole <- function(x, ..., min = NULL, max = NULL, allow_infinite = FALSE, allow_na = FALSE, allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (missing(x)) { exit_code <- IS_NUMBER_false } else if (0 == (exit_code <- .standalone_types_check_dot_call( ffi_standalone_check_number_1.0.7, x, allow_decimal = FALSE, min, max, allow_infinite, allow_na, allow_null ))) { return(invisible(NULL)) } .stop_not_number( x, ..., exit_code = exit_code, allow_decimal = FALSE, min = min, max = max, allow_na = allow_na, allow_null = allow_null, arg = arg, call = call ) } .stop_not_number <- function(x, ..., exit_code, allow_decimal, min, max, allow_na, allow_null, arg, call) { if (allow_decimal) { what <- "a number" } else { what <- "a whole number" } if (exit_code == IS_NUMBER_oob) { min <- min %||% -Inf max <- max %||% Inf if (min > -Inf && max < Inf) { what <- sprintf("%s between %s and %s", what, min, max) } else if (x < min) { what <- sprintf("%s larger than or equal to %s", what, min) } else if (x > max) { what <- sprintf("%s smaller than or equal to %s", what, max) } else { abort("Unexpected state in OOB check", .internal = TRUE) } } stop_input_type( x, what, ..., allow_na = allow_na, allow_null = allow_null, arg = arg, call = call ) } check_symbol <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is_symbol(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "a symbol", ..., allow_na = FALSE, allow_null = allow_null, arg = arg, call = call ) } check_arg <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is_symbol(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "an argument name", ..., allow_na = FALSE, allow_null = allow_null, arg = arg, call = call ) } check_call <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is_call(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "a defused call", ..., allow_na = FALSE, allow_null = allow_null, arg = arg, call = call ) } check_environment <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is_environment(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "an environment", ..., allow_na = FALSE, allow_null = allow_null, arg = arg, call = call ) } check_function <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is_function(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "a function", ..., allow_na = FALSE, allow_null = allow_null, arg = arg, call = call ) } check_closure <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is_closure(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "an R function", ..., allow_na = FALSE, allow_null = allow_null, arg = arg, call = call ) } check_formula <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is_formula(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "a formula", ..., allow_na = FALSE, allow_null = allow_null, arg = arg, call = call ) } # Vectors ----------------------------------------------------------------- # TODO: Figure out what to do with logical `NA` and `allow_na = TRUE` check_character <- function(x, ..., allow_na = TRUE, allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is_character(x)) { if (!allow_na && any(is.na(x))) { abort( sprintf("`%s` can't contain NA values.", arg), arg = arg, call = call ) } return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "a character vector", ..., allow_null = allow_null, arg = arg, call = call ) } check_logical <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is_logical(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "a logical vector", ..., allow_na = FALSE, allow_null = allow_null, arg = arg, call = call ) } check_data_frame <- function(x, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env()) { if (!missing(x)) { if (is.data.frame(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, "a data frame", ..., allow_null = allow_null, arg = arg, call = call ) } # nocov end scales/R/label-number-auto.R0000644000176200001440000000413415002117500015354 0ustar liggesusers#' Label numbers, avoiding scientific notation where possible #' #' Switches between [number_format()] and [scientific_format()] based on a set of #' heuristics designed to automatically generate useful labels across a wide #' range of inputs #' #' @inherit label_number return #' #' @export #' @family labels for continuous scales #' @examples #' # Very small and very large numbers get scientific notation #' demo_continuous(c(0, 1e-6), labels = label_number_auto()) #' demo_continuous(c(0, 1e9), labels = label_number_auto()) #' #' # Other ranges get the numbers printed in full #' demo_continuous(c(0, 1e-3), labels = label_number_auto()) #' demo_continuous(c(0, 1), labels = label_number_auto()) #' demo_continuous(c(0, 1e3), labels = label_number_auto()) #' demo_continuous(c(0, 1e6), labels = label_number_auto()) #' #' # Transformation is applied individually so you get as little #' # scientific notation as possible #' demo_log10(c(1, 1e7), labels = label_number_auto()) label_number_auto <- function() { function(x) { if (length(x) == 0) { return(character(0)) } if (sum(is.finite(x)) == 0) { return(format(x, trim = TRUE)) } max_magnitude <- max(abs(x[x != 0 & is.finite(x)])) min_magnitude <- min(abs(x[x != 0 & is.finite(x)])) if (max_magnitude > 1e6) { format_shortest( x, number_format(1), format_format(scientific = TRUE) ) } else if (min_magnitude < 1e-3) { format_shortest( x, format_format(scientific = FALSE), format_format(scientific = TRUE) ) } else if (all(x > 0) && min_magnitude >= 1000 && max_magnitude <= 2200) { # Probably a year so don't use commas format(x, trim = TRUE) } else if (max_magnitude > 1e3) { number(x, 1) } else { format(x, trim = TRUE) } } } format_shortest <- function(breaks, ...) { options <- list(...) labels <- vapply( options, function(labeller) labeller(breaks), character(length(breaks)) ) apply(matrix(labels, nrow = length(breaks)), 1, shortest) } shortest <- function(x) { x[which.min(nchar(x))] } scales/R/range.R0000644000176200001440000000204615002117500013135 0ustar liggesusers#' Mutable ranges #' #' Mutable ranges have a two methods (`train` and `reset`), and #' make it possible to build up complete ranges with multiple passes. #' #' @export Range <- R6::R6Class( "Range", list( range = NULL, initialize = function() { self$range <- NULL } ) ) #' @export #' @rdname Range DiscreteRange <- R6::R6Class( "DiscreteRange", inherit = Range, list( factor = NULL, train = function(x, drop = FALSE, na.rm = FALSE, call = caller_env()) { self$factor <- self$factor %||% is.factor(x) self$range <- train_discrete( x, self$range, drop, na.rm, self$factor, call = call ) }, reset = function() { self$range <- NULL self$factor <- NULL } ) ) #' @export #' @rdname Range ContinuousRange <- R6::R6Class( "ContinuousRange", inherit = Range, list( train = function(x, call = caller_env()) { self$range <- train_continuous(x, self$range, call = call) }, reset = function() self$range <- NULL ) ) scales/R/transform.R0000644000176200001440000001143415002117500014055 0ustar liggesusers#' Create a new transformation object #' #' A transformation encapsulates a transformation and its inverse, as well #' as the information needed to create pleasing breaks and labels. The `breaks()` #' function is applied on the un-transformed range of the data, and the #' `format()` function takes the output of the `breaks()` function and returns #' well-formatted labels. Transformations may also include the derivatives of the #' transformation and its inverse, but are not required to. #' #' @param name transformation name #' @param transform function, or name of function, that performs the #' transformation #' @param inverse function, or name of function, that performs the #' inverse of the transformation #' @param d_transform Optional function, or name of function, that gives the #' derivative of the transformation. May be `NULL`. #' @param d_inverse Optional function, or name of function, that gives the #' derivative of the inverse of the transformation. May be `NULL`. #' @param breaks default breaks function for this transformation. The breaks #' function is applied to the un-transformed data. #' @param minor_breaks default minor breaks function for this transformation. #' @param format default format for this transformation. The format is applied #' to breaks generated on the un-transformed data. #' @param domain the allowed range of the data to be transformed. The function #' in the `transform` argument is expected to be able to transform the `domain` #' argument. #' @seealso \Sexpr[results=rd,stage=build]{scales:::seealso_transform()} #' @export #' @keywords internal #' @aliases trans new_transform <- function( name, transform, inverse, d_transform = NULL, d_inverse = NULL, breaks = extended_breaks(), minor_breaks = regular_minor_breaks(), format = format_format(), domain = c(-Inf, Inf) ) { if (is.character(transform)) transform <- match.fun(transform) if (is.character(inverse)) inverse <- match.fun(inverse) if (is.character(d_transform)) d_transform <- match.fun(d_transform) if (is.character(d_inverse)) d_inverse <- match.fun(d_inverse) structure( list( name = name, transform = transform, inverse = inverse, d_transform = d_transform, d_inverse = d_inverse, breaks = breaks, minor_breaks = minor_breaks, format = format, domain = domain ), class = "transform" ) } #' @rdname new_transform #' @export trans_new <- new_transform #' @rdname new_transform #' @export is.transform <- function(x) inherits(x, "transform") #' @export #' @rdname new_transform is.trans <- is.transform #' @export print.transform <- function(x, ...) { cat( "Transformer: ", x$name, " [", x$domain[[1]], ", ", x$domain[[2]], "]\n", sep = "" ) invisible(x) } #' @export plot.transform <- function(x, y, ..., xlim, ylim = NULL) { if (is.null(ylim)) { ylim <- range( x$transform(seq(xlim[1], xlim[2], length = 100)), finite = TRUE ) } plot( xlim, ylim, xlab = "", ylab = "", type = "n", main = paste0("Transformer: ", x$name), ) graphics::grid(lty = "solid") graphics::abline(h = 0, v = 0, col = "grey90", lwd = 5) graphics::lines(x, xlim = xlim) } #' @export lines.transform <- function(x, ..., xlim) { xgrid <- seq(xlim[1], xlim[2], length = 100) y <- suppressWarnings(x$transform(xgrid)) graphics::lines(xgrid, y, ...) } #' @rdname new_transform #' @export as.transform <- function(x, arg = deparse(substitute(x))) { if (is.transform(x)) { return(x) } if (!(is.character(x) && length(x) >= 1)) { stop_input_type(x, "a character vector or transform object") } # A character vector is translated to a transform composition if (length(x) != 1) { return(transform_compose(!!!x)) } # Single characters are interpreted as function names with the # `transform_`-prefix f <- paste0("transform_", x) fun <- get0(f, mode = "function") # For backward compatibility we preserve `trans_`-prefixes if (is.null(fun)) { f2 <- paste0(x, "_trans") fun <- get0(f2, mode = "function") } if (is.null(fun)) { cli::cli_abort( "Could not find any function named {.fun {f}} or {.fun {f2}}" ) } fun() } #' @export #' @rdname new_transform as.trans <- as.transform #' Compute range of transformed values #' #' Silently drops any ranges outside of the domain of `transform`. #' #' @param transform a transformation object, or the name of a transformation object #' given as a string. #' @param x a numeric vector to compute the range of #' @export #' @keywords internal trim_to_domain <- function(transform, x) { transform <- as.transform(transform) range(transform$transform(range(squish(x, transform$domain), na.rm = TRUE))) } #' @export #' @rdname trim_to_domain trans_range <- trim_to_domain scales/R/pal-shape.r0000644000176200001440000000124614705443562013777 0ustar liggesusers#' Shape palette (discrete) #' #' @param solid should shapes be solid or not? #' @export pal_shape <- function(solid = TRUE) { force(solid) fun <- function(n) { if (n > 6) { cli::cli_warn(c( "The shape palette can deal with a maximum of 6 discrete values because more than 6 becomes difficult to discriminate", i = "you have requested {n} values. Consider specifying shapes manually if you need that many of them." )) } if (solid) { c(16, 17, 15, 3, 7, 8)[seq_len(n)] } else { c(1, 2, 0, 3, 7, 8)[seq_len(n)] } } new_discrete_palette(fun, "shape", 6) } #' @export #' @rdname pal_shape shape_pal <- pal_shape scales/R/import-standalone-obj-type.R0000644000176200001440000002113414705661306017250 0ustar liggesusers# Standalone file: do not edit by hand # Source: https://github.com/r-lib/rlang/blob/HEAD/R/standalone-obj-type.R # Generated by: usethis::use_standalone("r-lib/rlang", "obj-type") # ---------------------------------------------------------------------- # # --- # repo: r-lib/rlang # file: standalone-obj-type.R # last-updated: 2024-02-14 # license: https://unlicense.org # imports: rlang (>= 1.1.0) # --- # # ## Changelog # # 2024-02-14: # - `obj_type_friendly()` now works for S7 objects. # # 2023-05-01: # - `obj_type_friendly()` now only displays the first class of S3 objects. # # 2023-03-30: # - `stop_input_type()` now handles `I()` input literally in `arg`. # # 2022-10-04: # - `obj_type_friendly(value = TRUE)` now shows numeric scalars # literally. # - `stop_friendly_type()` now takes `show_value`, passed to # `obj_type_friendly()` as the `value` argument. # # 2022-10-03: # - Added `allow_na` and `allow_null` arguments. # - `NULL` is now backticked. # - Better friendly type for infinities and `NaN`. # # 2022-09-16: # - Unprefixed usage of rlang functions with `rlang::` to # avoid onLoad issues when called from rlang (#1482). # # 2022-08-11: # - Prefixed usage of rlang functions with `rlang::`. # # 2022-06-22: # - `friendly_type_of()` is now `obj_type_friendly()`. # - Added `obj_type_oo()`. # # 2021-12-20: # - Added support for scalar values and empty vectors. # - Added `stop_input_type()` # # 2021-06-30: # - Added support for missing arguments. # # 2021-04-19: # - Added support for matrices and arrays (#141). # - Added documentation. # - Added changelog. # # nocov start #' Return English-friendly type #' @param x Any R object. #' @param value Whether to describe the value of `x`. Special values #' like `NA` or `""` are always described. #' @param length Whether to mention the length of vectors and lists. #' @return A string describing the type. Starts with an indefinite #' article, e.g. "an integer vector". #' @noRd obj_type_friendly <- function(x, value = TRUE) { if (is_missing(x)) { return("absent") } if (is.object(x)) { if (inherits(x, "quosure")) { type <- "quosure" } else { type <- class(x)[[1L]] } return(sprintf("a <%s> object", type)) } if (!is_vector(x)) { return(.rlang_as_friendly_type(typeof(x))) } n_dim <- length(dim(x)) if (!n_dim) { if (!is_list(x) && length(x) == 1) { if (is_na(x)) { return(switch( typeof(x), logical = "`NA`", integer = "an integer `NA`", double = if (is.nan(x)) { "`NaN`" } else { "a numeric `NA`" }, complex = "a complex `NA`", character = "a character `NA`", .rlang_stop_unexpected_typeof(x) )) } show_infinites <- function(x) { if (x > 0) { "`Inf`" } else { "`-Inf`" } } str_encode <- function(x, width = 30, ...) { if (nchar(x) > width) { x <- substr(x, 1, width - 3) x <- paste0(x, "...") } encodeString(x, ...) } if (value) { if (is.numeric(x) && is.infinite(x)) { return(show_infinites(x)) } if (is.numeric(x) || is.complex(x)) { number <- as.character(round(x, 2)) what <- if (is.complex(x)) "the complex number" else "the number" return(paste(what, number)) } return(switch( typeof(x), logical = if (x) "`TRUE`" else "`FALSE`", character = { what <- if (nzchar(x)) "the string" else "the empty string" paste(what, str_encode(x, quote = "\"")) }, raw = paste("the raw value", as.character(x)), .rlang_stop_unexpected_typeof(x) )) } return(switch( typeof(x), logical = "a logical value", integer = "an integer", double = if (is.infinite(x)) show_infinites(x) else "a number", complex = "a complex number", character = if (nzchar(x)) "a string" else "\"\"", raw = "a raw value", .rlang_stop_unexpected_typeof(x) )) } if (length(x) == 0) { return(switch( typeof(x), logical = "an empty logical vector", integer = "an empty integer vector", double = "an empty numeric vector", complex = "an empty complex vector", character = "an empty character vector", raw = "an empty raw vector", list = "an empty list", .rlang_stop_unexpected_typeof(x) )) } } vec_type_friendly(x) } vec_type_friendly <- function(x, length = FALSE) { if (!is_vector(x)) { abort("`x` must be a vector.") } type <- typeof(x) n_dim <- length(dim(x)) add_length <- function(type) { if (length && !n_dim) { paste0(type, sprintf(" of length %s", length(x))) } else { type } } if (type == "list") { if (n_dim < 2) { return(add_length("a list")) } else if (is.data.frame(x)) { return("a data frame") } else if (n_dim == 2) { return("a list matrix") } else { return("a list array") } } type <- switch( type, logical = "a logical %s", integer = "an integer %s", numeric = , double = "a double %s", complex = "a complex %s", character = "a character %s", raw = "a raw %s", type = paste0("a ", type, " %s") ) if (n_dim < 2) { kind <- "vector" } else if (n_dim == 2) { kind <- "matrix" } else { kind <- "array" } out <- sprintf(type, kind) if (n_dim >= 2) { out } else { add_length(out) } } .rlang_as_friendly_type <- function(type) { switch( type, list = "a list", NULL = "`NULL`", environment = "an environment", externalptr = "a pointer", weakref = "a weak reference", S4 = "an S4 object", name = , symbol = "a symbol", language = "a call", pairlist = "a pairlist node", expression = "an expression vector", char = "an internal string", promise = "an internal promise", ... = "an internal dots object", any = "an internal `any` object", bytecode = "an internal bytecode object", primitive = , builtin = , special = "a primitive function", closure = "a function", type ) } .rlang_stop_unexpected_typeof <- function(x, call = caller_env()) { abort( sprintf("Unexpected type <%s>.", typeof(x)), call = call ) } #' Return OO type #' @param x Any R object. #' @return One of `"bare"` (for non-OO objects), `"S3"`, `"S4"`, #' `"R6"`, or `"S7"`. #' @noRd obj_type_oo <- function(x) { if (!is.object(x)) { return("bare") } class <- inherits(x, c("R6", "S7_object"), which = TRUE) if (class[[1]]) { "R6" } else if (class[[2]]) { "S7" } else if (isS4(x)) { "S4" } else { "S3" } } #' @param x The object type which does not conform to `what`. Its #' `obj_type_friendly()` is taken and mentioned in the error message. #' @param what The friendly expected type as a string. Can be a #' character vector of expected types, in which case the error #' message mentions all of them in an "or" enumeration. #' @param show_value Passed to `value` argument of `obj_type_friendly()`. #' @param ... Arguments passed to [abort()]. #' @inheritParams args_error_context #' @noRd stop_input_type <- function(x, what, ..., allow_na = FALSE, allow_null = FALSE, show_value = TRUE, arg = caller_arg(x), call = caller_env()) { # From standalone-cli.R cli <- env_get_list( nms = c("format_arg", "format_code"), last = topenv(), default = function(x) sprintf("`%s`", x), inherit = TRUE ) if (allow_na) { what <- c(what, cli$format_code("NA")) } if (allow_null) { what <- c(what, cli$format_code("NULL")) } if (length(what)) { what <- oxford_comma(what) } if (inherits(arg, "AsIs")) { format_arg <- identity } else { format_arg <- cli$format_arg } message <- sprintf( "%s must be %s, not %s.", format_arg(arg), what, obj_type_friendly(x, value = show_value) ) abort(message, ..., call = call, arg = arg) } oxford_comma <- function(chr, sep = ", ", final = "or") { n <- length(chr) if (n < 2) { return(chr) } head <- chr[seq_len(n - 1)] last <- chr[n] head <- paste(head, collapse = sep) # Write a or b. But a, b, or c. if (n > 2) { paste0(head, sep, final, " ", last) } else { paste0(head, " ", final, " ", last) } } # nocov end scales/R/scales-package.R0000644000176200001440000000053214672302077014723 0ustar liggesusers#' @keywords internal #' @importFrom R6 R6Class #' @import rlang "_PACKAGE" # The following block is used by usethis to automatically manage # roxygen namespace tags. Modify with care! ## usethis namespace: start #' @importFrom glue glue #' @importFrom lifecycle deprecate_soft #' @importFrom lifecycle deprecated ## usethis namespace: end NULL scales/R/colour-mapping.R0000644000176200001440000003317315002117500015002 0ustar liggesusers#' Colour mapping #' #' Conveniently maps data values (numeric or factor/character) to colours #' according to a given palette, which can be provided in a variety of formats. #' #' `col_numeric` is a simple linear mapping from continuous numeric data #' to an interpolated palette. #' #' @param palette The colours or colour function that values will be mapped to #' @param domain The possible values that can be mapped. #' #' For `col_numeric` and `col_bin`, this can be a simple numeric #' range (e.g. `c(0, 100)`); `col_quantile` needs representative #' numeric data; and `col_factor` needs categorical data. #' #' If `NULL`, then whenever the resulting colour function is called, the #' `x` value will represent the domain. This implies that if the function #' is invoked multiple times, the encoding between values and colours may not #' be consistent; if consistency is needed, you must provide a non-`NULL` #' domain. #' @param na.color The colour to return for `NA` values. Note that #' `na.color = NA` is valid. #' @param alpha Whether alpha channels should be respected or ignored. If `TRUE` #' then colors without explicit alpha information will be treated as fully #' opaque. #' @param reverse Whether the colors (or color function) in `palette` should be #' used in reverse order. For example, if the default order of a palette goes #' from blue to green, then `reverse = TRUE` will result in the colors going #' from green to blue. #' @return A function that takes a single parameter `x`; when called with a #' vector of numbers (except for `col_factor`, which expects #' factors/characters), #RRGGBB colour strings are returned (unless #' `alpha = TRUE` in which case #RRGGBBAA may also be possible). #' #' @export col_numeric <- function( palette, domain, na.color = "#808080", alpha = FALSE, reverse = FALSE ) { rng <- NULL if (length(domain) > 0) { rng <- range(domain, na.rm = TRUE) if (!all(is.finite(rng))) { cli::cli_abort("Wasn't able to determine range of {.arg domain}") } } pf <- safePaletteFunc(palette, na.color, alpha) withColorAttr("numeric", list(na.color = na.color), function(x) { if (length(x) == 0 || all(is.na(x))) { return(pf(x)) } if (is.null(rng)) rng <- range(x, na.rm = TRUE) rescaled <- rescale(x, from = rng) if (any(rescaled < 0 | rescaled > 1, na.rm = TRUE)) { cli::cli_warn( "Some values were outside the color scale and will be treated as NA" ) } if (reverse) { rescaled <- 1 - rescaled } pf(rescaled) }) } # Attach an attribute colorType to a color function f so we can derive legend # items from it withColorAttr <- function(type, args = list(), fun) { structure(fun, colorType = type, colorArgs = args) } # domain may or may not be NULL. # Iff domain is non-NULL, x may be NULL. # bins is non-NULL. It may be a scalar value (# of breaks) or a set of breaks. getBins <- function(domain, x, bins, pretty) { if (is.null(domain) && is.null(x)) { cli::cli_abort("{.arg domain} and {.arg x} can't both be NULL") } # Hard-coded bins if (length(bins) > 1) { return(bins) } if (bins < 2) { cli::cli_abort(c( "Invalid {.arg bins} value ({bins})", i = "bin count must be at least 2" )) } if (pretty) { base::pretty(domain %||% x, n = bins) } else { rng <- range(domain %||% x, na.rm = TRUE) seq(rng[1], rng[2], length.out = bins + 1) } } #' @details `col_bin` also maps continuous numeric data, but performs #' binning based on value (see the [base::cut()] function). `col_bin` #' defaults for the `cut` function are `include.lowest = TRUE` and #' `right = FALSE`. #' @param bins Either a numeric vector of two or more unique cut points or a #' single number (greater than or equal to 2) giving the number of intervals #' into which the domain values are to be cut. #' @param pretty Whether to use the function [pretty()] to generate #' the bins when the argument `bins` is a single number. When #' `pretty = TRUE`, the actual number of bins may not be the number of #' bins you specified. When `pretty = FALSE`, [seq()] is used #' to generate the bins and the breaks may not be "pretty". #' @param right parameter supplied to [base::cut()]. See Details #' @rdname col_numeric #' @export col_bin <- function( palette, domain, bins = 7, pretty = TRUE, na.color = "#808080", alpha = FALSE, reverse = FALSE, right = FALSE ) { # domain usually needs to be explicitly provided (even if NULL) but not if # breaks are specified if (missing(domain) && length(bins) > 1) { domain <- NULL } autobin <- is.null(domain) && length(bins) == 1 if (!is.null(domain)) { bins <- getBins(domain, NULL, bins, pretty) } numColors <- if (length(bins) == 1) bins else length(bins) - 1 colorFunc <- col_factor( palette, domain = if (!autobin) 1:numColors, na.color = na.color, alpha = alpha, reverse = reverse ) pf <- safePaletteFunc(palette, na.color, alpha) withColorAttr( "bin", list(bins = bins, na.color = na.color, right = right), function(x) { if (length(x) == 0 || all(is.na(x))) { return(pf(x)) } binsToUse <- getBins(domain, x, bins, pretty) ints <- cut( x, binsToUse, labels = FALSE, include.lowest = TRUE, right = right ) if (any(is.na(x) != is.na(ints))) { cli::cli_warn( "Some values were outside the color scale and will be treated as NA" ) } colorFunc(ints) } ) } #' @details `col_quantile` similarly bins numeric data, but via the #' [stats::quantile()] function. #' @param n Number of equal-size quantiles desired. For more precise control, #' use the `probs` argument instead. #' @param probs See [stats::quantile()]. If provided, the `n` #' argument is ignored. #' @rdname col_numeric #' @export col_quantile <- function( palette, domain, n = 4, probs = seq(0, 1, length.out = n + 1), na.color = "#808080", alpha = FALSE, reverse = FALSE, right = FALSE ) { if (!is.null(domain)) { bins <- safe_quantile(domain, probs) return(withColorAttr( "quantile", list(probs = probs, na.color = na.color, right = right), col_bin( palette, domain = NULL, bins = bins, na.color = na.color, alpha = alpha, reverse = reverse ) )) } # I don't have a precise understanding of how quantiles are meant to map to colors. # If you say probs = seq(0, 1, 0.25), which has length 5, does that map to 4 colors # or 5? 4, right? colorFunc <- col_factor( palette, domain = 1:(length(probs) - 1), na.color = na.color, alpha = alpha, reverse = reverse ) withColorAttr( "quantile", list(probs = probs, na.color = na.color, right = right), function(x) { binsToUse <- safe_quantile(x, probs) ints <- cut( x, binsToUse, labels = FALSE, include.lowest = TRUE, right = right ) if (any(is.na(x) != is.na(ints))) { cli::cli_warn( "Some values were outside the color scale and will be treated as NA" ) } colorFunc(ints) } ) } safe_quantile <- function(x, probs) { bins <- stats::quantile(x, probs, na.rm = TRUE, names = FALSE) if (anyDuplicated(bins)) { bins <- unique(bins) cli::cli_warn( "Skewed data means we can only allocate {length(bins)} unique colours not the {length(probs) - 1} requested" ) } bins } # If already a factor, return the levels. Otherwise, convert to factor then # return the levels. calcLevels <- function(x, ordered) { if (is.null(x)) { NULL } else if (is.factor(x)) { levels(x) } else if (ordered) { unique(x) } else { sort(unique(x)) } } getLevels <- function(domain, x, lvls, ordered) { if (!is.null(lvls)) { return(lvls) } if (!is.null(domain)) { return(calcLevels(domain, ordered)) } if (!is.null(x)) { return(calcLevels(x, ordered)) } } #' @details `col_factor` maps factors to colours. If the palette is #' discrete and has a different number of colours than the number of factors, #' interpolation is used. #' @param levels An alternate way of specifying levels; if specified, domain is #' ignored #' @param ordered If `TRUE` and `domain` needs to be coerced to a #' factor, treat it as already in the correct order #' @rdname col_numeric #' @export col_factor <- function( palette, domain, levels = NULL, ordered = FALSE, na.color = "#808080", alpha = FALSE, reverse = FALSE ) { # domain usually needs to be explicitly provided (even if NULL) but not if # levels are specified if (missing(domain) && !is.null(levels)) { domain <- NULL } if (!is.null(levels) && anyDuplicated(levels)) { cli::cli_warn("Duplicate levels detected") levels <- unique(levels) } lvls <- getLevels(domain, NULL, levels, ordered) force(palette) # palette loses scope withColorAttr("factor", list(na.color = na.color), function(x) { if (length(x) == 0 || all(is.na(x))) { return(rep.int(na.color, length(x))) } lvls <- getLevels(domain, x, lvls, ordered) pf <- safePaletteFunc( palette, na.color, alpha, nlevels = length(lvls) * ifelse(reverse, -1, 1) ) origNa <- is.na(x) x <- match(as.character(x), lvls) if (any(is.na(x) != origNa)) { cli::cli_warn( "Some values were outside the color scale and will be treated as NA" ) } scaled <- rescale(as.integer(x), from = c(1, length(lvls))) if (any(scaled < 0 | scaled > 1, na.rm = TRUE)) { cli::cli_warn( "Some values were outside the color scale and will be treated as NA" ) } if (reverse) { scaled <- 1 - scaled } pf(scaled) }) } #' @details The `palette` argument can be any of the following: #' \enumerate{ #' \item{A character vector of RGB or named colours. Examples: `palette()`, `c("#000000", "#0000FF", "#FFFFFF")`, `topo.colors(10)`} #' \item{The name of an RColorBrewer palette, e.g. `"BuPu"` or `"Greens"`.} #' \item{The full name of a viridis palette: `"viridis"`, `"magma"`, `"inferno"`, or `"plasma"`.} #' \item{A function that receives a single value between 0 and 1 and returns a colour. Examples: `colorRamp(c("#000000", "#FFFFFF"), interpolate="spline")`.} #' } #' @examples #' pal <- col_bin("Greens", domain = 0:100) #' show_col(pal(sort(runif(10, 60, 100)))) #' #' # Exponential distribution, mapped continuously #' show_col(col_numeric("Blues", domain = NULL)(sort(rexp(16)))) #' # Exponential distribution, mapped by interval #' show_col(col_bin("Blues", domain = NULL, bins = 4)(sort(rexp(16)))) #' # Exponential distribution, mapped by quantile #' show_col(col_quantile("Blues", domain = NULL)(sort(rexp(16)))) #' #' # Categorical data; by default, the values being coloured span the gamut... #' show_col(col_factor("RdYlBu", domain = NULL)(LETTERS[1:5])) #' # ...unless the data is a factor, without droplevels... #' show_col(col_factor("RdYlBu", domain = NULL)(factor(LETTERS[1:5], levels = LETTERS))) #' # ...or the domain is stated explicitly. #' show_col(col_factor("RdYlBu", levels = LETTERS)(LETTERS[1:5])) #' @rdname col_numeric #' @name col_numeric NULL safePaletteFunc <- function(pal, na.color, alpha, nlevels = NULL) { filterRange( filterNA( na.color = na.color, filterZeroLength( filterRGB( toPaletteFunc(pal, alpha = alpha, nlevels = nlevels) ) ) ) ) } toPaletteFunc <- function(pal, alpha, nlevels) { UseMethod("toPaletteFunc") } # Strings are interpreted as color names, unless length is 1 and it's the name # of an RColorBrewer palette that is marked as qualitative #' @export toPaletteFunc.character <- function(pal, alpha, nlevels) { if (length(pal) == 1 && pal %in% row.names(RColorBrewer::brewer.pal.info)) { paletteInfo <- RColorBrewer::brewer.pal.info[pal, ] if (!is.null(nlevels)) { # pal_brewer will return NAs if you ask for more colors than the palette has colors <- pal_brewer(palette = pal)(abs(nlevels)) colors <- colors[!is.na(colors)] } else { colors <- pal_brewer(palette = pal)(RColorBrewer::brewer.pal.info[ pal, "maxcolors" ]) # Get all colors } } else if ( length(pal) == 1 && pal %in% c("viridis", "magma", "inferno", "plasma") ) { colors <- pal_viridis(option = pal)(256) } else { colors <- pal } colour_ramp(colors, alpha = alpha) } # Accept colorRamp style matrix #' @export toPaletteFunc.matrix <- function(pal, alpha, nlevels) { toPaletteFunc(farver::decode_colour(pal), alpha = alpha) } # If a function, just assume it's already a function over [0-1] #' @export toPaletteFunc.function <- function(pal, alpha, nlevels) { pal } # colorRamp(space = 'Lab') throws error when called with # zero-length input filterZeroLength <- function(f) { force(f) function(x) { if (length(x) == 0) { character(0) } else { f(x) } } } # Wraps an underlying non-NA-safe function (like colorRamp). filterNA <- function(f, na.color) { force(f) function(x) { results <- character(length(x)) nas <- is.na(x) results[nas] <- na.color results[!nas] <- f(x[!nas]) results } } # Wraps a function that may return RGB color matrix instead of rgb string. filterRGB <- function(f) { force(f) function(x) { results <- f(x) if (is.character(results)) { results } else if (is.matrix(results)) { farver::encode_colour(results, from = "rgb") } else { cli::cli_abort("Unexpected result type {.cls {class(x)}}") } } } filterRange <- function(f) { force(f) function(x) { x[x < 0 | x > 1] <- NA f(x) } } scales/R/pal-brewer.R0000644000176200001440000000474315002117500014107 0ustar liggesusers#' Colour Brewer palette (discrete) #' #' @param type One of "seq" (sequential), "div" (diverging) or "qual" #' (qualitative) #' @param palette If a string, will use that named palette. If a number, will #' index into the list of palettes of appropriate `type` #' @param direction Sets the order of colours in the scale. If 1, the default, #' colours are as output by [RColorBrewer::brewer.pal()]. If -1, the #' order of colours is reversed. #' @references #' @export #' @examples #' show_col(pal_brewer()(10)) #' show_col(pal_brewer("div")(5)) #' show_col(pal_brewer(palette = "Greens")(5)) #' #' # Can use with gradient_n to create a continuous gradient #' cols <- pal_brewer("div")(5) #' show_col(pal_gradient_n(cols)(seq(0, 1, length.out = 30))) pal_brewer <- function(type = "seq", palette = 1, direction = 1) { pal <- pal_name(palette, type) force(direction) fun <- function(n) { # If <3 colors are requested, brewer.pal will return a 3-color palette and # give a warning. This warning isn't useful, so suppress it. # If the palette has k colors and >k colors are requested, brewer.pal will # return a k-color palette and give a warning. This warning is useful, so # don't suppress it. if (n < 3) { pal <- suppressWarnings(RColorBrewer::brewer.pal(n, pal)) } else { pal <- RColorBrewer::brewer.pal(n, pal) } # In both cases ensure we have n items pal <- pal[seq_len(n)] if (direction == -1) { pal <- rev(pal) } pal } nlevels <- RColorBrewer::brewer.pal.info[pal, "maxcolors"] new_discrete_palette(fun, "colour", nlevels) } #' @export #' @rdname pal_brewer brewer_pal <- pal_brewer pal_name <- function(palette, type) { if (is.character(palette)) { if (!palette %in% unlist(brewer)) { cli::cli_warn("Unknown palette: {.val {palette}}") palette <- "Greens" } return(palette) } type <- match.arg(type, c("div", "qual", "seq")) brewer[[type]][palette] } brewer <- list( div = c( "BrBG", "PiYG", "PRGn", "PuOr", "RdBu", "RdGy", "RdYlBu", "RdYlGn", "Spectral" ), qual = c( "Accent", "Dark2", "Paired", "Pastel1", "Pastel2", "Set1", "Set2", "Set3" ), seq = c( "Blues", "BuGn", "BuPu", "GnBu", "Greens", "Greys", "Oranges", "OrRd", "PuBu", "PuBuGn", "PuRd", "Purples", "RdPu", "Reds", "YlGn", "YlGnBu", "YlOrBr", "YlOrRd" ) ) scales/R/bounds.R0000644000176200001440000002630215002117500013334 0ustar liggesusers#' Rescale continuous vector to have specified minimum and maximum #' #' @param x continuous vector of values to manipulate. #' @param to output range (numeric vector of length two) #' @param from input range (vector of length two). If not given, is #' calculated from the range of `x` #' @param ... other arguments passed on to methods #' @details #' Objects of class `` are returned unaltered. #' #' @keywords manip #' @export #' @examples #' rescale(1:100) #' rescale(runif(50)) #' rescale(1) rescale <- function(x, to, from, ...) { UseMethod("rescale") } #' @rdname rescale #' @export rescale.numeric <- function( x, to = c(0, 1), from = range(x, na.rm = TRUE, finite = TRUE), ... ) { if (zero_range(from) || zero_range(to)) { return(ifelse(is.na(x), NA, mean(to))) } (x - from[1]) / diff(from) * diff(to) + to[1] } #' @export rescale.NULL <- function(...) NULL #' @rdname rescale #' @export rescale.dist <- rescale.numeric #' @rdname rescale #' @export rescale.logical <- rescale.numeric #' @rdname rescale #' @export rescale.POSIXt <- function( x, to = c(0, 1), from = range(x, na.rm = TRUE, finite = TRUE), ... ) { x <- as.numeric(x) from <- as.numeric(from) rescale.numeric(x = x, to = to, from = from) } #' @rdname rescale #' @export rescale.Date <- rescale.POSIXt #' @rdname rescale #' @export rescale.integer64 <- function( x, to = c(0, 1), from = range(x, na.rm = TRUE), ... ) { if (zero_range(from, tol = 0) || zero_range(to)) { return(ifelse(is.na(x), NA, mean(to))) } (x - from[1]) / diff(from) * diff(to) + to[1] } #' @rdname rescale #' @export rescale.difftime <- rescale.numeric #' @rdname rescale #' @export rescale.AsIs <- function(x, to, from, ...) x #' Rescale vector to have specified minimum, midpoint, and maximum #' #' @export #' @param x vector of values to manipulate. #' @param to output range (numeric vector of length two) #' @param from input range (vector of length two). If not given, is #' calculated from the range of `x` #' @param mid mid-point of input range #' @param ... other arguments passed on to methods #' @details #' Objects of class `` are returned unaltered. #' @examples #' rescale_mid(1:100, mid = 50.5) #' rescale_mid(runif(50), mid = 0.5) #' rescale_mid(1) rescale_mid <- function(x, to, from, mid, ...) { UseMethod("rescale_mid") } #' @rdname rescale_mid #' @export rescale_mid.numeric <- function( x, to = c(0, 1), from = range(x, na.rm = TRUE), mid = 0, ... ) { if (zero_range(from) || zero_range(to)) { return(ifelse(is.na(x), NA, mean(to))) } extent <- 2 * max(abs(from - mid)) (x - mid) / extent * diff(to) + mean(to) } #' @export rescale_mid.NULL <- function(...) NULL #' @rdname rescale_mid #' @export rescale_mid.logical <- rescale_mid.numeric #' @rdname rescale_mid #' @export rescale_mid.dist <- rescale_mid.numeric #' @rdname rescale_mid #' @export rescale_mid.POSIXt <- function( x, to = c(0, 1), from = range(x, na.rm = TRUE), mid, ... ) { x <- as.numeric(as.POSIXct(x)) if (!is.numeric(from)) { from <- as.numeric(as.POSIXct(from)) } if (!is.numeric(mid)) { mid <- as.numeric(as.POSIXct(mid)) } rescale_mid.numeric(x = x, to = to, from = from, mid = mid) } #' @rdname rescale_mid #' @export rescale_mid.Date <- rescale_mid.POSIXt #' @rdname rescale_mid #' @export rescale_mid.integer64 <- function( x, to = c(0, 1), from = range(x, na.rm = TRUE), mid = 0, ... ) { if (zero_range(from, tol = 0) || zero_range(to)) { return(ifelse(is.na(x), NA, mean(to))) } extent <- 2 * max(abs(from - mid)) (x - mid) / extent * diff(to) + mean(to) } #' @rdname rescale_mid #' @export rescale_mid.AsIs <- function(x, to, from, ...) x #' Rescale numeric vector to have specified maximum #' #' @export #' @param x numeric vector of values to manipulate. #' @param to output range (numeric vector of length two) #' @param from input range (numeric vector of length two). If not given, is #' calculated from the range of `x` #' @examples #' rescale_max(1:100) #' rescale_max(runif(50)) #' rescale_max(1) rescale_max <- function(x, to = c(0, 1), from = range(x, na.rm = TRUE)) { x / from[2] * to[2] } #' Don't perform rescaling #' #' @param x numeric vector of values to manipulate. #' @param ... all other arguments ignored #' @export #' @examples #' rescale_none(1:100) rescale_none <- function(x, ...) { x } #' Out of bounds handling #' #' @description #' This set of functions modify data values outside a given range. #' The `oob_*()` functions are designed to be passed as the `oob` argument of #' ggplot2 continuous and binned scales, with `oob_discard` being an exception. #' #' These functions affect out of bounds values in the following ways: #' #' * `oob_censor()` replaces out of bounds values with `NA`s. This is the #' default `oob` argument for continuous scales. #' * `oob_censor_any()` acts like `oob_censor()`, but also replaces infinite #' values with `NA`s. #' * `oob_squish()` replaces out of bounds values with the nearest limit. This #' is the default `oob` argument for binned scales. #' * `oob_squish_any()` acts like `oob_squish()`, but also replaces infinite #' values with the nearest limit. #' * `oob_squish_infinite()` only replaces infinite values by the nearest limit. #' * `oob_keep()` does not adjust out of bounds values. In position scales, #' behaves as zooming limits without data removal. #' * `oob_discard()` removes out of bounds values from the input. Not suitable #' for ggplot2 scales. #' #' @param x A numeric vector of values to modify. #' @param range A numeric vector of length two giving the minimum and maximum #' limit of the desired output range respectively. #' @param only.finite A logical of length one. When `TRUE`, only finite values #' are altered. When `FALSE`, also infinite values are altered. #' #' @return Most `oob_()` functions return a vector of numerical values of the #' same length as the `x` argument, wherein out of bounds values have been #' modified. Only `oob_discard()` returns a vector of less than or of equal #' length to the `x` argument. #' #' @details The `oob_censor_any()` and `oob_squish_any()` functions are the same #' as `oob_censor()` and `oob_squish()` with the `only.finite` argument set to #' `FALSE`. #' #' Replacing position values with `NA`s, as `oob_censor()` does, will typically #' lead to removal of those datapoints in ggplot. #' #' Setting ggplot coordinate limits is equivalent to using `oob_keep()` in #' position scales. #' #' @section Old interface: `censor()`, `squish()`, `squish_infinite()` and #' `discard()` are no longer recommended; please use `oob_censor()`, #' `oob_squish()`, `oob_squish_infinite()` and `oob_discard()` instead. #' #' @name oob #' #' @examples #' # Censoring replaces out of bounds values with NAs #' oob_censor(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) #' oob_censor_any(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) #' #' # Squishing replaces out of bounds values with the nearest range limit #' oob_squish(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) #' oob_squish_any(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) #' oob_squish_infinite(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) #' #' # Keeping does not alter values #' oob_keep(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) #' #' # Discarding will remove out of bounds values #' oob_discard(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) NULL #' @rdname oob #' @export oob_censor <- function(x, range = c(0, 1), only.finite = TRUE) { force(range) finite <- if (only.finite) is.finite(x) else TRUE x[finite & x < range[1]] <- NA_real_ x[finite & x > range[2]] <- NA_real_ x } #' @rdname oob #' @export oob_censor_any <- function(x, range = c(0, 1)) { oob_censor(x, range = range, only.finite = FALSE) } #' @rdname oob #' @export oob_discard <- function(x, range = c(0, 1)) { force(range) x[x >= range[1] & x <= range[2]] } #' @rdname oob #' @author `oob_squish()`: Homer Strong #' @export oob_squish <- function(x, range = c(0, 1), only.finite = TRUE) { force(range) finite <- if (only.finite) is.finite(x) else TRUE x[finite & x < range[1]] <- range[1] x[finite & x > range[2]] <- range[2] x } #' @rdname oob #' @export oob_squish_any <- function(x, range = c(0, 1)) { oob_squish(x, range, only.finite = FALSE) } #' @rdname oob #' @export oob_squish_infinite <- function(x, range = c(0, 1)) { force(range) x[x == -Inf] <- range[1] x[x == Inf] <- range[2] x } #' @rdname oob #' @export oob_keep <- function(x, range = c(0, 1)) { x } #' @rdname oob #' @export censor <- oob_censor #' @rdname oob #' @export discard <- oob_discard #' @rdname oob #' @export squish <- oob_squish #' @rdname oob #' @export squish_infinite <- oob_squish_infinite #' Expand a range with a multiplicative or additive constant #' #' @param range range of data, numeric vector of length 2 #' @param mul multiplicative constant #' @param add additive constant #' @param zero_width distance to use if range has zero width #' @export expand_range <- function(range, mul = 0, add = 0, zero_width = 1) { if (is.null(range)) { return() } width <- if (zero_range(range)) zero_width else diff(range) range + c(-1, 1) * (width * mul + add) } #' Determine if range of vector is close to zero, with a specified tolerance #' #' The machine epsilon is the difference between 1.0 and the next number #' that can be represented by the machine. By default, this function #' uses epsilon * 1000 as the tolerance. First it scales the values so that #' they have a mean of 1, and then it checks if the difference between #' them is larger than the tolerance. #' #' @examples #' eps <- .Machine$double.eps #' zero_range(c(1, 1 + eps)) #' zero_range(c(1, 1 + 99 * eps)) #' zero_range(c(1, 1 + 1001 * eps)) #' zero_range(c(1, 1 + 2 * eps), tol = eps) #' #' # Scaling up or down all the values has no effect since the values #' # are rescaled to 1 before checking against tol #' zero_range(100000 * c(1, 1 + eps)) #' zero_range(100000 * c(1, 1 + 1001 * eps)) #' zero_range(.00001 * c(1, 1 + eps)) #' zero_range(.00001 * c(1, 1 + 1001 * eps)) #' #' # NA values #' zero_range(c(1, NA)) # NA #' zero_range(c(1, NaN)) # NA #' #' # Infinite values #' zero_range(c(1, Inf)) # FALSE #' zero_range(c(-Inf, Inf)) # FALSE #' zero_range(c(Inf, Inf)) # TRUE #' #' @export #' @param x numeric range: vector of length 2 #' @param tol A value specifying the tolerance. #' @return logical `TRUE` if the relative difference of the endpoints of #' the range are not distinguishable from 0. zero_range <- function(x, tol = 1000 * .Machine$double.eps) { if (length(x) == 1) { return(TRUE) } if (length(x) != 2) cli::cli_abort("{.arg x} must be length 1 or 2") if (anyNA(x)) { return(NA) } # Special case: if they are equal as determined by ==, then there # is zero range. Also handles (Inf, Inf) and (-Inf, -Inf) if (x[1] == x[2]) { return(TRUE) } # If we reach this, then x must be (-Inf, ) or (, Inf) if (any(is.infinite(x))) { return(FALSE) } # Take the smaller (in magnitude) value of x, and use it as the scaling # factor. x <- as.numeric(unclass(x)) m <- min(abs(x)) # If we get here, then exactly one of the x's is 0. Return FALSE if (m == 0) { return(FALSE) } # If x[1] - x[2] (scaled to 1) is smaller than tol, then return # TRUE; otherwise return FALSE abs((x[1] - x[2]) / m) < tol } scales/R/full-seq.R0000644000176200001440000000342315002117500013571 0ustar liggesusers#' Generate sequence of fixed size intervals covering range. #' #' @param range range #' @param size interval size #' @param ... other arguments passed on to methods #' @keywords internal #' @export fullseq <- function(range, size, ...) UseMethod("fullseq") #' @export fullseq.numeric <- function(range, size, ..., pad = FALSE) { range <- sort(range) if (zero_range(range)) { return(range + size * c(-1, 1) / 2) } x <- seq( round_any(range[1], size, floor), round_any(range[2], size, ceiling), by = size ) if (pad) { # Add extra bin on bottom and on top, to guarantee that we cover complete # range of data, whether right = T or F c(min(x) - size, x, max(x) + size) } else { x } } #' @export fullseq.Date <- function(range, size, ...) { range <- sort(range) seq(floor_date(range[1], size), ceiling_date(range[2], size), by = size) } #' @export fullseq.POSIXt <- function(range, size, ...) { # for subsecond interval support # seq() does not support partial secs in character strings range <- sort(range) parsed <- parse_unit_spec(size) if (parsed$unit == "sec") { seq( floor_time(range[1], size), ceiling_time(range[2], size), by = parsed$mult ) } else { seq(floor_time(range[1], size), ceiling_time(range[2], size), by = size) } } #' @export fullseq.difftime <- function(range, size, ...) { if (is.numeric(size)) { size_seconds <- size } else { size_seconds <- unit_seconds(size) } input_units <- units(range) range <- sort(range) x <- seq( round_any(as.numeric(range[1], units = "secs"), size_seconds, floor), round_any(as.numeric(range[2], units = "secs"), size_seconds, ceiling), by = size_seconds ) x <- as.difftime(x, units = "secs") units(x) <- input_units x } scales/R/transform-date.R0000644000176200001440000000753015002117500014772 0ustar liggesusers#' Transformation for dates (class Date) #' #' @export #' @examples #' years <- seq(as.Date("1910/1/1"), as.Date("1999/1/1"), "years") #' t <- transform_date() #' t$transform(years) #' t$inverse(t$transform(years)) #' t$format(t$breaks(range(years))) transform_date <- function() { new_transform( "date", transform = "from_date", inverse = "to_date", breaks = breaks_pretty(), domain = to_date(c(-Inf, Inf)) ) } #' @export #' @rdname transform_date date_trans <- transform_date to_date <- function(x) structure(x, class = "Date") from_date <- function(x) { if (!inherits(x, "Date")) { cli::cli_abort( "{.fun transform_date} works with objects of class {.cls Date} only" ) } structure(as.numeric(x), names = names(x)) } #' Transformation for date-times (class POSIXt) #' #' @param tz Optionally supply the time zone. If `NULL`, the default, #' the time zone will be extracted from first input with a non-null tz. #' @export #' @examples #' hours <- seq(ISOdate(2000, 3, 20, tz = ""), by = "hour", length.out = 10) #' t <- transform_time() #' t$transform(hours) #' t$inverse(t$transform(hours)) #' t$format(t$breaks(range(hours))) transform_time <- function(tz = NULL) { force(tz) to_time <- function(x) { structure(x, class = c("POSIXct", "POSIXt"), tzone = tz) } from_time <- function(x) { if (!inherits(x, "POSIXct")) { cli::cli_abort( "{.fun transform_time} works with objects of class {.cls POSIXct} only" ) } if (is.null(tz)) { tz <<- attr(as.POSIXlt(x), "tzone")[[1]] } structure(as.numeric(x), names = names(x)) } new_transform( "time", transform = "from_time", inverse = "to_time", breaks = breaks_pretty(), domain = to_time(c(-Inf, Inf)) ) } #' @export #' @rdname transform_time time_trans <- transform_time #' Transformation for times (class hms) #' #' `transform_timespan()` provides transformations for data encoding time passed #' along with breaks and label formatting showing standard unit of time fitting #' the range of the data. `transform_hms()` provides the same but using standard #' hms idioms and formatting. #' #' @inheritParams label_timespan #' @export #' @examples #' # transform_timespan allows you to specify the time unit numeric data is #' # interpreted in #' trans_min <- transform_timespan("mins") #' demo_timespan(seq(0, 100), trans = trans_min) #' # Input already in difftime format is interpreted correctly #' demo_timespan(as.difftime(seq(0, 100), units = "secs"), trans = trans_min) #' #' if (require("hms")) { #' # transform_hms always assumes seconds #' hms <- round(runif(10) * 86400) #' t <- transform_hms() #' t$transform(hms) #' t$inverse(t$transform(hms)) #' t$breaks(hms) #' # The break labels also follow the hms format #' demo_timespan(hms, trans = t) #' } #' transform_timespan <- function( unit = c("secs", "mins", "hours", "days", "weeks") ) { unit <- arg_match(unit) new_transform( "timespan", transform = function(x) { structure( as.numeric(as.difftime(x, units = unit), units = "secs"), names = names(x) ) }, inverse = function(x) { x <- as.difftime(x, units = "secs") units(x) <- unit x }, breaks = breaks_timespan(unit), format = label_timespan(unit) ) } #' @export #' @rdname transform_timespan timespan_trans <- transform_timespan #' @rdname transform_timespan #' @export transform_hms <- function() { check_installed("hms", "for the 'hms' transformation.") new_transform( "hms", transform = function(x) { structure(as.numeric(x), names = names(x)) }, inverse = hms::as_hms, breaks = breaks_hms() ) } #' @rdname transform_timespan #' @export hms_trans <- transform_hms breaks_hms <- function(n = 5) { base_breaks <- breaks_timespan("secs", n) function(x) { hms::as_hms(base_breaks(x)) } } scales/R/pal-area.R0000644000176200001440000000104514672302130013530 0ustar liggesusers#' Area palettes (continuous) #' #' @param range Numeric vector of length two, giving range of possible sizes. #' Should be greater than 0. #' @export pal_area <- function(range = c(1, 6)) { force(range) new_continuous_palette( function(x) rescale(sqrt(x), range, c(0, 1)), type = "numeric" ) } #' @export #' @rdname pal_area area_pal <- pal_area #' @param max A number representing the maximum size. #' @export #' @rdname pal_area abs_area <- function(max) { force(max) function(x) rescale(sqrt(abs(x)), c(0, max), c(0, 1)) } scales/R/pal-dichromat.R0000644000176200001440000000171114705661306014604 0ustar liggesusers#' Dichromat (colour-blind) palette (discrete) #' #' @param name Name of colour palette. One of: #' \Sexpr[results=rd,stage=build]{scales:::dichromat_schemes()} #' @export #' @examples #' if (requireNamespace("dichromat", quietly = TRUE)) { #' show_col(pal_dichromat("BluetoOrange.10")(10)) #' show_col(pal_dichromat("BluetoOrange.10")(5)) #' #' # Can use with gradient_n to create a continuous gradient #' cols <- pal_dichromat("DarkRedtoBlue.12")(12) #' show_col(pal_gradient_n(cols)(seq(0, 1, length.out = 30))) #' } pal_dichromat <- function(name) { check_installed("dichromat") arg_match0(name, names(dichromat::colorschemes)) pal <- dichromat::colorschemes[[name]] pal_manual(pal, type = "colour") } #' @export #' @rdname pal_dichromat dichromat_pal <- pal_dichromat dichromat_schemes <- function() { if (requireNamespace("dichromat", quietly = TRUE)) { paste0("\\code{", names(dichromat::colorschemes), "}", collapse = ", ") } } scales/R/pal-.R0000644000176200001440000002271515002117500012677 0ustar liggesusers#' @name palette-recommendations #' @title Recommendations for colour palettes #' @description #' For the purposes of these recommendations, we define a palette as a function #' that either takes an `n` argument for the number of desired output colours or #' a `value` argument between 0-1 representing how far along a gradient output #' colours should be. The palette then returns a number of colours equal to `n` #' or `length(x)`. #' #' The convention in the scales package is to name functions that generate #' palettes (palette factories) with the `pal_`-prefix. The benefit of #' factories is that you can easily parameterise palettes, for example giving #' options for how a palette should be constructed. #' #' In the example below `pal_aurora()` is a palette factory parameterised by #' a `direction` argument. #' #' ```r #' pal_aurora <- function(direction = 1) { #' colours <- c("palegreen", "deepskyblue", "magenta") #' if (sign(direction) == -1) { #' colours <- rev(colours) #' } #' pal_manual(colours, type = "colour") #' } #' #' class(pal_aurora()) #' #> [1] "pal_discrete" "scales_pal" "function" #' ``` #' #' It is recommended that a palette factory returns a function with either the #' `pal_discrete` or `pal_continuous` class. If your factory constructs a #' plain vector of colours, then `pal_manual(type = "colour")` or #' `pal_gradient_n()` are useful to return a classed palette for this common #' use case. #' #' When your inner palette function does not return a defined vector of colours, #' it is recommended to use `new_discrete_palette` and `new_continuous_palette` #' instead and supplement the additional `type` and `na_safe`/`nlevels` #' properties. This should allow easy translation between discrete and #' continuous palettes. #' #' ```r #' pal_random <- function() { #' fun <- function(n) { #' sample(colours(distinct = TRUE), size = n) #' } #' new_discrete_palette(fun, type = "colour", nlevels = length(colours())) #' } #' ``` #' #' If you don't have parameterised palettes, but also if you have palette #' factories, it is encouraged to export an (inner) palette function or #' plain colour vector. This is in addition to exporting the palette factory. #' Exporting this makes it easy for users to specify for example #' `as_continuous_pal(mypackage::aurora)`. #' #' ``` #' #' @export #' aurora <- pal_aurora() #' #' # or: #' #' #' @export #' aurora <- c("palegreen", "deepskyblue", "magenta") #' ``` #' #' Lastly, for testing purposes we encourage that your palettes can be #' interpreted both as discrete palette, but also a continuous palette. #' To test for this, you can test the output of `as_discrete_pal()` and #' `as_continuous_pal()`. #' #' ```r #' test_that("pal_aurora can be discrete or continuous", { #' #' my_pal <- pal_aurora() #' colours <- c("palegreen", "deepskyblue", "magenta") #' #' expect_equal(as_discrete_pal(my_pal)(3), colours) #' expect_equal(as_continuous_pal(my_pal)(c(0, 0.5, 1)), alpha(colours, NA)) #' #' }) #' ``` #' @seealso [palette utilities][new_continuous_palette] NULL # Constructors ------------------------------------------------------------ #' Constructors for palettes #' #' These constructor functions attach metadata to palette functions. This #' metadata can be used in testing or coercion. #' #' @param fun A function to serve as a palette. For continuous palettes, these #' typically take vectors of numeric values between (0, 1) and return a #' vector of equal length. For discrete palettes, these typically take a #' scalar integer and return a vector of that length. #' @param type A string giving the type of return values. Some example strings #' include `"colour"`, `"numeric"`, `"linetype"` or `"shape"`. #' @param na_safe A boolean indicating whether `NA` values are translated to #' palette values (`TRUE`) or are kept as `NA` (`FALSE`). Applies to #' continuous palettes. #' @param nlevels An integer giving the number of distinct palette values #' that can be returned by the discrete palette. #' @param x An object to test or coerce. #' @param pal A palette to retrieve properties from. #' @param ... Additional arguments. Currently not in use. #' #' @return #' For `new_continuous_palette()`, `new_discret_palette()`, `as_discrete_pal()` #' and `as_continuous_pal()`: a function of class `pal_continuous` or `pal_discrete`. #' For `is_pal()`, `is_continuous_pal()`, `is_discret_pal()`, `is_colour_pal()`, #' or `is_numeric_pal()`: a logical value of length 1. #' For `palette_nlevels()` a single integer. For `palette_na_safe()` a boolean. #' For `palette_type()` a string. #' @export #' @seealso [palette recommendations][palette-recommendations] #' #' @examples #' # Creating a new discrete palette #' new_discrete_palette( #' fun = grDevices::terrain.colors, #' type = "colour", nlevels = 255 #' ) #' #' # Creating a new continuous palette #' new_continuous_palette( #' fun = function(x) rescale(x, to = c(1, 0)), #' type = "numeric", na_safe = FALSE #' ) #' #' # Testing palette properties #' is_continuous_pal(pal_seq_gradient()) #' is_discrete_pal(pal_viridis()) #' is_numeric_pal(pal_area()) #' is_colour_pal(pal_manual(c("red", "green"))) #' is_pal(transform_log10()) #' #' # Extracting properties #' palette_nlevels(pal_viridis()) #' palette_na_safe(colour_ramp(c("red", "green"), na.color = "grey50")) #' palette_type(pal_shape()) #' #' # Switching discrete to continuous #' pal <- as_continuous_pal(pal_viridis()) #' show_col(pal(c(0, 0.1, 0.2, 0.4, 1))) #' #' # Switching continuous to discrete #' pal <- as_discrete_pal(pal_div_gradient()) #' show_col(pal(9)) new_continuous_palette <- function(fun, type, na_safe = NA) { check_function(fun) class(fun) <- union(c("pal_continuous", "scales_pal"), class(fun)) attr(fun, "type") <- type attr(fun, "na_safe") <- na_safe fun } #' @rdname new_continuous_palette #' @export new_discrete_palette <- function(fun, type, nlevels = NA) { check_function(fun) class(fun) <- union(c("pal_discrete", "scales_pal"), class(fun)) attr(fun, "type") <- type attr(fun, "nlevels") <- nlevels fun } # Testing ----------------------------------------------------------------- #' @rdname new_continuous_palette #' @export is_pal <- function(x) inherits(x, c("pal_discrete", "pal_continuous")) #' @rdname new_continuous_palette #' @export is_continuous_pal <- function(x) inherits(x, "pal_continuous") #' @rdname new_continuous_palette #' @export is_discrete_pal <- function(x) inherits(x, "pal_discrete") #' @rdname new_continuous_palette #' @export is_colour_pal <- function(x) { is_pal(x) && any(palette_type(x) %in% c("color", "colour")) } #' @rdname new_continuous_palette #' @export is_numeric_pal <- function(x) { is_pal(x) && any(palette_type(x) %in% c("numeric", "double", "integer")) } # Getters ----------------------------------------------------------------- #' @rdname new_continuous_palette #' @export palette_nlevels <- function(pal) { as.integer(attr(pal, "nlevels")[1] %||% NA_integer_) } #' @rdname new_continuous_palette #' @export palette_na_safe <- function(pal) { as.logical(attr(pal, "na_safe")[1] %||% FALSE) } #' @rdname new_continuous_palette #' @export palette_type <- function(pal) { as.character(attr(pal, "type")[1] %||% NA_character_) } # Coercion ---------------------------------------------------------------- ## As discrete palette ---------------------------------------------------- #' @rdname new_continuous_palette #' @export as_discrete_pal <- function(x, ...) { UseMethod("as_discrete_pal") } #' @export as_discrete_pal.default <- function(x, ...) { cli::cli_abort("Cannot convert {.arg x} to a discrete palette.") } #' @export as_discrete_pal.function <- function(x, ...) { x } #' @export as_discrete_pal.pal_continuous <- function(x, ...) { force(x) new_discrete_palette( function(n) x(seq(0, 1, length.out = n)), type = palette_type(x), nlevels = 255 ) } #' @export as_discrete_pal.character <- function(x, ...) { if (length(x) > 1) { return(pal_manual(x)) } as_discrete_pal(get_palette(x, ...)) } ## As continuous palette -------------------------------------------------- #' @rdname new_continuous_palette #' @export as_continuous_pal <- function(x, ...) { UseMethod("as_continuous_pal") } #' @export as_continuous_pal.default <- function(x, ...) { cli::cli_abort("Cannot convert {.arg x} to a continuous palette.") } #' @export as_continuous_pal.function <- function(x, ...) { x } #' @export as_continuous_pal.pal_discrete <- function(x, ...) { nlevels <- palette_nlevels(x) if (!is_scalar_integerish(nlevels, finite = TRUE)) { cli::cli_abort(c( "Cannot convert {.arg x} to continuous palette.", i = "Unknown number of supported levels." )) } type <- palette_type(x) switch( type, color = , colour = colour_ramp(x(nlevels)), numeric = new_continuous_palette( stats::approxfun(seq(0, 1, length.out = nlevels), x(nlevels)), type = "numeric", na_safe = FALSE ), cli::cli_abort( "Don't know how to convert a discrete {.field {type}} palette to \\ a continuous palette." ) ) } #' @export as_continuous_pal.character <- function(x, ...) { if (length(x) > 1) { return(colour_ramp(x)) } as_continuous_pal(get_palette(x, ...)) } # Utility ----------------------------------------------------------------- #' @export plot.pal_discrete <- function(x, y, ..., n_max = 25) { show_col(x(pmin(n_max, palette_nlevels(x))), ...) } #' @export plot.pal_continuous <- function(x, y, ..., n_max = 25) { show_col(x(seq(0, 1, length.out = n_max)), ...) } scales/R/pal-linetype.R0000644000176200001440000000065015002117500014443 0ustar liggesusers#' Line type palette (discrete) #' #' Based on a set supplied by Richard Pearson, University of Manchester #' #' @export pal_linetype <- function() { types <- c( "solid", "22", "42", "44", "13", "1343", "73", "2262", "12223242", "F282", "F4448444", "224282F2", "F1" ) manual_pal(types, "linetype") } #' @export #' @rdname pal_linetype linetype_pal <- pal_linetype scales/R/colour-manip.R0000644000176200001440000002026515002117500014451 0ustar liggesusers#' Modify standard R colour in hcl colour space. #' #' Transforms rgb to hcl, sets non-missing arguments and then backtransforms #' to rgb. #' #' @param colour character vector of colours to be modified #' @param h Hue, `[0, 360]` #' @param l Luminance, `[0, 100]` #' @param c Chroma, `[0, 100]` #' @param alpha Alpha, `[0, 1]`. #' @export #' @family colour manipulation #' @examples #' reds <- rep("red", 6) #' show_col(col2hcl(reds, h = seq(0, 180, length = 6))) #' show_col(col2hcl(reds, c = seq(0, 80, length = 6))) #' show_col(col2hcl(reds, l = seq(0, 100, length = 6))) #' show_col(col2hcl(reds, alpha = seq(0, 1, length = 6))) col2hcl <- function(colour, h = NULL, c = NULL, l = NULL, alpha = NULL) { hcl <- farver::decode_colour(colour, to = "hcl") if (!is.null(h)) hcl[, "h"] <- h if (!is.null(c)) hcl[, "c"] <- c if (!is.null(l)) hcl[, "l"] <- l farver::encode_colour(hcl, alpha, from = "hcl") } #' Mute standard colour #' #' @param colour character vector of colours to modify #' @param l new luminance #' @param c new chroma #' @export #' @family colour manipulation #' @examples #' muted("red") #' muted("blue") #' show_col(c("red", "blue", muted("red"), muted("blue"))) muted <- function(colour, l = 30, c = 70) col2hcl(colour, l = l, c = c) #' Modify colour transparency #' #' Vectorised in both colour and alpha. #' #' @param colour colour #' @param alpha new alpha level in \[0,1]. If alpha is `NA`, #' existing alpha values are preserved. #' @export #' @family colour manipulation #' @examples #' alpha("red", 0.1) #' alpha(colours(), 0.5) #' alpha("red", seq(0, 1, length.out = 10)) #' alpha(c("first" = "gold", "second" = "lightgray", "third" = "#cd7f32"), .5) alpha <- function(colour, alpha = NA) { input <- recycle_common(colour = colour, alpha = alpha) colour <- input[["colour"]] alpha <- input[["alpha"]] rgb <- farver::decode_colour(colour, alpha = TRUE) rgb[!is.na(alpha), 4] <- alpha[!is.na(alpha)] farver::encode_colour(rgb, rgb[, 4]) } #' Show colours #' #' A quick and dirty way to show colours in a plot. #' #' @param colours A character vector of colours #' @param labels Label each colour with its hex name? #' @param borders Border colour for each tile. Default uses `par("fg")`. #' Use `border = NA` to omit borders. #' @param cex_label Size of printed labels, as multiplier of default size. #' @param ncol Number of columns. If not supplied, tries to be as square as #' possible. #' @export #' @importFrom graphics par plot rect text #' @keywords internal #' @examples #' show_col(pal_hue()(9)) #' show_col(pal_hue()(9), borders = NA) #' #' show_col(pal_viridis()(16)) #' show_col(pal_viridis()(16), labels = FALSE) show_col <- function( colours, labels = TRUE, borders = NULL, cex_label = 1, ncol = NULL ) { n <- length(colours) if (n == 1 && (is.function(colours) || !is_color(colours))) { colours <- as_discrete_pal(colours) n <- palette_nlevels(colours) n <- if (is.na(n)) 16 else n colours <- colours(n = n) n <- length(colours) } ncol <- ncol %||% ceiling(sqrt(length(colours))) nrow <- ceiling(n / ncol) colours <- c(colours, rep(NA, nrow * ncol - length(colours))) colours <- matrix(colours, ncol = ncol, byrow = TRUE) old <- par(pty = "s", mar = c(0, 0, 0, 0)) on.exit(par(old)) size <- max(dim(colours)) plot(c(0, size), c(0, -size), type = "n", xlab = "", ylab = "", axes = FALSE) rect( col(colours) - 1, -row(colours) + 1, col(colours), -row(colours), col = colours, border = borders ) if (labels) { hcl <- farver::decode_colour(colours, "rgb", "hcl") label_col <- ifelse(hcl[, "l"] > 50, "black", "white") text( col(colours) - 0.5, -row(colours) + 0.5, colours, cex = cex_label, col = label_col ) } } #' Mix colours #' #' Produces an interpolation of two colours. #' #' @param a Either a character vector of colours or a colour palette function. #' @param b A character vector of colours. #' @param amount A numeric fraction between 0 and 1 giving the contribution of #' the `b` colour. #' @param space A string giving a colour space to perform mixing operation in. #' Polar spaces are not recommended. #' #' @return A character vector of colours. #' @family colour manipulation #' @export #' #' @examples #' col_mix("blue", "red") # purple #' col_mix("blue", "red", amount = 1) # red #' col_mix("blue", "red", amount = 0) # blue #' #' # Not recommended: #' col_mix("blue", "red", space = "hcl") # green! col_mix <- function(a, b, amount = 0.5, space = "rgb") { UseMethod("col_mix") } #' @export col_mix.default <- function(a, b, amount = 0.5, space = "rgb") { input <- recycle_common(a = a, b = b, amount = amount) if (any(input$amount < 0 | input$amount > 1)) { cli::cli_abort("{.arg amount} must be between (0, 1).") } a <- farver::decode_colour(input$a, alpha = TRUE, to = space) b <- farver::decode_colour(input$b, alpha = TRUE, to = space) new <- (a * (1 - amount) + b * amount) alpha <- new[, "alpha"] farver::encode_colour(new, alpha = alpha, from = space) } #' @export col_mix.scales_pal <- function(a, b, amount = 0.5, space = "rgb") { wrap_col_adjustment(a, col_mix, list(b = b, amount = amount, space = space)) } #' Colour manipulation #' #' These are a set of convenience functions for standard colour manipulation #' operations. #' #' @param col A character vector of colours or a colour palette function. #' @param amount A numeric vector giving the change. The interpretation depends #' on the function: #' * `col_shift()` takes a number between -360 and 360 for shifting hues in #' HCL space. #' * `col_lighter()` and `col_darker()` take a number between -100 and 100 for #' adding (or subtracting) to the lightness channel in HSL space. #' * `col_saturate()` takes a number between -100 and 100 for adding to the #' saturation channel in HSL space. Negative numbers desaturate the colour. #' #' @details #' `col_shift()` considers the hue channel to be periodic, so adding 180 to #' a colour with hue 270 will result in a colour with hue 90. #' #' @return A vector of colours. #' @name colour_manip #' @family colour manipulation #' #' @examples #' col_shift("red", 180) # teal #' col_lighter("red", 50) # light red #' col_darker("red", 50) # dark red #' col_saturate("red", -50) # brick-red NULL #' @export #' @rdname colour_manip col_shift <- function(col, amount = 10) { UseMethod("col_shift") } #' @export col_shift.default <- function(col, amount = 10) { input <- recycle_common(col = col, amount = amount) new <- farver::decode_colour(input$col, alpha = TRUE, to = "hcl") new[, "h"] <- (new[, "h"] + input$amount) %% 360 farver::encode_colour(new, new[, "alpha"], from = "hcl") } #' @export col_shift.scales_pal <- function(col, amount = 10) { wrap_col_adjustment(col, col_shift, list(amount = amount)) } #' @export #' @rdname colour_manip col_lighter <- function(col, amount = 10) { UseMethod("col_lighter") } #' @export col_lighter.default <- function(col, amount = 10) { input <- recycle_common(col = col, amount = amount) farver::add_to_channel(input$col, "l", input$amount, space = "hsl") } #' @export col_lighter.scales_pal <- function(col, amount = 10) { wrap_col_adjustment(col, col_lighter, list(amount = amount)) } #' @export #' @rdname colour_manip col_darker <- function(col, amount = 10) { col_lighter(col, amount = -amount) } #' @export #' @rdname colour_manip col_saturate <- function(col, amount = 10) { UseMethod("col_saturate") } #' @export col_saturate.default <- function(col, amount = 10) { input <- recycle_common(col = col, amount = amount) farver::add_to_channel(input$col, "s", input$amount, space = "hsl") } #' @export col_saturate.scales_pal <- function(col, amount = 10) { wrap_col_adjustment(col, col_saturate, list(amount = amount)) } wrap_col_adjustment <- function(inner, outer, args, call = caller_env()) { check_object(inner, is_colour_pal, "a {.field colour} palette") force_all(inner, outer, args) fun <- function(...) inject(outer(inner(...), !!!args)) if (is_discrete_pal(inner)) { new_discrete_palette(fun, type = "colour", nlevels = palette_nlevels(inner)) } else { new_continuous_palette( fun, type = "colour", na_safe = palette_na_safe(inner) ) } } scales/R/label-number.R0000644000176200001440000003765715002124357014436 0ustar liggesusers#' Label numbers in decimal format (e.g. 0.12, 1,234) #' #' Use `label_number()` to force decimal display of numbers (i.e. don't use #' [scientific][label_scientific] notation). `label_comma()` is a special case #' that inserts a comma every three digits. #' #' @return #' All `label_()` functions return a "labelling" function, i.e. a function that #' takes a vector `x` and returns a character vector of `length(x)` giving a #' label for each input value. #' #' Labelling functions are designed to be used with the `labels` argument of #' ggplot2 scales. The examples demonstrate their use with x scales, but #' they work similarly for all scales, including those that generate legends #' rather than axes. #' #' @param accuracy A number to round to. Use (e.g.) `0.01` to show 2 decimal #' places of precision. If `NULL`, the default, uses a heuristic that should #' ensure breaks have the minimum number of digits needed to show the #' difference between adjacent values. #' #' Applied to rescaled data. #' @param scale A scaling factor: `x` will be multiplied by `scale` before #' formatting. This is useful if the underlying data is very small or very #' large. #' @param prefix Additional text to display before the number. The suffix is #' applied to absolute value before `style_positive` and `style_negative` are #' processed so that `prefix = "$"` will yield (e.g.) `-$1` and `($1)`. #' @param suffix Additional text to display after the number. #' @param big.mark Character used between every 3 digits to separate thousands. #' The default (`NULL`) retrieves the setting from the #' [number options][number_options]. #' @param decimal.mark The character to be used to indicate the numeric #' decimal point. The default (`NULL`) retrieves the setting from the #' [number options][number_options]. #' @param style_positive A string that determines the style of positive numbers: #' #' * `"none"` (the default): no change, e.g. `1`. #' * `"plus"`: preceded by `+`, e.g. `+1`. #' * `"space"`: preceded by a Unicode "figure space", i.e., a space equally #' as wide as a number or `+`. Compared to `"none"`, adding a figure space #' can ensure numbers remain properly aligned when they are left- or #' right-justified. #' #' The default (`NULL`) retrieves the setting from the #' [number options][number_options]. #' @param style_negative A string that determines the style of negative numbers: #' #' * `"hyphen"` (the default): preceded by a standard hyphen `-`, e.g. `-1`. #' * `"minus"`, uses a proper Unicode minus symbol. This is a typographical #' nicety that ensures `-` aligns with the horizontal bar of the #' the horizontal bar of `+`. #' * `"parens"`, wrapped in parentheses, e.g. `(1)`. #' #' The default (`NULL`) retrieves the setting from the #' [number options][number_options]. #' @param scale_cut Named numeric vector that allows you to rescale large #' (or small) numbers and add a prefix. Built-in helpers include: #' * `cut_short_scale()`: [10^3, 10^6) = K, [10^6, 10^9) = M, [10^9, 10^12) = B, [10^12, Inf) = T. #' * `cut_long_scale()`: [10^3, 10^6) = K, [10^6, 10^12) = M, [10^12, 10^18) = B, [10^18, Inf) = T. #' * `cut_si(unit)`: uses standard SI units. #' #' If you supply a vector `c(a = 100, b = 1000)`, absolute values in the #' range `[0, 100)` will not be rescaled, absolute values in the range `[100, 1000)` #' will be divided by 100 and given the suffix "a", and absolute values in #' the range `[1000, Inf)` will be divided by 1000 and given the suffix "b". #' If the division creates an irrational value (or one with many digits), the #' cut value below will be tried to see if it improves the look of the final #' label. #' @param trim Logical, if `FALSE`, values are right-justified to a common #' width (see [base::format()]). #' @param ... Other arguments passed on to [base::format()]. #' @export #' @examplesIf getRversion() >= "3.5" #' demo_continuous(c(-1e6, 1e6)) #' demo_continuous(c(-1e6, 1e6), labels = label_number()) #' demo_continuous(c(-1e6, 1e6), labels = label_comma()) #' #' # Use scale to rescale very small or large numbers to generate #' # more readable labels #' demo_continuous(c(0, 1e6), labels = label_number()) #' demo_continuous(c(0, 1e6), labels = label_number(scale = 1 / 1e3)) #' demo_continuous(c(0, 1e-6), labels = label_number()) #' demo_continuous(c(0, 1e-6), labels = label_number(scale = 1e6)) #' #' #' Use scale_cut to automatically add prefixes for large/small numbers #' demo_log10( #' c(1, 1e9), #' breaks = log_breaks(10), #' labels = label_number(scale_cut = cut_short_scale()) #' ) #' demo_log10( #' c(1, 1e9), #' breaks = log_breaks(10), #' labels = label_number(scale_cut = cut_si("m")) #' ) #' demo_log10( #' c(1e-9, 1), #' breaks = log_breaks(10), #' labels = label_number(scale_cut = cut_si("g")) #' ) #' # use scale and scale_cut when data already uses SI prefix #' # for example, if data was stored in kg #' demo_log10( #' c(1e-9, 1), #' breaks = log_breaks(10), #' labels = label_number(scale_cut = cut_si("g"), scale = 1e3) #' ) #' #' #' # Use style arguments to vary the appearance of positive and negative numbers #' demo_continuous(c(-1e3, 1e3), labels = label_number( #' style_positive = "plus", #' style_negative = "minus" #' )) #' demo_continuous(c(-1e3, 1e3), labels = label_number(style_negative = "parens")) #' #' # You can use prefix and suffix for other types of display #' demo_continuous(c(32, 212), labels = label_number(suffix = "\u00b0F")) #' demo_continuous(c(0, 100), labels = label_number(suffix = "\u00b0C")) label_number <- function( accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = NULL, decimal.mark = NULL, style_positive = NULL, style_negative = NULL, scale_cut = NULL, trim = TRUE, ... ) { force_all( accuracy, scale, prefix, suffix, big.mark, decimal.mark, style_positive, style_negative, scale_cut, trim, ... ) function(x) { number( x, accuracy = accuracy, scale = scale, prefix = prefix, suffix = suffix, big.mark = big.mark, decimal.mark = decimal.mark, style_positive = style_positive, style_negative = style_negative, scale_cut = scale_cut, trim = trim, ... ) } } #' @export #' @rdname label_number #' @param digits `r lifecycle::badge("deprecated")` Use `accuracy` instead. label_comma <- function( accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = ",", decimal.mark = ".", trim = TRUE, digits, ... ) { if (!missing(digits)) { lifecycle::deprecate_stop( when = "1.0.0", what = "label_comma(digits)", with = "label_comma(accuracy)" ) } number_format( accuracy = accuracy, scale = scale, prefix = prefix, suffix = suffix, big.mark = big.mark, decimal.mark = decimal.mark, trim = trim, ... ) } #' Superseded interface to `label_number()`/`label_comma()` #' #' @description #' `r lifecycle::badge("superseded")` #' #' These functions are kept for backward compatibility; you should switch #' to [label_number()]/[label_comma()] for new code. #' #' @keywords internal #' @export #' @inheritParams label_number #' @param x A numeric vector to format. comma <- function( x, accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = ",", decimal.mark = ".", trim = TRUE, digits, ... ) { if (!missing(digits)) { lifecycle::deprecate_stop( when = "1.0.0", what = "comma(digits)", with = "comma(accuracy)" ) } number( x = x, accuracy = accuracy, scale = scale, prefix = prefix, suffix = suffix, big.mark = big.mark, decimal.mark = decimal.mark, trim = trim, ... ) } #' @export #' @rdname comma number_format <- label_number #' @export #' @rdname comma comma_format <- label_comma #' A low-level numeric formatter #' #' This function is a low-level helper that powers many of the labelling #' functions. You should generally not need to call it directly unless you #' are creating your own labelling function. #' #' @keywords internal #' @export #' @inheritParams label_number #' @return A character vector of `length(x)`. number <- function( x, accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = NULL, decimal.mark = NULL, style_positive = NULL, style_negative = NULL, scale_cut = NULL, trim = TRUE, ... ) { if (length(x) == 0) { return(character()) } big.mark <- big.mark %||% getOption("scales.big.mark", default = " ") decimal.mark <- decimal.mark %||% getOption("scales.decimal.mark", default = ".") style_positive <- style_positive %||% getOption("scales.style_positive", default = "none") style_negative <- style_negative %||% getOption("scales.style_negative", default = "hyphen") style_positive <- arg_match(style_positive, c("none", "plus", "space")) style_negative <- arg_match(style_negative, c("hyphen", "minus", "parens")) if (!is.null(scale_cut)) { cut <- scale_cut( x, breaks = scale_cut, scale = scale, accuracy = accuracy, suffix = suffix ) scale <- cut$scale suffix <- cut$suffix accuracy <- cut$accuracy } accuracy <- accuracy %||% precision(x * scale) x <- round_any(x, accuracy / scale) nsmalls <- -floor(log10(accuracy)) nsmalls <- pmin(pmax(nsmalls, 0), 20) sign <- sign(x) sign[is.na(sign)] <- 0 x <- abs(x) x_scaled <- scale * x ret <- character(length(x)) for (nsmall in unique(nsmalls)) { idx <- nsmall == nsmalls ret[idx] <- format( x_scaled[idx], big.mark = big.mark, decimal.mark = decimal.mark, trim = trim, nsmall = nsmall, scientific = FALSE, ... ) } ret <- paste0(prefix, ret, suffix) ret[is.infinite(x)] <- as.character(x[is.infinite(x)]) if (style_negative == "hyphen") { ret[sign < 0] <- paste0("-", ret[sign < 0]) } else if (style_negative == "minus") { ret[sign < 0] <- paste0("\u2212", ret[sign < 0]) } else if (style_negative == "parens") { ret[sign < 0] <- paste0("(", ret[sign < 0], ")") } if (style_positive == "plus") { ret[sign > 0] <- paste0("+", ret[sign > 0]) } else if (style_positive == "space") { ret[sign > 0] <- paste0("\u2007", ret[sign > 0]) } # restore NAs from input vector ret[is.na(x)] <- NA names(ret) <- names(x) ret } #' Number options #' #' Control the settings for formatting numbers globally. #' #' @inheritParams label_number #' @param currency.prefix,currency.suffix,currency.decimal.mark,currency.big.mark #' Settings for [`label_currency()`] passed on without the `currency.`-prefix. #' @param ordinal.rules Setting for [`label_ordinal()`] passed on without the #' `ordinal.`-prefix. #' #' @return The old options invisibly #' @export #' #' @examples #' # Default number formatting #' x <- c(0.1, 1, 1000) #' label_number()(x) #' #' # Now again with new options set #' number_options(style_positive = "plus", decimal.mark = ",") #' label_number()(x) #' #' # The options are the argument names with a 'scales.'-prefix #' options("scales.style_positive") #' #' # Resetting the options to their defaults #' number_options() #' label_number()(x) number_options <- function( decimal.mark = ".", big.mark = " ", style_positive = c("none", "plus", "space"), style_negative = c("hyphen", "minus", "parens"), currency.prefix = "$", currency.suffix = "", currency.decimal.mark = decimal.mark, currency.big.mark = setdiff(c(".", ","), currency.decimal.mark)[1], ordinal.rules = ordinal_english() ) { opts <- options( scales.decimal.mark = decimal.mark, scales.big.mark = big.mark, scales.style_positive = arg_match(style_positive), scales.style_negative = arg_match(style_negative), scales.currency.prefix = currency.prefix, scales.currency.suffix = currency.suffix, scales.currency.decimal.mark = currency.decimal.mark, scales.currency.big.mark = currency.big.mark, scales.ordinal.rules = ordinal.rules ) invisible(opts) } # Helpers ----------------------------------------------------------------- precision <- function(x) { x <- unique(x) # ignore NA and Inf/-Inf x <- x[is.finite(x)] if (length(x) <= 1) { return(1) } smallest_diff <- min(diff(sort(x))) if (smallest_diff < sqrt(.Machine$double.eps)) { 1 } else { precision <- 10^(floor(log10(smallest_diff)) - 1) # reduce precision when final digit always 0 if (all(round(x / precision) %% 10 == 0)) { precision <- precision * 10 } # Never return precision bigger than 1 pmin(precision, 1) } } # each value of x is assigned a suffix and associated scaling factor scale_cut <- function(x, breaks, scale = 1, accuracy = NULL, suffix = "") { check_object(breaks, is.numeric, "a numeric vector", arg = caller_arg(breaks)) if (is.null(names(breaks))) { cli::cli_abort("{.arg scale_cut} must have names") } breaks <- sort(breaks, na.last = TRUE) if (anyNA(breaks)) { cli::cli_abort("{.arg scale_cut} values must not be missing") } break_suffix <- as.character(cut( abs(x * scale), breaks = c(unname(breaks), Inf), labels = c(names(breaks)), right = FALSE )) break_suffix[is.na(break_suffix)] <- "" # See if any of the cuts aren't perfect cuts bad_break <- ((x * scale / breaks[break_suffix]) %% 1 != 0) %|% FALSE if (any(bad_break)) { # If the break below result in a perfect cut, prefer it lower_break <- breaks[match(break_suffix[bad_break], names(breaks)) - 1] lower_break[lower_break == 0] <- 1 # Avoid choosing a non-existent break improved_break <- (x[bad_break] * scale / lower_break) %% 1 == 0 # Unless the break below is a power of 10 change (1.25 is as good as 1250) power10_break <- breaks[break_suffix[bad_break]] / lower_break power10_break <- log10(power10_break) %% 1 == 0 break_suffix[bad_break][ improved_break & !power10_break ] <- names(lower_break[improved_break & !power10_break]) } break_scale <- scale * unname(1 / breaks[break_suffix]) break_scale[which(break_scale %in% c(Inf, NA))] <- scale # exact zero is not scaled, nor are values below lowest break break_scale[abs(x) == 0 | is.na(break_scale)] <- 1 suffix <- paste0(break_suffix, suffix) accuracy <- accuracy %||% stats::ave(x * break_scale, break_scale, FUN = precision) list( scale = break_scale, suffix = suffix, accuracy = accuracy ) } #' #' See [Metric Prefix](https://en.wikipedia.org/wiki/Metric_prefix) on Wikipedia #' for more details. #' @export #' @rdname number #' @param space Add a space before the scale suffix? cut_short_scale <- function(space = FALSE) { out <- c(0, K = 1e3, M = 1e6, B = 1e9, T = 1e12) if (space) { names(out) <- paste0(" ", names(out)) } out } #' @export #' @rdname number cut_long_scale <- function(space = FALSE) { out <- c(0, K = 1e3, M = 1e6, B = 1e12, T = 1e18) if (space) { names(out) <- paste0(" ", names(out)) } out } #' @export #' @rdname number cut_time_scale <- function(space = FALSE) { out <- c( 0, "ns" = 1e-9, "us" = 1e-6, "ms" = 1e-3, "s" = 1, "m" = 60, "h" = 3600, "d" = 24 * 3600, "w" = 7 * 24 * 3600 ) if (l10n_info()[["UTF-8"]]) { names(out)[3] <- "\u03BCs" } if (space) { names(out) <- paste0(" ", names(out)) } out } # power-of-ten prefixes used by the International System of Units (SI) # https://www.bipm.org/en/measurement-units/prefixes.html # # note: irregular prefixes (hecto, deca, deci, centi) are not stored # because they don't commonly appear in scientific usage anymore si_powers <- c( y = -24, z = -21, a = -18, f = -15, p = -12, n = -9, micro = -6, m = -3, 0, k = 3, M = 6, G = 9, T = 12, P = 15, E = 18, Z = 21, Y = 24 ) # Avoid using UTF8 as symbol names(si_powers)[si_powers == -6] <- "\u00b5" #' @export #' @rdname number #' @param unit SI unit abbreviation. cut_si <- function(unit) { out <- c(0, 10^si_powers) names(out) <- c(paste0(" ", unit), paste0(" ", names(si_powers), unit)) out } scales/R/breaks.R0000644000176200001440000001632715002146671013332 0ustar liggesusers#' Equally spaced breaks #' #' Useful for numeric, date, and date-time scales. #' #' @param width Distance between each break. Either a number, or for #' date/times, a single string of the form `"{n} {unit}"`, e.g. "1 month", #' "5 days". Unit can be of one "sec", "min", "hour", "day", "week", #' "month", "year". #' @param offset Use if you don't want breaks to start at zero, or on a #' conventional date or time boundary such as the 1st of January or midnight. #' Either a number, or for date/times, a single string of the form #' `"{n} {unit}"`, as for `width`. #' #' `offset` can be a vector, which will accumulate in the order given. This #' is mostly useful for dates, where e.g. `c("3 months", "5 days")` will #' offset by three months and five days, which is useful for the UK tax year. #' Note that due to way that dates are rounded, there's no guarantee that #' `offset = c(x, y)` will give the same result as `offset = c(y, x)`. #' #' @return #' All `breaks_()` functions return a function for generating breaks. These #' functions takes, as their first argument a vector of values that represent #' the data range to provide breaks for. Some will optionally take a second #' argument that allows you to specify the number of breaks to recieve. #' #' @export #' @examples #' demo_continuous(c(0, 100)) #' demo_continuous(c(0, 100), breaks = breaks_width(10)) #' demo_continuous(c(0, 100), breaks = breaks_width(20, -4)) #' demo_continuous(c(0, 100), breaks = breaks_width(20, 4)) #' #' # This is also useful for dates #' one_month <- as.POSIXct(c("2020-05-01", "2020-06-01")) #' demo_datetime(one_month) #' demo_datetime(one_month, breaks = breaks_width("1 week")) #' demo_datetime(one_month, breaks = breaks_width("5 days")) #' # This is so useful that scale_x_datetime() has a shorthand: #' demo_datetime(one_month, date_breaks = "5 days") #' #' # hms times also work #' one_hour <- hms::hms(hours = 0:1) #' demo_time(one_hour) #' demo_time(one_hour, breaks = breaks_width("15 min")) #' demo_time(one_hour, breaks = breaks_width("600 sec")) #' #' # Offets are useful for years that begin on dates other than the 1st of #' # January, such as the UK financial year, which begins on the 1st of April. #' three_years <- as.POSIXct(c("2020-01-01", "2021-01-01", "2022-01-01")) #' demo_datetime( #' three_years, #' breaks = breaks_width("1 year", offset = "3 months") #' ) #' #' # The offset can be a vector, to create offsets that have compound units, #' # such as the UK fiscal (tax) year, which begins on the 6th of April. #' demo_datetime( #' three_years, #' breaks = breaks_width("1 year", offset = c("3 months", "5 days")) #' ) breaks_width <- function(width, offset = 0) { force_all(width, offset) function(x) { x <- fullseq(x, width) for (i in offset) { x <- offset_by(x, i) } x } } #' Automatic breaks for numeric axes #' #' Uses Wilkinson's extended breaks algorithm as implemented in the #' \pkg{labeling} package. #' #' @param n Desired number of breaks. You may get slightly more or fewer #' breaks that requested. #' @param ... other arguments passed on to [labeling::extended()] #' #' @inherit breaks_width return #' #' @references Talbot, J., Lin, S., Hanrahan, P. (2010) An Extension of #' Wilkinson's Algorithm for Positioning Tick Labels on Axes, InfoVis #' 2010 . #' @export #' @examples #' demo_continuous(c(0, 10)) #' demo_continuous(c(0, 10), breaks = breaks_extended(3)) #' demo_continuous(c(0, 10), breaks = breaks_extended(10)) breaks_extended <- function(n = 5, ...) { n_default <- n function(x, n = n_default) { x <- x[is.finite(x)] if (length(x) == 0) { return(numeric()) } rng <- range(x) labeling::extended(rng[1], rng[2], n, ...) } } #' @export #' @usage NULL #' @rdname breaks_extended extended_breaks <- breaks_extended #' Pretty breaks for date/times #' #' Uses default R break algorithm as implemented in [pretty()]. This is #' primarily useful for date/times, as [extended_breaks()] should do a slightly #' better job for numeric scales. #' #' @inheritParams breaks_extended #' @param ... other arguments passed on to [pretty()] #' #' @inherit breaks_width return #' #' @export #' @examples #' one_month <- as.POSIXct(c("2020-05-01", "2020-06-01")) #' demo_datetime(one_month) #' demo_datetime(one_month, breaks = breaks_pretty(2)) #' demo_datetime(one_month, breaks = breaks_pretty(4)) #' #' # Tightly spaced date breaks often need custom labels too #' demo_datetime(one_month, breaks = breaks_pretty(12)) #' demo_datetime(one_month, #' breaks = breaks_pretty(12), #' labels = label_date_short() #' ) breaks_pretty <- function(n = 5, ...) { force_all(n, ...) n_default <- n function(x, n = n_default) { if (length(x) > 0 && zero_range(range(as.numeric(x), na.rm = TRUE))) { return(x[1]) } breaks <- pretty(x, n, ...) names(breaks) <- attr(breaks, "labels") breaks } } #' Superseded interface to `breaks_pretty()` #' #' @description #' `r lifecycle::badge("superseded")` #' #' These functions are kept for backward compatibility; you should switch #' to [breaks_pretty()] for new code. #' #' @keywords internal #' @export #' @inheritParams breaks_pretty pretty_breaks <- breaks_pretty #' Breaks for timespan data #' #' As timespan units span a variety of bases (1000 below seconds, 60 for second #' and minutes, 24 for hours, and 7 for days), the range of the input data #' determines the base used for calculating breaks #' #' @param unit The unit used to interpret numeric data input #' #' @inherit breaks_width return #' #' @inheritParams breaks_extended #' @export #' @examples #' demo_timespan(seq(0, 100), breaks = breaks_timespan()) #' breaks_timespan <- function( unit = c("secs", "mins", "hours", "days", "weeks"), n = 5 ) { unit <- arg_match(unit) force(n) function(x) { x <- as.numeric(as.difftime(x, units = unit), units = "secs") rng <- range(x) diff <- rng[2] - rng[1] if (diff <= 2 * 60) { scale <- 1 } else if (diff <= 2 * 3600) { scale <- 60 } else if (diff <= 2 * 86400) { scale <- 3600 } else if (diff <= 2 * 604800) { scale <- 86400 } else { scale <- 604800 } rng <- rng / scale breaks <- labeling::extended( rng[1], rng[2], n, Q = c(1, 2, 1.5, 4, 3), only.loose = FALSE ) as.difftime(breaks * scale, units = "secs") } } #' Breaks for exponentially transformed data #' #' This breaks function typically labels zero and the last `n - 1` integers of a #' range if that range is large enough (currently: 3). For smaller ranges, it #' uses [`breaks_extended()`]. #' #' @inheritParams breaks_extended #' #' @inherit breaks_width return #' #' @export #' @examples #' # Small range #' demo_continuous(c(100, 102), transform = "exp", breaks = breaks_exp()) #' # Large range #' demo_continuous(c(0, 100), transform = "exp", breaks = breaks_exp(n = 4)) breaks_exp <- function(n = 5, ...) { n_default <- n default <- extended_breaks(n = n_default, ...) function(x, n = n_default) { # Discard -Infs x <- sort(pmax(x, 0)) top <- floor(x[2]) if (top >= 3 && abs(diff(x)) >= 3) { unique(c(top - seq_len(min(top, n_default - 1)) + 1, 0)) } else { default(x) } } } scales/R/colour-ramp.R0000644000176200001440000000557614672302130014323 0ustar liggesusers#' Fast colour interpolation #' #' Returns a function that maps the interval \[0,1] to a set of colours. #' Interpolation is performed in the CIELAB colour space. Similar to #' \code{\link[grDevices]{colorRamp}(space = 'Lab')}, but hundreds of #' times faster, and provides results in `"#RRGGBB"` (or #' `"#RRGGBBAA"`) character form instead of RGB colour matrices. #' #' @param colors Colours to interpolate; must be a valid argument to #' [grDevices::col2rgb()]. This can be a character vector of #' `"#RRGGBB"` or `"#RRGGBBAA"`, colour names from #' [grDevices::colors()], or a positive integer that indexes into #' [grDevices::palette()]. #' @param na.color The colour to map to `NA` values (for example, #' `"#606060"` for dark grey, or `"#00000000"` for transparent) and #' values outside of \[0,1]. Can itself by `NA`, which will simply cause #' an `NA` to be inserted into the output. #' @param alpha Whether to include alpha transparency channels in interpolation. #' If `TRUE` then the alpha information is included in the interpolation. #' The returned colours will be provided in `"#RRGGBBAA"` format when needed, #' i.e., in cases where the colour is not fully opaque, so that the `"AA"` #' part is not equal to `"FF"`. Fully opaque colours will be returned in #' `"#RRGGBB"` format. If `FALSE`, the alpha information is discarded #' before interpolation and colours are always returned as `"#RRGGBB"`. #' #' @return A function that takes a numeric vector and returns a character vector #' of the same length with RGB or RGBA hex colours. #' #' @seealso \code{\link[grDevices]{colorRamp}} #' #' @export #' @examples #' ramp <- colour_ramp(c("red", "green", "blue")) #' show_col(ramp(seq(0, 1, length = 12))) colour_ramp <- function(colors, na.color = NA, alpha = TRUE) { if (length(colors) == 0) { cli::cli_abort("Must provide at least one colour to create a colour ramp") } if (length(colors) == 1) { return(structure( function(x) { ifelse(is.na(x), na.color, colors) }, safe_palette_func = TRUE )) } # farver is not currently case insensitive, but col2rgb() is colors <- tolower(colors) lab_in <- farver::decode_colour( colour = colors, alpha = TRUE, to = "lab", na_value = "transparent" ) x_in <- seq(0, 1, length.out = length(colors)) l_interp <- stats::approxfun(x_in, lab_in[, 1]) u_interp <- stats::approxfun(x_in, lab_in[, 2]) v_interp <- stats::approxfun(x_in, lab_in[, 3]) if (!alpha || all(lab_in[, 4] == 1)) { alpha_interp <- function(x) NULL } else { alpha_interp <- stats::approxfun(x_in, lab_in[, 4]) } fun <- function(x) { lab_out <- cbind(l_interp(x), u_interp(x), v_interp(x)) out <- farver::encode_colour(lab_out, alpha = alpha_interp(x), from = "lab") out[is.na(out)] <- na.color out } new_continuous_palette(fun, type = "colour", na_safe = !is.na(na.color)) } scales/R/pal-rescale.R0000644000176200001440000000077015002117500014233 0ustar liggesusers#' Rescale palette (continuous) #' #' Just rescales the input to the specific output range. Useful for #' alpha, size, and continuous position. #' #' @param range Numeric vector of length two, giving range of possible #' values. Should be between 0 and 1. #' @export pal_rescale <- function(range = c(0.1, 1)) { force(range) new_continuous_palette( function(x) rescale(x, range, c(0, 1)), "numeric", na_safe = FALSE ) } #' @export #' @rdname pal_rescale rescale_pal <- pal_rescale scales/R/pal-identity.R0000644000176200001440000000033314672302077014462 0ustar liggesusers#' Identity palette #' #' Leaves values unchanged - useful when the data is already scaled. #' #' @export pal_identity <- function() { function(x) x } #' @export #' @rdname pal_identity identity_pal <- pal_identity scales/R/scale-continuous.R0000644000176200001440000000463315002146671015353 0ustar liggesusers#' Continuous scale #' #' @param x vector of continuous values to scale #' @param palette palette to use. #' #' Built in palettes: #' \Sexpr[results=rd,stage=build]{scales:::seealso_pal()} #' @param na.value value to use for missing values #' @param trans transformation object describing the how to transform the #' raw data prior to scaling. Defaults to the identity transformation which #' leaves the data unchanged. #' #' Built in transformations: #' \Sexpr[results=rd,stage=build]{scales:::seealso_transform()}. #' @export #' @examples #' with(mtcars, plot(disp, mpg, cex = cscale(hp, pal_rescale()))) #' with(mtcars, plot(disp, mpg, cex = cscale(hp, pal_rescale(), #' trans = transform_sqrt() #' ))) #' with(mtcars, plot(disp, mpg, cex = cscale(hp, pal_area()))) #' with(mtcars, plot(disp, mpg, #' pch = 20, cex = 5, #' col = cscale(hp, pal_seq_gradient("grey80", "black")) #' )) cscale <- function( x, palette, na.value = NA_real_, trans = transform_identity() ) { check_object(trans, is.transform, "a {.cls transform} object") x <- trans$transform(x) limits <- train_continuous(x) map_continuous(palette, x, limits, na.value) } #' Train (update) a continuous scale #' #' Strips attributes and always returns a numeric vector #' #' @inheritParams train_discrete #' @export train_continuous <- function(new, existing = NULL, call = caller_env()) { if (is.null(new)) { return(existing) } new <- try_fetch( suppressWarnings(range(new, na.rm = TRUE, finite = TRUE)), error = function(cnd) new ) if (is.factor(new) || !typeof(new) %in% c("integer", "double")) { example <- unique(new) example <- example[seq_len(pmin(length(example), 5))] cli::cli_abort( c( "Discrete value supplied to a continuous scale.", i = "Example values: {.and {.val {example}}}." ), call = call ) } # Needs casting to numeric because some `new` vectors can misbehave when # combined with a NULL `existing` (#369) suppressWarnings(range( existing, as.numeric(new), na.rm = TRUE, finite = TRUE )) } # Map values for a continuous palette. # # @param oob out of bounds behaviour. Defaults to \code{\link{censor}} # which turns oob values into missing values. map_continuous <- function( palette, x, limits, na.value = NA_real_, oob = censor ) { x <- oob(rescale(x, from = limits)) pal <- palette(x) ifelse(!is.na(x), pal, na.value) } scales/R/palette-registry.R0000644000176200001440000001034115002117500015342 0ustar liggesusers.known_palettes <- new_environment(parent = empty_env()) #' Known palettes #' #' The scales packages keeps track of a set of palettes it considers 'known'. #' The benefit of a known palette is that it can be called by name in functions #' as `as_continuous_pal()` or `as_discrete_pal()`. #' #' @param name A string giving the palette name. #' @param palette A [palette][new_continuous_palette], `function` or character #' vector. #' @param warn_conflict A boolean which if `TRUE` (default), warns when #' replacing a known palette. #' @param ... Additional arguments to pass to palette when it is a function #' but not a palette class function. #' #' @return The `get_palette()` function returns a palette. The `set_palette()` #' function is called for side effects and returns nothing. #' @noRd #' #' @examples #' # Get one of the known palettes #' get_palette("hue") #' #' # Set a new custom palette #' cols <- c("palegreen", "deepskyblue", "magenta") #' set_palette("aurora", palette = cols) #' #' # Palette is now known #' "aurora" %in% palette_names() #' as_continuous_pal("aurora") #' #' # Resetting palettes #' reset_palettes() get_palette <- function(name, ...) { name <- tolower(name) if (!exists(name, envir = .known_palettes)) { cli::cli_abort("Unknown palette: {name}") } pal <- env_get(.known_palettes, name) # Palette could be factory, in which case we want the product, or # palette can be a palette function that isn't registered as such, # in which case we want the colours it gives if (is_function(pal) && !is_pal(pal)) { pal <- try_fetch( pal(...), error = function(cnd) { cli::cli_abort("Failed to interpret {name} as palette.", parent = cnd) } ) } if (is.character(pal)) { pal <- manual_pal(pal, type = "colour") } if (is_pal(pal)) { return(pal) } cli::cli_abort("Failed to interpret {name} as palette.") } set_palette <- function(name, palette, warn_conflict = TRUE) { name <- tolower(name) if (!is_function(palette) && !is_character(palette)) { cli::cli_abort( "The {.arg palette} argument must be a {.cls function} or \\ {.cls character} vector." ) } if (warn_conflict & exists(name, envir = .known_palettes)) { cli::cli_warn("Overwriting pre-existing {.val {name}} palette.") } env_bind(.known_palettes, !!name := palette) invisible(NULL) } palette_names <- function() { names(.known_palettes) } reset_palettes <- function() { env_unbind(.known_palettes, palette_names()) init_palettes() } init_palettes <- function() { register_hcl_pals() register_base_pals() register_viridis_pals() register_brewer_pals() register_dichromat_pals() set_palette("grey", pal_grey, warn_conflict = FALSE) set_palette("hue", pal_hue, warn_conflict = FALSE) } on_load(init_palettes()) register_hcl_pals <- function(n = 31) { names <- grDevices::hcl.pals() for (name in names) { fun <- colour_ramp(grDevices::hcl.colors(n, palette = name)) set_palette(name, fun, warn_conflict = FALSE) } invisible(NULL) } register_base_pals <- function() { if (getRversion() < "4.0.0") { return(invisible(NULL)) } names <- utils::getFromNamespace("palette.pals", "grDevices")() palette <- utils::getFromNamespace("palette.colors", "grDevices") for (name in names) { fun <- manual_pal(palette(palette = name), type = "colour") set_palette(name, fun, warn_conflict = FALSE) } invisible(NULL) } register_viridis_pals <- function() { names <- c( "magma", "inferno", "plasma", "viridis", "cividis", "rocket", "mako", "turbo" ) for (name in names) { fun <- pal_viridis(option = name) set_palette(name, fun, warn_conflict = FALSE) } invisible(NULL) } register_brewer_pals <- function() { names <- rownames(RColorBrewer::brewer.pal.info) for (name in names) { fun <- pal_brewer(palette = name) set_palette(name, fun, warn_conflict = FALSE) } invisible(NULL) } register_dichromat_pals <- function() { if (!is_installed("dichromat")) { return(invisible(NULL)) } names <- names(dichromat::colorschemes) for (name in names) { fun <- manual_pal(dichromat::colorschemes[[name]], type = "colour") set_palette(name, fun, warn_conflict = FALSE) } invisible(NULL) } scales/R/labels-retired.R0000644000176200001440000001016715002117500014742 0ustar liggesusers#' Older interface to `label_bytes()` #' #' @description #' `r lifecycle::badge('superseded')` #' #' These functions are kept for backward compatibility, but you should switch #' to [label_bytes()] for new code. #' #' @keywords internal #' @param symbol byte symbol to use. If "auto" the symbol used will be #' determined separately for each value of `x`. Valid symbols are "B", "kB", #' "MB", "GB", "TB", "PB", "EB", "ZB", and "YB" for SI units, and the "iB" #' variants for binary units. #' @param units which unit base to use, "binary" (1024 base) or "si" (1000 base) #' @export number_bytes_format <- function(symbol = "auto", units = "binary", ...) { force_all(symbol, units, ...) function(x) { number_bytes(x, symbol, units, ...) } } #' @export #' @rdname number_bytes_format number_bytes <- function( x, symbol = "auto", units = c("binary", "si"), accuracy = 1, ... ) { units <- match.arg(units, c("binary", "si")) powers <- si_powers[si_powers >= 3] / 3 # powers of 1000 prefix <- names(powers) symbols <- c( "B", switch( units, si = paste0(prefix, "B"), binary = paste0(toupper(prefix), "iB") ) ) symbol <- validate_byte_symbol(symbol, symbols) base <- switch(units, binary = 1024, si = 1000) if (symbol == "auto") { power <- findInterval(abs(x), base^powers) symbol <- symbols[1L + power] } else { power <- match(symbol, symbols) - 1L } number(x / base^power, accuracy = accuracy, suffix = paste0(" ", symbol), ...) } validate_byte_symbol <- function(symbol, symbols, default = "auto") { if (length(symbol) != 1) { cli::cli_abort( "{.arg symbol} must have length 1, not length {length(symbol)}" ) } valid_symbols <- c(default, symbols) if (!(symbol %in% valid_symbols)) { cli::cli_warn(c( "{.arg symbol} must be one of {.or {.or {valid_symbols}}}", i = "The provided value ({.val {symbol}}) will be changed to the default ({.val {default}})" )) symbol <- default } symbol } #' Format labels after transformation #' #' `r lifecycle::badge('superseded')` #' #' @param trans transformation to apply #' @param format additional formatter to apply after transformation #' @return a function with single parameter x, a numeric vector, that #' returns a character vector of list of expressions #' @export #' @keywords internal #' @examples #' tf <- trans_format("log10", scientific_format()) #' tf(10^1:6) trans_format <- function(trans, format = scientific_format()) { if (is.character(trans)) trans <- match.fun(trans) force(format) function(x) { x <- trans(x) format(x) } } #' Unit labels #' #' @description #' `r lifecycle::badge('superseded')` #' #' This function is kept for backward compatiblity; you should either use #' [label_number()] or [label_number_si()] instead. #' #' @inheritParams number_format #' @keywords internal #' @param unit The units to append. #' @param sep The separator between the number and the unit label. #' @export #' @examples #' # Label with units #' demo_continuous(c(0, 1), labels = unit_format(unit = "m")) #' # Labels in kg, but original data in g #' km <- unit_format(unit = "km", scale = 1e-3, digits = 2) #' demo_continuous(c(0, 2500), labels = km) unit_format <- function( accuracy = NULL, scale = 1, prefix = "", unit = "m", sep = " ", suffix = paste0(sep, unit), big.mark = NULL, decimal.mark = NULL, trim = TRUE, ... ) { number_format( accuracy = accuracy, scale = scale, prefix = prefix, suffix = suffix, big.mark = big.mark, decimal.mark = decimal.mark, trim = trim, ... ) } #' Label using `format()` #' #' @description #' `r lifecycle::badge('superseded')` #' #' This function is kept for backward compatiblity; you should either use #' [label_number()] or [label_date()] instead. #' #' @param ... Arguments passed on to [format()]. #' @export #' @keywords internal format_format <- function(...) { force_all(...) function(x) { if (!is.null(names(x))) { return(names(x)) } ret <- format(x, ..., trim = TRUE, justify = "left") # format.character() renders NA as "NA" ret[is.na(x)] <- NA ret } } scales/R/transform-compose.R0000644000176200001440000000550315002117500015520 0ustar liggesusers#' Compose two or more transformations together #' #' This transformer provides a general mechanism for composing two or more #' transformers together. The most important use case is to combine reverse #' with other transformations. #' #' @param ... One or more transformers, either specified with string or #' as individual transformer objects. #' @export #' @examples #' demo_continuous(10^c(-2:4), trans = "log10", labels = label_log()) #' demo_continuous(10^c(-2:4), trans = c("log10", "reverse"), labels = label_log()) transform_compose <- function(...) { trans_list <- lapply(list2(...), as.transform) if (length(trans_list) == 0) { cli::cli_abort( "{.fun transform_compose} must include at least 1 transformer to compose" ) } # Resolve domains. First push the domain of the first transformation all the # way forward through the sequence of transformations, intersecting it with # all domains along the way, to get the range. Then push the range back # through the inverses to get the domain. range <- trans_list[[1]]$transform(trans_list[[1]]$domain) for (trans in trans_list[-1]) { lower <- max(min(trans$domain), min(range)) upper <- min(max(trans$domain), max(range)) if (isTRUE(lower <= upper)) { range <- trans$transform(c(lower, upper)) } else { range <- c(NA_real_, NA_real_) break } } domain <- compose_rev(range, trans_list) if (any(is.na(domain))) { cli::cli_abort("Sequence of transformations yields invalid domain") } domain <- range(domain) names <- vapply(trans_list, "[[", "name", FUN.VALUE = character(1)) has_d_transform <- all(lengths(lapply(trans_list, "[[", "d_transform")) > 0) has_d_inverse <- all(lengths(lapply(trans_list, "[[", "d_inverse")) > 0) new_transform( paste0("composition(", paste0(names, collapse = ","), ")"), transform = function(x) compose_fwd(x, trans_list), inverse = function(x) compose_rev(x, trans_list), d_transform = if (has_d_transform) function(x) compose_deriv_fwd(x, trans_list), d_inverse = if (has_d_inverse) function(x) compose_deriv_rev(x, trans_list), breaks = function(x) trans_list[[1]]$breaks(x), domain = domain ) } #' @export #' @rdname transform_compose compose_trans <- transform_compose compose_fwd <- function(x, trans_list) { for (trans in trans_list) { x <- trans$transform(x) } x } compose_rev <- function(x, trans_list) { for (trans in rev(trans_list)) { x <- trans$inverse(x) } x } compose_deriv_fwd <- function(x, trans_list) { x_deriv <- 1 for (trans in trans_list) { x_deriv <- trans$d_transform(x) * x_deriv x <- trans$transform(x) } x_deriv } compose_deriv_rev <- function(x, trans_list) { x_deriv <- 1 for (trans in rev(trans_list)) { x_deriv <- trans$d_inverse(x) * x_deriv x <- trans$inverse(x) } x_deriv } scales/R/scale-discrete.R0000644000176200001440000000610615002146671014744 0ustar liggesusers#' Discrete scale #' #' @param x vector of discrete values to scale #' @param palette aesthetic palette to use #' @param na.value aesthetic to use for missing values #' @export #' @examples #' with(mtcars, plot(disp, mpg, #' pch = 20, cex = 3, #' col = dscale(factor(cyl), pal_brewer()) #' )) dscale <- function(x, palette, na.value = NA) { limits <- train_discrete(x) map_discrete(palette, x, limits, na.value) } is.discrete <- function(x) { !is.null(levels(x)) || is.character(x) || is.logical(x) } #' Train (update) a discrete scale #' #' @param new New data to add to scale #' @param existing Optional existing scale to update #' @param drop `TRUE`, will drop factor levels not associated with data #' @param na.rm If `TRUE`, will remove missing values #' @param fct Treat `existing` as if it came from a factor (ie. don't sort the range) #' @param call A call to display in error messages #' @export train_discrete <- function( new, existing = NULL, drop = FALSE, na.rm = FALSE, fct = NA, call = caller_env() ) { if (is.null(new)) { return(existing) } if (!is.discrete(new)) { example <- unique(new) example <- example[seq_len(pmin(length(example), 5))] cli::cli_abort( c( "Continuous value supplied to a discrete scale.", i = "Example values: {.and {.val {example}}}." ), call = call ) } discrete_range(existing, new, drop = drop, na.rm = na.rm, fct = fct) } discrete_range <- function(old, new, drop = FALSE, na.rm = FALSE, fct = NA) { new_is_factor <- is.factor(new) old_is_factor <- is.factor(old) || isTRUE(fct) new <- clevels(new, drop = drop, na.rm = na.rm) if (is.null(old)) { return(new) } if (old_is_factor && !is.factor(old)) { old <- factor(old, old) } if (!is.character(old)) { old <- clevels(old, na.rm = na.rm) } else { old <- sort(old, na.last = if (na.rm) NA else TRUE) } # If new is more rich than old it becomes the primary if (new_is_factor && !old_is_factor) { tmp <- old old <- new new <- tmp tmp <- old_is_factor old_is_factor <- new_is_factor new_is_factor <- tmp } new_levels <- setdiff(new, old) # Keep as a factor if we don't have any new levels if (length(new_levels) == 0) { return(old) } range <- c(old, new_levels) # Avoid sorting levels when dealing with factors. `old` will always be a # factor if either `new` or `old` was a factor going in if (old_is_factor) { return(range) } sort(range, na.last = if (na.rm) NA else TRUE) } clevels <- function(x, drop = FALSE, na.rm = FALSE) { if (is.null(x)) { character() } else if (!is.null(levels(x))) { if (drop && !is.character(x)) x <- droplevels(x) values <- levels(x) if (na.rm) { values <- values[!is.na(values)] } else if (any(is.na(x))) { values <- c(values, NA) } values } else { sort(unique(x), na.last = if (na.rm) NA else TRUE) } } map_discrete <- function(palette, x, limits, na.value = NA) { n <- length(limits) pal <- palette(n)[match(as.character(x), limits)] ifelse(!is.na(x), pal, na.value) } scales/R/label-glue.R0000644000176200001440000000260415002117500014052 0ustar liggesusers#' Interpolated labels #' #' Use `label_glue()` to perform string interpolation using the \pkg{glue} #' package. Enclosed expressions will be evaluated as R code. #' #' @inherit label_number return #' @param pattern A glue string used for formatting. The `x` variable holds the #' breaks, so that `"{x}"` (default) returns the breaks as-is. #' @param ... Arguments passed on to [`glue::glue()`]. #' @param parse Whether to return labels as expressions. #' @inheritParams glue::glue #' @export #' @family labels for continuous scales #' @family labels for discrete scales #' #' @examples #' # Example variables #' animal <- "penguin" #' species <- c("Adelie", "Chinstrap", "Emperor", "Gentoo") #' #' # Typical use, note that {x} will become the breaks #' demo_discrete(species, labels = label_glue("The {x}\n{animal}")) #' # It adapts to the breaks that are present #' demo_discrete(species[-3], labels = label_glue("The {x}\n{animal}")) #' # Contrary to directly glueing species + animal, which results in mislabelling! #' demo_discrete(species[-3], labels = glue::glue("The {species}\n{animal}")) label_glue <- function( pattern = "{x}", ..., parse = FALSE, .envir = caller_env() ) { args <- list2(...) force_all(pattern, parse, .envir) function(x) { x <- inject(glue::glue_data(list(x = x), pattern, !!!args, .envir = .envir)) if (parse) { x <- parse_safe(x) } x } } scales/R/label-compose.R0000644000176200001440000000216115002117500014561 0ustar liggesusers#' Compose two or more label formatters together #' #' This labeller provides a general mechanism for composing two or more #' labellers together. #' #' @inherit label_number return #' @param ... One or more labelling functions. These will be applied to breaks #' consecutively. #' [Lambda syntax][rlang::as_function] is allowed. #' @param call A call to display in error messages. #' #' @export #' #' @examples #' demo_continuous( #' c(-100, 100), #' labels = compose_label(abs, number, \(x) paste0(x, " foobar"), toupper) #' ) #' #' # Same result #' demo_continuous( #' c(-100, 100), #' labels = compose_label(abs, label_number(suffix = " FOOBAR")) #' ) compose_label <- function(..., call = caller_env()) { label_list <- list2(...) if (length(label_list) == 0) { return(identity) } label_list <- lapply(label_list, as_function, call = call) function(x) { if (length(x) == 0) { return(character()) } orig <- x for (labeller in label_list) { x <- labeller(x) attr(x, "orig_breaks") <- orig } x[is.na(orig)] <- NA names(x) <- names(x) %||% names(orig) x } } scales/R/date-time.R0000644000176200001440000000355115002117500013714 0ustar liggesusers# Minimal date time code so no external dependencies needed, and # we can do the date operations we need. Need to look at this again once we # switch to S4 for lubridate. "%||%" <- function(a, b) if (!is.null(a)) a else b floor_date <- function(date, time) { prec <- parse_unit_spec(time) if (prec$unit == "day") { structure(round_any(as.numeric(date), prec$mult), class = "Date") } else { as.Date(cut(date, time, right = TRUE, include.lowest = TRUE)) } } floor_time <- function(date, time) { to_time <- function(x) { force(x) structure( x, class = c("POSIXt", "POSIXct"), tzone = attr(date, "tzone", exact = TRUE) %||% "" ) } prec <- parse_unit_spec(time) if (prec$unit == "sec") { to_time(round_any(as.numeric(date), prec$mult)) } else if (prec$unit == "min") { to_time(round_any(as.numeric(date), prec$mult * 60)) } else { as.POSIXct( cut(date, time, right = TRUE, include.lowest = TRUE), tz = attr(date, "tzone", exact = TRUE) %||% "" ) } } ceiling_date <- function(date, time) { prec <- parse_unit_spec(time) up <- c("day" = 1, "week" = 7, "month" = 31, "year" = 365) date <- date + prec$mult * up[prec$unit] floor_date(date, time) } ceiling_time <- function(date, time) { date <- date + unit_seconds(time) floor_time(date, time) } unit_seconds <- function(unitspec) { prec <- parse_unit_spec(unitspec) unit_in_seconds <- c( "sec" = 1, "min" = 60, "hour" = 3600, c("day" = 1, "week" = 7, "month" = 31, "year" = 365) * 3600 * 24 ) prec$mult * unit_in_seconds[prec$unit] } parse_unit_spec <- function(unitspec) { parts <- strsplit(unitspec, " ")[[1]] if (length(parts) == 1) { mult <- 1 unit <- unitspec } else { mult <- as.numeric(parts[[1]]) unit <- parts[[2]] } unit <- gsub("s$", "", unit) list(unit = unit, mult = mult) } scales/R/breaks-retired.R0000644000176200001440000000712115002117500014743 0ustar liggesusers#' Regularly spaced dates #' #' @description #' `r lifecycle::badge('superseded')` #' #' Use `breaks_width()` instead. #' #' @param width an interval specification, one of "sec", "min", "hour", #' "day", "week", "month", "year". Can be by an integer and a space, or #' followed by "s". Fractional seconds are supported. #' @keywords internal #' @export date_breaks <- function(width = "1 month") { force(width) function(x) fullseq(x, width) } #' Pretty breaks on transformed scale #' #' @description #' `r lifecycle::badge('superseded')` #' #' These often do not produce very attractive breaks. #' #' @param trans function of single variable, `x`, that given a numeric #' vector returns the transformed values #' @param inv inverse of the transformation function #' @param n desired number of ticks #' @param ... other arguments passed on to pretty #' @keywords internal #' @export #' @examples #' trans_breaks("log10", function(x) 10^x)(c(1, 1e6)) #' trans_breaks("sqrt", function(x) x^2)(c(1, 100)) #' trans_breaks(function(x) 1 / x, function(x) 1 / x)(c(1, 100)) #' trans_breaks(function(x) -x, function(x) -x)(c(1, 100)) trans_breaks <- function(trans, inv, n = 5, ...) { trans <- match.fun(trans) inv <- match.fun(inv) force_all(n, ...) n_default <- n function(x, n = n_default) { inv(pretty(trans(x), n, ...)) } } #' Compute breaks for continuous scale #' #' @description #' `r lifecycle::badge('superseded')` #' #' This function wraps up the components needed to go from a continuous range #' to a set of breaks and labels suitable for display on axes or legends. #' #' @param range numeric vector of length 2 giving the range of the underlying #' data #' @param breaks either a vector of break values, or a break function that #' will make a vector of breaks when given the range of the data #' @param labels either a vector of labels (character vector or list of #' expression) or a format function that will make a vector of labels when #' called with a vector of breaks. Labels can only be specified manually if #' breaks are - it is extremely dangerous to supply labels if you don't know #' what the breaks will be. #' @keywords internal #' @export #' @examples #' cbreaks(c(0, 100)) #' cbreaks(c(0, 100), breaks_pretty(3)) #' cbreaks(c(0, 100), breaks_pretty(10)) #' cbreaks(c(1, 100), log_breaks()) #' cbreaks(c(1, 1e4), log_breaks()) #' #' cbreaks(c(0, 100), labels = math_format()) #' cbreaks(c(0, 1), labels = percent_format()) #' cbreaks(c(0, 1e6), labels = comma_format()) #' cbreaks(c(0, 1e6), labels = dollar_format()) #' cbreaks(c(0, 30), labels = dollar_format()) #' #' # You can also specify them manually: #' cbreaks(c(0, 100), breaks = c(15, 20, 80)) #' cbreaks(c(0, 100), breaks = c(15, 20, 80), labels = c(1.5, 2.0, 8.0)) #' cbreaks(c(0, 100), #' breaks = c(15, 20, 80), #' labels = expression(alpha, beta, gamma) #' ) cbreaks <- function( range, breaks = extended_breaks(), labels = scientific_format() ) { if (zero_range(range)) { return(list(breaks = range[1], labels = format(range[1]))) } if (is.function(breaks)) { breaks <- breaks(range) if (!is.function(labels)) { cli::cli_abort( "{.arg labels} can only be manually specified in conjunction with {.arg breaks}" ) } } if (is.function(labels)) { labels <- labels(breaks) } else { if (length(labels) != length(breaks)) { cli::cli_abort("{.arg labels} and {.arg breaks} must be same length") } if (is.expression(labels)) { labels <- as.list(labels) } else { labels <- as.character(labels) } } list(breaks = breaks, labels = labels) } scales/R/breaks-log.R0000644000176200001440000001504215002117500014067 0ustar liggesusers#' Breaks for log axes #' #' This algorithm starts by looking for integer powers of `base`. If that #' doesn't provide enough breaks, it then looks for additional intermediate #' breaks which are integer multiples of integer powers of base. If that fails #' (which it can for very small ranges), we fall back to [extended_breaks()] #' #' @details #' The algorithm starts by looking for a set of integer powers of `base` that #' cover the range of the data. If that does not generate at least `n - 2` #' breaks, we look for an integer between 1 and `base` that splits the interval #' approximately in half. For example, in the case of `base = 10`, this integer #' is 3 because `log10(3) = 0.477`. This leaves 2 intervals: `c(1, 3)` and #' `c(3, 10)`. If we still need more breaks, we look for another integer #' that splits the largest remaining interval (on the log-scale) approximately #' in half. For `base = 10`, this is 5 because `log10(5) = 0.699`. #' #' The generic algorithm starts with a set of integers `steps` containing #' only 1 and a set of candidate integers containing all integers larger than 1 #' and smaller than `base`. Then for each remaining candidate integer #' `x`, the smallest interval (on the log-scale) in the vector #' `sort(c(x, steps, base))` is calculated. The candidate `x` which #' yields the largest minimal interval is added to `steps` and removed from #' the candidate set. This is repeated until either a sufficient number of #' breaks, `>= n-2`, are returned or all candidates have been used. #' @param n desired number of breaks #' @param base base of logarithm to use #' #' @inherit breaks_width return #' #' @export #' @examples #' demo_log10(c(1, 1e5)) #' demo_log10(c(1, 1e6)) #' #' # Request more breaks by setting n #' demo_log10(c(1, 1e6), breaks = breaks_log(6)) #' #' # Some tricky ranges #' demo_log10(c(2000, 9000)) #' demo_log10(c(2000, 14000)) #' demo_log10(c(2000, 85000), expand = c(0, 0)) #' #' # An even smaller range that requires falling back to linear breaks #' demo_log10(c(1800, 2000)) breaks_log <- function(n = 5, base = 10) { force_all(n, base) n_default <- n function(x, n = n_default) { raw_rng <- suppressWarnings(range(x, na.rm = TRUE)) if (any(!is.finite(raw_rng))) { return(numeric()) } rng <- log(raw_rng, base = base) min <- floor(rng[1]) max <- ceiling(rng[2]) if (max == min) { return(base^min) } by <- floor((max - min) / n) + 1 breaks <- base^seq(min, max, by = by) relevant_breaks <- base^rng[1] <= breaks & breaks <= base^rng[2] if (sum(relevant_breaks) >= (n - 2)) { return(breaks) } # the easy solution to get more breaks is to decrease 'by' while (by > 1) { by <- by - 1 breaks <- base^seq(min, max, by = by) relevant_breaks <- base^rng[1] <= breaks & breaks <= base^rng[2] if (sum(relevant_breaks) >= (n - 2)) { return(breaks) } } log_sub_breaks(rng, n = n, base = base) } } #' @export #' @usage NULL #' @rdname breaks_log log_breaks <- breaks_log #' Minor breaks for log-10 axes #' #' This break function is designed to mark every power, multiples of 5 and/or 1 #' of that power for base 10. #' #' @param detail Any of `1`, `5` and `10` to mark multiples of #' powers, multiples of 5 of powers or just powers respectively. #' @param smallest Smallest absolute value to mark when the range includes #' negative numbers. #' #' @return A function to generate minor ticks. #' #' @export #' #' @examples #' # Standard usage with log10 scale #' demo_log10(c(1, 1e10), minor_breaks = minor_breaks_log()) #' # Increasing detail over many powers #' demo_log10(c(1, 1e10), minor_breaks = minor_breaks_log(detail = 1)) #' # Adjusting until where to draw minor breaks #' demo_continuous( #' c(-1000, 1000), #' transform = asinh_trans(), #' minor_breaks = minor_breaks_log(smallest = 1) #' ) minor_breaks_log <- function(detail = NULL, smallest = NULL) { if (!is.null(detail) && (!length(detail) == 1 || !detail %in% c(1, 5, 10))) { cli::cli_abort("The {.arg detail} argument must be one of 1, 5 or 10.") } if ( !is.null(smallest) && (!length(smallest) == 1 || smallest < 1e-100 || !is.finite(smallest)) ) { cli::cli_abort( "The {.arg smallest} argument must be a finite, positive, non-zero number." ) } force(smallest) function(x, ...) { has_negatives <- any(x <= 0) if (has_negatives) { large <- max(abs(x)) small <- smallest %||% min(c(1, large) * 0.1) x <- sort(c(small * 10, large)) } start <- floor(log10(min(x))) - 1L end <- ceiling(log10(max(x))) + 1L if (is.null(detail)) { i <- findInterval(abs(end - start), c(8, 15), left.open = TRUE) + 1L detail <- c(1, 5, 10)[i] } ladder <- 10^seq(start, end, by = 1L) tens <- fives <- ones <- numeric() if (detail %in% c(10, 5, 1)) { tens <- ladder } if (detail %in% c(5, 1)) { fives <- 5 * ladder } if (detail == 1) { ones <- as.vector(outer(1:9, ladder)) ones <- setdiff(ones, c(tens, fives)) } if (has_negatives) { tens <- tens[tens >= small] tens <- c(tens, -tens, 0) fives <- fives[fives >= small] fives <- c(fives, -fives) ones <- ones[ones >= small] ones <- c(ones, -ones) } ticks <- c(tens, fives, ones) n <- c(length(tens), length(fives), length(ones)) attr(ticks, "detail") <- rep(c(10, 5, 1), n) ticks } } #' @author Thierry Onkelinx, \email{thierry.onkelinx@inbo.be} #' @noRd log_sub_breaks <- function(rng, n = 5, base = 10) { min <- floor(rng[1]) max <- ceiling(rng[2]) if (base <= 2) { return(base^(min:max)) } steps <- 1 # 'delta()' calculates the smallest distance in the log scale between the # currectly selected breaks and a new candidate 'x' delta <- function(x) { min(diff(log(sort(c(x, steps, base)), base = base))) } candidate <- seq_len(base) candidate <- candidate[1 < candidate & candidate < base] while (length(candidate)) { best <- which.max(vapply(candidate, delta, 0)) steps <- c(steps, candidate[best]) candidate <- candidate[-best] breaks <- as.vector(outer(base^seq(min, max), steps)) relevant_breaks <- base^rng[1] <= breaks & breaks <= base^rng[2] if (sum(relevant_breaks) >= (n - 2)) { break } } if (sum(relevant_breaks) >= (n - 2)) { breaks <- sort(breaks) lower_end <- pmax(min(which(base^rng[1] <= breaks)) - 1, 1) upper_end <- pmin(max(which(breaks <= base^rng[2])) + 1, length(breaks)) breaks[lower_end:upper_end] } else { extended_breaks(n = n)(base^rng) } } scales/R/utils.R0000644000176200001440000000564015002117500013204 0ustar liggesusers# Evaluates all arguments (see #81) force_all <- function(...) list(...) demo_ggplot <- function(x, scale_name, ...) { call <- substitute(list(...)) call[[1]] <- as.name(scale_name) cat(paste0(deparse(call), "\n", collapse = "")) if (!requireNamespace("ggplot2", quietly = TRUE)) { cli::cli_inform("Skipping; {.pkg ggplot2} not installed") return(invisible()) } scale <- getExportedValue("ggplot2", scale_name) df <- data.frame(x = x, stringsAsFactors = FALSE) ggplot2::ggplot(df, ggplot2::aes(x, 1)) + ggplot2::geom_blank() + scale(NULL, ...) + ggplot2::scale_y_continuous(NULL, breaks = NULL) + ggplot2::theme(aspect.ratio = 1 / 5) } #' Demonstrate scales functions with ggplot2 code #' #' These functions generate ggplot2 code needed to use scales functions for #' real code. #' #' @param x A vector of data #' @keywords internal #' @export demo_continuous <- function(x, ...) { demo_ggplot(x, "scale_x_continuous", ...) } #' @rdname demo_continuous #' @export demo_log10 <- function(x, ...) { demo_ggplot(x, "scale_x_log10", ...) } #' @rdname demo_continuous #' @export demo_discrete <- function(x, ...) { demo_ggplot(x, "scale_x_discrete", ...) } #' @rdname demo_continuous #' @export demo_datetime <- function(x, ...) { demo_ggplot(x, "scale_x_datetime", ...) } #' @rdname demo_continuous #' @export demo_time <- function(x, ...) { demo_ggplot(x, "scale_x_time", ...) } #' @rdname demo_continuous #' @export demo_timespan <- function(x, ...) { demo_ggplot(x, "scale_x_continuous", ...) } # Based on rlang/R/standalone-vctrs.R shim recycle_common <- function(..., size = NULL, call = caller_env()) { x <- list2(...) sizes <- lengths(x) n <- unique(sizes) if (length(n) == 1 && is.null(size)) { return(x) } n <- setdiff(n, 1L) ns <- length(n) if (ns == 1) { if (is.null(size)) { size <- n } else if (n != size) { bad <- names(sizes)[sizes != size] cli::cli_abort( "Cannot recycle {.and {.arg {bad}}} to length {size}.", call = call ) } } else { bad <- names(sizes)[!(sizes %in% c(1, size))] what <- if (is.null(size)) "a common size" else paste0("length ", size) cli::cli_abort( "Cannot recycle {.and {.arg {bad}}} to {what}.", call = call ) } to_recycle <- sizes == 1L x[to_recycle] <- lapply(x[to_recycle], rep_len, length.out = size) x } as_cli <- function(..., env = caller_env()) { cli::cli_fmt(cli::cli_text(..., .envir = env)) } check_object <- function( x, check_fun, what, ..., allow_null = FALSE, arg = caller_arg(x), call = caller_env() ) { if (!missing(x)) { if (check_fun(x)) { return(invisible(NULL)) } if (allow_null && is_null(x)) { return(invisible(NULL)) } } stop_input_type( x, as_cli(what), ..., allow_null = allow_null, arg = arg, call = call ) } .onLoad <- function(lib, pkg) { run_on_load() } scales/R/pal-hue.R0000644000176200001440000000330115002117500013367 0ustar liggesusers#' Hue palette (discrete) #' #' @param h range of hues to use, in \[0, 360] #' @param l luminance (lightness), in \[0, 100] #' @param c chroma (intensity of colour), maximum value varies depending on #' combination of hue and luminance. #' @param h.start hue to start at #' @param direction direction to travel around the colour wheel, #' 1 = clockwise, -1 = counter-clockwise #' @export #' @examples #' show_col(pal_hue()(4)) #' show_col(pal_hue()(9)) #' show_col(pal_hue(l = 90)(9)) #' show_col(pal_hue(l = 30)(9)) #' #' show_col(pal_hue()(9)) #' show_col(pal_hue(direction = -1)(9)) #' show_col(pal_hue(h.start = 30)(9)) #' show_col(pal_hue(h.start = 90)(9)) #' #' show_col(pal_hue()(9)) #' show_col(pal_hue(h = c(0, 90))(9)) #' show_col(pal_hue(h = c(90, 180))(9)) #' show_col(pal_hue(h = c(180, 270))(9)) #' show_col(pal_hue(h = c(270, 360))(9)) pal_hue <- function( h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, direction = 1 ) { if (length(h) != 2) cli::cli_abort("{.arg h} must have length 2.") if (length(l) != 1) cli::cli_abort("{.arg l} must have length 1.") if (length(c) != 1) cli::cli_abort("{.arg c} must have length 1.") force_all(h, c, l, h.start, direction) fun <- function(n) { if (n == 0) { cli::cli_abort("Must request at least one colour from a hue palette.") } if ((diff(h) %% 360) < 1) { h[2] <- h[2] - 360 / n } hues <- seq(h[1], h[2], length.out = n) hues <- (hues + h.start) %% 360 hcl <- cbind(hues, c, l) pal <- farver::encode_colour(hcl, from = "hcl") if (direction == -1) { rev(pal) } else { pal } } new_discrete_palette(fun, "colour", 255) } #' @export #' @rdname pal_hue hue_pal <- pal_hue scales/R/label-log.R0000644000176200001440000000341615002117500013701 0ustar liggesusers#' Label numbers in log format (10^3, 10^6, etc) #' #' `label_log()` and `format_log()` display numbers as base^exponent, using #' superscript formatting. `label_log()` returns expressions suitable for #' labelling in scales, whereas `format_log()` returns deparsed text. #' #' @inherit label_number return #' @param x A numeric vector to format #' @param base Base of logarithm to use #' @param digits Number of significant digits to show for the exponent. Argument #' is passed on to [base::format()]. #' @param signed Should a `+` or `-` be displayed as a prefix? The #' default, `NULL`, displays signs if there are zeroes or negative numbers #' present. #' @param ... Passed on to `format()`. #' #' @seealso [breaks_log()] for the related breaks algorithm. #' @export #' @family labels for log scales #' @examples #' demo_log10(c(1, 1e5), labels = label_log()) #' demo_log10(c(1, 1e5), breaks = breaks_log(base = 2), labels = label_log(base = 2)) #' format_log(c(0.1, 1, 10)) label_log <- function(base = 10, digits = 3, signed = NULL) { function(x) { text <- format_log(x, base = base, signed = signed, digits = digits) ret <- parse_safe(text) # restore NAs from input vector ret[is.na(x)] <- NA ret } } #' @export #' @rdname label_log format_log <- function(x, base = 10, signed = NULL, ...) { if (length(x) == 0) { return(character()) } prefix <- rep("", length(x)) finites <- x[is.finite(x)] signed <- signed %||% any(finites <= 0) if (signed) { sign <- sign(x) prefix[sign == +1] <- "+" prefix[sign == -1] <- "-" x <- abs(x) x[x == 0] <- 1 } exponent <- format(zapsmall(log(x, base = base)), ...) text <- paste0(prefix, base, "^", exponent) if (signed) { text[sign == 0] <- "0" } text[is.na(x)] <- NA text } scales/R/pal-manual.R0000644000176200001440000000164415002117500014073 0ustar liggesusers#' Manual palette (discrete) #' #' @param values vector of values to be used as a palette. #' @inheritParams new_continuous_palette #' @export pal_manual <- function(values, type = NULL) { force(values) fun <- function(n) { n_values <- length(values) if (n > n_values) { cli::cli_warn( "This manual palette can handle a maximum of {n_values} values. You have supplied {n}" ) } unname(values[seq_len(n)]) } type <- type %||% guess_pal_type(values) new_discrete_palette( fun, type, length(values) ) } #' @export #' @rdname pal_manual manual_pal <- pal_manual guess_pal_type <- function(x) { if (is.numeric(x)) { "numeric" } else if (all(is_color(x))) { "colour" } else { typeof(x) } } is_color <- function(x) { # '#' followed by 3,4,6 or 8 hex digits grepl("^#(([[:xdigit:]]{2}){3,4}|([[:xdigit:]]){3,4})$", x) | x %in% grDevices::colours() } scales/R/pal-viridis.R0000644000176200001440000000210615002117500014261 0ustar liggesusers#' Viridis palette #' #' @inheritParams viridisLite::viridis #' @param begin,end The (corrected) hue in `[0,1]` at which the color map #' begins and ends. #' @param option A character string indicating the color map option to use. #' Eight options are available: #' * `"magma"` (or `"A"`) #' * `"inferno"` (or `"B"`) #' * `"plasma"` (or `"C"`) #' * `"viridis"` (or `"D"`) #' * `"cividis"` (or `"E"`) #' * `"rocket"` (or `"F"`) #' * `"mako"` (or `"G"`) #' * `"turbo"` (or `"H"`) #' @references #' @export #' @examples #' show_col(pal_viridis()(10)) #' show_col(pal_viridis(direction = -1)(6)) #' show_col(pal_viridis(begin = 0.2, end = 0.8)(4)) #' show_col(pal_viridis(option = "plasma")(6)) pal_viridis <- function( alpha = 1, begin = 0, end = 1, direction = 1, option = "D" ) { force_all(alpha, begin, end, direction, option) fun <- function(n) { viridisLite::viridis(n, alpha, begin, end, direction, option) } new_discrete_palette(fun, "colour", 255) } #' @export #' @rdname pal_viridis viridis_pal <- pal_viridis scales/R/minor_breaks.R0000644000176200001440000000447014672302077014540 0ustar liggesusers#' Minor breaks #' #' Generate minor breaks between major breaks either spaced with a fixed width, #' or having a fixed number. #' #' @inheritParams breaks_width #' @export #' @examples #' demo_log10(c(1, 1e6)) #' if (FALSE) { #' # Requires https://github.com/tidyverse/ggplot2/pull/3591 #' demo_log10(c(1, 1e6), minor_breaks = minor_breaks_n(10)) #' } minor_breaks_width <- function(width, offset) { # Check that has needed version of ggplot2 f <- breaks_width(width, offset) function(range, breaks) { loop_breaks(range, breaks, f) } } #' @export #' @param n number of breaks #' @rdname minor_breaks_width minor_breaks_n <- function(n) { # Check that has needed version of ggplot2 force(n) f <- function(rng) seq(rng[1], rng[2], length = n) function(range, breaks) { loop_breaks(range, breaks, f) } } loop_breaks <- function(range, breaks, f) { n <- length(breaks) out <- vector("list", n + 1) out[[1]] <- f(c(range[[1]], breaks[[1]])) for (i in seq2(2, n)) { out[[i]] <- f(breaks[c(i - 1L, i)]) } out[[n + 1]] <- f(c(breaks[[n]], range[[2]])) unique(unlist(out)) } # old interface ----------------------------------------------------------- #' Minor breaks #' #' Places minor breaks between major breaks. #' #' @param reverse if TRUE, calculates the minor breaks for a reversed scale #' @keywords internal #' @export #' @examples #' m <- extended_breaks()(c(1, 10)) #' regular_minor_breaks()(m, c(1, 10), n = 2) #' #' n <- extended_breaks()(c(0, -9)) #' regular_minor_breaks(reverse = TRUE)(n, c(0, -9), n = 2) regular_minor_breaks <- function(reverse = FALSE) { function(b, limits, n) { b <- b[!is.na(b)] if (length(b) < 2) { return() } bd <- diff(b)[1] # Allow minor breaks to extend outside major breaks towards limits if (!reverse) { if (min(limits) < min(b)) b <- c(b[1] - bd, b) if (max(limits) > max(b)) b <- c(b, b[length(b)] + bd) } else { if (max(limits) > max(b)) b <- c(b[1] - bd, b) if (min(limits) < min(b)) b <- c(b, b[length(b)] + bd) } # Find minor breaks between major breaks seq_between <- function(a, b) { seq(a, b, length.out = n + 1)[-(n + 1)] } breaks <- unlist(Map(seq_between, b[-length(b)], b[-1])) # Add the final break back breaks <- c(breaks, b[length(b)]) breaks } } scales/R/round-any.R0000644000176200001440000000070014672302077013771 0ustar liggesusers# Methods used to round to multiple of any number. Added from plyr. round_any <- function(x, accuracy, f = round) { UseMethod("round_any") } #' @export round_any.numeric <- function(x, accuracy, f = round) { f(x / accuracy) * accuracy } #' @export round_any.POSIXct <- function(x, accuracy, f = round) { tz <- format(x[1], "%Z") xr <- round_any(as.numeric(x), accuracy, f) as.POSIXct(xr, origin = "1970-01-01 00:00.00 UTC", tz = tz) } scales/R/label-dictionary.R0000644000176200001440000000313615002117500015264 0ustar liggesusers#' Labels from lookup tables #' #' Use `label_dictionary()` for looking up succinct breaks in a named character #' vector giving complete labels. #' #' @inherit label_number return #' @param dictionary A named character vector of labels. The names are expected #' to match the breaks, and the values become the labels. #' @param nomatch A string to label breaks that do not match any name in #' `dictionary`. When `NULL` (default), the breaks are not translated but are #' kept as-is. #' #' @export #' @family labels for discrete scales #' @examples #' # Example lookup table #' lut <- c( #' "4" = "four wheel drive", #' "r" = "rear wheel drive", #' "f" = "front wheel drive" #' ) #' #' # Typical usage #' demo_discrete(c("4", "r", "f"), labels = label_dictionary(lut)) #' # By default, extra values ('w') will remain as-is #' demo_discrete(c("4", "r", "f", "w"), labels = label_dictionary(lut)) #' # Alternatively, you can relabel extra values #' demo_discrete( #' c("4", "r", "f", "w"), #' labels = label_dictionary(lut, nomatch = "unknown") #' ) label_dictionary <- function(dictionary = character(), nomatch = NULL) { if (!is.character(dictionary)) { cli::cli_abort("The {.arg dictionary} argument must be a character vector.") } if (!is_named2(dictionary)) { cli::cli_abort("The {.arg dictionary} argument must have names.") } names <- names(dictionary) values <- unname(dictionary) force(nomatch) function(x) { i <- match(x, names, nomatch = NA_integer_) out <- values[i] missing <- is.na(i) out[missing] <- if (is.null(nomatch)) x[missing] else nomatch out } } scales/R/label-scientific.R0000644000176200001440000000350415002117500015236 0ustar liggesusers#' Label numbers with scientific notation (e.g. 1e05, 1.5e-02) #' #' @inherit label_number return params #' @param digits Number of digits to show before exponent. #' @param prefix,suffix Symbols to display before and after value. #' @param ... Other arguments passed on to [base::format()]. #' @family labels for continuous scales #' @family labels for log scales #' @export #' @examples #' demo_continuous(c(1, 10)) #' demo_continuous(c(1, 10), labels = label_scientific()) #' demo_continuous(c(1, 10), labels = label_scientific(digits = 3)) #' #' demo_log10(c(1, 1e9)) label_scientific <- function( digits = 3, scale = 1, prefix = "", suffix = "", decimal.mark = NULL, trim = TRUE, ... ) { force_all(digits, scale, prefix, suffix, decimal.mark, trim, ...) function(x) { scientific( x, digits = digits, scale = scale, prefix = prefix, suffix = suffix, decimal.mark = decimal.mark, ... ) } } #' Superseded interface to `label_scientific()` #' #' @description #' `r lifecycle::badge("superseded")` #' #' These functions are kept for backward compatibility; you should switch #' to [label_scientific()] for new code. #' #' @keywords internal #' @export #' @inheritParams label_scientific scientific_format <- label_scientific #' @export #' @rdname scientific_format scientific <- function( x, digits = 3, scale = 1, prefix = "", suffix = "", decimal.mark = NULL, trim = TRUE, ... ) { if (length(x) == 0) { return(character()) } x <- signif(x * scale, digits) decimal.mark <- decimal.mark %||% getOption("scales.decimal.mark", default = ".") ret <- paste0( prefix, format(x, decimal.mark = decimal.mark, trim = trim, scientific = TRUE, ...), suffix ) # restore NAs from input vector ret[is.na(x)] <- NA names(ret) <- names(x) ret } scales/R/label-currency.R0000644000176200001440000001237515002117500014756 0ustar liggesusers#' Label currencies ($100, €2.50, etc) #' #' Format numbers as currency, rounding values to monetary or fractional #' monetary using unit a convenient heuristic. #' #' @inherit label_number return params #' @param accuracy,largest_with_fractional Number to round #' to. If `NULL`, the default, values will be rounded to the nearest integer, #' unless any of the values has non-zero fractional component (e.g. cents) and #' the largest value is less than `largest_with_fractional` which by default #' is 100,000. #' @param prefix,suffix Symbols to display before and after value. #' #' @inheritDotParams number #' @export #' @family labels for continuous scales #' @examples #' demo_continuous(c(0, 1), labels = label_currency()) #' demo_continuous(c(1, 100), labels = label_currency()) #' #' # Customise currency display with prefix and suffix #' demo_continuous(c(1, 100), labels = label_currency(prefix = "USD ")) #' yen <- label_currency( #' prefix = "¥", #' suffix = "", #' big.mark = ".", #' decimal.mark = "," #' ) #' demo_continuous(c(1000, 1100), labels = yen) #' #' # Use style_negative = "parens" for finance style display #' demo_continuous(c(-100, 100), labels = label_currency(style_negative = "parens")) #' #' # Use scale_cut to use K/M/B where appropriate #' demo_log10(c(1, 1e16), #' breaks = log_breaks(7, 1e3), #' labels = label_currency(scale_cut = cut_short_scale()) #' ) #' # cut_short_scale() uses B = one thousand million #' # cut_long_scale() uses B = one million million #' demo_log10(c(1, 1e16), #' breaks = log_breaks(7, 1e3), #' labels = label_currency(scale_cut = cut_long_scale()) #' ) #' #' # You can also define your own breaks #' gbp <- label_currency( #' prefix = "\u00a3", #' scale_cut = c(0, k = 1e3, m = 1e6, bn = 1e9, tn = 1e12) #' ) #' demo_log10(c(1, 1e12), breaks = log_breaks(5, 1e3), labels = gbp) label_currency <- function( accuracy = NULL, scale = 1, prefix = NULL, suffix = NULL, big.mark = NULL, decimal.mark = NULL, trim = TRUE, largest_with_fractional = 100000, ... ) { force_all( accuracy, scale, prefix, suffix, big.mark, decimal.mark, trim, largest_with_fractional, ... ) function(x) { dollar( x, accuracy = accuracy, scale = scale, prefix = prefix, suffix = suffix, big.mark = big.mark, decimal.mark = decimal.mark, trim = trim, largest_with_cents = largest_with_fractional, ... ) } } needs_cents <- function(x, threshold) { if (all(is.na(x))) { return(FALSE) } if (max(abs(x), na.rm = TRUE) > threshold) { return(FALSE) } !all(x == floor(x), na.rm = TRUE) } #' Superseded interface to `label_currency()` #' #' @description #' `r lifecycle::badge("superseded")` #' #' These functions are kept for backward compatibility; you should switch #' to [label_currency()] for new code. #' #' @keywords internal #' @export #' @inheritParams label_currency #' @param largest_with_cents Like `largest_with_fractional()` in #' [label_currency()] #' @param negative_parens `r lifecycle::badge("deprecated")` Use #' `style_negative = "parens"` instead. dollar_format <- function( accuracy = NULL, scale = 1, prefix = "$", suffix = "", big.mark = ",", decimal.mark = ".", trim = TRUE, largest_with_cents = 100000, negative_parens = deprecated(), ... ) { force_all( accuracy, scale, prefix, suffix, big.mark, decimal.mark, trim, largest_with_cents, negative_parens, ... ) function(x) { dollar( x, accuracy = accuracy, scale = scale, prefix = prefix, suffix = suffix, big.mark = big.mark, decimal.mark = decimal.mark, trim = trim, largest_with_cents = largest_with_cents, negative_parens = negative_parens, ... ) } } #' @export #' @rdname dollar_format #' @param x A numeric vector dollar <- function( x, accuracy = NULL, scale = 1, prefix = NULL, suffix = NULL, big.mark = NULL, decimal.mark = NULL, trim = TRUE, largest_with_cents = 100000, negative_parens = deprecated(), style_negative = c("hyphen", "minus", "parens"), scale_cut = NULL, ... ) { prefix <- prefix %||% getOption("scales.currency.prefix", default = "$") suffix <- suffix %||% getOption("scales.currency.suffix", default = "") big.mark <- big.mark %||% getOption("scales.currency.big.mark", default = ",") decimal.mark <- decimal.mark %||% getOption("scales.currency.decimal.mark", default = ".") if (length(x) == 0) { return(character()) } if (is.null(accuracy) && is.null(scale_cut)) { if (needs_cents(x * scale, largest_with_cents)) { accuracy <- .01 } else { accuracy <- 1 } } if (identical(big.mark, ",") & identical(decimal.mark, ",")) { big.mark <- " " } if (lifecycle::is_present(negative_parens)) { lifecycle::deprecate_stop( "1.2.0", "dollar(negative_parens)", "dollar(style_negative)" ) } number( x, accuracy = accuracy, scale = scale, prefix = prefix, suffix = suffix, big.mark = big.mark, decimal.mark = decimal.mark, trim = trim, style_negative = style_negative, scale_cut = scale_cut, ... ) } #' @export #' @rdname dollar_format label_dollar <- dollar_format scales/R/label-expression.R0000644000176200001440000000420014672302077015330 0ustar liggesusers#' Label with mathematical annotations #' #' `label_parse()` produces expression from strings by parsing them; #' `label_math()` constructs expressions by replacing the pronoun `.x` #' with each string. #' #' @inherit label_number return #' @seealso [plotmath] for the details of mathematical formatting in R. #' @export #' @family labels for continuous scales #' @family labels for discrete scales #' @examples #' # Use label_parse() with discrete scales #' greek <- c("alpha", "beta", "gamma") #' demo_discrete(greek) #' demo_discrete(greek, labels = label_parse()) #' #' # Use label_math() with continuous scales #' demo_continuous(c(1, 5)) #' demo_continuous(c(1, 5), labels = label_math(alpha[.x])) #' demo_continuous(c(1, 5), labels = label_math()) label_parse <- function() { function(text) { parse_safe(as.character(text)) } } #' @rdname label_parse #' @export #' @param expr expression to use #' @param format another format function to apply prior to mathematical #' transformation - this makes it easier to use floating point numbers in #' mathematical expressions. label_math <- function(expr = 10^.x, format = force) { .x <- NULL quoted <- substitute(expr) subs <- function(x) { do.call("substitute", list(quoted, list(.x = x))) } function(x) { x <- format(x) ret <- lapply(x, subs) ret <- as.expression(ret) # restore NAs from input vector ret[is.na(x)] <- NA names(ret) <- names(x) ret } } #' Superseded interface to `label_parse()`/`label_math()` #' #' @description #' `r lifecycle::badge("superseded")` #' #' These functions are kept for backward compatibility; you should switch #' to [label_parse()]/[label_math()] for new code. #' #' @keywords internal #' @export #' @inheritParams label_parse parse_format <- label_parse #' @rdname parse_format #' @export math_format <- label_math # From ggplot2:::parse_safe # See https://github.com/tidyverse/ggplot2/issues/2864 for discussion. parse_safe <- function(text) { out <- vector("expression", length(text)) for (i in seq_along(text)) { expr <- parse(text = text[[i]]) out[[i]] <- if (length(expr) == 0) NA else expr[[1]] } out } scales/R/pal-gradient.R0000644000176200001440000000520715002117500014412 0ustar liggesusers#' Arbitrary colour gradient palette (continuous) #' #' @param colours vector of colours #' @param values if colours should not be evenly positioned along the gradient #' this vector gives the position (between 0 and 1) for each colour in the #' `colours` vector. See [rescale()] for a convenience function #' to map an arbitrary range to between 0 and 1. #' @param space colour space in which to calculate gradient. Must be "Lab" - #' other values are deprecated. #' @export pal_gradient_n <- function(colours, values = NULL, space = "Lab") { if (!identical(space, "Lab")) { lifecycle::deprecate_stop( "0.3.0", "pal_gradient_n(space = 'only supports be \"Lab\"')" ) } ramp <- colour_ramp(colours) force(values) fun <- function(x) { if (length(x) == 0) { return(character()) } if (!is.null(values)) { xs <- seq(0, 1, length.out = length(values)) f <- stats::approxfun(values, xs) x <- f(x) } ramp(x) } new_continuous_palette(fun, "colour", na_safe = FALSE) } #' @export #' @rdname pal_gradient_n gradient_n_pal <- pal_gradient_n #' Diverging colour gradient (continuous). #' #' @param low colour for low end of gradient. #' @param mid colour for mid point #' @param high colour for high end of gradient. #' @inheritParams pal_gradient_n #' @export #' @examples #' x <- seq(-1, 1, length.out = 100) #' r <- sqrt(outer(x^2, x^2, "+")) #' image(r, col = pal_div_gradient()(seq(0, 1, length.out = 12))) #' image(r, col = pal_div_gradient()(seq(0, 1, length.out = 30))) #' image(r, col = pal_div_gradient()(seq(0, 1, length.out = 100))) #' #' pal <- pal_div_gradient(low = "#2E6A70") #' image(r, col = pal(seq(0, 1, length.out = 100))) pal_div_gradient <- function( low = "#2B6788", # munsell::mnsl("10B 4/6"), mid = "#CBCBCB", # munsell::mnsl("N 8/0"), high = "#90503F", # munsell::mnsl("10R 4/6"), space = "Lab" ) { pal_gradient_n(c(low, mid, high), space = space) } #' @export #' @rdname pal_div_gradient div_gradient_pal <- pal_div_gradient #' Sequential colour gradient palette (continuous) #' #' @param low colour for low end of gradient. #' @param high colour for high end of gradient. #' @inheritParams pal_gradient_n #' @export #' @examples #' x <- seq(0, 1, length.out = 25) #' show_col(pal_seq_gradient()(x)) #' show_col(pal_seq_gradient("white", "black")(x)) #' #' show_col(pal_seq_gradient("white", "#90503F")(x)) pal_seq_gradient <- function( low = "#2B6788", # munsell::mnsl("10B 4/6"), high = "#90503F", # munsell::mnsl("10R 4/6"), space = "Lab" ) { pal_gradient_n(c(low, high), space = space) } #' @export #' @rdname pal_seq_gradient seq_gradient_pal <- pal_seq_gradient scales/R/label-date.R0000644000176200001440000001402415002117500014032 0ustar liggesusers#' Label date/times #' #' `label_date()` and `label_time()` label date/times using date/time format #' strings. `label_date_short()` automatically constructs a short format string #' sufficient to uniquely identify labels. It's inspired by matplotlib's #' [`ConciseDateFormatter`](https://matplotlib.org/stable/api/dates_api.html#matplotlib.dates.ConciseDateFormatter), #' but uses a slightly different approach: `ConciseDateFormatter` formats #' "firsts" (e.g. first day of month, first day of day) specially; #' `date_short()` formats changes (e.g. new month, new year) specially. #' `label_timespan()` is intended to show time passed and adds common time units #' suffix to the input (ns, us, ms, s, m, h, d, w). #' #' @inherit label_number return #' @param format For `label_date()` and `label_time()` a date/time format #' string using standard POSIX specification. See [strptime()] for details. #' #' For `label_date_short()` a character vector of length 4 giving the format #' components to use for year, month, day, and hour respectively. #' @param tz a time zone name, see [timezones()]. Defaults #' to UTC #' @param locale Locale to use when for day and month names. The default #' uses the current locale. Setting this argument requires stringi, and you #' can see a complete list of supported locales with #' [stringi::stri_locale_list()]. #' @param leading A string to replace leading zeroes with. Can be `""` to #' disable leading characters or `"\u2007"` for figure-spaces. #' #' @export #' @examples #' date_range <- function(start, days) { #' start <- as.POSIXct(start) #' c(start, start + days * 24 * 60 * 60) #' } #' #' two_months <- date_range("2020-05-01", 60) #' demo_datetime(two_months) #' demo_datetime(two_months, labels = label_date("%m/%d")) #' demo_datetime(two_months, labels = label_date("%e %b", locale = "fr")) #' demo_datetime(two_months, labels = label_date("%e %B", locale = "es")) #' # ggplot2 provides a short-hand: #' demo_datetime(two_months, date_labels = "%m/%d") #' #' # An alternative labelling system is label_date_short() #' demo_datetime(two_months, date_breaks = "7 days", labels = label_date_short()) #' # This is particularly effective for dense labels #' one_year <- date_range("2020-05-01", 365) #' demo_datetime(one_year, date_breaks = "month") #' demo_datetime(one_year, date_breaks = "month", labels = label_date_short()) label_date <- function(format = "%Y-%m-%d", tz = "UTC", locale = NULL) { force_all(format, tz, locale) function(x) { format_dt(x, format = format, tz = tz, locale = locale) } } #' @export #' @rdname label_date #' @param sep Separator to use when combining date formats into a single string. label_date_short <- function( format = c("%Y", "%b", "%d", "%H:%M"), sep = "\n", leading = "0", tz = "UTC", locale = NULL ) { force_all(format, sep, leading, tz, locale) function(x) { dt <- unclass(as.POSIXlt(x)) changes <- cbind( year = changed(dt$year), month = changed(dt$mon), day = changed(dt$mday) ) # Ensure large unit changes implies that small units change too # Would be more elegant with cumany() but cumsum() does the job changes <- t(apply(changes, 1, cumsum)) >= 1 # Trim out "firsts" from smallest to largest - only want to trim (e.g.) # January if all dates are the first of the month. if (inherits(x, "Date") || all(dt$hour == 0 & dt$min == 0, na.rm = TRUE)) { format[[4]] <- NA if (all(dt$mday == 1, na.rm = TRUE)) { format[[3]] <- NA if (all(dt$mon == 0, na.rm = TRUE)) { format[[2]] <- NA } } } for_mat <- cbind( ifelse(changes[, 1], format[[1]], NA), ifelse(changes[, 2], format[[2]], NA), ifelse(changes[, 3], format[[3]], NA), format[[4]] ) format <- apply( for_mat, 1, function(x) paste(rev(x[!is.na(x)]), collapse = sep) ) x <- format_dt(x, format, tz = tz, locale = locale) if (isTRUE(leading == "0")) { return(x) } # Replace leading 0s with `leading` character x <- gsub("^0", leading, x) x <- gsub(paste0(sep, "0"), paste0(sep, leading), x, fixed = TRUE) x } } changed <- function(x) c(TRUE, is.na(x[-length(x)]) | x[-1] != x[-length(x)]) append_if <- function(x, cond, value) { x[cond] <- lapply(x[cond], c, value) x } #' @export #' @rdname label_date label_time <- function(format = "%H:%M:%S", tz = "UTC", locale = NULL) { force_all(format, tz) function(x) { if (inherits(x, "POSIXt")) { format_dt(x, format = format, tz = tz, locale = locale) } else if (inherits(x, "difftime")) { format(as.POSIXct(x), format = format, tz = tz) } else { stop_input_type( x, as_cli("used with a {.cls POSIXt} or {.cls difftime} object"), arg = I(as_cli("{.fn label_time}")) ) } } } #' @export #' @rdname label_date #' @param unit The unit used to interpret numeric input #' @param space Add a space before the time unit? #' @inheritDotParams number accuracy scale prefix suffix big.mark decimal.mark style_positive style_negative trim label_timespan <- function( unit = c("secs", "mins", "hours", "days", "weeks"), space = FALSE, ... ) { unit <- arg_match(unit) force_all(...) function(x) { x <- as.numeric(as.difftime(x, units = unit), units = "secs") number( x, scale_cut = cut_time_scale(space), ... ) } } format_dt <- function(x, format, tz = "UTC", locale = NULL) { if (is.null(locale)) { format(x, format = format, tz = tz) } else { check_installed("stringi") format <- stringi::stri_datetime_fstr(format) stringi::stri_datetime_format(x, format, tz = tz, locale = locale) } } #' Superseded interface to `label_date()`/`label_time()` #' #' @description #' `r lifecycle::badge("superseded")` #' #' These functions are kept for backward compatibility; you should switch #' to [label_date()]/[label_time()] for new code. #' #' @keywords internal #' @export #' @inheritParams label_date date_format <- label_date #' @export #' @rdname date_format time_format <- label_time scales/R/pal-grey.R0000644000176200001440000000102715002117500013557 0ustar liggesusers#' Grey scale palette (discrete) #' #' @param start grey value at low end of palette #' @param end grey value at high end of palette #' @seealso [pal_seq_gradient()] for continuous version #' @export #' @examples #' show_col(pal_grey()(25)) #' show_col(pal_grey(0, 1)(25)) pal_grey <- function(start = 0.2, end = 0.8) { force_all(start, end) new_discrete_palette( function(n) grDevices::grey.colors(n, start = start, end = end), type = "colour", nlevels = 255 ) } #' @export #' @rdname pal_grey grey_pal <- pal_grey scales/R/label-wrap.R0000644000176200001440000000172115002117500014066 0ustar liggesusers#' Label strings by wrapping across multiple lines #' #' Uses [strwrap()] to split long labels across multiple lines. #' #' @inherit label_number return #' @param width Number of characters per line. #' @export #' @family labels for discrete scales #' @examples #' x <- c( #' "this is a long label", #' "this is another long label", #' "this a label this is even longer" #' ) #' demo_discrete(x) #' demo_discrete(x, labels = label_wrap(10)) #' demo_discrete(x, labels = label_wrap(20)) label_wrap <- function(width) { force(width) function(x) { unlist(lapply( strwrap(x, width = width, simplify = FALSE), paste0, collapse = "\n" )) } } #' Superseded interface to `label_wrap()` #' #' @description #' `r lifecycle::badge("superseded")` #' #' These functions are kept for backward compatibility; you should switch #' to [label_wrap()] for new code. #' #' @keywords internal #' @export #' @inheritParams label_wrap wrap_format <- label_wrap scales/R/documentation.R0000644000176200001440000000053014672302077014727 0ustar liggesusers# Functions used for producing Rd chunks to reduce duplication in # documentation seealso <- function(pattern) { require("scales") names <- ls("package:scales", pattern = pattern) paste0("\\code{\\link{", names, "}}", collapse = ", ") } seealso_transform <- function() seealso("^transform_") seealso_pal <- function() seealso("^pal_") scales/R/transform-numeric.R0000644000176200001440000003344115002117500015517 0ustar liggesusers#' Arc-sin square root transformation #' #' This is the variance stabilising transformation for the binomial #' distribution. #' #' @export #' @examples #' plot(transform_asn(), xlim = c(0, 1)) transform_asn <- function() { new_transform( "asn", function(x) 2 * asin(sqrt(x)), function(x) sin(x / 2)^2, d_transform = function(x) 1 / sqrt(x - x^2), d_inverse = function(x) sin(x) / 2, domain = c(0, 1) ) } #' @rdname transform_asn #' @export asn_trans <- transform_asn #' Arc-tangent transformation #' #' @export #' @examples #' plot(transform_atanh(), xlim = c(-1, 1)) transform_atanh <- function() { new_transform( "atanh", "atanh", "tanh", d_transform = function(x) 1 / (1 - x^2), d_inverse = function(x) 1 / cosh(x)^2, domain = c(-1, 1) ) } #' @export #' @rdname transform_atanh atanh_trans <- transform_atanh #' Inverse Hyperbolic Sine transformation #' #' @export #' @examples #' plot(transform_asinh(), xlim = c(-1e2, 1e2)) transform_asinh <- function() { new_transform( "asinh", transform = asinh, inverse = sinh, d_transform = function(x) 1 / sqrt(x^2 + 1), d_inverse = cosh ) } #' @export #' @rdname transform_asinh asinh_trans <- transform_asinh #' Box-Cox & modulus transformations #' #' The Box-Cox transformation is a flexible transformation, often used to #' transform data towards normality. The modulus transformation generalises #' Box-Cox to also work with negative values. #' #' The Box-Cox power transformation (type 1) requires strictly positive values and #' takes the following form for \eqn{\lambda > 0}: #' \deqn{y^{(\lambda)} = \frac{y^\lambda - 1}{\lambda}}{y^(\lambda) = (y^\lambda - 1)/\lambda} #' When \eqn{\lambda = 0}, the natural log transform is used. #' #' The modulus transformation implements a generalisation of the Box-Cox #' transformation that works for data with both positive and negative values. #' The equation takes the following forms, when \eqn{\lambda \neq 0} : #' \deqn{y^{(\lambda)} = sign(y) * \frac{(|y| + 1)^\lambda - 1}{\lambda}}{ #' y^(\lambda) = sign(y)*((|y|+1)^\lambda - 1)/\lambda} #' and when \eqn{\lambda = 0}: \deqn{y^{(\lambda)} = sign(y) * \ln(|y| + 1)}{ #' y^(\lambda) = sign(y) * ln(|y| + 1)} #' #' @param p Transformation exponent, \eqn{\lambda}. #' @param offset Constant offset. 0 for Box-Cox type 1, #' otherwise any non-negative constant (Box-Cox type 2). `transform_modulus()` #' sets the default to 1. #' @seealso [transform_yj()] #' @references Box, G. E., & Cox, D. R. (1964). An analysis of transformations. #' Journal of the Royal Statistical Society. Series B (Methodological), 211-252. #' \url{https://www.jstor.org/stable/2984418} #' #' John, J. A., & Draper, N. R. (1980). #' An alternative family of transformations. Applied Statistics, 190-197. #' \url{https://www.jstor.org/stable/2986305} #' @export #' @examples #' plot(transform_boxcox(-1), xlim = c(0, 10)) #' plot(transform_boxcox(0), xlim = c(0, 10)) #' plot(transform_boxcox(1), xlim = c(0, 10)) #' plot(transform_boxcox(2), xlim = c(0, 10)) #' #' plot(transform_modulus(-1), xlim = c(-10, 10)) #' plot(transform_modulus(0), xlim = c(-10, 10)) #' plot(transform_modulus(1), xlim = c(-10, 10)) #' plot(transform_modulus(2), xlim = c(-10, 10)) transform_boxcox <- function(p, offset = 0) { if (abs(p) < 1e-07) { trans <- function(x) log(x + offset) inv <- function(x) exp(x) - offset d_trans <- function(x) 1 / (x + offset) d_inv <- "exp" } else { trans <- function(x) ((x + offset)^p - 1) / p inv <- function(x) (x * p + 1)^(1 / p) - offset d_trans <- function(x) (x + offset)^(p - 1) d_inv <- function(x) (x * p + 1)^(1 / p - 1) } trans_with_check <- function(x) { if (any((x + offset) < 0, na.rm = TRUE)) { cli::cli_abort(c( "{.fun transform_boxcox} must be given only positive values", i = "Consider using {.fun transform_modulus} instead?" )) } trans(x) } new_transform( paste0("pow-", format(p)), trans_with_check, inv, d_transform = d_trans, d_inverse = d_inv, domain = c(0, Inf) ) } #' @export #' @rdname transform_boxcox boxcox_trans <- transform_boxcox #' @rdname transform_boxcox #' @export transform_modulus <- function(p, offset = 1) { if (abs(p) < 1e-07) { trans <- function(x) sign(x) * log(abs(x) + offset) inv <- function(x) sign(x) * (exp(abs(x)) - offset) d_trans <- function(x) 1 / (abs(x) + offset) d_inv <- function(x) exp(abs(x)) } else { trans <- function(x) sign(x) * ((abs(x) + offset)^p - 1) / p inv <- function(x) sign(x) * ((abs(x) * p + 1)^(1 / p) - offset) d_trans <- function(x) (abs(x) + offset)^(p - 1) d_inv <- function(x) (abs(x) * p + 1)^(1 / p - 1) } new_transform( paste0("mt-pow-", format(p)), trans, inv, d_transform = d_trans, d_inverse = d_inv ) } #' @rdname transform_boxcox #' @export modulus_trans <- transform_modulus #' Yeo-Johnson transformation #' #' The Yeo-Johnson transformation is a flexible transformation that is similar #' to Box-Cox, [transform_boxcox()], but does not require input values to be #' greater than zero. #' #' The transformation takes one of four forms depending on the values of `y` and \eqn{\lambda}. #' #' * \eqn{y \ge 0} and \eqn{\lambda \neq 0}{\lambda != 0} : #' \eqn{y^{(\lambda)} = \frac{(y + 1)^\lambda - 1}{\lambda}}{y^(\lambda) = ((y + 1)^\lambda - 1)/\lambda} #' * \eqn{y \ge 0} and \eqn{\lambda = 0}: #' \eqn{y^{(\lambda)} = \ln(y + 1)}{y^(\lambda) = ln(y + 1)} #' * \eqn{y < 0} and \eqn{\lambda \neq 2}{\lambda != 2}: #' \eqn{y^{(\lambda)} = -\frac{(-y + 1)^{(2 - \lambda)} - 1}{2 - \lambda}}{y^(\lambda) = -((-y + 1)^(2 - \lambda) - 1)/(2 - \lambda)} #' * \eqn{y < 0} and \eqn{\lambda = 2}: #' \eqn{y^{(\lambda)} = -\ln(-y + 1)}{y^(\lambda) = -ln(-y + 1)} #' #' @param p Transformation exponent, \eqn{\lambda}. #' @references Yeo, I., & Johnson, R. (2000). #' A New Family of Power Transformations to Improve Normality or Symmetry. Biometrika, 87(4), 954-959. #' \url{https://www.jstor.org/stable/2673623} #' @export #' @examples #' plot(transform_yj(-1), xlim = c(-10, 10)) #' plot(transform_yj(0), xlim = c(-10, 10)) #' plot(transform_yj(1), xlim = c(-10, 10)) #' plot(transform_yj(2), xlim = c(-10, 10)) transform_yj <- function(p) { eps <- 1e-7 if (abs(p) < eps) { trans_pos <- log1p inv_pos <- expm1 d_trans_pos <- function(x) 1 / (1 + x) d_inv_pos <- exp } else { trans_pos <- function(x) ((x + 1)^p - 1) / p inv_pos <- function(x) (p * x + 1)^(1 / p) - 1 d_trans_pos <- function(x) (x + 1)^(p - 1) d_inv_pos <- function(x) (p * x + 1)^(1 / p - 1) } if (abs(2 - p) < eps) { trans_neg <- function(x) -log1p(-x) inv_neg <- function(x) 1 - exp(-x) d_trans_neg <- function(x) 1 / (1 - x) d_inv_new <- function(x) exp(-x) } else { trans_neg <- function(x) -((-x + 1)^(2 - p) - 1) / (2 - p) inv_neg <- function(x) 1 - (-(2 - p) * x + 1)^(1 / (2 - p)) d_trans_neg <- function(x) (1 - x)^(1 - p) d_inv_neg <- function(x) (-(2 - p) * x + 1)^(1 / (2 - p) - 1) } new_transform( paste0("yeo-johnson-", format(p)), function(x) trans_two_sided(x, trans_pos, trans_neg), function(x) trans_two_sided(x, inv_pos, inv_neg), d_transform = function(x) trans_two_sided(x, d_trans_pos, d_trans_neg, f_at_0 = 1), d_inverse = function(x) trans_two_sided(x, d_inv_pos, d_inv_neg, f_at_0 = 1) ) } #' @export #' @rdname transform_yj yj_trans <- transform_yj trans_two_sided <- function(x, pos, neg, f_at_0 = 0) { out <- rep(NA_real_, length(x)) present <- !is.na(x) out[present & x > 0] <- pos(x[present & x > 0]) out[present & x < 0] <- neg(x[present & x < 0]) out[present & x == 0] <- f_at_0 out } #' Exponential transformation (inverse of log transformation) #' #' @param base Base of logarithm #' @export #' @examples #' plot(transform_exp(0.5), xlim = c(-2, 2)) #' plot(transform_exp(1), xlim = c(-2, 2)) #' plot(transform_exp(2), xlim = c(-2, 2)) #' plot(transform_exp(), xlim = c(-2, 2)) transform_exp <- function(base = exp(1)) { force(base) new_transform( paste0("power-", format(base)), function(x) base^x, function(x) log(x, base = base), d_transform = function(x) base^x * log(base), d_inverse = function(x) 1 / x / log(base) ) } #' @export #' @rdname transform_exp exp_trans <- transform_exp #' Identity transformation (do nothing) #' #' @export #' @examples #' plot(transform_identity(), xlim = c(-1, 1)) transform_identity <- function() { new_transform( "identity", "force", "force", d_transform = function(x) rep(1, length(x)), d_inverse = function(x) rep(1, length(x)) ) } #' @export #' @rdname transform_identity identity_trans <- transform_identity #' Log transformations #' #' * `transform_log()`: `log(x)` #' * `log1p()`: `log(x + 1)` #' * `transform_pseudo_log()`: smoothly transition to linear scale around 0. #' #' @param base base of logarithm #' @export #' @examples #' plot(transform_log2(), xlim = c(0, 5)) #' plot(transform_log(), xlim = c(0, 5)) #' plot(transform_log10(), xlim = c(0, 5)) #' #' plot(transform_log(), xlim = c(0, 2)) #' plot(transform_log1p(), xlim = c(-1, 1)) #' #' # The pseudo-log is defined for all real numbers #' plot(transform_pseudo_log(), xlim = c(-5, 5)) #' lines(transform_log(), xlim = c(0, 5), col = "red") #' #' # For large positives numbers it's very close to log #' plot(transform_pseudo_log(), xlim = c(1, 20)) #' lines(transform_log(), xlim = c(1, 20), col = "red") transform_log <- function(base = exp(1)) { force(base) new_transform( paste0("log-", format(base)), function(x) log(x, base), function(x) base^x, d_transform = function(x) 1 / x / log(base), d_inverse = function(x) base^x * log(base), breaks = log_breaks(base = base), domain = c(1e-100, Inf) ) } #' @export #' @rdname transform_log transform_log10 <- function() { transform_log(10) } #' @export #' @rdname transform_log transform_log2 <- function() { transform_log(2) } #' @rdname transform_log #' @export transform_log1p <- function() { new_transform( "log1p", "log1p", "expm1", d_transform = function(x) 1 / (1 + x), d_inverse = "exp", domain = c(-1 + .Machine$double.eps, Inf) ) } #' @export #' @rdname transform_log log_trans <- transform_log #' @export #' @rdname transform_log log10_trans <- transform_log10 #' @export #' @rdname transform_log log2_trans <- transform_log2 #' @export #' @rdname transform_log log1p_trans <- transform_log1p #' @rdname transform_log #' @param sigma Scaling factor for the linear part of pseudo-log transformation. #' @export transform_pseudo_log <- function(sigma = 1, base = exp(1)) { new_transform( "pseudo_log", function(x) asinh(x / (2 * sigma)) / log(base), function(x) 2 * sigma * sinh(x * log(base)), d_transform = function(x) 1 / (sqrt(4 + x^2 / sigma^2) * sigma * log(base)), d_inverse = function(x) 2 * sigma * cosh(x * log(base)) * log(base) ) } #' @export #' @rdname transform_log pseudo_log_trans <- transform_pseudo_log #' Probability transformation #' #' @param distribution probability distribution. Should be standard R #' abbreviation so that "p" + distribution is a valid cumulative distribution #' function, "q" + distribution is a valid quantile function, and #' "d" + distribution is a valid probability density function. #' @param ... other arguments passed on to distribution and quantile functions #' @export #' @examples #' plot(transform_logit(), xlim = c(0, 1)) #' plot(transform_probit(), xlim = c(0, 1)) transform_probability <- function(distribution, ...) { qfun <- match.fun(paste0("q", distribution)) pfun <- match.fun(paste0("p", distribution)) dfun <- match.fun(paste0("d", distribution)) new_transform( paste0("prob-", distribution), function(x) qfun(x, ...), function(x) pfun(x, ...), d_transform = function(x) 1 / dfun(qfun(x, ...), ...), d_inverse = function(x) dfun(x, ...), domain = c(0, 1) ) } #' @export #' @rdname transform_probability transform_logit <- function() transform_probability("logis") #' @export #' @rdname transform_probability transform_probit <- function() transform_probability("norm") #' @export #' @rdname transform_probability probability_trans <- transform_probability #' @export #' @rdname transform_probability logit_trans <- transform_logit #' @export #' @rdname transform_probability probit_trans <- transform_probit #' Reciprocal transformation #' #' @export #' @examples #' plot(transform_reciprocal(), xlim = c(0, 1)) transform_reciprocal <- function() { new_transform( "reciprocal", function(x) 1 / x, function(x) 1 / x, d_transform = function(x) -1 / x^2, d_inverse = function(x) -1 / x^2 ) } #' @export #' @rdname transform_reciprocal reciprocal_trans <- transform_reciprocal #' Reverse transformation #' #' reversing transformation works by multiplying the input with -1. This means #' that reverse transformation cannot easily be composed with transformations #' that require positive input unless the reversing is done as a final step. #' #' @export #' @examples #' plot(transform_reverse(), xlim = c(-1, 1)) transform_reverse <- function() { new_transform( "reverse", function(x) -x, function(x) -x, d_transform = function(x) rep(-1, length(x)), d_inverse = function(x) rep(-1, length(x)), minor_breaks = regular_minor_breaks(reverse = TRUE) ) } #' @export #' @rdname transform_reverse reverse_trans <- transform_reverse #' Square-root transformation #' #' This is the variance stabilising transformation for the Poisson #' distribution. #' #' @export #' @examples #' plot(transform_sqrt(), xlim = c(0, 5)) transform_sqrt <- function() { new_transform( "sqrt", "sqrt", function(x) ifelse(x < 0, NA_real_, x^2), d_transform = function(x) 0.5 / sqrt(x), d_inverse = function(x) 2 * x, domain = c(0, Inf) ) } #' @export #' @rdname transform_sqrt sqrt_trans <- transform_sqrt scales/R/label-number-si.R0000644000176200001440000000226615002117500015023 0ustar liggesusers#' Label numbers with SI prefixes (2 kg, 5 mm, etc) #' #' @description #' `r lifecycle::badge("deprecated")` #' #' `label_number_si()` is deprecated because the previous unit didn't actually #' use SI units, but instead used the so called "short scale". You can now get the #' same results as before with #' `label_number(scale_cut = cut_short_scale())`, or if you want correct SI #' units, `label_number(scale_cut = cut_si("unit"))`. #' #' @keywords internal #' @inherit label_number return params #' @param unit Unit of measurement (e.g. `"m"` for meter, the SI unit of length). #' @param scale A scaling factor: `x` will be multiplied by `scale` before #' formatting. This is useful if the underlying data is already using an SI #' prefix. #' @inheritDotParams label_number #' @export #' @family labels for continuous scales #' @family labels for log scales label_number_si <- function( unit = "", accuracy = NULL, scale = 1, suffix = "", ... ) { lifecycle::deprecate_stop( when = "1.2.0", what = "label_number_si()", with = "label_number(scale_cut)" ) } cut_bad_si <- function(unit) { out <- cut_short_scale(unit != "") names(out) <- paste0(names(out), unit) out } scales/R/label-ordinal.R0000644000176200001440000000622115002117500014545 0ustar liggesusers#' Label ordinal numbers (1st, 2nd, 3rd, etc) #' #' Round values to integers and then display as ordinal values (e.g. 1st, 2nd, #' 3rd). Built-in rules are provided for English, French, and Spanish. #' #' @inherit label_number return params #' @param prefix,suffix Symbols to display before and after value. #' @param rules Named list of regular expressions, matched in order. #' Name gives suffix, and value specifies which numbers to match. #' @param gender Masculin or feminin gender for French ordinal. #' @param plural Plural or singular for French ordinal. #' @inheritDotParams number #' @export #' @family labels for continuous scales #' @examples #' demo_continuous(c(1, 5)) #' demo_continuous(c(1, 5), labels = label_ordinal()) #' demo_continuous(c(1, 5), labels = label_ordinal(rules = ordinal_french())) #' #' # The rules are just a set of regular expressions that are applied in turn #' ordinal_french() #' ordinal_english() #' #' # Note that ordinal rounds values, so you may need to adjust the breaks too #' demo_continuous(c(1, 10)) #' demo_continuous(c(1, 10), labels = label_ordinal()) #' demo_continuous(c(1, 10), #' labels = label_ordinal(), #' breaks = breaks_width(2) #' ) label_ordinal <- function( prefix = "", suffix = "", big.mark = NULL, rules = NULL, ... ) { force_all(prefix, suffix, big.mark, rules, ...) function(x) { ordinal( x, prefix = prefix, suffix = suffix, big.mark = big.mark, rules = rules, ... ) } } #' @export #' @rdname label_ordinal ordinal_english <- function() { list( st = "(? [1] "1 kiB" "1 MiB" "1 GiB" ``` * New `label_date_short()` creates labels for a date axis that only show the components of the date that have changed since the previous label. For example, if you have Jan 10, Jan 20, Jan 30, and Feb 1, `label_date_short()` will use labels Jan 10, 20, 30, Feb 1 (#209). * `label_dollar()` now correctly formats negative numbers as (e.g.) -$200 (#216). * `label_math()` now returns an expression vector, and doesn't coerce inputs to names. * `label_number()` takes `scale` into account when computing `accuracy`, if not supplied. This means that `label_percent()` should have better default accuracy in many cases (#192). * `label_number()` now picks the accuracy automatically by default. The underlying heuristic has been improved to use the distance between adjacent breaks (rather than the total range of the break). * New `label_number_auto()` automatically picks between `number_format()` and `scientific_format()` based on the range of the input. It should produce nice output over a very wide range of inputs (@paleolimbot, #208). * New `label_number_si()` formats numeric vectors with limited SI units. Individual values are scaled and labelled with abbreviations "K", "M", "B", or "T" dependent on magnitude (@dpseidel, #83). * `label_parse()` now generates an expression object that can be used to display formatted labels in ggplot2 (@agila5, #203). * `label_pvalue()` now reports values close to 1 (as determined by `accuracy`) as (e.g.) ">0.99". You can control the prefixes used with the new `prefix` argument (#213). ## Breaks * The built in breaks functions now returns a function that takes both a range and a desired number of breaks, making it possible to overwrite the defaults number of desired breaks given in the constructor call (@thomasp85). * `breaks_log()` has nicer behaviour when there are no finite inputs (#210). It also provides usable breaks even with very small ranges (@billdenney, #168) * New `breaks_width()` which allows you to specify a fixed distance between breaks (along with optional offset). ## Transformations * New `yj_trans()` implements the Yeo-Johnson transformation (@zamorarr, #196) * `trans` objects gets methods for `plot()` and `lines()`, and all numeric transformations get an example showing the transformation. * `boxcox_trans()` no longer throws an error when given NA values (@sflippl, #181). ## Other bug fixes and minor improvements * scales now uses the farver package for colour manipulation instead of a combination of grDevices and hand-rolled C++ code (#223). * `alpha()` now preserves element names (@wibeasley, #195) * `ContinuousRange` and `DiscreteRange` methods now properly inherit and are fully mutable (@dpseidel). * `col_numeric()`, `col_bin()`, `col_quantile()`, and `col_factor()` now support viridis colors. Just pass a palette name (`"magma"`, `"inferno"`, `"plasma"`, or `"viridis"`) as the `palette` argument (@jcheng5, #191). * `col_numeric()`, `col_bin()`, `col_quantile()`, and `col_factor()` now have a `reverse` parameter, to apply color palettes in the opposite of their usual order (i.e. high-to-low instead of low-to-high) (@jcheng5, #191). * `col_bin()` and `col_quantile()` now take a `right` argument, which is passed to `base::cut()`; it indicates whether the bin/quantile intervals should be closed on the right (and open on the left), or vice versa (@jcheng5, #191). * `col_factor()` now tries to avoid interpolating qualitative RColorBrewer palettes. Instead, it attempts to assign a palette color to each factor level. Interpolation will still be used if there are more factor levels than available colors, and a warning will be emitted in that case (@jcheng5, #191). * `dichromat_pal()` documentation now builds without requiring suggested `dichromat` package to be installed (@dpseidel, #172). * `date_breaks()` now supports subsecond intervals (@dpseidel, #85). # scales 1.0.0 ## New Features ### Formatters * `comma_format()`, `percent_format()` and `unit_format()` gain new arguments: `accuracy`, `scale`, `prefix`, `suffix`, `decimal.mark`, `big.mark` (@larmarange, #146). * `dollar_format()` gains new arguments: `accuracy`, `scale`, `decimal.mark`, `trim` (@larmarange, #148). * New `number_bytes_format()` and `number_bytes()` format numeric vectors into byte measurements (@hrbrmstr, @dpseidel). * New `number_format()` provides a generic formatter for numbers (@larmarange, #142). * New `pvalue_format()` formats p-values (@larmarange, #145). * `ordinal_format()` gains new arguments: `prefix`, `suffix`, `big.mark`, `rules`; rules for French and Spanish are also provided (@larmarange, #149). * `scientific_format()` gains new arguments: `scale`, `prefix`, `suffix`, `decimal.mark`, `trim` (@larmarange, #147). * New `time_format()` formats `POSIXt` and `hms` objects (@dpseidel, #88). ### Transformations & breaks * `boxcox_trans()` is now invertible for `x >= 0` and requires positive values. A new argument `offset` allows specification of both type-1 and type-2 Box-Cox transformations (@dpseidel, #103). * `log_breaks()` returns integer multiples of integer powers of base when finer breaks are needed (@ThierryO, #117). * New function `modulus_trans()` implements the modulus transformation for positive and negative values (@dpseidel). * New `pseudo_log_trans()` for transforming numerics into a signed logarithmic scale with a smooth transition to a linear scale around 0 (@lepennec, #106). ## Minor bug fixes and improvements * scales functions now work as expected when it is used inside a for loop. In previous package versions if a scales function was used with variable custom parameters inside a for loop, some of the parameters were not evaluated until the end of the loop, due to how R lazy evaluation works (@zeehio, #81). * `colour_ramp()` now uses `alpha = TRUE` by default (@clauswilke, #108). * `date_breaks()` now supports subsecond intervals (@dpseidel, #85). * Removes `dichromat` and `plyr` dependencies. `dichromat` is now suggested (@dpseidel, #118). * `expand_range()` arguments `mul` and `add` now affect scales with a range of 0 (@dpseidel, [ggplot2-2281](https://github.com/tidyverse/ggplot2/issues/2281)). * `extended_breaks()` now allows user specification of the `labeling::extended()` argument `only.loose` to permit more flexible breaks specification (@dpseidel, #99). * New `rescale()` and `rescale_mid()` methods support `dist` objects (@zeehio, #105). * `rescale_mid()` now properly handles NAs (@foo-bar-baz-qux, #104). # scales 0.5.0 * New function `regular_minor_breaks()` calculates minor breaks as a property of the transformation (@karawoo). * Adds `viridis_pal()` for creating palettes with color maps from the viridisLite package (@karawoo). * Switched from reference classes to R6 (#96). * `rescale()` and `rescale_mid()` are now S3 generics, and work with `numeric`, `Date`, `POSIXct`, `POSIXlt` and `bit64::integer64` objects (@zeehio, #74). # scales 0.4.1 * `extended_breaks()` no longer fails on pathological inputs. * New `hms_trans()` for transforming hms time vectors. * `train_discrete()` gets a new `na.rm` argument which controls whether `NA`s are preserved or dropped. # scales 0.4.0 * Switched from `NEWS` to `NEWS.md`. * `manual_pal()` produces a warning if n is greater than the number of values in the palette (@jrnold, #68). * `precision(0)` now returns 1, which means `percent(0)` now returns 0% (#50). * `scale_continuous()` uses a more correct check for numeric values. * NaN is correctly recognised as a missing value by the gradient palettes ([ggplot2-1482](https://github.com/tidyverse/ggplot2/issues/1482)). # scales 0.3.0 * `rescale()` preserves missing values in input when the range of `x` is (effectively) 0 ([ggplot2-985](https://github.com/tidyverse/ggplot2/issues/985)). * Continuous colour palettes now use `colour_ramp()` instead of `colorRamp()`. This only supports interpolation in Lab colour space, but is hundreds of times faster. # scales 0.2.5 ## Improved formatting functions * `date_format()` gains an option to specify time zone (#51). * `dollar_format()` is now more flexible and can add either prefixes or suffixes for different currencies (#53). It gains a `negative_parens` argument to show negative values as `($100)` and now passes missing values through unchanged (@dougmitarotonda, #40). * New `ordinal_format()` generates ordinal numbers (1st, 2nd, etc) (@aaronwolen, #55). * New `unit_format()` makes it easier to add units to labels, optionally scaling (@ThierryO, #46). * New `wrap_format()` function to wrap character vectors to a desired width. (@jimhester, #37). ## New colour scaling functions * New color scaling functions `col_numeric()`, `col_bin()`, `col_quantile()`, and `col_factor()`. These functions provide concise ways to map continuous or categorical values to color spectra. * New `colour_ramp()` function for performing color interpolation in the CIELAB color space (like `grDevices::colorRamp(space = 'Lab')`, but much faster). ## Other bug fixes and minor improvements * `boxcox_trans()` returns correct value when p is close to zero (#31). * `dollar()` and `percent()` both correctly return a zero length string for zero length input (@BrianDiggs, #35). * `brewer_pal()` gains a `direction` argument to easily invert the order of colours (@jiho, #36). * `show_col()` has additional options to showcase colors better (@jiho, #52). * Relaxed tolerance in `zero_range()` to `.Machine$double.eps * 1000` (#33). # scales 0.2.4 * Eliminate stringr dependency. * Fix outstanding errors in R CMD check. # scales 0.2.3 * `floor_time()` calls `to_time()`, but that function was moved into a function so it was no longer available in the scales namespace. Now `floor_time()` has its own copy of that function (Thanks to Stefan Novak). * Color palettes generated by `brewer_pal()` no longer give warnings when fewer than 3 colors are requested (@wch). * `abs_area()` and `rescale_max()` functions have been added, for scaling the area of points to be proportional to their value. These are used by `scale_size_area()` in ggplot2. # scales 0.2.2 * `zero_range()` has improved behaviour thanks to Brian Diggs. * `brewer_pal()` complains if you give it an incorrect palette type. (Fixes #15, thanks to Jean-Olivier Irisson). * `shape_pal()` warns if asked for more than 6 values. (Fixes #16, thanks to Jean-Olivier Irisson). * `time_trans()` gains an optional argument `tz` to specify the time zone to use for the times. If not specified, it will be guess from the first input with a non-null time zone. * `date_trans()` and `time_trans()` now check that their inputs are of the correct type. This prevents ggplot2 scales from silently giving incorrect outputs when given incorrect inputs. * Change the default breaks algorithm for `cbreaks()` and `trans_new()`. Previously it was `pretty_breaks()`, and now it's `extended_breaks()`, which uses the `extended()` algorithm from the labeling package. * fixed namespace problem with `fullseq()`. # scales 0.2.1 * `suppressWarnings` from `train_continuous()` so zero-row or all infinite data frames don't potentially cause problems. * check for zero-length colour in `gradient_n_pal()`. * added `extended_breaks()` which implements an extension to Wilkinson's labelling approach, as implemented in the `labeling` package. This should generally produce nicer breaks than `pretty_breaks()`. * `alpha()` can now preserve existing alpha values if `alpha()` is missing. * `log_breaks()` always gives breaks evenly spaced on the log scale, never evenly spaced on the data scale. This will result in really bad breaks for some ranges (e.g 0.5-0.6), but you probably shouldn't be using log scales in that situation anyway. # scales 0.2.0 * `censor()` and `squish()` gain `only.finite` argument and default to operating only on finite values. This is needed for ggplot2, and reflects the use of Inf and -Inf as special values. * `bounds` functions now `force` evaluation of range to avoid bug with S3 method dispatch inside primitive functions (e.g. `[`). * Simplified algorithm for `discrete_range()` that is robust to `stringsAsFactors` global option. Now, the order of a factor will only be preserved if the full factor is the first object seen, and all subsequent inputs are subsets of the levels of the original factor. * `scientific()` ensures output is always in scientific format and off the specified number of significant digits. `comma()` ensures output is never in scientific format (Fixes #7). * Another tweak to `zero_range()` to better detect when a range has zero length (Fixes #6). scales/README.md0000644000176200001440000001206715002111057013001 0ustar liggesusers # scales scales website [![CRAN status](https://www.r-pkg.org/badges/version/scales)](https://CRAN.R-project.org/package=scales) [![R-CMD-check](https://github.com/r-lib/scales/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/scales/actions/workflows/R-CMD-check.yaml) [![Codecov test coverage](https://codecov.io/gh/r-lib/scales/graph/badge.svg)](https://app.codecov.io/gh/r-lib/scales) One of the most difficult parts of any graphics package is scaling, converting from data values to perceptual properties. The inverse of scaling, making guides (legends and axes) that can be used to read the graph, is often even harder! The scales packages provides the internal scaling infrastructure used by [ggplot2](https://ggplot2.tidyverse.org/), and gives you tools to override the default breaks, labels, transformations and palettes. ## Installation ``` r # Scales is installed when you install ggplot2 or the tidyverse. # But you can install just scales from CRAN: install.packages("scales") # Or the development version from Github: # install.packages("pak") pak::pak("r-lib/scales") ``` ## Usage ### Breaks and labels The most common use of the scales package is to control the appearance of axis and legend labels. Use a `break_` function to control how breaks are generated from the limits, and a `label_` function to control how breaks are turned in to labels. ``` r library(ggplot2) library(dplyr, warn.conflicts = FALSE) library(lubridate, warn.conflicts = FALSE) txhousing %>% mutate(date = make_date(year, month, 1)) %>% group_by(city) %>% filter(min(sales) > 5e2) %>% ggplot(aes(date, sales, group = city)) + geom_line(na.rm = TRUE) + scale_x_date( NULL, breaks = scales::breaks_width("2 years"), labels = scales::label_date("'%y") ) + scale_y_log10( "Total sales", labels = scales::label_number(scale_cut = scales::cut_short_scale()) ) ``` A line plot created with ggplot2, showing property sales in Texas. The x scale uses `scales::break_width()` to place breaks every second year, and `scales::label_date()` to create a custom format for the labels. The y-scale uses `scales::label_number()` to reformat the labels with `scales::cut_short_scale()`. ``` r economics %>% filter(date < ymd("1970-01-01")) %>% ggplot(aes(date, pce)) + geom_line() + scale_x_date(NULL, breaks = scales::breaks_width("3 months"), labels = scales::label_date_short() ) + scale_y_continuous("Personal consumption expenditures", breaks = scales::breaks_extended(8), labels = scales::label_dollar() ) ``` A line plot created with ggplot2, showing personal expenses between 1967 and 1970. The x axis uses `scales::break_width()` to put a break every 3 months and `scales::label_date_short()` to only show the year on the first occuring break of that year. The y axis uses `scales::breaks_extended()` to request 8 breaks, though only 6 are ultimately provided, and `scales::label_dollar()` to format the label as a dollar value. Generally, I don’t recommend running `library(scales)` because when you type (e.g.) `scales::label_` autocomplete will provide you with a list of labelling functions to jog your memory. ### Advanced features Scales colour palettes are used to power the scales in ggplot2, but you can use them in any plotting system. The following example shows how you might apply them to a base plot. ``` r library(scales) # pull a list of colours from any palette pal_viridis()(4) #> [1] "#440154FF" "#31688EFF" "#35B779FF" "#FDE725FF" # use in combination with baseR `palette()` to set new defaults palette(pal_brewer(palette = "Set2")(4)) par(mar = c(5, 5, 1, 1)) plot(Sepal.Length ~ Sepal.Width, data = iris, col = Species, pch = 20) ``` A scatterplot created with base plot showing the relationship between sepal length and sepal width in the Iris dataset. The points are coloured according to species and the `scales::pal_brewer()` are used to provide the colours. scales also gives users the ability to define and apply their own custom transformation functions for repeated use. ``` r # use new_transform to build a new transformation transform_logp3 <- new_transform( name = "logp", transform = function(x) log(x + 3), inverse = function(x) exp(x) - 3, breaks = log_breaks() ) set.seed(1234) # Ensures same sampling dsamp <- sample_n(diamonds, 100) ggplot(dsamp, aes(carat, price, colour = color)) + geom_point() + scale_y_continuous(trans = transform_logp3) ``` A scatterplot created with ggplot2 showing the relationship between diamond price and its carat for a subset of the data in the diamonds dataset. The y scale uses a custom log transform created with `scales::new_transform()`. scales/build/0000755000176200001440000000000015002230364012616 5ustar liggesusersscales/build/partial.rdb0000644000176200001440000001666615002230364014762 0ustar liggesusers][sHvhoG^oIdٖk|g-/-; 3*hX kRyC˾Tm~>oK>piM|L&`y˜9f/ӟarjԐ,*!1*VY'n*+|Q49r,ȻTe9CO_|/leV [WCWE,۟qWܦVAxliWnje]VOTÛ2`R,`&G4˪dWκ|fT3 l>hja({̈=UtUSr^Ő sM ?ywjkyvrxvwwsRSQ;Z^^_ʙeIf.i_.iݗ}h~8Y4^\݌'`3AE<2jcDߨ>w6G^g1y9VH0n U*AY/7T$K5hck5\mسMߌ= 5Nbӈ68w0,<`9rQ0 k(:~,'zo~N" |$k,J"|4]2 T?IL dHHW@ R,U/haIL=.“KϨdctcĪ9HG7<5HOqv KJcFJ t%}8"LeͰg-riFʌa(=hHIZ=*VJKΧSv ^MsYc%R#)5:')3RfvgJK n)MN_Sr/0TRtUz iϒr+}I.ràeŏrS~]~أFz>%W[0?#e)3l;3̆Hف[8}ʋ^B|֊X ݆k#BOd`<^QLG1WX=HR1opx]@4!l vkBhu}"!rr5jVxlD< cb['vOƚzsdJs!\zl" {w^BHHJEc:S9Nr2rw>{:OJLuj3:t^ZSMVxn\ʞdqwQfLJ%ԏpωAg7fd5WEU-  m+KG>i(!̚9E`~Oi>}n$#֕xR 7F!f-+G;RqfM?BqCłh?[Qte4.& ӂ,*w)1"_*ʿm"#" p+b[XU~\Ap_7c ]?P4Yp?p^am$.l[wWjW7q7PJ%A(G ~0*2W!O"K*/bE"/ܚyVV%{ +0!H<̾6 ^#K+z)Q;KBA+ezXh  wM;_l8v_֭J}N&3MSG`P0EbUo*GKU޽{yAr_8`mY|5/m@4γ%\Hq> a_ܛlf]G~fji~_ dHaB \a{x[[$ku3kAs9ZsɂͲ;Ca({lhc#\sZګradc;4Am-UN`nn`l厼W+rڏβD$H1e;FBnuavHK  i~5 *OaSO?ژv{qXRJP. sfn^_O0*5 B eV>^_#ͻM gN8ӝ8 Z'[:Iw(H;#.>)-el1Jp _*qEKm1e_|z@VN܈뭩& E$O7|$^7yĺItkZG7I#O7|By$ivi~{ 9Ә> ve2DQ 1oT{D+QͲƜE"U22<`)VӢLuNff˧<~irZxAdb. x;QT@>IL`pP34FirldTC(G1?yߚvD(aZbD< 60<$^ȡ\ݫw;H\SLJهV,ݰ)L i}hPA nB) gQ>FlV v`w$! 2P`L^JDIHw - vP(obf"|kk_ rN:Txo>F^=Yw#$'8?K8@ gQm@u 5nr畈 > P|Hpq?}܄rIͻ61?$^[Ԁ+O&n:1CbC`Pc>ʥpw_Z]b7J}Mv#Xeh瘏?yXP*KcfS[Oeɒd\y{P '1ƷW B"| r󳑽ԏ6cj6\D3AA=ǠkQ<=5GHlwEߺ$ǽ5]{ , a mB͝czg;iyhBc$vFjS댠NRg5PgVHlO+&C~K32*W)]%nJetU)zD=tHq1$n?ܛмg3/FycfC` Z;9oy5j\$Ԙv]4%%3,))5-j~r#iqzݬ)9.9Z+SfCA#%FJNba8ĘmCf)aʎaCի)1Rbt.k0bSjSR#FĕQc5eF aP>RR[ rSmהn-r4 $5in'HڳJ_aҦ)?0hYa,)?R~tL ȩgZH)3̰8̘mgِ);xOy ^ubNYϵ NbJERxKPkTW%p5Cq(1WLB))IL1M)fQC =GQdW'fp_7䀚Pb~6v m<'1ESء:t`3I>NUW[X{okdܞd**9hN]Y{C75lx=ٿzJMEW+kyy}z+g%%(=c0ct|ZA+C?8RmuL*+|Q49|CO_|%J-Z2糁^γ%6W8) 6A{Yx,v.;C hQm {@9S0 Da0ICZHsw2P%NbJ2Uv 5zlZfd-S2dzX*@eQ2/+&EBD[\jvK:;fi"ڭpOBSL\h90Z ={@#X+}kQU";1)c$3AYNbLp1Dx=D{ᑵ!>*>bm >V\ZjɘtGm0`XpNco`~#, (( $FKDZ!SAd2xL\)&C "Ak~QMcqEWcH \e#R!x~!7[$;jdn.,s1b]F!cI-}>ty%?0_?"㦄۩c·}+KdSk_ƺ]'':y"iiRX5R5$YaԮƝ~,f)ZSo^M af|_"><*[:0ayeWD#nK &0_$+DZժ-Mō·s 2 ٟB+|@XHH}B/}rWF ߎDih cCt;ZsI\?v>NjwVd8Bscales/man/0000755000176200001440000000000015002117500012266 5ustar liggesusersscales/man/transform_compose.Rd0000644000176200001440000000135214672302077016337 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-compose.R \name{transform_compose} \alias{transform_compose} \alias{compose_trans} \title{Compose two or more transformations together} \usage{ transform_compose(...) compose_trans(...) } \arguments{ \item{...}{One or more transformers, either specified with string or as individual transformer objects.} } \description{ This transformer provides a general mechanism for composing two or more transformers together. The most important use case is to combine reverse with other transformations. } \examples{ demo_continuous(10^c(-2:4), trans = "log10", labels = label_log()) demo_continuous(10^c(-2:4), trans = c("log10", "reverse"), labels = label_log()) } scales/man/breaks_log.Rd0000644000176200001440000000474414706713437014723 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks-log.R \name{breaks_log} \alias{breaks_log} \alias{log_breaks} \title{Breaks for log axes} \usage{ breaks_log(n = 5, base = 10) } \arguments{ \item{n}{desired number of breaks} \item{base}{base of logarithm to use} } \value{ All \code{breaks_()} functions return a function for generating breaks. These functions takes, as their first argument a vector of values that represent the data range to provide breaks for. Some will optionally take a second argument that allows you to specify the number of breaks to recieve. } \description{ This algorithm starts by looking for integer powers of \code{base}. If that doesn't provide enough breaks, it then looks for additional intermediate breaks which are integer multiples of integer powers of base. If that fails (which it can for very small ranges), we fall back to \code{\link[=extended_breaks]{extended_breaks()}} } \details{ The algorithm starts by looking for a set of integer powers of \code{base} that cover the range of the data. If that does not generate at least \code{n - 2} breaks, we look for an integer between 1 and \code{base} that splits the interval approximately in half. For example, in the case of \code{base = 10}, this integer is 3 because \code{log10(3) = 0.477}. This leaves 2 intervals: \code{c(1, 3)} and \code{c(3, 10)}. If we still need more breaks, we look for another integer that splits the largest remaining interval (on the log-scale) approximately in half. For \code{base = 10}, this is 5 because \code{log10(5) = 0.699}. The generic algorithm starts with a set of integers \code{steps} containing only 1 and a set of candidate integers containing all integers larger than 1 and smaller than \code{base}. Then for each remaining candidate integer \code{x}, the smallest interval (on the log-scale) in the vector \code{sort(c(x, steps, base))} is calculated. The candidate \code{x} which yields the largest minimal interval is added to \code{steps} and removed from the candidate set. This is repeated until either a sufficient number of breaks, \verb{>= n-2}, are returned or all candidates have been used. } \examples{ demo_log10(c(1, 1e5)) demo_log10(c(1, 1e6)) # Request more breaks by setting n demo_log10(c(1, 1e6), breaks = breaks_log(6)) # Some tricky ranges demo_log10(c(2000, 9000)) demo_log10(c(2000, 14000)) demo_log10(c(2000, 85000), expand = c(0, 0)) # An even smaller range that requires falling back to linear breaks demo_log10(c(1800, 2000)) } scales/man/fullseq.Rd0000644000176200001440000000065314672302077014255 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/full-seq.R \name{fullseq} \alias{fullseq} \title{Generate sequence of fixed size intervals covering range.} \usage{ fullseq(range, size, ...) } \arguments{ \item{range}{range} \item{size}{interval size} \item{...}{other arguments passed on to methods} } \description{ Generate sequence of fixed size intervals covering range. } \keyword{internal} scales/man/pal_grey.Rd0000644000176200001440000000106214672302077014377 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-grey.R \name{pal_grey} \alias{pal_grey} \alias{grey_pal} \title{Grey scale palette (discrete)} \usage{ pal_grey(start = 0.2, end = 0.8) grey_pal(start = 0.2, end = 0.8) } \arguments{ \item{start}{grey value at low end of palette} \item{end}{grey value at high end of palette} } \description{ Grey scale palette (discrete) } \examples{ show_col(pal_grey()(25)) show_col(pal_grey(0, 1)(25)) } \seealso{ \code{\link[=pal_seq_gradient]{pal_seq_gradient()}} for continuous version } scales/man/label_scientific.Rd0000644000176200001440000000433514705655135016065 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-scientific.R \name{label_scientific} \alias{label_scientific} \title{Label numbers with scientific notation (e.g. 1e05, 1.5e-02)} \usage{ label_scientific( digits = 3, scale = 1, prefix = "", suffix = "", decimal.mark = NULL, trim = TRUE, ... ) } \arguments{ \item{digits}{Number of digits to show before exponent.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix, suffix}{Symbols to display before and after value.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{...}{Other arguments passed on to \code{\link[base:format]{base::format()}}.} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Label numbers with scientific notation (e.g. 1e05, 1.5e-02) } \examples{ demo_continuous(c(1, 10)) demo_continuous(c(1, 10), labels = label_scientific()) demo_continuous(c(1, 10), labels = label_scientific(digits = 3)) demo_log10(c(1, 1e9)) } \seealso{ Other labels for continuous scales: \code{\link{label_bytes}()}, \code{\link{label_currency}()}, \code{\link{label_glue}()}, \code{\link{label_number_auto}()}, \code{\link{label_number_si}()}, \code{\link{label_ordinal}()}, \code{\link{label_parse}()}, \code{\link{label_percent}()}, \code{\link{label_pvalue}()} Other labels for log scales: \code{\link{label_bytes}()}, \code{\link{label_log}()}, \code{\link{label_number_si}()} } \concept{labels for continuous scales} \concept{labels for log scales} scales/man/number_options.Rd0000644000176200001440000000532214705661306015643 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-number.R \name{number_options} \alias{number_options} \title{Number options} \usage{ number_options( decimal.mark = ".", big.mark = " ", style_positive = c("none", "plus", "space"), style_negative = c("hyphen", "minus", "parens"), currency.prefix = "$", currency.suffix = "", currency.decimal.mark = decimal.mark, currency.big.mark = setdiff(c(".", ","), currency.decimal.mark)[1], ordinal.rules = ordinal_english() ) } \arguments{ \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{style_positive}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{style_negative}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{currency.prefix, currency.suffix, currency.decimal.mark, currency.big.mark}{Settings for \code{\link[=label_currency]{label_currency()}} passed on without the \code{currency.}-prefix.} \item{ordinal.rules}{Setting for \code{\link[=label_ordinal]{label_ordinal()}} passed on without the \code{ordinal.}-prefix.} } \value{ The old options invisibly } \description{ Control the settings for formatting numbers globally. } \examples{ # Default number formatting x <- c(0.1, 1, 1000) label_number()(x) # Now again with new options set number_options(style_positive = "plus", decimal.mark = ",") label_number()(x) # The options are the argument names with a 'scales.'-prefix options("scales.style_positive") # Resetting the options to their defaults number_options() label_number()(x) } scales/man/transform_boxcox.Rd0000644000176200001440000000444714705443562016206 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_boxcox} \alias{transform_boxcox} \alias{boxcox_trans} \alias{transform_modulus} \alias{modulus_trans} \title{Box-Cox & modulus transformations} \usage{ transform_boxcox(p, offset = 0) boxcox_trans(p, offset = 0) transform_modulus(p, offset = 1) modulus_trans(p, offset = 1) } \arguments{ \item{p}{Transformation exponent, \eqn{\lambda}.} \item{offset}{Constant offset. 0 for Box-Cox type 1, otherwise any non-negative constant (Box-Cox type 2). \code{transform_modulus()} sets the default to 1.} } \description{ The Box-Cox transformation is a flexible transformation, often used to transform data towards normality. The modulus transformation generalises Box-Cox to also work with negative values. } \details{ The Box-Cox power transformation (type 1) requires strictly positive values and takes the following form for \eqn{\lambda > 0}: \deqn{y^{(\lambda)} = \frac{y^\lambda - 1}{\lambda}}{y^(\lambda) = (y^\lambda - 1)/\lambda} When \eqn{\lambda = 0}, the natural log transform is used. The modulus transformation implements a generalisation of the Box-Cox transformation that works for data with both positive and negative values. The equation takes the following forms, when \eqn{\lambda \neq 0} : \deqn{y^{(\lambda)} = sign(y) * \frac{(|y| + 1)^\lambda - 1}{\lambda}}{ y^(\lambda) = sign(y)*((|y|+1)^\lambda - 1)/\lambda} and when \eqn{\lambda = 0}: \deqn{y^{(\lambda)} = sign(y) * \ln(|y| + 1)}{ y^(\lambda) = sign(y) * ln(|y| + 1)} } \examples{ plot(transform_boxcox(-1), xlim = c(0, 10)) plot(transform_boxcox(0), xlim = c(0, 10)) plot(transform_boxcox(1), xlim = c(0, 10)) plot(transform_boxcox(2), xlim = c(0, 10)) plot(transform_modulus(-1), xlim = c(-10, 10)) plot(transform_modulus(0), xlim = c(-10, 10)) plot(transform_modulus(1), xlim = c(-10, 10)) plot(transform_modulus(2), xlim = c(-10, 10)) } \references{ Box, G. E., & Cox, D. R. (1964). An analysis of transformations. Journal of the Royal Statistical Society. Series B (Methodological), 211-252. \url{https://www.jstor.org/stable/2984418} John, J. A., & Draper, N. R. (1980). An alternative family of transformations. Applied Statistics, 190-197. \url{https://www.jstor.org/stable/2986305} } \seealso{ \code{\link[=transform_yj]{transform_yj()}} } scales/man/pal_div_gradient.Rd0000644000176200001440000000206214705655135016074 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-gradient.R \name{pal_div_gradient} \alias{pal_div_gradient} \alias{div_gradient_pal} \title{Diverging colour gradient (continuous).} \usage{ pal_div_gradient( low = "#2B6788", mid = "#CBCBCB", high = "#90503F", space = "Lab" ) div_gradient_pal( low = "#2B6788", mid = "#CBCBCB", high = "#90503F", space = "Lab" ) } \arguments{ \item{low}{colour for low end of gradient.} \item{mid}{colour for mid point} \item{high}{colour for high end of gradient.} \item{space}{colour space in which to calculate gradient. Must be "Lab" - other values are deprecated.} } \description{ Diverging colour gradient (continuous). } \examples{ x <- seq(-1, 1, length.out = 100) r <- sqrt(outer(x^2, x^2, "+")) image(r, col = pal_div_gradient()(seq(0, 1, length.out = 12))) image(r, col = pal_div_gradient()(seq(0, 1, length.out = 30))) image(r, col = pal_div_gradient()(seq(0, 1, length.out = 100))) pal <- pal_div_gradient(low = "#2E6A70") image(r, col = pal(seq(0, 1, length.out = 100))) } scales/man/transform_reverse.Rd0000644000176200001440000000104214672302077016341 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_reverse} \alias{transform_reverse} \alias{reverse_trans} \title{Reverse transformation} \usage{ transform_reverse() reverse_trans() } \description{ reversing transformation works by multiplying the input with -1. This means that reverse transformation cannot easily be composed with transformations that require positive input unless the reversing is done as a final step. } \examples{ plot(transform_reverse(), xlim = c(-1, 1)) } scales/man/pal_dichromat.Rd0000644000176200001440000000141214705655135015405 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-dichromat.R \name{pal_dichromat} \alias{pal_dichromat} \alias{dichromat_pal} \title{Dichromat (colour-blind) palette (discrete)} \usage{ pal_dichromat(name) dichromat_pal(name) } \arguments{ \item{name}{Name of colour palette. One of: \Sexpr[results=rd,stage=build]{scales:::dichromat_schemes()}} } \description{ Dichromat (colour-blind) palette (discrete) } \examples{ if (requireNamespace("dichromat", quietly = TRUE)) { show_col(pal_dichromat("BluetoOrange.10")(10)) show_col(pal_dichromat("BluetoOrange.10")(5)) # Can use with gradient_n to create a continuous gradient cols <- pal_dichromat("DarkRedtoBlue.12")(12) show_col(pal_gradient_n(cols)(seq(0, 1, length.out = 30))) } } scales/man/trans_format.Rd0000644000176200001440000000136214672302077015277 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/labels-retired.R \name{trans_format} \alias{trans_format} \title{Format labels after transformation} \usage{ trans_format(trans, format = scientific_format()) } \arguments{ \item{trans}{transformation to apply} \item{format}{additional formatter to apply after transformation} } \value{ a function with single parameter x, a numeric vector, that returns a character vector of list of expressions } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} } \examples{ tf <- trans_format("log10", scientific_format()) tf(10^1:6) } \keyword{internal} scales/man/label_pvalue.Rd0000644000176200001440000000436214705655135015241 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-pvalue.R \name{label_pvalue} \alias{label_pvalue} \title{Label p-values (e.g. <0.001, 0.25, p >= 0.99)} \usage{ label_pvalue( accuracy = 0.001, decimal.mark = NULL, prefix = NULL, add_p = FALSE ) } \arguments{ \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{prefix}{A character vector of length 3 giving the prefixes to put in front of numbers. The default values are \code{c("p<", "p=", "p>")} if \code{add_p} is \code{TRUE} and \code{c("<", "", ">")} if \code{FALSE}.} \item{add_p}{Add "p=" before the value?} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Formatter for p-values, using "<" and ">" for p-values close to 0 and 1. } \examples{ demo_continuous(c(0, 1)) demo_continuous(c(0, 1), labels = label_pvalue()) demo_continuous(c(0, 1), labels = label_pvalue(accuracy = 0.1)) demo_continuous(c(0, 1), labels = label_pvalue(add_p = TRUE)) # Or provide your own prefixes prefix <- c("p < ", "p = ", "p > ") demo_continuous(c(0, 1), labels = label_pvalue(prefix = prefix)) } \seealso{ Other labels for continuous scales: \code{\link{label_bytes}()}, \code{\link{label_currency}()}, \code{\link{label_glue}()}, \code{\link{label_number_auto}()}, \code{\link{label_number_si}()}, \code{\link{label_ordinal}()}, \code{\link{label_parse}()}, \code{\link{label_percent}()}, \code{\link{label_scientific}()} } \concept{labels for continuous scales} scales/man/breaks_exp.Rd0000644000176200001440000000215414706713437014727 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks.R \name{breaks_exp} \alias{breaks_exp} \title{Breaks for exponentially transformed data} \usage{ breaks_exp(n = 5, ...) } \arguments{ \item{n}{Desired number of breaks. You may get slightly more or fewer breaks that requested.} \item{...}{other arguments passed on to \code{\link[labeling:extended]{labeling::extended()}}} } \value{ All \code{breaks_()} functions return a function for generating breaks. These functions takes, as their first argument a vector of values that represent the data range to provide breaks for. Some will optionally take a second argument that allows you to specify the number of breaks to recieve. } \description{ This breaks function typically labels zero and the last \code{n - 1} integers of a range if that range is large enough (currently: 3). For smaller ranges, it uses \code{\link[=breaks_extended]{breaks_extended()}}. } \examples{ # Small range demo_continuous(c(100, 102), transform = "exp", breaks = breaks_exp()) # Large range demo_continuous(c(0, 100), transform = "exp", breaks = breaks_exp(n = 4)) } scales/man/breaks_extended.Rd0000644000176200001440000000227314706713437015735 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks.R \name{breaks_extended} \alias{breaks_extended} \alias{extended_breaks} \title{Automatic breaks for numeric axes} \usage{ breaks_extended(n = 5, ...) } \arguments{ \item{n}{Desired number of breaks. You may get slightly more or fewer breaks that requested.} \item{...}{other arguments passed on to \code{\link[labeling:extended]{labeling::extended()}}} } \value{ All \code{breaks_()} functions return a function for generating breaks. These functions takes, as their first argument a vector of values that represent the data range to provide breaks for. Some will optionally take a second argument that allows you to specify the number of breaks to recieve. } \description{ Uses Wilkinson's extended breaks algorithm as implemented in the \pkg{labeling} package. } \examples{ demo_continuous(c(0, 10)) demo_continuous(c(0, 10), breaks = breaks_extended(3)) demo_continuous(c(0, 10), breaks = breaks_extended(10)) } \references{ Talbot, J., Lin, S., Hanrahan, P. (2010) An Extension of Wilkinson's Algorithm for Positioning Tick Labels on Axes, InfoVis 2010 \url{http://vis.stanford.edu/files/2010-TickLabels-InfoVis.pdf}. } scales/man/pal_seq_gradient.Rd0000644000176200001440000000146214705655135016105 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-gradient.R \name{pal_seq_gradient} \alias{pal_seq_gradient} \alias{seq_gradient_pal} \title{Sequential colour gradient palette (continuous)} \usage{ pal_seq_gradient(low = "#2B6788", high = "#90503F", space = "Lab") seq_gradient_pal(low = "#2B6788", high = "#90503F", space = "Lab") } \arguments{ \item{low}{colour for low end of gradient.} \item{high}{colour for high end of gradient.} \item{space}{colour space in which to calculate gradient. Must be "Lab" - other values are deprecated.} } \description{ Sequential colour gradient palette (continuous) } \examples{ x <- seq(0, 1, length.out = 25) show_col(pal_seq_gradient()(x)) show_col(pal_seq_gradient("white", "black")(x)) show_col(pal_seq_gradient("white", "#90503F")(x)) } scales/man/new_continuous_palette.Rd0000644000176200001440000000612715001712000017353 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-.R \name{new_continuous_palette} \alias{new_continuous_palette} \alias{new_discrete_palette} \alias{is_pal} \alias{is_continuous_pal} \alias{is_discrete_pal} \alias{is_colour_pal} \alias{is_numeric_pal} \alias{palette_nlevels} \alias{palette_na_safe} \alias{palette_type} \alias{as_discrete_pal} \alias{as_continuous_pal} \title{Constructors for palettes} \usage{ new_continuous_palette(fun, type, na_safe = NA) new_discrete_palette(fun, type, nlevels = NA) is_pal(x) is_continuous_pal(x) is_discrete_pal(x) is_colour_pal(x) is_numeric_pal(x) palette_nlevels(pal) palette_na_safe(pal) palette_type(pal) as_discrete_pal(x, ...) as_continuous_pal(x, ...) } \arguments{ \item{fun}{A function to serve as a palette. For continuous palettes, these typically take vectors of numeric values between (0, 1) and return a vector of equal length. For discrete palettes, these typically take a scalar integer and return a vector of that length.} \item{type}{A string giving the type of return values. Some example strings include \code{"colour"}, \code{"numeric"}, \code{"linetype"} or \code{"shape"}.} \item{na_safe}{A boolean indicating whether \code{NA} values are translated to palette values (\code{TRUE}) or are kept as \code{NA} (\code{FALSE}). Applies to continuous palettes.} \item{nlevels}{An integer giving the number of distinct palette values that can be returned by the discrete palette.} \item{x}{An object to test or coerce.} \item{pal}{A palette to retrieve properties from.} \item{...}{Additional arguments. Currently not in use.} } \value{ For \code{new_continuous_palette()}, \code{new_discret_palette()}, \code{as_discrete_pal()} and \code{as_continuous_pal()}: a function of class \code{pal_continuous} or \code{pal_discrete}. For \code{is_pal()}, \code{is_continuous_pal()}, \code{is_discret_pal()}, \code{is_colour_pal()}, or \code{is_numeric_pal()}: a logical value of length 1. For \code{palette_nlevels()} a single integer. For \code{palette_na_safe()} a boolean. For \code{palette_type()} a string. } \description{ These constructor functions attach metadata to palette functions. This metadata can be used in testing or coercion. } \examples{ # Creating a new discrete palette new_discrete_palette( fun = grDevices::terrain.colors, type = "colour", nlevels = 255 ) # Creating a new continuous palette new_continuous_palette( fun = function(x) rescale(x, to = c(1, 0)), type = "numeric", na_safe = FALSE ) # Testing palette properties is_continuous_pal(pal_seq_gradient()) is_discrete_pal(pal_viridis()) is_numeric_pal(pal_area()) is_colour_pal(pal_manual(c("red", "green"))) is_pal(transform_log10()) # Extracting properties palette_nlevels(pal_viridis()) palette_na_safe(colour_ramp(c("red", "green"), na.color = "grey50")) palette_type(pal_shape()) # Switching discrete to continuous pal <- as_continuous_pal(pal_viridis()) show_col(pal(c(0, 0.1, 0.2, 0.4, 1))) # Switching continuous to discrete pal <- as_discrete_pal(pal_div_gradient()) show_col(pal(9)) } \seealso{ \link[=palette-recommendations]{palette recommendations} } scales/man/label_number.Rd0000644000176200001440000001451414705655135015235 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-number.R \name{label_number} \alias{label_number} \alias{label_comma} \title{Label numbers in decimal format (e.g. 0.12, 1,234)} \usage{ label_number( accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = NULL, decimal.mark = NULL, style_positive = NULL, style_negative = NULL, scale_cut = NULL, trim = TRUE, ... ) label_comma( accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = ",", decimal.mark = ".", trim = TRUE, digits, ... ) } \arguments{ \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix}{Additional text to display before the number. The suffix is applied to absolute value before \code{style_positive} and \code{style_negative} are processed so that \code{prefix = "$"} will yield (e.g.) \verb{-$1} and \verb{($1)}.} \item{suffix}{Additional text to display after the number.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{style_positive}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{style_negative}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{scale_cut}{Named numeric vector that allows you to rescale large (or small) numbers and add a prefix. Built-in helpers include: \itemize{ \item \code{cut_short_scale()}: [10^3, 10^6) = K, [10^6, 10^9) = M, [10^9, 10^12) = B, [10^12, Inf) = T. \item \code{cut_long_scale()}: [10^3, 10^6) = K, [10^6, 10^12) = M, [10^12, 10^18) = B, [10^18, Inf) = T. \item \code{cut_si(unit)}: uses standard SI units. } If you supply a vector \code{c(a = 100, b = 1000)}, absolute values in the range \verb{[0, 100)} will not be rescaled, absolute values in the range \verb{[100, 1000)} will be divided by 100 and given the suffix "a", and absolute values in the range \verb{[1000, Inf)} will be divided by 1000 and given the suffix "b". If the division creates an irrational value (or one with many digits), the cut value below will be tried to see if it improves the look of the final label.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{...}{Other arguments passed on to \code{\link[base:format]{base::format()}}.} \item{digits}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Use \code{accuracy} instead.} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Use \code{label_number()} to force decimal display of numbers (i.e. don't use \link[=label_scientific]{scientific} notation). \code{label_comma()} is a special case that inserts a comma every three digits. } \examples{ \dontshow{if (getRversion() >= "3.5") (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} demo_continuous(c(-1e6, 1e6)) demo_continuous(c(-1e6, 1e6), labels = label_number()) demo_continuous(c(-1e6, 1e6), labels = label_comma()) # Use scale to rescale very small or large numbers to generate # more readable labels demo_continuous(c(0, 1e6), labels = label_number()) demo_continuous(c(0, 1e6), labels = label_number(scale = 1 / 1e3)) demo_continuous(c(0, 1e-6), labels = label_number()) demo_continuous(c(0, 1e-6), labels = label_number(scale = 1e6)) #' Use scale_cut to automatically add prefixes for large/small numbers demo_log10( c(1, 1e9), breaks = log_breaks(10), labels = label_number(scale_cut = cut_short_scale()) ) demo_log10( c(1, 1e9), breaks = log_breaks(10), labels = label_number(scale_cut = cut_si("m")) ) demo_log10( c(1e-9, 1), breaks = log_breaks(10), labels = label_number(scale_cut = cut_si("g")) ) # use scale and scale_cut when data already uses SI prefix # for example, if data was stored in kg demo_log10( c(1e-9, 1), breaks = log_breaks(10), labels = label_number(scale_cut = cut_si("g"), scale = 1e3) ) #' # Use style arguments to vary the appearance of positive and negative numbers demo_continuous(c(-1e3, 1e3), labels = label_number( style_positive = "plus", style_negative = "minus" )) demo_continuous(c(-1e3, 1e3), labels = label_number(style_negative = "parens")) # You can use prefix and suffix for other types of display demo_continuous(c(32, 212), labels = label_number(suffix = "\u00b0F")) demo_continuous(c(0, 100), labels = label_number(suffix = "\u00b0C")) \dontshow{\}) # examplesIf} } scales/man/col2hcl.Rd0000644000176200001440000000172014672302130014112 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/colour-manip.R \name{col2hcl} \alias{col2hcl} \title{Modify standard R colour in hcl colour space.} \usage{ col2hcl(colour, h = NULL, c = NULL, l = NULL, alpha = NULL) } \arguments{ \item{colour}{character vector of colours to be modified} \item{h}{Hue, \verb{[0, 360]}} \item{c}{Chroma, \verb{[0, 100]}} \item{l}{Luminance, \verb{[0, 100]}} \item{alpha}{Alpha, \verb{[0, 1]}.} } \description{ Transforms rgb to hcl, sets non-missing arguments and then backtransforms to rgb. } \examples{ reds <- rep("red", 6) show_col(col2hcl(reds, h = seq(0, 180, length = 6))) show_col(col2hcl(reds, c = seq(0, 80, length = 6))) show_col(col2hcl(reds, l = seq(0, 100, length = 6))) show_col(col2hcl(reds, alpha = seq(0, 1, length = 6))) } \seealso{ Other colour manipulation: \code{\link{alpha}()}, \code{\link{col_mix}()}, \code{\link{colour_manip}}, \code{\link{muted}()} } \concept{colour manipulation} scales/man/label_log.Rd0000644000176200001440000000345714705443562014531 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-log.R \name{label_log} \alias{label_log} \alias{format_log} \title{Label numbers in log format (10^3, 10^6, etc)} \usage{ label_log(base = 10, digits = 3, signed = NULL) format_log(x, base = 10, signed = NULL, ...) } \arguments{ \item{base}{Base of logarithm to use} \item{digits}{Number of significant digits to show for the exponent. Argument is passed on to \code{\link[base:format]{base::format()}}.} \item{signed}{Should a \code{+} or \code{-} be displayed as a prefix? The default, \code{NULL}, displays signs if there are zeroes or negative numbers present.} \item{x}{A numeric vector to format} \item{...}{Passed on to \code{format()}.} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ \code{label_log()} and \code{format_log()} display numbers as base^exponent, using superscript formatting. \code{label_log()} returns expressions suitable for labelling in scales, whereas \code{format_log()} returns deparsed text. } \examples{ demo_log10(c(1, 1e5), labels = label_log()) demo_log10(c(1, 1e5), breaks = breaks_log(base = 2), labels = label_log(base = 2)) format_log(c(0.1, 1, 10)) } \seealso{ \code{\link[=breaks_log]{breaks_log()}} for the related breaks algorithm. Other labels for log scales: \code{\link{label_bytes}()}, \code{\link{label_number_si}()}, \code{\link{label_scientific}()} } \concept{labels for log scales} scales/man/parse_format.Rd0000644000176200001440000000156714672302077015271 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-expression.R \name{parse_format} \alias{parse_format} \alias{math_format} \title{Superseded interface to \code{label_parse()}/\code{label_math()}} \usage{ parse_format() math_format(expr = 10^.x, format = force) } \arguments{ \item{expr}{expression to use} \item{format}{another format function to apply prior to mathematical transformation - this makes it easier to use floating point numbers in mathematical expressions.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=label_parse]{label_parse()}}/\code{\link[=label_math]{label_math()}} for new code. } \keyword{internal} scales/man/dollar_format.Rd0000644000176200001440000000465614705655135015441 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-currency.R \name{dollar_format} \alias{dollar_format} \alias{dollar} \alias{label_dollar} \title{Superseded interface to \code{label_currency()}} \usage{ dollar_format( accuracy = NULL, scale = 1, prefix = "$", suffix = "", big.mark = ",", decimal.mark = ".", trim = TRUE, largest_with_cents = 1e+05, negative_parens = deprecated(), ... ) dollar( x, accuracy = NULL, scale = 1, prefix = NULL, suffix = NULL, big.mark = NULL, decimal.mark = NULL, trim = TRUE, largest_with_cents = 1e+05, negative_parens = deprecated(), style_negative = c("hyphen", "minus", "parens"), scale_cut = NULL, ... ) label_dollar( accuracy = NULL, scale = 1, prefix = "$", suffix = "", big.mark = ",", decimal.mark = ".", trim = TRUE, largest_with_cents = 1e+05, negative_parens = deprecated(), ... ) } \arguments{ \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix, suffix}{Symbols to display before and after value.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{largest_with_cents}{Like \code{largest_with_fractional()} in \code{\link[=label_currency]{label_currency()}}} \item{negative_parens}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Use \code{style_negative = "parens"} instead.} \item{...}{Other arguments passed on to \code{\link[base:format]{base::format()}}.} \item{x}{A numeric vector} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=label_currency]{label_currency()}} for new code. } \keyword{internal} scales/man/new_transform.Rd0000644000176200001440000000453314672302077015467 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform.R \name{new_transform} \alias{new_transform} \alias{trans} \alias{trans_new} \alias{is.transform} \alias{is.trans} \alias{as.transform} \alias{as.trans} \title{Create a new transformation object} \usage{ new_transform( name, transform, inverse, d_transform = NULL, d_inverse = NULL, breaks = extended_breaks(), minor_breaks = regular_minor_breaks(), format = format_format(), domain = c(-Inf, Inf) ) trans_new( name, transform, inverse, d_transform = NULL, d_inverse = NULL, breaks = extended_breaks(), minor_breaks = regular_minor_breaks(), format = format_format(), domain = c(-Inf, Inf) ) is.transform(x) is.trans(x) as.transform(x, arg = deparse(substitute(x))) as.trans(x, arg = deparse(substitute(x))) } \arguments{ \item{name}{transformation name} \item{transform}{function, or name of function, that performs the transformation} \item{inverse}{function, or name of function, that performs the inverse of the transformation} \item{d_transform}{Optional function, or name of function, that gives the derivative of the transformation. May be \code{NULL}.} \item{d_inverse}{Optional function, or name of function, that gives the derivative of the inverse of the transformation. May be \code{NULL}.} \item{breaks}{default breaks function for this transformation. The breaks function is applied to the un-transformed data.} \item{minor_breaks}{default minor breaks function for this transformation.} \item{format}{default format for this transformation. The format is applied to breaks generated on the un-transformed data.} \item{domain}{the allowed range of the data to be transformed. The function in the \code{transform} argument is expected to be able to transform the \code{domain} argument.} } \description{ A transformation encapsulates a transformation and its inverse, as well as the information needed to create pleasing breaks and labels. The \code{breaks()} function is applied on the un-transformed range of the data, and the \code{format()} function takes the output of the \code{breaks()} function and returns well-formatted labels. Transformations may also include the derivatives of the transformation and its inverse, but are not required to. } \seealso{ \Sexpr[results=rd,stage=build]{scales:::seealso_transform()} } \keyword{internal} scales/man/number_bytes_format.Rd0000644000176200001440000000203114672302077016640 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/labels-retired.R \name{number_bytes_format} \alias{number_bytes_format} \alias{number_bytes} \title{Older interface to \code{label_bytes()}} \usage{ number_bytes_format(symbol = "auto", units = "binary", ...) number_bytes(x, symbol = "auto", units = c("binary", "si"), accuracy = 1, ...) } \arguments{ \item{symbol}{byte symbol to use. If "auto" the symbol used will be determined separately for each value of \code{x}. Valid symbols are "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", and "YB" for SI units, and the "iB" variants for binary units.} \item{units}{which unit base to use, "binary" (1024 base) or "si" (1000 base)} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility, but you should switch to \code{\link[=label_bytes]{label_bytes()}} for new code. } \keyword{internal} scales/man/trans_breaks.Rd0000644000176200001440000000171714672302077015262 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks-retired.R \name{trans_breaks} \alias{trans_breaks} \title{Pretty breaks on transformed scale} \usage{ trans_breaks(trans, inv, n = 5, ...) } \arguments{ \item{trans}{function of single variable, \code{x}, that given a numeric vector returns the transformed values} \item{inv}{inverse of the transformation function} \item{n}{desired number of ticks} \item{...}{other arguments passed on to pretty} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These often do not produce very attractive breaks. } \examples{ trans_breaks("log10", function(x) 10^x)(c(1, 1e6)) trans_breaks("sqrt", function(x) x^2)(c(1, 100)) trans_breaks(function(x) 1 / x, function(x) 1 / x)(c(1, 100)) trans_breaks(function(x) -x, function(x) -x)(c(1, 100)) } \keyword{internal} scales/man/transform_asinh.Rd0000644000176200001440000000056014672302077015774 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_asinh} \alias{transform_asinh} \alias{asinh_trans} \title{Inverse Hyperbolic Sine transformation} \usage{ transform_asinh() asinh_trans() } \description{ Inverse Hyperbolic Sine transformation } \examples{ plot(transform_asinh(), xlim = c(-1e2, 1e2)) } scales/man/expand_range.Rd0000644000176200001440000000102214672302077015224 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bounds.R \name{expand_range} \alias{expand_range} \title{Expand a range with a multiplicative or additive constant} \usage{ expand_range(range, mul = 0, add = 0, zero_width = 1) } \arguments{ \item{range}{range of data, numeric vector of length 2} \item{mul}{multiplicative constant} \item{add}{additive constant} \item{zero_width}{distance to use if range has zero width} } \description{ Expand a range with a multiplicative or additive constant } scales/man/label_percent.Rd0000644000176200001440000001134514705655135015404 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-percent.R \name{label_percent} \alias{label_percent} \title{Label percentages (2.5\%, 50\%, etc)} \usage{ label_percent( accuracy = NULL, scale = 100, prefix = "", suffix = "\%", big.mark = NULL, decimal.mark = NULL, trim = TRUE, ... ) } \arguments{ \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix}{Additional text to display before the number. The suffix is applied to absolute value before \code{style_positive} and \code{style_negative} are processed so that \code{prefix = "$"} will yield (e.g.) \verb{-$1} and \verb{($1)}.} \item{suffix}{Additional text to display after the number.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{...}{ Arguments passed on to \code{\link[=label_number]{label_number}} \describe{ \item{\code{style_positive}}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_negative}}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{scale_cut}}{Named numeric vector that allows you to rescale large (or small) numbers and add a prefix. Built-in helpers include: \itemize{ \item \code{cut_short_scale()}: [10^3, 10^6) = K, [10^6, 10^9) = M, [10^9, 10^12) = B, [10^12, Inf) = T. \item \code{cut_long_scale()}: [10^3, 10^6) = K, [10^6, 10^12) = M, [10^12, 10^18) = B, [10^18, Inf) = T. \item \code{cut_si(unit)}: uses standard SI units. } If you supply a vector \code{c(a = 100, b = 1000)}, absolute values in the range \verb{[0, 100)} will not be rescaled, absolute values in the range \verb{[100, 1000)} will be divided by 100 and given the suffix "a", and absolute values in the range \verb{[1000, Inf)} will be divided by 1000 and given the suffix "b". If the division creates an irrational value (or one with many digits), the cut value below will be tried to see if it improves the look of the final label.} }} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Label percentages (2.5\%, 50\%, etc) } \examples{ demo_continuous(c(0, 1)) demo_continuous(c(0, 1), labels = label_percent()) # Use prefix and suffix to create your own variants french_percent <- label_percent( decimal.mark = ",", suffix = " \%" ) demo_continuous(c(0, .01), labels = french_percent) } \seealso{ Other labels for continuous scales: \code{\link{label_bytes}()}, \code{\link{label_currency}()}, \code{\link{label_glue}()}, \code{\link{label_number_auto}()}, \code{\link{label_number_si}()}, \code{\link{label_ordinal}()}, \code{\link{label_parse}()}, \code{\link{label_pvalue}()}, \code{\link{label_scientific}()} } \concept{labels for continuous scales} scales/man/wrap_format.Rd0000644000176200001440000000113314672302077015115 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-wrap.R \name{wrap_format} \alias{wrap_format} \title{Superseded interface to \code{label_wrap()}} \usage{ wrap_format(width) } \arguments{ \item{width}{Number of characters per line.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=label_wrap]{label_wrap()}} for new code. } \keyword{internal} scales/man/transform_sqrt.Rd0000644000176200001440000000060014672302077015656 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_sqrt} \alias{transform_sqrt} \alias{sqrt_trans} \title{Square-root transformation} \usage{ transform_sqrt() sqrt_trans() } \description{ This is the variance stabilising transformation for the Poisson distribution. } \examples{ plot(transform_sqrt(), xlim = c(0, 5)) } scales/man/label_bytes.Rd0000644000176200001440000001322514706713437015072 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-bytes.R \name{label_bytes} \alias{label_bytes} \title{Label bytes (1 kB, 2 MB, etc)} \usage{ label_bytes(units = "auto_si", accuracy = 1, scale = 1, ...) } \arguments{ \item{units}{Unit to use. Should either one of: \itemize{ \item "kB", "MB", "GB", "TB", "PB", "EB", "ZB", and "YB" for SI units (base 1000). \item "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", and "YiB" for binary units (base 1024). \item \code{auto_si} or \code{auto_binary} to automatically pick the most appropriate unit for each value. }} \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{...}{ Arguments passed on to \code{\link[=number]{number}} \describe{ \item{\code{prefix}}{Additional text to display before the number. The suffix is applied to absolute value before \code{style_positive} and \code{style_negative} are processed so that \code{prefix = "$"} will yield (e.g.) \verb{-$1} and \verb{($1)}.} \item{\code{suffix}}{Additional text to display after the number.} \item{\code{big.mark}}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{decimal.mark}}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_positive}}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_negative}}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{scale_cut}}{Named numeric vector that allows you to rescale large (or small) numbers and add a prefix. Built-in helpers include: \itemize{ \item \code{cut_short_scale()}: [10^3, 10^6) = K, [10^6, 10^9) = M, [10^9, 10^12) = B, [10^12, Inf) = T. \item \code{cut_long_scale()}: [10^3, 10^6) = K, [10^6, 10^12) = M, [10^12, 10^18) = B, [10^18, Inf) = T. \item \code{cut_si(unit)}: uses standard SI units. } If you supply a vector \code{c(a = 100, b = 1000)}, absolute values in the range \verb{[0, 100)} will not be rescaled, absolute values in the range \verb{[100, 1000)} will be divided by 100 and given the suffix "a", and absolute values in the range \verb{[1000, Inf)} will be divided by 1000 and given the suffix "b". If the division creates an irrational value (or one with many digits), the cut value below will be tried to see if it improves the look of the final label.} \item{\code{trim}}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} }} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Scale bytes into human friendly units. Can use either SI units (e.g. kB = 1000 bytes) or binary units (e.g. kiB = 1024 bytes). See \href{https://en.wikipedia.org/wiki/Units_of_information}{Units of Information} on Wikipedia for more details. } \examples{ demo_continuous(c(1, 1e6)) demo_continuous(c(1, 1e6), labels = label_bytes()) # Auto units are particularly nice on log scales demo_log10(c(1, 1e7), labels = label_bytes()) # You can also set the units demo_continuous(c(1, 1e6), labels = label_bytes("kB")) # You can also use binary units where a megabyte is defined as # (1024) ^ 2 bytes rather than (1000) ^ 2. You'll need to override # the default breaks to make this more informative. demo_continuous(c(1, 1024^2), breaks = breaks_width(250 * 1024), labels = label_bytes("auto_binary") ) } \seealso{ Other labels for continuous scales: \code{\link{label_currency}()}, \code{\link{label_glue}()}, \code{\link{label_number_auto}()}, \code{\link{label_number_si}()}, \code{\link{label_ordinal}()}, \code{\link{label_parse}()}, \code{\link{label_percent}()}, \code{\link{label_pvalue}()}, \code{\link{label_scientific}()} Other labels for log scales: \code{\link{label_log}()}, \code{\link{label_number_si}()}, \code{\link{label_scientific}()} } \concept{labels for continuous scales} \concept{labels for log scales} scales/man/rescale_max.Rd0000644000176200001440000000115614672302077015064 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bounds.R \name{rescale_max} \alias{rescale_max} \title{Rescale numeric vector to have specified maximum} \usage{ rescale_max(x, to = c(0, 1), from = range(x, na.rm = TRUE)) } \arguments{ \item{x}{numeric vector of values to manipulate.} \item{to}{output range (numeric vector of length two)} \item{from}{input range (numeric vector of length two). If not given, is calculated from the range of \code{x}} } \description{ Rescale numeric vector to have specified maximum } \examples{ rescale_max(1:100) rescale_max(runif(50)) rescale_max(1) } scales/man/transform_identity.Rd0000644000176200001440000000057214672302077016526 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_identity} \alias{transform_identity} \alias{identity_trans} \title{Identity transformation (do nothing)} \usage{ transform_identity() identity_trans() } \description{ Identity transformation (do nothing) } \examples{ plot(transform_identity(), xlim = c(-1, 1)) } scales/man/palette-recommendations.Rd0000644000176200001440000000645015001712000017400 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-.R \name{palette-recommendations} \alias{palette-recommendations} \title{Recommendations for colour palettes} \description{ For the purposes of these recommendations, we define a palette as a function that either takes an \code{n} argument for the number of desired output colours or a \code{value} argument between 0-1 representing how far along a gradient output colours should be. The palette then returns a number of colours equal to \code{n} or \code{length(x)}. The convention in the scales package is to name functions that generate palettes (palette factories) with the \code{pal_}-prefix. The benefit of factories is that you can easily parameterise palettes, for example giving options for how a palette should be constructed. In the example below \code{pal_aurora()} is a palette factory parameterised by a \code{direction} argument. \if{html}{\out{
}}\preformatted{pal_aurora <- function(direction = 1) \{ colours <- c("palegreen", "deepskyblue", "magenta") if (sign(direction) == -1) \{ colours <- rev(colours) \} pal_manual(colours, type = "colour") \} class(pal_aurora()) #> [1] "pal_discrete" "scales_pal" "function" }\if{html}{\out{
}} It is recommended that a palette factory returns a function with either the \code{pal_discrete} or \code{pal_continuous} class. If your factory constructs a plain vector of colours, then \code{pal_manual(type = "colour")} or \code{pal_gradient_n()} are useful to return a classed palette for this common use case. When your inner palette function does not return a defined vector of colours, it is recommended to use \code{new_discrete_palette} and \code{new_continuous_palette} instead and supplement the additional \code{type} and \code{na_safe}/\code{nlevels} properties. This should allow easy translation between discrete and continuous palettes. \if{html}{\out{
}}\preformatted{pal_random <- function() \{ fun <- function(n) \{ sample(colours(distinct = TRUE), size = n) \} new_discrete_palette(fun, type = "colour", nlevels = length(colours())) \} }\if{html}{\out{
}} If you don't have parameterised palettes, but also if you have palette factories, it is encouraged to export an (inner) palette function or plain colour vector. This is in addition to exporting the palette factory. Exporting this makes it easy for users to specify for example \code{as_continuous_pal(mypackage::aurora)}. \if{html}{\out{
}}\preformatted{#' @export aurora <- pal_aurora() # or: #' @export aurora <- c("palegreen", "deepskyblue", "magenta") }\if{html}{\out{
}} Lastly, for testing purposes we encourage that your palettes can be interpreted both as discrete palette, but also a continuous palette. To test for this, you can test the output of \code{as_discrete_pal()} and \code{as_continuous_pal()}. \if{html}{\out{
}}\preformatted{test_that("pal_aurora can be discrete or continuous", \{ my_pal <- pal_aurora() colours <- c("palegreen", "deepskyblue", "magenta") expect_equal(as_discrete_pal(my_pal)(3), colours) expect_equal(as_continuous_pal(my_pal)(c(0, 0.5, 1)), alpha(colours, NA)) \}) }\if{html}{\out{
}} } \seealso{ \link[=new_continuous_palette]{palette utilities} } scales/man/pal_manual.Rd0000644000176200001440000000101714672302130014674 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-manual.R \name{pal_manual} \alias{pal_manual} \alias{manual_pal} \title{Manual palette (discrete)} \usage{ pal_manual(values, type = NULL) manual_pal(values, type = NULL) } \arguments{ \item{values}{vector of values to be used as a palette.} \item{type}{A string giving the type of return values. Some example strings include \code{"colour"}, \code{"numeric"}, \code{"linetype"} or \code{"shape"}.} } \description{ Manual palette (discrete) } scales/man/transform_reciprocal.Rd0000644000176200001440000000055714672302077017023 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_reciprocal} \alias{transform_reciprocal} \alias{reciprocal_trans} \title{Reciprocal transformation} \usage{ transform_reciprocal() reciprocal_trans() } \description{ Reciprocal transformation } \examples{ plot(transform_reciprocal(), xlim = c(0, 1)) } scales/man/transform_time.Rd0000644000176200001440000000125014672302077015625 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-date.R \name{transform_time} \alias{transform_time} \alias{time_trans} \title{Transformation for date-times (class POSIXt)} \usage{ transform_time(tz = NULL) time_trans(tz = NULL) } \arguments{ \item{tz}{Optionally supply the time zone. If \code{NULL}, the default, the time zone will be extracted from first input with a non-null tz.} } \description{ Transformation for date-times (class POSIXt) } \examples{ hours <- seq(ISOdate(2000, 3, 20, tz = ""), by = "hour", length.out = 10) t <- transform_time() t$transform(hours) t$inverse(t$transform(hours)) t$format(t$breaks(range(hours))) } scales/man/colour_ramp.Rd0000644000176200001440000000374714672302077015133 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/colour-ramp.R \name{colour_ramp} \alias{colour_ramp} \title{Fast colour interpolation} \usage{ colour_ramp(colors, na.color = NA, alpha = TRUE) } \arguments{ \item{colors}{Colours to interpolate; must be a valid argument to \code{\link[grDevices:col2rgb]{grDevices::col2rgb()}}. This can be a character vector of \code{"#RRGGBB"} or \code{"#RRGGBBAA"}, colour names from \code{\link[grDevices:colors]{grDevices::colors()}}, or a positive integer that indexes into \code{\link[grDevices:palette]{grDevices::palette()}}.} \item{na.color}{The colour to map to \code{NA} values (for example, \code{"#606060"} for dark grey, or \code{"#00000000"} for transparent) and values outside of [0,1]. Can itself by \code{NA}, which will simply cause an \code{NA} to be inserted into the output.} \item{alpha}{Whether to include alpha transparency channels in interpolation. If \code{TRUE} then the alpha information is included in the interpolation. The returned colours will be provided in \code{"#RRGGBBAA"} format when needed, i.e., in cases where the colour is not fully opaque, so that the \code{"AA"} part is not equal to \code{"FF"}. Fully opaque colours will be returned in \code{"#RRGGBB"} format. If \code{FALSE}, the alpha information is discarded before interpolation and colours are always returned as \code{"#RRGGBB"}.} } \value{ A function that takes a numeric vector and returns a character vector of the same length with RGB or RGBA hex colours. } \description{ Returns a function that maps the interval [0,1] to a set of colours. Interpolation is performed in the CIELAB colour space. Similar to \code{\link[grDevices]{colorRamp}(space = 'Lab')}, but hundreds of times faster, and provides results in \code{"#RRGGBB"} (or \code{"#RRGGBBAA"}) character form instead of RGB colour matrices. } \examples{ ramp <- colour_ramp(c("red", "green", "blue")) show_col(ramp(seq(0, 1, length = 12))) } \seealso{ \code{\link[grDevices]{colorRamp}} } scales/man/demo_continuous.Rd0000644000176200001440000000112114672302077016003 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{demo_continuous} \alias{demo_continuous} \alias{demo_log10} \alias{demo_discrete} \alias{demo_datetime} \alias{demo_time} \alias{demo_timespan} \title{Demonstrate scales functions with ggplot2 code} \usage{ demo_continuous(x, ...) demo_log10(x, ...) demo_discrete(x, ...) demo_datetime(x, ...) demo_time(x, ...) demo_timespan(x, ...) } \arguments{ \item{x}{A vector of data} } \description{ These functions generate ggplot2 code needed to use scales functions for real code. } \keyword{internal} scales/man/date_format.Rd0000644000176200001440000000261514705655135015072 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-date.R \name{date_format} \alias{date_format} \alias{time_format} \title{Superseded interface to \code{label_date()}/\code{label_time()}} \usage{ date_format(format = "\%Y-\%m-\%d", tz = "UTC", locale = NULL) time_format(format = "\%H:\%M:\%S", tz = "UTC", locale = NULL) } \arguments{ \item{format}{For \code{label_date()} and \code{label_time()} a date/time format string using standard POSIX specification. See \code{\link[=strptime]{strptime()}} for details. For \code{label_date_short()} a character vector of length 4 giving the format components to use for year, month, day, and hour respectively.} \item{tz}{a time zone name, see \code{\link[=timezones]{timezones()}}. Defaults to UTC} \item{locale}{Locale to use when for day and month names. The default uses the current locale. Setting this argument requires stringi, and you can see a complete list of supported locales with \code{\link[stringi:stri_locale_list]{stringi::stri_locale_list()}}.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=label_date]{label_date()}}/\code{\link[=label_time]{label_time()}} for new code. } \keyword{internal} scales/man/breaks_width.Rd0000644000176200001440000000524414706713437015255 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks.R \name{breaks_width} \alias{breaks_width} \title{Equally spaced breaks} \usage{ breaks_width(width, offset = 0) } \arguments{ \item{width}{Distance between each break. Either a number, or for date/times, a single string of the form \code{"{n} {unit}"}, e.g. "1 month", "5 days". Unit can be of one "sec", "min", "hour", "day", "week", "month", "year".} \item{offset}{Use if you don't want breaks to start at zero, or on a conventional date or time boundary such as the 1st of January or midnight. Either a number, or for date/times, a single string of the form \code{"{n} {unit}"}, as for \code{width}. \code{offset} can be a vector, which will accumulate in the order given. This is mostly useful for dates, where e.g. \code{c("3 months", "5 days")} will offset by three months and five days, which is useful for the UK tax year. Note that due to way that dates are rounded, there's no guarantee that \code{offset = c(x, y)} will give the same result as \code{offset = c(y, x)}.} } \value{ All \code{breaks_()} functions return a function for generating breaks. These functions takes, as their first argument a vector of values that represent the data range to provide breaks for. Some will optionally take a second argument that allows you to specify the number of breaks to recieve. } \description{ Useful for numeric, date, and date-time scales. } \examples{ demo_continuous(c(0, 100)) demo_continuous(c(0, 100), breaks = breaks_width(10)) demo_continuous(c(0, 100), breaks = breaks_width(20, -4)) demo_continuous(c(0, 100), breaks = breaks_width(20, 4)) # This is also useful for dates one_month <- as.POSIXct(c("2020-05-01", "2020-06-01")) demo_datetime(one_month) demo_datetime(one_month, breaks = breaks_width("1 week")) demo_datetime(one_month, breaks = breaks_width("5 days")) # This is so useful that scale_x_datetime() has a shorthand: demo_datetime(one_month, date_breaks = "5 days") # hms times also work one_hour <- hms::hms(hours = 0:1) demo_time(one_hour) demo_time(one_hour, breaks = breaks_width("15 min")) demo_time(one_hour, breaks = breaks_width("600 sec")) # Offets are useful for years that begin on dates other than the 1st of # January, such as the UK financial year, which begins on the 1st of April. three_years <- as.POSIXct(c("2020-01-01", "2021-01-01", "2022-01-01")) demo_datetime( three_years, breaks = breaks_width("1 year", offset = "3 months") ) # The offset can be a vector, to create offsets that have compound units, # such as the UK fiscal (tax) year, which begins on the 6th of April. demo_datetime( three_years, breaks = breaks_width("1 year", offset = c("3 months", "5 days")) ) } scales/man/pal_linetype.Rd0000644000176200001440000000047614672302077015272 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-linetype.R \name{pal_linetype} \alias{pal_linetype} \alias{linetype_pal} \title{Line type palette (discrete)} \usage{ pal_linetype() linetype_pal() } \description{ Based on a set supplied by Richard Pearson, University of Manchester } scales/man/breaks_timespan.Rd0000644000176200001440000000175714706713437015763 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks.R \name{breaks_timespan} \alias{breaks_timespan} \title{Breaks for timespan data} \usage{ breaks_timespan(unit = c("secs", "mins", "hours", "days", "weeks"), n = 5) } \arguments{ \item{unit}{The unit used to interpret numeric data input} \item{n}{Desired number of breaks. You may get slightly more or fewer breaks that requested.} } \value{ All \code{breaks_()} functions return a function for generating breaks. These functions takes, as their first argument a vector of values that represent the data range to provide breaks for. Some will optionally take a second argument that allows you to specify the number of breaks to recieve. } \description{ As timespan units span a variety of bases (1000 below seconds, 60 for second and minutes, 24 for hours, and 7 for days), the range of the input data determines the base used for calculating breaks } \examples{ demo_timespan(seq(0, 100), breaks = breaks_timespan()) } scales/man/pal_brewer.Rd0000644000176200001440000000212214672302077014715 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-brewer.R \name{pal_brewer} \alias{pal_brewer} \alias{brewer_pal} \title{Colour Brewer palette (discrete)} \usage{ pal_brewer(type = "seq", palette = 1, direction = 1) brewer_pal(type = "seq", palette = 1, direction = 1) } \arguments{ \item{type}{One of "seq" (sequential), "div" (diverging) or "qual" (qualitative)} \item{palette}{If a string, will use that named palette. If a number, will index into the list of palettes of appropriate \code{type}} \item{direction}{Sets the order of colours in the scale. If 1, the default, colours are as output by \code{\link[RColorBrewer:ColorBrewer]{RColorBrewer::brewer.pal()}}. If -1, the order of colours is reversed.} } \description{ Colour Brewer palette (discrete) } \examples{ show_col(pal_brewer()(10)) show_col(pal_brewer("div")(5)) show_col(pal_brewer(palette = "Greens")(5)) # Can use with gradient_n to create a continuous gradient cols <- pal_brewer("div")(5) show_col(pal_gradient_n(cols)(seq(0, 1, length.out = 30))) } \references{ \url{https://colorbrewer2.org} } scales/man/unit_format.Rd0000644000176200001440000000455014705655135015134 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/labels-retired.R \name{unit_format} \alias{unit_format} \title{Unit labels} \usage{ unit_format( accuracy = NULL, scale = 1, prefix = "", unit = "m", sep = " ", suffix = paste0(sep, unit), big.mark = NULL, decimal.mark = NULL, trim = TRUE, ... ) } \arguments{ \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix}{Additional text to display before the number. The suffix is applied to absolute value before \code{style_positive} and \code{style_negative} are processed so that \code{prefix = "$"} will yield (e.g.) \verb{-$1} and \verb{($1)}.} \item{unit}{The units to append.} \item{sep}{The separator between the number and the unit label.} \item{suffix}{Additional text to display after the number.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{...}{Other arguments passed on to \code{\link[base:format]{base::format()}}.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} This function is kept for backward compatiblity; you should either use \code{\link[=label_number]{label_number()}} or \code{\link[=label_number_si]{label_number_si()}} instead. } \examples{ # Label with units demo_continuous(c(0, 1), labels = unit_format(unit = "m")) # Labels in kg, but original data in g km <- unit_format(unit = "km", scale = 1e-3, digits = 2) demo_continuous(c(0, 2500), labels = km) } \keyword{internal} scales/man/trim_to_domain.Rd0000644000176200001440000000103014672302077015574 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform.R \name{trim_to_domain} \alias{trim_to_domain} \alias{trans_range} \title{Compute range of transformed values} \usage{ trim_to_domain(transform, x) trans_range(transform, x) } \arguments{ \item{transform}{a transformation object, or the name of a transformation object given as a string.} \item{x}{a numeric vector to compute the range of} } \description{ Silently drops any ranges outside of the domain of \code{transform}. } \keyword{internal} scales/man/transform_yj.Rd0000644000176200001440000000302414672302077015312 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_yj} \alias{transform_yj} \alias{yj_trans} \title{Yeo-Johnson transformation} \usage{ transform_yj(p) yj_trans(p) } \arguments{ \item{p}{Transformation exponent, \eqn{\lambda}.} } \description{ The Yeo-Johnson transformation is a flexible transformation that is similar to Box-Cox, \code{\link[=transform_boxcox]{transform_boxcox()}}, but does not require input values to be greater than zero. } \details{ The transformation takes one of four forms depending on the values of \code{y} and \eqn{\lambda}. \itemize{ \item \eqn{y \ge 0} and \eqn{\lambda \neq 0}{\lambda != 0} : \eqn{y^{(\lambda)} = \frac{(y + 1)^\lambda - 1}{\lambda}}{y^(\lambda) = ((y + 1)^\lambda - 1)/\lambda} \item \eqn{y \ge 0} and \eqn{\lambda = 0}: \eqn{y^{(\lambda)} = \ln(y + 1)}{y^(\lambda) = ln(y + 1)} \item \eqn{y < 0} and \eqn{\lambda \neq 2}{\lambda != 2}: \eqn{y^{(\lambda)} = -\frac{(-y + 1)^{(2 - \lambda)} - 1}{2 - \lambda}}{y^(\lambda) = -((-y + 1)^(2 - \lambda) - 1)/(2 - \lambda)} \item \eqn{y < 0} and \eqn{\lambda = 2}: \eqn{y^{(\lambda)} = -\ln(-y + 1)}{y^(\lambda) = -ln(-y + 1)} } } \examples{ plot(transform_yj(-1), xlim = c(-10, 10)) plot(transform_yj(0), xlim = c(-10, 10)) plot(transform_yj(1), xlim = c(-10, 10)) plot(transform_yj(2), xlim = c(-10, 10)) } \references{ Yeo, I., & Johnson, R. (2000). A New Family of Power Transformations to Improve Normality or Symmetry. Biometrika, 87(4), 954-959. \url{https://www.jstor.org/stable/2673623} } scales/man/comma.Rd0000644000176200001440000001114714705655135013701 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-number.R \name{comma} \alias{comma} \alias{number_format} \alias{comma_format} \title{Superseded interface to \code{label_number()}/\code{label_comma()}} \usage{ comma( x, accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = ",", decimal.mark = ".", trim = TRUE, digits, ... ) number_format( accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = NULL, decimal.mark = NULL, style_positive = NULL, style_negative = NULL, scale_cut = NULL, trim = TRUE, ... ) comma_format( accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = ",", decimal.mark = ".", trim = TRUE, digits, ... ) } \arguments{ \item{x}{A numeric vector to format.} \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix}{Additional text to display before the number. The suffix is applied to absolute value before \code{style_positive} and \code{style_negative} are processed so that \code{prefix = "$"} will yield (e.g.) \verb{-$1} and \verb{($1)}.} \item{suffix}{Additional text to display after the number.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{digits}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Use \code{accuracy} instead.} \item{...}{Other arguments passed on to \code{\link[base:format]{base::format()}}.} \item{style_positive}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{style_negative}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{scale_cut}{Named numeric vector that allows you to rescale large (or small) numbers and add a prefix. Built-in helpers include: \itemize{ \item \code{cut_short_scale()}: [10^3, 10^6) = K, [10^6, 10^9) = M, [10^9, 10^12) = B, [10^12, Inf) = T. \item \code{cut_long_scale()}: [10^3, 10^6) = K, [10^6, 10^12) = M, [10^12, 10^18) = B, [10^18, Inf) = T. \item \code{cut_si(unit)}: uses standard SI units. } If you supply a vector \code{c(a = 100, b = 1000)}, absolute values in the range \verb{[0, 100)} will not be rescaled, absolute values in the range \verb{[100, 1000)} will be divided by 100 and given the suffix "a", and absolute values in the range \verb{[1000, Inf)} will be divided by 1000 and given the suffix "b". If the division creates an irrational value (or one with many digits), the cut value below will be tried to see if it improves the look of the final label.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=label_number]{label_number()}}/\code{\link[=label_comma]{label_comma()}} for new code. } \keyword{internal} scales/man/breaks_pretty.Rd0000644000176200001440000000246214706713437015464 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks.R \name{breaks_pretty} \alias{breaks_pretty} \title{Pretty breaks for date/times} \usage{ breaks_pretty(n = 5, ...) } \arguments{ \item{n}{Desired number of breaks. You may get slightly more or fewer breaks that requested.} \item{...}{other arguments passed on to \code{\link[=pretty]{pretty()}}} } \value{ All \code{breaks_()} functions return a function for generating breaks. These functions takes, as their first argument a vector of values that represent the data range to provide breaks for. Some will optionally take a second argument that allows you to specify the number of breaks to recieve. } \description{ Uses default R break algorithm as implemented in \code{\link[=pretty]{pretty()}}. This is primarily useful for date/times, as \code{\link[=extended_breaks]{extended_breaks()}} should do a slightly better job for numeric scales. } \examples{ one_month <- as.POSIXct(c("2020-05-01", "2020-06-01")) demo_datetime(one_month) demo_datetime(one_month, breaks = breaks_pretty(2)) demo_datetime(one_month, breaks = breaks_pretty(4)) # Tightly spaced date breaks often need custom labels too demo_datetime(one_month, breaks = breaks_pretty(12)) demo_datetime(one_month, breaks = breaks_pretty(12), labels = label_date_short() ) } scales/man/zero_range.Rd0000644000176200001440000000263514672302077014737 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bounds.R \name{zero_range} \alias{zero_range} \title{Determine if range of vector is close to zero, with a specified tolerance} \usage{ zero_range(x, tol = 1000 * .Machine$double.eps) } \arguments{ \item{x}{numeric range: vector of length 2} \item{tol}{A value specifying the tolerance.} } \value{ logical \code{TRUE} if the relative difference of the endpoints of the range are not distinguishable from 0. } \description{ The machine epsilon is the difference between 1.0 and the next number that can be represented by the machine. By default, this function uses epsilon * 1000 as the tolerance. First it scales the values so that they have a mean of 1, and then it checks if the difference between them is larger than the tolerance. } \examples{ eps <- .Machine$double.eps zero_range(c(1, 1 + eps)) zero_range(c(1, 1 + 99 * eps)) zero_range(c(1, 1 + 1001 * eps)) zero_range(c(1, 1 + 2 * eps), tol = eps) # Scaling up or down all the values has no effect since the values # are rescaled to 1 before checking against tol zero_range(100000 * c(1, 1 + eps)) zero_range(100000 * c(1, 1 + 1001 * eps)) zero_range(.00001 * c(1, 1 + eps)) zero_range(.00001 * c(1, 1 + 1001 * eps)) # NA values zero_range(c(1, NA)) # NA zero_range(c(1, NaN)) # NA # Infinite values zero_range(c(1, Inf)) # FALSE zero_range(c(-Inf, Inf)) # FALSE zero_range(c(Inf, Inf)) # TRUE } scales/man/pvalue_format.Rd0000644000176200001440000000270214705655135015446 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-pvalue.R \name{pvalue_format} \alias{pvalue_format} \alias{pvalue} \title{Superseded interface to \code{label_pvalue()}} \usage{ pvalue_format( accuracy = 0.001, decimal.mark = NULL, prefix = NULL, add_p = FALSE ) pvalue(x, accuracy = 0.001, decimal.mark = NULL, prefix = NULL, add_p = FALSE) } \arguments{ \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{prefix}{A character vector of length 3 giving the prefixes to put in front of numbers. The default values are \code{c("p<", "p=", "p>")} if \code{add_p} is \code{TRUE} and \code{c("<", "", ">")} if \code{FALSE}.} \item{add_p}{Add "p=" before the value?} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=label_pvalue]{label_pvalue()}} for new code. } \keyword{internal} scales/man/pal_gradient_n.Rd0000644000176200001440000000150314672302077015543 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-gradient.R \name{pal_gradient_n} \alias{pal_gradient_n} \alias{gradient_n_pal} \title{Arbitrary colour gradient palette (continuous)} \usage{ pal_gradient_n(colours, values = NULL, space = "Lab") gradient_n_pal(colours, values = NULL, space = "Lab") } \arguments{ \item{colours}{vector of colours} \item{values}{if colours should not be evenly positioned along the gradient this vector gives the position (between 0 and 1) for each colour in the \code{colours} vector. See \code{\link[=rescale]{rescale()}} for a convenience function to map an arbitrary range to between 0 and 1.} \item{space}{colour space in which to calculate gradient. Must be "Lab" - other values are deprecated.} } \description{ Arbitrary colour gradient palette (continuous) } scales/man/rescale_none.Rd0000644000176200001440000000056114672302077015235 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bounds.R \name{rescale_none} \alias{rescale_none} \title{Don't perform rescaling} \usage{ rescale_none(x, ...) } \arguments{ \item{x}{numeric vector of values to manipulate.} \item{...}{all other arguments ignored} } \description{ Don't perform rescaling } \examples{ rescale_none(1:100) } scales/man/dscale.Rd0000644000176200001440000000074514672302077014037 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scale-discrete.R \name{dscale} \alias{dscale} \title{Discrete scale} \usage{ dscale(x, palette, na.value = NA) } \arguments{ \item{x}{vector of discrete values to scale} \item{palette}{aesthetic palette to use} \item{na.value}{aesthetic to use for missing values} } \description{ Discrete scale } \examples{ with(mtcars, plot(disp, mpg, pch = 20, cex = 3, col = dscale(factor(cyl), pal_brewer()) )) } scales/man/label_number_auto.Rd0000644000176200001440000000357114706713437016267 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-number-auto.R \name{label_number_auto} \alias{label_number_auto} \title{Label numbers, avoiding scientific notation where possible} \usage{ label_number_auto() } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Switches between \code{\link[=number_format]{number_format()}} and \code{\link[=scientific_format]{scientific_format()}} based on a set of heuristics designed to automatically generate useful labels across a wide range of inputs } \examples{ # Very small and very large numbers get scientific notation demo_continuous(c(0, 1e-6), labels = label_number_auto()) demo_continuous(c(0, 1e9), labels = label_number_auto()) # Other ranges get the numbers printed in full demo_continuous(c(0, 1e-3), labels = label_number_auto()) demo_continuous(c(0, 1), labels = label_number_auto()) demo_continuous(c(0, 1e3), labels = label_number_auto()) demo_continuous(c(0, 1e6), labels = label_number_auto()) # Transformation is applied individually so you get as little # scientific notation as possible demo_log10(c(1, 1e7), labels = label_number_auto()) } \seealso{ Other labels for continuous scales: \code{\link{label_bytes}()}, \code{\link{label_currency}()}, \code{\link{label_glue}()}, \code{\link{label_number_si}()}, \code{\link{label_ordinal}()}, \code{\link{label_parse}()}, \code{\link{label_percent}()}, \code{\link{label_pvalue}()}, \code{\link{label_scientific}()} } \concept{labels for continuous scales} scales/man/regular_minor_breaks.Rd0000644000176200001440000000106414672302077016773 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/minor_breaks.R \name{regular_minor_breaks} \alias{regular_minor_breaks} \title{Minor breaks} \usage{ regular_minor_breaks(reverse = FALSE) } \arguments{ \item{reverse}{if TRUE, calculates the minor breaks for a reversed scale} } \description{ Places minor breaks between major breaks. } \examples{ m <- extended_breaks()(c(1, 10)) regular_minor_breaks()(m, c(1, 10), n = 2) n <- extended_breaks()(c(0, -9)) regular_minor_breaks(reverse = TRUE)(n, c(0, -9), n = 2) } \keyword{internal} scales/man/train_discrete.Rd0000644000176200001440000000132614705417700015574 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scale-discrete.R \name{train_discrete} \alias{train_discrete} \title{Train (update) a discrete scale} \usage{ train_discrete( new, existing = NULL, drop = FALSE, na.rm = FALSE, fct = NA, call = caller_env() ) } \arguments{ \item{new}{New data to add to scale} \item{existing}{Optional existing scale to update} \item{drop}{\code{TRUE}, will drop factor levels not associated with data} \item{na.rm}{If \code{TRUE}, will remove missing values} \item{fct}{Treat \code{existing} as if it came from a factor (ie. don't sort the range)} \item{call}{A call to display in error messages} } \description{ Train (update) a discrete scale } scales/man/col_numeric.Rd0000644000176200001440000001257514672302077015107 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/colour-mapping.R \name{col_numeric} \alias{col_numeric} \alias{col_bin} \alias{col_quantile} \alias{col_factor} \title{Colour mapping} \usage{ col_numeric( palette, domain, na.color = "#808080", alpha = FALSE, reverse = FALSE ) col_bin( palette, domain, bins = 7, pretty = TRUE, na.color = "#808080", alpha = FALSE, reverse = FALSE, right = FALSE ) col_quantile( palette, domain, n = 4, probs = seq(0, 1, length.out = n + 1), na.color = "#808080", alpha = FALSE, reverse = FALSE, right = FALSE ) col_factor( palette, domain, levels = NULL, ordered = FALSE, na.color = "#808080", alpha = FALSE, reverse = FALSE ) } \arguments{ \item{palette}{The colours or colour function that values will be mapped to} \item{domain}{The possible values that can be mapped. For \code{col_numeric} and \code{col_bin}, this can be a simple numeric range (e.g. \code{c(0, 100)}); \code{col_quantile} needs representative numeric data; and \code{col_factor} needs categorical data. If \code{NULL}, then whenever the resulting colour function is called, the \code{x} value will represent the domain. This implies that if the function is invoked multiple times, the encoding between values and colours may not be consistent; if consistency is needed, you must provide a non-\code{NULL} domain.} \item{na.color}{The colour to return for \code{NA} values. Note that \code{na.color = NA} is valid.} \item{alpha}{Whether alpha channels should be respected or ignored. If \code{TRUE} then colors without explicit alpha information will be treated as fully opaque.} \item{reverse}{Whether the colors (or color function) in \code{palette} should be used in reverse order. For example, if the default order of a palette goes from blue to green, then \code{reverse = TRUE} will result in the colors going from green to blue.} \item{bins}{Either a numeric vector of two or more unique cut points or a single number (greater than or equal to 2) giving the number of intervals into which the domain values are to be cut.} \item{pretty}{Whether to use the function \code{\link[=pretty]{pretty()}} to generate the bins when the argument \code{bins} is a single number. When \code{pretty = TRUE}, the actual number of bins may not be the number of bins you specified. When \code{pretty = FALSE}, \code{\link[=seq]{seq()}} is used to generate the bins and the breaks may not be "pretty".} \item{right}{parameter supplied to \code{\link[base:cut]{base::cut()}}. See Details} \item{n}{Number of equal-size quantiles desired. For more precise control, use the \code{probs} argument instead.} \item{probs}{See \code{\link[stats:quantile]{stats::quantile()}}. If provided, the \code{n} argument is ignored.} \item{levels}{An alternate way of specifying levels; if specified, domain is ignored} \item{ordered}{If \code{TRUE} and \code{domain} needs to be coerced to a factor, treat it as already in the correct order} } \value{ A function that takes a single parameter \code{x}; when called with a vector of numbers (except for \code{col_factor}, which expects factors/characters), #RRGGBB colour strings are returned (unless \code{alpha = TRUE} in which case #RRGGBBAA may also be possible). } \description{ Conveniently maps data values (numeric or factor/character) to colours according to a given palette, which can be provided in a variety of formats. } \details{ \code{col_numeric} is a simple linear mapping from continuous numeric data to an interpolated palette. \code{col_bin} also maps continuous numeric data, but performs binning based on value (see the \code{\link[base:cut]{base::cut()}} function). \code{col_bin} defaults for the \code{cut} function are \code{include.lowest = TRUE} and \code{right = FALSE}. \code{col_quantile} similarly bins numeric data, but via the \code{\link[stats:quantile]{stats::quantile()}} function. \code{col_factor} maps factors to colours. If the palette is discrete and has a different number of colours than the number of factors, interpolation is used. The \code{palette} argument can be any of the following: \enumerate{ \item{A character vector of RGB or named colours. Examples: \code{palette()}, \code{c("#000000", "#0000FF", "#FFFFFF")}, \code{topo.colors(10)}} \item{The name of an RColorBrewer palette, e.g. \code{"BuPu"} or \code{"Greens"}.} \item{The full name of a viridis palette: \code{"viridis"}, \code{"magma"}, \code{"inferno"}, or \code{"plasma"}.} \item{A function that receives a single value between 0 and 1 and returns a colour. Examples: \code{colorRamp(c("#000000", "#FFFFFF"), interpolate="spline")}.} } } \examples{ pal <- col_bin("Greens", domain = 0:100) show_col(pal(sort(runif(10, 60, 100)))) # Exponential distribution, mapped continuously show_col(col_numeric("Blues", domain = NULL)(sort(rexp(16)))) # Exponential distribution, mapped by interval show_col(col_bin("Blues", domain = NULL, bins = 4)(sort(rexp(16)))) # Exponential distribution, mapped by quantile show_col(col_quantile("Blues", domain = NULL)(sort(rexp(16)))) # Categorical data; by default, the values being coloured span the gamut... show_col(col_factor("RdYlBu", domain = NULL)(LETTERS[1:5])) # ...unless the data is a factor, without droplevels... show_col(col_factor("RdYlBu", domain = NULL)(factor(LETTERS[1:5], levels = LETTERS))) # ...or the domain is stated explicitly. show_col(col_factor("RdYlBu", levels = LETTERS)(LETTERS[1:5])) } scales/man/scientific_format.Rd0000644000176200001440000000276714705655135016305 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-scientific.R \name{scientific_format} \alias{scientific_format} \alias{scientific} \title{Superseded interface to \code{label_scientific()}} \usage{ scientific_format( digits = 3, scale = 1, prefix = "", suffix = "", decimal.mark = NULL, trim = TRUE, ... ) scientific( x, digits = 3, scale = 1, prefix = "", suffix = "", decimal.mark = NULL, trim = TRUE, ... ) } \arguments{ \item{digits}{Number of digits to show before exponent.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix, suffix}{Symbols to display before and after value.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{...}{Other arguments passed on to \code{\link[base:format]{base::format()}}.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=label_scientific]{label_scientific()}} for new code. } \keyword{internal} scales/man/pretty_breaks.Rd0000644000176200001440000000134614672302077015460 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks.R \name{pretty_breaks} \alias{pretty_breaks} \title{Superseded interface to \code{breaks_pretty()}} \usage{ pretty_breaks(n = 5, ...) } \arguments{ \item{n}{Desired number of breaks. You may get slightly more or fewer breaks that requested.} \item{...}{other arguments passed on to \code{\link[=pretty]{pretty()}}} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=breaks_pretty]{breaks_pretty()}} for new code. } \keyword{internal} scales/man/date_breaks.Rd0000644000176200001440000000121214672302077015036 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks-retired.R \name{date_breaks} \alias{date_breaks} \title{Regularly spaced dates} \usage{ date_breaks(width = "1 month") } \arguments{ \item{width}{an interval specification, one of "sec", "min", "hour", "day", "week", "month", "year". Can be by an integer and a space, or followed by "s". Fractional seconds are supported.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} Use \code{breaks_width()} instead. } \keyword{internal} scales/man/label_number_si.Rd0000644000176200001440000001222314705655135015723 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-number-si.R \name{label_number_si} \alias{label_number_si} \title{Label numbers with SI prefixes (2 kg, 5 mm, etc)} \usage{ label_number_si(unit = "", accuracy = NULL, scale = 1, suffix = "", ...) } \arguments{ \item{unit}{Unit of measurement (e.g. \code{"m"} for meter, the SI unit of length).} \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is already using an SI prefix.} \item{suffix}{Additional text to display after the number.} \item{...}{ Arguments passed on to \code{\link[=label_number]{label_number}} \describe{ \item{\code{prefix}}{Additional text to display before the number. The suffix is applied to absolute value before \code{style_positive} and \code{style_negative} are processed so that \code{prefix = "$"} will yield (e.g.) \verb{-$1} and \verb{($1)}.} \item{\code{big.mark}}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{decimal.mark}}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_positive}}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_negative}}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{scale_cut}}{Named numeric vector that allows you to rescale large (or small) numbers and add a prefix. Built-in helpers include: \itemize{ \item \code{cut_short_scale()}: [10^3, 10^6) = K, [10^6, 10^9) = M, [10^9, 10^12) = B, [10^12, Inf) = T. \item \code{cut_long_scale()}: [10^3, 10^6) = K, [10^6, 10^12) = M, [10^12, 10^18) = B, [10^18, Inf) = T. \item \code{cut_si(unit)}: uses standard SI units. } If you supply a vector \code{c(a = 100, b = 1000)}, absolute values in the range \verb{[0, 100)} will not be rescaled, absolute values in the range \verb{[100, 1000)} will be divided by 100 and given the suffix "a", and absolute values in the range \verb{[1000, Inf)} will be divided by 1000 and given the suffix "b". If the division creates an irrational value (or one with many digits), the cut value below will be tried to see if it improves the look of the final label.} \item{\code{trim}}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} }} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} \code{label_number_si()} is deprecated because the previous unit didn't actually use SI units, but instead used the so called "short scale". You can now get the same results as before with \code{label_number(scale_cut = cut_short_scale())}, or if you want correct SI units, \code{label_number(scale_cut = cut_si("unit"))}. } \seealso{ Other labels for continuous scales: \code{\link{label_bytes}()}, \code{\link{label_currency}()}, \code{\link{label_glue}()}, \code{\link{label_number_auto}()}, \code{\link{label_ordinal}()}, \code{\link{label_parse}()}, \code{\link{label_percent}()}, \code{\link{label_pvalue}()}, \code{\link{label_scientific}()} Other labels for log scales: \code{\link{label_bytes}()}, \code{\link{label_log}()}, \code{\link{label_scientific}()} } \concept{labels for continuous scales} \concept{labels for log scales} \keyword{internal} scales/man/minor_breaks_log.Rd0000644000176200001440000000176714705655135016130 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks-log.R \name{minor_breaks_log} \alias{minor_breaks_log} \title{Minor breaks for log-10 axes} \usage{ minor_breaks_log(detail = NULL, smallest = NULL) } \arguments{ \item{detail}{Any of \code{1}, \code{5} and \code{10} to mark multiples of powers, multiples of 5 of powers or just powers respectively.} \item{smallest}{Smallest absolute value to mark when the range includes negative numbers.} } \value{ A function to generate minor ticks. } \description{ This break function is designed to mark every power, multiples of 5 and/or 1 of that power for base 10. } \examples{ # Standard usage with log10 scale demo_log10(c(1, 1e10), minor_breaks = minor_breaks_log()) # Increasing detail over many powers demo_log10(c(1, 1e10), minor_breaks = minor_breaks_log(detail = 1)) # Adjusting until where to draw minor breaks demo_continuous( c(-1000, 1000), transform = asinh_trans(), minor_breaks = minor_breaks_log(smallest = 1) ) } scales/man/pal_rescale.Rd0000644000176200001440000000076414672302077015057 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-rescale.R \name{pal_rescale} \alias{pal_rescale} \alias{rescale_pal} \title{Rescale palette (continuous)} \usage{ pal_rescale(range = c(0.1, 1)) rescale_pal(range = c(0.1, 1)) } \arguments{ \item{range}{Numeric vector of length two, giving range of possible values. Should be between 0 and 1.} } \description{ Just rescales the input to the specific output range. Useful for alpha, size, and continuous position. } scales/man/oob.Rd0000644000176200001440000000747014672302077013365 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bounds.R \name{oob} \alias{oob} \alias{oob_censor} \alias{oob_censor_any} \alias{oob_discard} \alias{oob_squish} \alias{oob_squish_any} \alias{oob_squish_infinite} \alias{oob_keep} \alias{censor} \alias{discard} \alias{squish} \alias{squish_infinite} \title{Out of bounds handling} \usage{ oob_censor(x, range = c(0, 1), only.finite = TRUE) oob_censor_any(x, range = c(0, 1)) oob_discard(x, range = c(0, 1)) oob_squish(x, range = c(0, 1), only.finite = TRUE) oob_squish_any(x, range = c(0, 1)) oob_squish_infinite(x, range = c(0, 1)) oob_keep(x, range = c(0, 1)) censor(x, range = c(0, 1), only.finite = TRUE) discard(x, range = c(0, 1)) squish(x, range = c(0, 1), only.finite = TRUE) squish_infinite(x, range = c(0, 1)) } \arguments{ \item{x}{A numeric vector of values to modify.} \item{range}{A numeric vector of length two giving the minimum and maximum limit of the desired output range respectively.} \item{only.finite}{A logical of length one. When \code{TRUE}, only finite values are altered. When \code{FALSE}, also infinite values are altered.} } \value{ Most \code{oob_()} functions return a vector of numerical values of the same length as the \code{x} argument, wherein out of bounds values have been modified. Only \code{oob_discard()} returns a vector of less than or of equal length to the \code{x} argument. } \description{ This set of functions modify data values outside a given range. The \verb{oob_*()} functions are designed to be passed as the \code{oob} argument of ggplot2 continuous and binned scales, with \code{oob_discard} being an exception. These functions affect out of bounds values in the following ways: \itemize{ \item \code{oob_censor()} replaces out of bounds values with \code{NA}s. This is the default \code{oob} argument for continuous scales. \item \code{oob_censor_any()} acts like \code{oob_censor()}, but also replaces infinite values with \code{NA}s. \item \code{oob_squish()} replaces out of bounds values with the nearest limit. This is the default \code{oob} argument for binned scales. \item \code{oob_squish_any()} acts like \code{oob_squish()}, but also replaces infinite values with the nearest limit. \item \code{oob_squish_infinite()} only replaces infinite values by the nearest limit. \item \code{oob_keep()} does not adjust out of bounds values. In position scales, behaves as zooming limits without data removal. \item \code{oob_discard()} removes out of bounds values from the input. Not suitable for ggplot2 scales. } } \details{ The \code{oob_censor_any()} and \code{oob_squish_any()} functions are the same as \code{oob_censor()} and \code{oob_squish()} with the \code{only.finite} argument set to \code{FALSE}. Replacing position values with \code{NA}s, as \code{oob_censor()} does, will typically lead to removal of those datapoints in ggplot. Setting ggplot coordinate limits is equivalent to using \code{oob_keep()} in position scales. } \section{Old interface}{ \code{censor()}, \code{squish()}, \code{squish_infinite()} and \code{discard()} are no longer recommended; please use \code{oob_censor()}, \code{oob_squish()}, \code{oob_squish_infinite()} and \code{oob_discard()} instead. } \examples{ # Censoring replaces out of bounds values with NAs oob_censor(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) oob_censor_any(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) # Squishing replaces out of bounds values with the nearest range limit oob_squish(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) oob_squish_any(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) oob_squish_infinite(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) # Keeping does not alter values oob_keep(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) # Discarding will remove out of bounds values oob_discard(c(-Inf, -1, 0.5, 1, 2, NA, Inf)) } \author{ \code{oob_squish()}: Homer Strong \href{mailto:homer.strong@gmail.com}{homer.strong@gmail.com} } scales/man/ordinal_format.Rd0000644000176200001440000000223514705655135015603 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-ordinal.R \name{ordinal_format} \alias{ordinal_format} \alias{ordinal} \title{Superseded interface to \code{label_ordinal()}} \usage{ ordinal_format(prefix = "", suffix = "", big.mark = NULL, rules = NULL, ...) ordinal(x, prefix = "", suffix = "", big.mark = " ", rules = NULL, ...) } \arguments{ \item{prefix, suffix}{Symbols to display before and after value.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{rules}{Named list of regular expressions, matched in order. Name gives suffix, and value specifies which numbers to match.} \item{...}{Other arguments passed on to \code{\link[base:format]{base::format()}}.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=label_ordinal]{label_ordinal()}} for new code. } \keyword{internal} scales/man/label_wrap.Rd0000644000176200001440000000227114705661306014710 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-wrap.R \name{label_wrap} \alias{label_wrap} \title{Label strings by wrapping across multiple lines} \usage{ label_wrap(width) } \arguments{ \item{width}{Number of characters per line.} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Uses \code{\link[=strwrap]{strwrap()}} to split long labels across multiple lines. } \examples{ x <- c( "this is a long label", "this is another long label", "this a label this is even longer" ) demo_discrete(x) demo_discrete(x, labels = label_wrap(10)) demo_discrete(x, labels = label_wrap(20)) } \seealso{ Other labels for discrete scales: \code{\link{label_dictionary}()}, \code{\link{label_glue}()}, \code{\link{label_parse}()} } \concept{labels for discrete scales} scales/man/col_mix.Rd0000644000176200001440000000175314705662053014236 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/colour-manip.R \name{col_mix} \alias{col_mix} \title{Mix colours} \usage{ col_mix(a, b, amount = 0.5, space = "rgb") } \arguments{ \item{a}{Either a character vector of colours or a colour palette function.} \item{b}{A character vector of colours.} \item{amount}{A numeric fraction between 0 and 1 giving the contribution of the \code{b} colour.} \item{space}{A string giving a colour space to perform mixing operation in. Polar spaces are not recommended.} } \value{ A character vector of colours. } \description{ Produces an interpolation of two colours. } \examples{ col_mix("blue", "red") # purple col_mix("blue", "red", amount = 1) # red col_mix("blue", "red", amount = 0) # blue # Not recommended: col_mix("blue", "red", space = "hcl") # green! } \seealso{ Other colour manipulation: \code{\link{alpha}()}, \code{\link{col2hcl}()}, \code{\link{colour_manip}}, \code{\link{muted}()} } \concept{colour manipulation} scales/man/figures/0000755000176200001440000000000015002111057013733 5ustar liggesusersscales/man/figures/README-unnamed-chunk-3-1.png0000644000176200001440000006437715002111056020447 0ustar liggesusersPNG  IHDR l+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*i L@IDATx ׽wqud2THLMB&J"3e!L()SD!] y?w9{<>{|]Zz*!'B@! V0! BVGB@!P HWzB@ `! Հp5G ! VB@!P _5<b ~wož>݅~t>׿/qG{]ZkY]C k `F[dRFP?VT=mJ]W\:i!: 74ZIOPir뮛l,  ?O?dpEڎI@kA a͚5˃<`?f[4u1Bk\sMkSbKڠF6QW;H?(!zW)[w5n~ YC1„C-;OjSI'+BJR0! "  BH! 0SN-&GF-B@ -/"׺ukW_]p={x r! ō@l|m'|mnرUVw^z?~|q ! X3f͚_~=m۶-[,r! ō@@8K/ ~9~>蠃E^! "-Zկ_JK1=;"թSǵi͘1/VaY)oFEB@! * _{5Rܡzzg͗{5l,Z[ۻN8z<u{ܸqcB@!P;{E 6dBw,XO,+h שS'{omV1cƘDB \O˻첋- Cwmg>S뮻TPA#z,5=B@!P O/ض/ڼ뮻l\;w:t;U)Vk p_}*!+FzT>DP)lԨQ_|׿kRVf.s=׮a}g*t=/kio]zP?B X`2eɁ{![=]|ƪ0(RAeJDb/s5 7 b}٦:Fcz|l}RL@†.w>4K.5?C iLV7Nu $\/[3ȑKPPY|B% g(?o6 E[$K*![w5n\r7jƽ,ϟomLlZhvmRaow?N2DZ0by5*DHJ"dL>}mrӑtbO>ժUmjV7tS)ܛ6l3׷ok'x4|x)"c(#R~d!1 Lg.SWrhpLCZs5d0]]ҝ3e9`&TQPkv!U9lw5n1EKPce = m30BWri4?:@*]5RՃ !~!rz뭷jZTuIw~|B&= ٦-B)/_(B A_w>}fmLLzlxoCiF]w]Z w#/ɓjQ /09r2d\>Ug dIL-121W~A;?^7]w>oy9 UPeHB  \!x6 UW6ȷ_6 M٘ܝ|?v>~m hP{'NKK%EB@!45r{w-ƞ{qrIf 4p/BJ5oE*BtVrj*B@dM7d$RѣG %7j(G99nVf͚#OϞ=3x.B@\D#uY2RG+[;K;we iҤil2FF'Bj ȫ^z%v"3p_*pM7ݴd4*7dc?=m4wmڪ9Z WEMZg?gK2.y0?,7P[!:b=={zUEWFi |*%sn3;Osɓ:B@Vd+8Dxr3VvaZ&No:\U0 oa/wyrJwꩧھ.ifuvۙ gYgD={,!g CL'i'Y!&A.6MI9 Aڦ-8#… m\][kԨ-Lo)/.oyڡ9.H%u0~aLƬl=Q r"*eVd@uLoxV>;,V5fn\GfOOT1j׮:`q`8QLBx k0ؕh YPl>F_}~/T"|G;PW_!껚-n,Nԏ 82Ɛ\oeڦh9o{;H錰P_O>ݑO*?Ol憰dXx:+QA5ƸAyx6xBUA\r}yǀCQP!:|< 8~0*iеkW{>]6Ev!  S1Rl(1"TIČ [&hji܊ԩX5o]znРA*gn f񨑢UV: ~ljF[6>TnB xW@oq/@kµ:u27|6|s;;f[1* Oh^R$/0 @'%ZU= j.@ @>!)#qGCcԨQ!#N^!:h٪#Q XFXDd<В1LF&&тH! "@B ׹~g- QQK~4{lwZ4sSN-jUy! @" [V%EB#KHU)M$BC$"@U|Ϟ^KPHD E]d /b p- "N,SBP$2diCL BolL6":&|LÇGOBG@>g,-'5a+s0CøDP Gh~ɒZT` ˖2BC*j׎N.|!Uy愠m /MB[?,u]gY'Oj++[zRGr4!Q ŋ>G}CB./9D3[ Q6MiPe0//ߎr>42HSP0³!w1b;T;C(ceڦMrb ;8s$ q_!83Oz{ >?KLe\J!vْoee yQPulCw ~-^6h3p;Νk衇lF 7?POxfK 5CzWH~+R?Onf&9k#H!hD .*Recbc\F|]ӧOw pz &͙3"cUch! @ 2G{+&lb `]vwĈf͚N+B@˗/+lhK,ɷy@@^s5r&KoСA%?[}Ν;~ƍ]޽-RD7pݻww+Vp,&ZnP -[4|g9p@ OEt:u FGkfF Bw-z@l4>{キnV1cXT￿0P-(;6'N([0[%g7sL}¯=䓥C!PE6n9|q \B ئ"T["A'B@LU]vzerU@03Gf\sC>wmY~*+$HIp&'9)@ b9ضm[״iS }AY@ub3Ve-[6hX"! @&\Ovl.,="!ne=z饗,^* ڧ Z6mqzdD%W?8H(?CG*0ܠy^B8`K|ǻJq Z#0#`L*ď?ho;s_p 宻jqÇw|;vE9caÆ9db曥j2dG_4qՐ-g$+RQrXb%Mhj=cG9&հCz0R6k6xU8繟nܸq)B ` x2quT"C0Ԅ$BI3i|.]^|Euֵ&@S&M܌3\ڵ8yY%DǨ'OlI&;kSıK$F|:(XwuP[>y~`'D}ߦrڔrM% jSf׷kw5n\0ٴoC2G16!.y_njg9\Ҝׯ>Gf 駟ZjuI^,: j諯*3eos6B 7o A /d+zƉ%6DfOB!I].A\Ck}PmZFX_(lɟ%L򗽙n qgxwt>hQFًu9/YKHxYg8 23}"v5]qhbƖ^~V]! ~8O{ |Xu+?v`i7wG:G{ҮX7'F&믿&ۯV!ڀg?ldo޼yNpm{'L@ecn!P11[_1CBFB!˴lib`pLU|a"gR.]%dKBl2xb78& L￿G]V-S[{Pa:} !`|e=PjGF5Gb `VFُp*馛R֝VOPfˬX0^q5,Yb}\bcd{g— oau. ɪkeo  p߾}]>}lK O`ܵkW8Zu4Kg׳G9aDB@.LY2<$ 1,% a7onȃ =σ,%;v4AuA>?hG.OxH@_PBbPC !R{dz+>W]uixlڄ{lQVw5T|-woPmCյ2x3T]3)C2J+̋+olY&Cg,2*ˆY~< B" ?/)}$ċMCrUDbzaÆ.]8rOu90(Ulww-Ļʪ+D={J 1_1ķk/n 9TlpNG7pp5"k"3Ƶk.B O@5}tw[hY,/;͓B HFXe?cf![DU,•|O /5\cB7ڨTB H+v$$T 'O.3%_  @x'[AȾ&tI ;:v~{[o[C ?^y{:.XC+gg58 l 1mj׮mµuE ͦW;ip'Z> &X6$3Qge-@#V<`a!-[:wln[lQFFB .0*mۺ LÍ Fʳ[ ]'@|V2d?;E]o?[(E$@" rx[h)-]͜9ndB 'k)[o=3=zE*JB %IO,%!|4ibNZRB ]]˖-ݒ%K,ߤIIRDB@0l%cH/#<`._~gW\@e#{%;:t`z)7G~ w#/#GÇ[*>ly#d8jG fM2RnJep` !EB|'?_ڦ B -XQi+B ;qI':uJ᩻@."[ZfDD,,%wu衤QhA! D࣏>r'pU{>"!  ot,|D!oGquZp[xq);mgՍV[mUz_H<[,B7n,Aw#駟:ާ 7=CyߢH@,L ,\J;*:J>]VX7F$dR"2Ba>`sZ4\<,L?7"Eڻkr-oivR@"%L$—HE &%6mڔ\BB'|=#fգGG8K:Ĩ0"8|Fa k/S}vA9X-KǏƍ]@^!&'G+B%IAؾ}{[y^zr(f͚E@^i/f͚u:\>c OJBX%٨%Իw\(sc(Boe#?!L?!67>1<-I:} cPaC)Иj\~WCf7O: U>աs~$(ʐ<6b'6MZ$0He]5jd+eU _̌F@y/B)= 4 y|(>bepxjڵkp2}u}0hTzM׵kWv}{̄AJu4ڵk:&rT U(Nb ^zيsY q`dҼys%38OduPG37bS֭m/\EB `"[)@ĉRpXQX%4ٵeDo7!\J!P`GD .rω(nb `ERYN%(X*~ ;|m{]ӦMꪧi-T2^婠ݣcBO`3j[ : x/rGIfϞŜ8ޣu(l,X`[¯ڹ["[' ~W\L@"X^`Rń@"86bR$"dUB W3g4_]τoYf@Q#@.ي,]-[ha~LPC(&Lbv{챇GZ_u#[' TѬC?^w@U=C x/B@C 0^{BPF G`ȑHqmڴq-&W@b .w ={AJ#&B :t,?,4Byր*Fb n͑cǎuZ2 O;V$ c讻:$WhbBuBb&7v&u |2DiM%%1wMC(ܟVm/u(^PegaVL@ Ѧ QO_Pu_ȲQ.&*JB^{ABp< Q. #/?PQQ,L^b zʕ7$tAQ|#-ח\&~!^ُB7tB$BN31 /4/fZ6OG0L& =z:uɌ3\~=o.3_5HgZA%9&?vxʋ0^L>O9gYt=3+~Xٰ*ɦlIlSBͯ.C z C C(WUf1Hˢ,TCi(FW-[4䳹`oH2d4i;7|SUV݄db `ʱn)NV "ϺnݺzV[mUANM!?2duQGX~w pwzJT! Gq;wv˗/_$:j۾}{wW*[/r 2ݻ`^1osYUlsqv w6tB +ꫯvkNGDŽ@A tRt&<Ȃ*!@!Kww[n{7r*-_|~a @!CXE0Qc8ǪA D 38ЗlDUB2-#@2JDDWgv ЄDn o>)O-u&M]wezŅ@lTHT'D;;?l|cxb;a~ɂ$Ԛ_}‰B Z h"dP58>Xx"s/ VNM8=֯|I*D?mfmVG@lJO^N|駟v0^x# |k֬YB@'C M$Z0IG#Gtd?/bѣM*{̙eX/v}]aÆk͙3r"EŇ1IٸqcS?@=`r 6k^uUnr={L'tĒ>|0aD%fQʸ,XI?~7n߿aԩ# !P`yĈm۶VZ4B'%,@5 fbE.VJWqc'&/>!|!V?'OW_5kXSO(VD AE+4?"$?6w!x&p}-qlroHsAfTyin_&` C38dmK#m_w+P1$T&./;OCBF;eZ?bxmuo6my)c;︕+W:b'|b g͚e ػwow[8@VojVXFeo7W)gf2 lL˝B 5 /4v7v}~pe%= Pem_d']Kr.ιP,ϒi$^l\+[ry~-1!K`tT|WG] C= 5vΊPE HTD&%.]X'g@}&3ox+@HqfC-V9[&dsKG\dAP&bc3zJafZ^z4he7`ձcGCHe}Hz(nW(܈lHH!F毋2{okV:<Ȥ{euv*IfR ᛈJOW^y1ØJ$wb$^`2K]v, cH(X.<ش(-[o! @"[SCVO Bk1!CT#! @#[]%@ȼEpbp'B@ ҒXp`=묳 Ō@F*bJuZ05tP7c -/LՖNOB@d@ZUxmQi$Ōg}fY|A ѡC/fLTw!  <0EB"ךDz訣{gp{@Z`'7>"!)dBKD5RKr裏v|$\IDAT묳Ni Lz! @> V?@U?&L~7o<'x«$zBzH+T]m0a@%YDB |ɓ- i-7!z ! r {=d9F\$kM;!W_6l3͊"! @1#[㎳ m۶uӦMs+ +}j=~1!NI}R>D4Ԁq MC^!/\,BpmCQ(KyB oW,L^k2;찃e~n"\|U{yfd ɏl >1 믿N;4K*ɦMZL܏?魫]KM?^c-QOpsYd [r8חw ~xdP /Ի{] [t R^{/³CvCBFB!˴l X@nY._24l1"r-)H܈H/9eE! VG nVwGf͚9v}w `ĉs֑C[z_ ! @rb &M j ל9sO?l&9rv>}تw/{) TO! @0fOs_}=_NM6ٺXt;Q u/_^5S@l#Ν;'\ r)W'SO5 bc'B@xcmӦ޽G%-*.0·^zy7/.T[! @o,Qڵ|nwn&wUWC9Č4Ub!RoQe3sC=3ݘ1c>! X+`jCs=-ZȄ1X7hEo]pZKUK!P5O< Ik"+^2W#ׯ* ! ؾB3ظU\v=_p\c'B@-i}ϟԩ5j:`t HѡCkQFKRQeO! @>![ϝ;ru]qᇛOԐ˖-smQKt. `~ǎ-qlCSQ@,+hصkW{/R}n$1Y^ҏȟr{gJ#o(Z(L(<~Ǝki(?Eŋ@0$VD}y'x"aȑ#-1?s 0>cUM~ankvp؇$ r-ovR /hFH! "KdJj)q>|ѣ'%|Y^}e(Xu]{Ծ}{w 'XC,E(s\I \cĸקq15XÄ*6\s5r7  !/dy#!^~St toB5B7?GqzˤMYɝ;w6i׮D =?TxT!%0j^0fb;20aBbvay涟6 hKP\R+qxGb1ճ 8$ ʘ[VUB@$0 BƒdV]adҽ{2߃QXy߬CZB:;6l37c e@QH8.B@D bU'XҲM66MO'cMZXbi+41Cj9~tB@6׿|MknC* ۑנAs "@Ib_Qɮ:Jʱ?DC!Pl;Sqs=K4z LP| zI'd|+J{͡@hH>! @8b `  C7,ɱ&'ӦMswyk6Dr&$ ֧NjI- 9F!&B B4d!"D$~!0|w)@j3FXGq;_s,Th#R٢rhnСNu ! @#KS o":& i~Մ$V[mbD~ ,QX#Jdͺ h"B@B "8{ɭZIi0bKF'%ѪuqY&ftgϞmԸza)SHFo! @!{{DBeJ$ŋ@0# yiYL2׀kY1nK'JF"! ]b `XZliB0:#M-/XT>[1y!W^i˿+DC:G1-VыB tԩ{-LCVcG࣏>2*&3~ X=cA=rH B %G9sJ!#1">`lU+PBxfJ7Yo]r}+h_Ol lnFs½lBLz3O:PO!clɗ/D w Y6_ (媌zW)#u /T=}?ْM) v܇21J|ɳMjH7z")Wh0?^w屢G2M}>?7A!ew*PE/k6߾yCBF|CLV^X2OӦM" %ּJٳ',aLY+Tܭ*2rcqjҤ{G^{eeHuZke^BxGnŊqD ?^V'[bHD+[BXRW&!zi*Ÿlh!ڀg?hWw5 Ѷ[yzbr ?- 7Vf`c2-)n\  6O˹EE2jĈn}F[dI@z ! @ b `V];wQ\BoݢX1&(nFR(@P%B cZA#x 3τ4$@ƥɓP;6҇D0QS7ORB@T#iW%CݺuMʞ~R5ֹf_8X2~ͻUnB@C 8qe2d.|͢cŐ 4B@ V/[Vw;jժ>X eR1zl-B \Ҭ s͗c.I~`[! @  S`KB@Lpz! X!  LB@!  DB@!))ɷ*ӛLr2DWpZp{7ܑGi ŎPfFw}w[d[4?$vnCrK>[orKWf\*壏>rn9Ul쳮9U6 3g馛78駟:lJerl~vm7GF\e={ِlFT4+l{6x$=B@!PH]`QB@! <?˗/wO?lrF%믿'|Tkfi}]EdzJ}naZpdMt/:0vm#G/]]˅ hYIVФ *u=\)kDpd%4 ym8$4m۶5M؏hhy~7G C.p HI}9|蓕A%~e[˖-KCa̟-5k=2wy٣A۴ic}K.2&}RM$}ףGe>M7;8Ǥ}3ϴr1aI|p n֓Gb|o& ~Y4߄e+>w,o,dU aݺu]we;#8)u YNڒH5Ç{VӦMI*SO= {رcM!$Rr~uɀx!>U:JMaÆDᩧr52 |`rNY $!h 'zL|+!Cʚ2/]MPVe%=l̘1^E?Cn=4MN<9&4}/;:>^C;{4iOt‡eR{W+bV+p @25#(KBƥeJiAʤ޽{*ErtAvh¶aÆC@FHWt^xacGPN =8Vs~@xժUˌT0 MJh[ԥ,u ’pՕ53m@(RVC &|뭷=8!L.#.ne/ᆴI&o<{ֲroW?@aĥ2vϡd7w\7&wLP(/$O:-Q!8>&Xf\<ɿs%/JOpb 1g 2WA6nT}S,0X)Q^ `V šf,)N:]z饥E` ľ׆&/&12eҀ0_@!'.L^u[Oɢ?fvիj>&LО1bPYVh|$ ]uU*[VJ-u<󿑬+u~5'pc0`7*"  *7"&?KdU !:Yy4hN"a Yf*f%ΪLy0KUL P G Bp7Q3EE`v07QfV4~{/mJ>ƬoXz4x 9% +vD?{+T; ` XweM|9kԨa oL1W_}մ\L)Zfu]ʠ|oHG72QB];t.;ۥ12x^r%# 1xo1cvڙ0a1iڴi' aԩ/YR^qLe"Nn9GQcQ YV^3)-lO;Rse9&}Qc"VcB s_}㾪&7@MM17:OQV&H%hE#|o E鑨ofQ`lc؛b}9 rXU`vHve FG{-qdKDlXĄu*Fkh4 ef]鞑kQSn懲*|._vU +*|{r={4+Vg"_Ք! \S-ĎQPYƂꫯ߉ d }F,˫C\J|Wq*p?'ݷ[:tRpv3R  TD9>Dh]`m5Zr |*[>e^B@!P(Cph Ԑ_ITy,j1"(^Nߊ7Q\fo7FmL8`^,F,"! *|ӽɞcB Is+X\`y"ݺu BY!~"y9W#)@ވ U^\QiRӽ{w_wuQv+Z&@D5 "]M~GB 6%1Q|:Wɬ*.-čaU(MeUKb*qM%+U\U+%U%qW/JWXwU ,K" ٿ%1W?U%>U%WK&@J|wC@w5-@Ep.DEʊoTL8vmge3 N SԪ5+sCZʞ8άb~g%fŋǘ(Sg!1[Q]|WSʼnj H0G[2)倠+M %̀J-hq - djKZ,XQLr*XE-@hJ--}Wy ^H <&Z OZtL'@!JɊڨb-j"`s,H>!=K$R>H'@ yWS#@@E %MT]t1AwVq%h>+A22$)bBM_bRAe/jD$WgՌƁxg ȻB  ,yt26PE]WRaǾ9A;|2(>XWghY;HߨEw5=U{B(pQ6*-Սpu/EpQ6*-Սpu/EpQ6*-Սpu/EpQ6*-Սd8Dx8IENDB`scales/man/figures/README-labels-2.png0000644000176200001440000006437714672302077017036 0ustar liggesusersPNG  IHDR l+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*i L@IDATx ׽wqud2THLMB&J"3e!L()SD!] y?w9{<>{|]Zz*!'B@! V0! BVGB@!P HWzB@ `! Հp5G ! VB@!P _5<b ~wož>݅~t>׿/qG{]ZkY]C k `F[dRFP?VT=mJ]W\:i!: 74ZIOPir뮛l,  ?O?dpEڎI@kA a͚5˃<`?f[4u1Bk\sMkSbKڠF6QW;H?(!zW)[w5n~ YC1„C-;OjSI'+BJR0! "  BH! 0SN-&GF-B@ -/"׺ukW_]p={x r! ō@l|m'|mnرUVw^z?~|q ! X3f͚_~=m۶-[,r! ō@@8K/ ~9~>蠃E^! "-Zկ_JK1=;"թSǵi͘1/VaY)oFEB@! * _{5Rܡzzg͗{5l,Z[ۻN8z<u{ܸqcB@!P;{E 6dBw,XO,+h שS'{omV1cƘDB \O˻첋- Cwmg>S뮻TPA#z,5=B@!P O/ض/ڼ뮻l\;w:t;U)Vk p_}*!+FzT>DP)lԨQ_|׿kRVf.s=׮a}g*t=/kio]zP?B X`2eɁ{![=]|ƪ0(RAeJDb/s5 7 b}٦:Fcz|l}RL@†.w>4K.5?C iLV7Nu $\/[3ȑKPPY|B% g(?o6 E[$K*![w5n\r7jƽ,ϟomLlZhvmRaow?N2DZ0by5*DHJ"dL>}mrӑtbO>ժUmjV7tS)ܛ6l3׷ok'x4|x)"c(#R~d!1 Lg.SWrhpLCZs5d0]]ҝ3e9`&TQPkv!U9lw5n1EKPce = m30BWri4?:@*]5RՃ !~!rz뭷jZTuIw~|B&= ٦-B)/_(B A_w>}fmLLzlxoCiF]w]Z w#/ɓjQ /09r2d\>Ug dIL-121W~A;?^7]w>oy9 UPeHB  \!x6 UW6ȷ_6 M٘ܝ|?v>~m hP{'NKK%EB@!45r{w-ƞ{qrIf 4p/BJ5oE*BtVrj*B@dM7d$RѣG %7j(G99nVf͚#OϞ=3x.B@\D#uY2RG+[;K;we iҤil2FF'Bj ȫ^z%v"3p_*pM7ݴd4*7dc?=m4wmڪ9Z WEMZg?gK2.y0?,7P[!:b=={zUEWFi |*%sn3;Osɓ:B@Vd+8Dxr3VvaZ&No:\U0 oa/wyrJwꩧھ.ifuvۙ gYgD={,!g CL'i'Y!&A.6MI9 Aڦ-8#… m\][kԨ-Lo)/.oyڡ9.H%u0~aLƬl=Q r"*eVd@uLoxV>;,V5fn\GfOOT1j׮:`q`8QLBx k0ؕh YPl>F_}~/T"|G;PW_!껚-n,Nԏ 82Ɛ\oeڦh9o{;H錰P_O>ݑO*?Ol憰dXx:+QA5ƸAyx6xBUA\r}yǀCQP!:|< 8~0*iеkW{>]6Ev!  S1Rl(1"TIČ [&hji܊ԩX5o]znРA*gn f񨑢UV: ~ljF[6>TnB xW@oq/@kµ:u27|6|s;;f[1* Oh^R$/0 @'%ZU= j.@ @>!)#qGCcԨQ!#N^!:h٪#Q XFXDd<В1LF&&тH! "@B ׹~g- QQK~4{lwZ4sSN-jUy! @" [V%EB#KHU)M$BC$"@U|Ϟ^KPHD E]d /b p- "N,SBP$2diCL BolL6":&|LÇGOBG@>g,-'5a+s0CøDP Gh~ɒZT` ˖2BC*j׎N.|!Uy愠m /MB[?,u]gY'Oj++[zRGr4!Q ŋ>G}CB./9D3[ Q6MiPe0//ߎr>42HSP0³!w1b;T;C(ceڦMrb ;8s$ q_!83Oz{ >?KLe\J!vْoee yQPulCw ~-^6h3p;Νk衇lF 7?POxfK 5CzWH~+R?Onf&9k#H!hD .*Recbc\F|]ӧOw pz &͙3"cUch! @ 2G{+&lb `]vwĈf͚N+B@˗/+lhK,ɷy@@^s5r&KoСA%?[}Ν;~ƍ]޽-RD7pݻww+Vp,&ZnP -[4|g9p@ OEt:u FGkfF Bw-z@l4>{キnV1cXT￿0P-(;6'N([0[%g7sL}¯=䓥C!PE6n9|q \B ئ"T["A'B@LU]vzerU@03Gf\sC>wmY~*+$HIp&'9)@ b9ضm[״iS }AY@ub3Ve-[6hX"! @&\Ovl.,="!ne=z饗,^* ڧ Z6mqzdD%W?8H(?CG*0ܠy^B8`K|ǻJq Z#0#`L*ď?ho;s_p 宻jqÇw|;vE9caÆ9db曥j2dG_4qՐ-g$+RQrXb%Mhj=cG9&հCz0R6k6xU8繟nܸq)B ` x2quT"C0Ԅ$BI3i|.]^|Euֵ&@S&M܌3\ڵ8yY%DǨ'OlI&;kSıK$F|:(XwuP[>y~`'D}ߦrڔrM% jSf׷kw5n\0ٴoC2G16!.y_njg9\Ҝׯ>Gf 駟ZjuI^,: j諯*3eos6B 7o A /d+zƉ%6DfOB!I].A\Ck}PmZFX_(lɟ%L򗽙n qgxwt>hQFًu9/YKHxYg8 23}"v5]qhbƖ^~V]! ~8O{ |Xu+?v`i7wG:G{ҮX7'F&믿&ۯV!ڀg?ldo޼yNpm{'L@ecn!P11[_1CBFB!˴lib`pLU|a"gR.]%dKBl2xb78& L￿G]V-S[{Pa:} !`|e=PjGF5Gb `VFُp*馛R֝VOPfˬX0^q5,Yb}\bcd{g— oau. ɪkeo  p߾}]>}lK O`ܵkW8Zu4Kg׳G9aDB@.LY2<$ 1,% a7onȃ =σ,%;v4AuA>?hG.OxH@_PBbPC !R{dz+>W]uixlڄ{lQVw5T|-woPmCյ2x3T]3)C2J+̋+olY&Cg,2*ˆY~< B" ?/)}$ċMCrUDbzaÆ.]8rOu90(Ulww-Ļʪ+D={J 1_1ķk/n 9TlpNG7pp5"k"3Ƶk.B O@5}tw[hY,/;͓B HFXe?cf![DU,•|O /5\cB7ڨTB H+v$$T 'O.3%_  @x'[AȾ&tI ;:v~{[o[C ?^y{:.XC+gg58 l 1mj׮mµuE ͦW;ip'Z> &X6$3Qge-@#V<`a!-[:wln[lQFFB .0*mۺ LÍ Fʳ[ ]'@|V2d?;E]o?[(E$@" rx[h)-]͜9ndB 'k)[o=3=zE*JB %IO,%!|4ibNZRB ]]˖-ݒ%K,ߤIIRDB@0l%cH/#<`._~gW\@e#{%;:t`z)7G~ w#/#GÇ[*>ly#d8jG fM2RnJep` !EB|'?_ڦ B -XQi+B ;qI':uJ᩻@."[ZfDD,,%wu衤QhA! D࣏>r'pU{>"!  ot,|D!oGquZp[xq);mgՍV[mUz_H<[,B7n,Aw#駟:ާ 7=CyߢH@,L ,\J;*:J>]VX7F$dR"2Ba>`sZ4\<,L?7"Eڻkr-oivR@"%L$—HE &%6mڔ\BB'|=#fգGG8K:Ĩ0"8|Fa k/S}vA9X-KǏƍ]@^!&'G+B%IAؾ}{[y^zr(f͚E@^i/f͚u:\>c OJBX%٨%Իw\(sc(Boe#?!L?!67>1<-I:} cPaC)Иj\~WCf7O: U>աs~$(ʐ<6b'6MZ$0He]5jd+eU _̌F@y/B)= 4 y|(>bepxjڵkp2}u}0hTzM׵kWv}{̄AJu4ڵk:&rT U(Nb ^zيsY q`dҼys%38OduPG37bS֭m/\EB `"[)@ĉRpXQX%4ٵeDo7!\J!P`GD .rω(nb `ERYN%(X*~ ;|m{]ӦMꪧi-T2^婠ݣcBO`3j[ : x/rGIfϞŜ8ޣu(l,X`[¯ڹ["[' ~W\L@"X^`Rń@"86bR$"dUB W3g4_]τoYf@Q#@.ي,]-[ha~LPC(&Lbv{챇GZ_u#[' TѬC?^w@U=C x/B@C 0^{BPF G`ȑHqmڴq-&W@b .w ={AJ#&B :t,?,4Byր*Fb n͑cǎuZ2 O;V$ c讻:$WhbBuBb&7v&u |2DiM%%1wMC(ܟVm/u(^PegaVL@ Ѧ QO_Pu_ȲQ.&*JB^{ABp< Q. #/?PQQ,L^b zʕ7$tAQ|#-ח\&~!^ُB7tB$BN31 /4/fZ6OG0L& =z:uɌ3\~=o.3_5HgZA%9&?vxʋ0^L>O9gYt=3+~Xٰ*ɦlIlSBͯ.C z C C(WUf1Hˢ,TCi(FW-[4䳹`oH2d4i;7|SUV݄db `ʱn)NV "ϺnݺzV[mUANM!?2duQGX~w pwzJT! Gq;wv˗/_$:j۾}{wW*[/r 2ݻ`^1osYUlsqv w6tB +ꫯvkNGDŽ@A tRt&<Ȃ*!@!Kww[n{7r*-_|~a @!CXE0Qc8ǪA D 38ЗlDUB2-#@2JDDWgv ЄDn o>)O-u&M]wezŅ@lTHT'D;;?l|cxb;a~ɂ$Ԛ_}‰B Z h"dP58>Xx"s/ VNM8=֯|I*D?mfmVG@lJO^N|駟v0^x# |k֬YB@'C M$Z0IG#Gtd?/bѣM*{̙eX/v}]aÆk͙3r"EŇ1IٸqcS?@=`r 6k^uUnr={L'tĒ>|0aD%fQʸ,XI?~7n߿aԩ# !P`yĈm۶VZ4B'%,@5 fbE.VJWqc'&/>!|!V?'OW_5kXSO(VD AE+4?"$?6w!x&p}-qlroHsAfTyin_&` C38dmK#m_w+P1$T&./;OCBF;eZ?bxmuo6my)c;︕+W:b'|b g͚e ػwow[8@VojVXFeo7W)gf2 lL˝B 5 /4v7v}~pe%= Pem_d']Kr.ιP,ϒi$^l\+[ry~-1!K`tT|WG] C= 5vΊPE HTD&%.]X'g@}&3ox+@HqfC-V9[&dsKG\dAP&bc3zJafZ^z4he7`ձcGCHe}Hz(nW(܈lHH!F毋2{okV:<Ȥ{euv*IfR ᛈJOW^y1ØJ$wb$^`2K]v, cH(X.<ش(-[o! @"[SCVO Bk1!CT#! @#[]%@ȼEpbp'B@ ҒXp`=묳 Ō@F*bJuZ05tP7c -/LՖNOB@d@ZUxmQi$Ōg}fY|A ѡC/fLTw!  <0EB"ךDz訣{gp{@Z`'7>"!)dBKD5RKr裏v|$\IDAT묳Ni Lz! @> V?@U?&L~7o<'x«$zBzH+T]m0a@%YDB |ɓ- i-7!z ! r {=d9F\$kM;!W_6l3͊"! @1#[㎳ m۶uӦMs+ +}j=~1!NI}R>D4Ԁq MC^!/\,BpmCQ(KyB oW,L^k2;찃e~n"\|U{yfd ɏl >1 믿N;4K*ɦMZL܏?魫]KM?^c-QOpsYd [r8חw ~xdP /Ի{] [t R^{/³CvCBFB!˴l X@nY._24l1"r-)H܈H/9eE! VG nVwGf͚9v}w `ĉs֑C[z_ ! @rb &M j ל9sO?l&9rv>}تw/{) TO! @0fOs_}=_NM6ٺXt;Q u/_^5S@l#Ν;'\ r)W'SO5 bc'B@xcmӦ޽G%-*.0·^zy7/.T[! @o,Qڵ|nwn&wUWC9Č4Ub!RoQe3sC=3ݘ1c>! X+`jCs=-ZȄ1X7hEo]pZKUK!P5O< Ik"+^2W#ׯ* ! ؾB3ظU\v=_p\c'B@-i}ϟԩ5j:`t HѡCkQFKRQeO! @>![ϝ;ru]qᇛOԐ˖-smQKt. `~ǎ-qlCSQ@,+hصkW{/R}n$1Y^ҏȟr{gJ#o(Z(L(<~Ǝki(?Eŋ@0$VD}y'x"aȑ#-1?s 0>cUM~ankvp؇$ r-ovR /hFH! "KdJj)q>|ѣ'%|Y^}e(Xu]{Ծ}{w 'XC,E(s\I \cĸקq15XÄ*6\s5r7  !/dy#!^~St toB5B7?GqzˤMYɝ;w6i׮D =?TxT!%0j^0fb;20aBbvay涟6 hKP\R+qxGb1ճ 8$ ʘ[VUB@$0 BƒdV]adҽ{2߃QXy߬CZB:;6l37c e@QH8.B@D bU'XҲM66MO'cMZXbi+41Cj9~tB@6׿|MknC* ۑנAs "@Ib_Qɮ:Jʱ?DC!Pl;Sqs=K4z LP| zI'd|+J{͡@hH>! @8b `  C7,ɱ&'ӦMswyk6Dr&$ ֧NjI- 9F!&B B4d!"D$~!0|w)@j3FXGq;_s,Th#R٢rhnСNu ! @#KS o":& i~Մ$V[mbD~ ,QX#Jdͺ h"B@B "8{ɭZIi0bKF'%ѪuqY&ftgϞmԸza)SHFo! @!{{DBeJ$ŋ@0# yiYL2׀kY1nK'JF"! ]b `XZliB0:#M-/XT>[1y!W^i˿+DC:G1-VыB tԩ{-LCVcG࣏>2*&3~ X=cA=rH B %G9sJ!#1">`lU+PBxfJ7Yo]r}+h_Ol lnFs½lBLz3O:PO!clɗ/D w Y6_ (媌zW)#u /T=}?ْM) v܇21J|ɳMjH7z")Wh0?^w屢G2M}>?7A!ew*PE/k6߾yCBF|CLV^X2OӦM" %ּJٳ',aLY+Tܭ*2rcqjҤ{G^{eeHuZke^BxGnŊqD ?^V'[bHD+[BXRW&!zi*Ÿlh!ڀg?hWw5 Ѷ[yzbr ?- 7Vf`c2-)n\  6O˹EE2jĈn}F[dI@z ! @ b `V];wQ\BoݢX1&(nFR(@P%B cZA#x 3τ4$@ƥɓP;6҇D0QS7ORB@T#iW%CݺuMʞ~R5ֹf_8X2~ͻUnB@C 8qe2d.|͢cŐ 4B@ V/[Vw;jժ>X eR1zl-B \Ҭ s͗c.I~`[! @  S`KB@Lpz! X!  LB@!  DB@!))ɷ*ӛLr2DWpZp{7ܑGi ŎPfFw}w[d[4?$vnCrK>[orKWf\*壏>rn9Ul쳮9U6 3g馛78駟:lJerl~vm7GF\e={ِlFT4+l{6x$=B@!PH]`QB@! <?˗/wO?lrF%믿'|Tkfi}]EdzJ}naZpdMt/:0vm#G/]]˅ hYIVФ *u=\)kDpd%4 ym8$4m۶5M؏hhy~7G C.p HI}9|蓕A%~e[˖-KCa̟-5k=2wy٣A۴ic}K.2&}RM$}ףGe>M7;8Ǥ}3ϴr1aI|p n֓Gb|o& ~Y4߄e+>w,o,dU aݺu]we;#8)u YNڒH5Ç{VӦMI*SO= {رcM!$Rr~uɀx!>U:JMaÆDᩧr52 |`rNY $!h 'zL|+!Cʚ2/]MPVe%=l̘1^E?Cn=4MN<9&4}/;:>^C;{4iOt‡eR{W+bV+p @25#(KBƥeJiAʤ޽{*ErtAvh¶aÆC@FHWt^xacGPN =8Vs~@xժUˌT0 MJh[ԥ,u ’pՕ53m@(RVC &|뭷=8!L.#.ne/ᆴI&o<{ֲroW?@aĥ2vϡd7w\7&wLP(/$O:-Q!8>&Xf\<ɿs%/JOpb 1g 2WA6nT}S,0X)Q^ `V šf,)N:]z饥E` ľ׆&/&12eҀ0_@!'.L^u[Oɢ?fvիj>&LО1bPYVh|$ ]uU*[VJ-u<󿑬+u~5'pc0`7*"  *7"&?KdU !:Yy4hN"a Yf*f%ΪLy0KUL P G Bp7Q3EE`v07QfV4~{/mJ>ƬoXz4x 9% +vD?{+T; ` XweM|9kԨa oL1W_}մ\L)Zfu]ʠ|oHG72QB];t.;ۥ12x^r%# 1xo1cvڙ0a1iڴi' aԩ/YR^qLe"Nn9GQcQ YV^3)-lO;Rse9&}Qc"VcB s_}㾪&7@MM17:OQV&H%hE#|o E鑨ofQ`lc؛b}9 rXU`vHve FG{-qdKDlXĄu*Fkh4 ef]鞑kQSn懲*|._vU +*|{r={4+Vg"_Ք! \S-ĎQPYƂꫯ߉ d }F,˫C\J|Wq*p?'ݷ[:tRpv3R  TD9>Dh]`m5Zr |*[>e^B@!P(Cph Ԑ_ITy,j1"(^Nߊ7Q\fo7FmL8`^,F,"! *|ӽɞcB Is+X\`y"ݺu BY!~"y9W#)@ވ U^\QiRӽ{w_wuQv+Z&@D5 "]M~GB 6%1Q|:Wɬ*.-čaU(MeUKb*qM%+U\U+%U%qW/JWXwU ,K" ٿ%1W?U%>U%WK&@J|wC@w5-@Ep.DEʊoTL8vmge3 N SԪ5+sCZʞ8άb~g%fŋǘ(Sg!1[Q]|WSʼnj H0G[2)倠+M %̀J-hq - djKZ,XQLr*XE-@hJ--}Wy ^H <&Z OZtL'@!JɊڨb-j"`s,H>!=K$R>H'@ yWS#@@E %MT]t1AwVq%h>+A22$)bBM_bRAe/jD$WgՌƁxg ȻB  ,yt26PE]WRaǾ9A;|2(>XWghY;HߨEw5=U{B(pQ6*-Սpu/EpQ6*-Սpu/EpQ6*-Սpu/EpQ6*-Սd8Dx8IENDB`scales/man/figures/README-unnamed-chunk-4-1.png0000644000176200001440000006437714710642104020460 0ustar liggesusersPNG  IHDR l+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*i L@IDATx ׽wqud2THLMB&J"3e!L()SD!] y?w9{<>{|]Zz*!'B@! V0! BVGB@!P HWzB@ `! Հp5G ! VB@!P _5<b ~wož>݅~t>׿/qG{]ZkY]C k `F[dRFP?VT=mJ]W\:i!: 74ZIOPir뮛l,  ?O?dpEڎI@kA a͚5˃<`?f[4u1Bk\sMkSbKڠF6QW;H?(!zW)[w5n~ YC1„C-;OjSI'+BJR0! "  BH! 0SN-&GF-B@ -/"׺ukW_]p={x r! ō@l|m'|mnرUVw^z?~|q ! X3f͚_~=m۶-[,r! ō@@8K/ ~9~>蠃E^! "-Zկ_JK1=;"թSǵi͘1/VaY)oFEB@! * _{5Rܡzzg͗{5l,Z[ۻN8z<u{ܸqcB@!P;{E 6dBw,XO,+h שS'{omV1cƘDB \O˻첋- Cwmg>S뮻TPA#z,5=B@!P O/ض/ڼ뮻l\;w:t;U)Vk p_}*!+FzT>DP)lԨQ_|׿kRVf.s=׮a}g*t=/kio]zP?B X`2eɁ{![=]|ƪ0(RAeJDb/s5 7 b}٦:Fcz|l}RL@†.w>4K.5?C iLV7Nu $\/[3ȑKPPY|B% g(?o6 E[$K*![w5n\r7jƽ,ϟomLlZhvmRaow?N2DZ0by5*DHJ"dL>}mrӑtbO>ժUmjV7tS)ܛ6l3׷ok'x4|x)"c(#R~d!1 Lg.SWrhpLCZs5d0]]ҝ3e9`&TQPkv!U9lw5n1EKPce = m30BWri4?:@*]5RՃ !~!rz뭷jZTuIw~|B&= ٦-B)/_(B A_w>}fmLLzlxoCiF]w]Z w#/ɓjQ /09r2d\>Ug dIL-121W~A;?^7]w>oy9 UPeHB  \!x6 UW6ȷ_6 M٘ܝ|?v>~m hP{'NKK%EB@!45r{w-ƞ{qrIf 4p/BJ5oE*BtVrj*B@dM7d$RѣG %7j(G99nVf͚#OϞ=3x.B@\D#uY2RG+[;K;we iҤil2FF'Bj ȫ^z%v"3p_*pM7ݴd4*7dc?=m4wmڪ9Z WEMZg?gK2.y0?,7P[!:b=={zUEWFi |*%sn3;Osɓ:B@Vd+8Dxr3VvaZ&No:\U0 oa/wyrJwꩧھ.ifuvۙ gYgD={,!g CL'i'Y!&A.6MI9 Aڦ-8#… m\][kԨ-Lo)/.oyڡ9.H%u0~aLƬl=Q r"*eVd@uLoxV>;,V5fn\GfOOT1j׮:`q`8QLBx k0ؕh YPl>F_}~/T"|G;PW_!껚-n,Nԏ 82Ɛ\oeڦh9o{;H錰P_O>ݑO*?Ol憰dXx:+QA5ƸAyx6xBUA\r}yǀCQP!:|< 8~0*iеkW{>]6Ev!  S1Rl(1"TIČ [&hji܊ԩX5o]znРA*gn f񨑢UV: ~ljF[6>TnB xW@oq/@kµ:u27|6|s;;f[1* Oh^R$/0 @'%ZU= j.@ @>!)#qGCcԨQ!#N^!:h٪#Q XFXDd<В1LF&&тH! "@B ׹~g- QQK~4{lwZ4sSN-jUy! @" [V%EB#KHU)M$BC$"@U|Ϟ^KPHD E]d /b p- "N,SBP$2diCL BolL6":&|LÇGOBG@>g,-'5a+s0CøDP Gh~ɒZT` ˖2BC*j׎N.|!Uy愠m /MB[?,u]gY'Oj++[zRGr4!Q ŋ>G}CB./9D3[ Q6MiPe0//ߎr>42HSP0³!w1b;T;C(ceڦMrb ;8s$ q_!83Oz{ >?KLe\J!vْoee yQPulCw ~-^6h3p;Νk衇lF 7?POxfK 5CzWH~+R?Onf&9k#H!hD .*Recbc\F|]ӧOw pz &͙3"cUch! @ 2G{+&lb `]vwĈf͚N+B@˗/+lhK,ɷy@@^s5r&KoСA%?[}Ν;~ƍ]޽-RD7pݻww+Vp,&ZnP -[4|g9p@ OEt:u FGkfF Bw-z@l4>{キnV1cXT￿0P-(;6'N([0[%g7sL}¯=䓥C!PE6n9|q \B ئ"T["A'B@LU]vzerU@03Gf\sC>wmY~*+$HIp&'9)@ b9ضm[״iS }AY@ub3Ve-[6hX"! @&\Ovl.,="!ne=z饗,^* ڧ Z6mqzdD%W?8H(?CG*0ܠy^B8`K|ǻJq Z#0#`L*ď?ho;s_p 宻jqÇw|;vE9caÆ9db曥j2dG_4qՐ-g$+RQrXb%Mhj=cG9&հCz0R6k6xU8繟nܸq)B ` x2quT"C0Ԅ$BI3i|.]^|Euֵ&@S&M܌3\ڵ8yY%DǨ'OlI&;kSıK$F|:(XwuP[>y~`'D}ߦrڔrM% jSf׷kw5n\0ٴoC2G16!.y_njg9\Ҝׯ>Gf 駟ZjuI^,: j諯*3eos6B 7o A /d+zƉ%6DfOB!I].A\Ck}PmZFX_(lɟ%L򗽙n qgxwt>hQFًu9/YKHxYg8 23}"v5]qhbƖ^~V]! ~8O{ |Xu+?v`i7wG:G{ҮX7'F&믿&ۯV!ڀg?ldo޼yNpm{'L@ecn!P11[_1CBFB!˴lib`pLU|a"gR.]%dKBl2xb78& L￿G]V-S[{Pa:} !`|e=PjGF5Gb `VFُp*馛R֝VOPfˬX0^q5,Yb}\bcd{g— oau. ɪkeo  p߾}]>}lK O`ܵkW8Zu4Kg׳G9aDB@.LY2<$ 1,% a7onȃ =σ,%;v4AuA>?hG.OxH@_PBbPC !R{dz+>W]uixlڄ{lQVw5T|-woPmCյ2x3T]3)C2J+̋+olY&Cg,2*ˆY~< B" ?/)}$ċMCrUDbzaÆ.]8rOu90(Ulww-Ļʪ+D={J 1_1ķk/n 9TlpNG7pp5"k"3Ƶk.B O@5}tw[hY,/;͓B HFXe?cf![DU,•|O /5\cB7ڨTB H+v$$T 'O.3%_  @x'[AȾ&tI ;:v~{[o[C ?^y{:.XC+gg58 l 1mj׮mµuE ͦW;ip'Z> &X6$3Qge-@#V<`a!-[:wln[lQFFB .0*mۺ LÍ Fʳ[ ]'@|V2d?;E]o?[(E$@" rx[h)-]͜9ndB 'k)[o=3=zE*JB %IO,%!|4ibNZRB ]]˖-ݒ%K,ߤIIRDB@0l%cH/#<`._~gW\@e#{%;:t`z)7G~ w#/#GÇ[*>ly#d8jG fM2RnJep` !EB|'?_ڦ B -XQi+B ;qI':uJ᩻@."[ZfDD,,%wu衤QhA! D࣏>r'pU{>"!  ot,|D!oGquZp[xq);mgՍV[mUz_H<[,B7n,Aw#駟:ާ 7=CyߢH@,L ,\J;*:J>]VX7F$dR"2Ba>`sZ4\<,L?7"Eڻkr-oivR@"%L$—HE &%6mڔ\BB'|=#fգGG8K:Ĩ0"8|Fa k/S}vA9X-KǏƍ]@^!&'G+B%IAؾ}{[y^zr(f͚E@^i/f͚u:\>c OJBX%٨%Իw\(sc(Boe#?!L?!67>1<-I:} cPaC)Иj\~WCf7O: U>աs~$(ʐ<6b'6MZ$0He]5jd+eU _̌F@y/B)= 4 y|(>bepxjڵkp2}u}0hTzM׵kWv}{̄AJu4ڵk:&rT U(Nb ^zيsY q`dҼys%38OduPG37bS֭m/\EB `"[)@ĉRpXQX%4ٵeDo7!\J!P`GD .rω(nb `ERYN%(X*~ ;|m{]ӦMꪧi-T2^婠ݣcBO`3j[ : x/rGIfϞŜ8ޣu(l,X`[¯ڹ["[' ~W\L@"X^`Rń@"86bR$"dUB W3g4_]τoYf@Q#@.ي,]-[ha~LPC(&Lbv{챇GZ_u#[' TѬC?^w@U=C x/B@C 0^{BPF G`ȑHqmڴq-&W@b .w ={AJ#&B :t,?,4Byր*Fb n͑cǎuZ2 O;V$ c讻:$WhbBuBb&7v&u |2DiM%%1wMC(ܟVm/u(^PegaVL@ Ѧ QO_Pu_ȲQ.&*JB^{ABp< Q. #/?PQQ,L^b zʕ7$tAQ|#-ח\&~!^ُB7tB$BN31 /4/fZ6OG0L& =z:uɌ3\~=o.3_5HgZA%9&?vxʋ0^L>O9gYt=3+~Xٰ*ɦlIlSBͯ.C z C C(WUf1Hˢ,TCi(FW-[4䳹`oH2d4i;7|SUV݄db `ʱn)NV "ϺnݺzV[mUANM!?2duQGX~w pwzJT! Gq;wv˗/_$:j۾}{wW*[/r 2ݻ`^1osYUlsqv w6tB +ꫯvkNGDŽ@A tRt&<Ȃ*!@!Kww[n{7r*-_|~a @!CXE0Qc8ǪA D 38ЗlDUB2-#@2JDDWgv ЄDn o>)O-u&M]wezŅ@lTHT'D;;?l|cxb;a~ɂ$Ԛ_}‰B Z h"dP58>Xx"s/ VNM8=֯|I*D?mfmVG@lJO^N|駟v0^x# |k֬YB@'C M$Z0IG#Gtd?/bѣM*{̙eX/v}]aÆk͙3r"EŇ1IٸqcS?@=`r 6k^uUnr={L'tĒ>|0aD%fQʸ,XI?~7n߿aԩ# !P`yĈm۶VZ4B'%,@5 fbE.VJWqc'&/>!|!V?'OW_5kXSO(VD AE+4?"$?6w!x&p}-qlroHsAfTyin_&` C38dmK#m_w+P1$T&./;OCBF;eZ?bxmuo6my)c;︕+W:b'|b g͚e ػwow[8@VojVXFeo7W)gf2 lL˝B 5 /4v7v}~pe%= Pem_d']Kr.ιP,ϒi$^l\+[ry~-1!K`tT|WG] C= 5vΊPE HTD&%.]X'g@}&3ox+@HqfC-V9[&dsKG\dAP&bc3zJafZ^z4he7`ձcGCHe}Hz(nW(܈lHH!F毋2{okV:<Ȥ{euv*IfR ᛈJOW^y1ØJ$wb$^`2K]v, cH(X.<ش(-[o! @"[SCVO Bk1!CT#! @#[]%@ȼEpbp'B@ ҒXp`=묳 Ō@F*bJuZ05tP7c -/LՖNOB@d@ZUxmQi$Ōg}fY|A ѡC/fLTw!  <0EB"ךDz訣{gp{@Z`'7>"!)dBKD5RKr裏v|$\IDAT묳Ni Lz! @> V?@U?&L~7o<'x«$zBzH+T]m0a@%YDB |ɓ- i-7!z ! r {=d9F\$kM;!W_6l3͊"! @1#[㎳ m۶uӦMs+ +}j=~1!NI}R>D4Ԁq MC^!/\,BpmCQ(KyB oW,L^k2;찃e~n"\|U{yfd ɏl >1 믿N;4K*ɦMZL܏?魫]KM?^c-QOpsYd [r8חw ~xdP /Ի{] [t R^{/³CvCBFB!˴l X@nY._24l1"r-)H܈H/9eE! VG nVwGf͚9v}w `ĉs֑C[z_ ! @rb &M j ל9sO?l&9rv>}تw/{) TO! @0fOs_}=_NM6ٺXt;Q u/_^5S@l#Ν;'\ r)W'SO5 bc'B@xcmӦ޽G%-*.0·^zy7/.T[! @o,Qڵ|nwn&wUWC9Č4Ub!RoQe3sC=3ݘ1c>! X+`jCs=-ZȄ1X7hEo]pZKUK!P5O< Ik"+^2W#ׯ* ! ؾB3ظU\v=_p\c'B@-i}ϟԩ5j:`t HѡCkQFKRQeO! @>![ϝ;ru]qᇛOԐ˖-smQKt. `~ǎ-qlCSQ@,+hصkW{/R}n$1Y^ҏȟr{gJ#o(Z(L(<~Ǝki(?Eŋ@0$VD}y'x"aȑ#-1?s 0>cUM~ankvp؇$ r-ovR /hFH! "KdJj)q>|ѣ'%|Y^}e(Xu]{Ծ}{w 'XC,E(s\I \cĸקq15XÄ*6\s5r7  !/dy#!^~St toB5B7?GqzˤMYɝ;w6i׮D =?TxT!%0j^0fb;20aBbvay涟6 hKP\R+qxGb1ճ 8$ ʘ[VUB@$0 BƒdV]adҽ{2߃QXy߬CZB:;6l37c e@QH8.B@D bU'XҲM66MO'cMZXbi+41Cj9~tB@6׿|MknC* ۑנAs "@Ib_Qɮ:Jʱ?DC!Pl;Sqs=K4z LP| zI'd|+J{͡@hH>! @8b `  C7,ɱ&'ӦMswyk6Dr&$ ֧NjI- 9F!&B B4d!"D$~!0|w)@j3FXGq;_s,Th#R٢rhnСNu ! @#KS o":& i~Մ$V[mbD~ ,QX#Jdͺ h"B@B "8{ɭZIi0bKF'%ѪuqY&ftgϞmԸza)SHFo! @!{{DBeJ$ŋ@0# yiYL2׀kY1nK'JF"! ]b `XZliB0:#M-/XT>[1y!W^i˿+DC:G1-VыB tԩ{-LCVcG࣏>2*&3~ X=cA=rH B %G9sJ!#1">`lU+PBxfJ7Yo]r}+h_Ol lnFs½lBLz3O:PO!clɗ/D w Y6_ (媌zW)#u /T=}?ْM) v܇21J|ɳMjH7z")Wh0?^w屢G2M}>?7A!ew*PE/k6߾yCBF|CLV^X2OӦM" %ּJٳ',aLY+Tܭ*2rcqjҤ{G^{eeHuZke^BxGnŊqD ?^V'[bHD+[BXRW&!zi*Ÿlh!ڀg?hWw5 Ѷ[yzbr ?- 7Vf`c2-)n\  6O˹EE2jĈn}F[dI@z ! @ b `V];wQ\BoݢX1&(nFR(@P%B cZA#x 3τ4$@ƥɓP;6҇D0QS7ORB@T#iW%CݺuMʞ~R5ֹf_8X2~ͻUnB@C 8qe2d.|͢cŐ 4B@ V/[Vw;jժ>X eR1zl-B \Ҭ s͗c.I~`[! @  S`KB@Lpz! X!  LB@!  DB@!))ɷ*ӛLr2DWpZp{7ܑGi ŎPfFw}w[d[4?$vnCrK>[orKWf\*壏>rn9Ul쳮9U6 3g馛78駟:lJerl~vm7GF\e={ِlFT4+l{6x$=B@!PH]`QB@! <?˗/wO?lrF%믿'|Tkfi}]EdzJ}naZpdMt/:0vm#G/]]˅ hYIVФ *u=\)kDpd%4 ym8$4m۶5M؏hhy~7G C.p HI}9|蓕A%~e[˖-KCa̟-5k=2wy٣A۴ic}K.2&}RM$}ףGe>M7;8Ǥ}3ϴr1aI|p n֓Gb|o& ~Y4߄e+>w,o,dU aݺu]we;#8)u YNڒH5Ç{VӦMI*SO= {رcM!$Rr~uɀx!>U:JMaÆDᩧr52 |`rNY $!h 'zL|+!Cʚ2/]MPVe%=l̘1^E?Cn=4MN<9&4}/;:>^C;{4iOt‡eR{W+bV+p @25#(KBƥeJiAʤ޽{*ErtAvh¶aÆC@FHWt^xacGPN =8Vs~@xժUˌT0 MJh[ԥ,u ’pՕ53m@(RVC &|뭷=8!L.#.ne/ᆴI&o<{ֲroW?@aĥ2vϡd7w\7&wLP(/$O:-Q!8>&Xf\<ɿs%/JOpb 1g 2WA6nT}S,0X)Q^ `V šf,)N:]z饥E` ľ׆&/&12eҀ0_@!'.L^u[Oɢ?fvիj>&LО1bPYVh|$ ]uU*[VJ-u<󿑬+u~5'pc0`7*"  *7"&?KdU !:Yy4hN"a Yf*f%ΪLy0KUL P G Bp7Q3EE`v07QfV4~{/mJ>ƬoXz4x 9% +vD?{+T; ` XweM|9kԨa oL1W_}մ\L)Zfu]ʠ|oHG72QB];t.;ۥ12x^r%# 1xo1cvڙ0a1iڴi' aԩ/YR^qLe"Nn9GQcQ YV^3)-lO;Rse9&}Qc"VcB s_}㾪&7@MM17:OQV&H%hE#|o E鑨ofQ`lc؛b}9 rXU`vHve FG{-qdKDlXĄu*Fkh4 ef]鞑kQSn懲*|._vU +*|{r={4+Vg"_Ք! \S-ĎQPYƂꫯ߉ d }F,˫C\J|Wq*p?'ݷ[:tRpv3R  TD9>Dh]`m5Zr |*[>e^B@!P(Cph Ԑ_ITy,j1"(^Nߊ7Q\fo7FmL8`^,F,"! *|ӽɞcB Is+X\`y"ݺu BY!~"y9W#)@ވ U^\QiRӽ{w_wuQv+Z&@D5 "]M~GB 6%1Q|:Wɬ*.-čaU(MeUKb*qM%+U\U+%U%qW/JWXwU ,K" ٿ%1W?U%>U%WK&@J|wC@w5-@Ep.DEʊoTL8vmge3 N SԪ5+sCZʞ8άb~g%fŋǘ(Sg!1[Q]|WSʼnj H0G[2)倠+M %̀J-hq - djKZ,XQLr*XE-@hJ--}Wy ^H <&Z OZtL'@!JɊڨb-j"`s,H>!=K$R>H'@ yWS#@@E %MT]t1AwVq%h>+A22$)bBM_bRAe/jD$WgՌƁxg ȻB  ,yt26PE]WRaǾ9A;|2(>XWghY;HߨEw5=U{B(pQ6*-Սpu/EpQ6*-Սpu/EpQ6*-Սpu/EpQ6*-Սd8Dx8IENDB`scales/man/figures/README-labels-1.png0000644000176200001440000015614315002111056017005 0ustar liggesusersPNG  IHDR l+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*i L@IDATx }t?Қ~UE:*m m䫪Z<$<UcHLP bJ1E!Jc JjTfR|9swYsϰ^΅í3fV\x[s390s`́3< ́3f x70}ŕ3fl+X|?O,>{y{~;?x޷˵́3f9mo~sqG.8]tq-g.>-}{/>4_/>Om=׿~q.~o]Of90s`ʁmOӋ;l}>wyG{'.G/>ū_]5Yp ]j?_90s`́{o; ?/~񋋷m[Yk_ڋ _{v83;y^xްx󟿸ҕ=?N=?O|9Ѕ.Ԕ:}}iz\<﬑B&E.h+.zы6udiyRMɶ&Ko_ָ+|d[ &i}7)OG%.qmk]ZMsVN>..sl]5 ozӛU/˻ܺF L^[ʪ6)O]6E:>m:|ڤ¼.aSylmJ;l:M{EjޛtKŷ?߄y/| }Cx_OA&mp+,o-m*.wŗ卥K_i3эMѥ.uObW! cmC?Cկ~uUhܴ<囔'y;lk:ܗMe/{WM%㗾:yæk8^mT{l\W޼}ﻠTַΠzx>90s`́{v+___韚P[ np-%y\e=l?}[瓙3f9r`1~>nMCi-oyusQG13f90s`bl;Jխnoތ# /֑<́3f80ܕ|}́3fIح!=sYf90s`vr`́3f83Ϣ0s`́3vf L90s`́=Mm+ 93fؓ9p/wiMwMrwN{́3v 9#8O|b3fL;2w JcAl9=x;ޱMnpé>{ xqdmćg/x9'v/|]ܞ}wBnv-f.NXߧ=%̚ovs1 [ ?fOp| O~rx OӋݗ }ܙF|#i>CL3d_u5;_ uYMq'MZl}8Ӛ?]SfNx;=5sg}v18`rӓ|kJ7M}c}s;ӲSѻBe׽1UO~K^|~{9|ӛtS?S$dJEgq3lN}.F7)Oy$}}׸r—XT'~b3`V>O-oo?́=_W__r7~7X].nsls?svs=wں'''Mf3f́9`!~|o, 4s`U@AlZaEs*WJsg?'*o~sq[zd~zqy-or}Ẃ/݌|G,(. "!BhO˛b.dWz#K%^ܤ0 ?xkpwӀ>Siy4s23ҕ$?Ë_D,,,|>f|裏nLnA~ر9[tEfm_}{<\eryo3x,g#?Bbk1T <(Ek_Tz^f(3l翋^K]R[_=pf>qL#}# ew CZa6s`'8C/҆6G<ر.O}S Joy\'ohgf`|Ɂ!F3PQ_\bk UƩIcJQk_c_s":21yLxvp;/7^B8 C0/ґ.>wq ڞ[˶͌Ƌ;mE鼦?u[<h4u>3osX,e_`1#nfw-LK6-5Cv.Ѫly/AewT^=mo[ز %cE9U6 yD,woo/x Xkܽ}qqǶp$=|}gc2vNx꯶_y(t7pŐ}s,7\C% #@z)]xaIؙcc8k}|` 9QQl7a+6 Otqe>V2p||B^'&҄1/ThgKZ-iʸ\nΧy#F &YgӝliKX;TcK=}lȤ%JZyK)^##N~z]tw]~ v 9m@F;']D___J6nx1`3u~$v/Αߔmo6/~{0fv)O𒗼=8:|'6rh\mc2"{a"7m~ ceJ |I8oM{caǎxcN,{d/-X]>c Onv[u~r Z,enUy}_? 6kM%/y!z!^d1o~Wa7i 11&+ne8 1rNfrlBs9SQc&a%ٟ٦_:i&{&y~7ﴝ+ WUL[9Bh(Ig>ИTP$cB!902^,µQ/C|zf CwHzֳv)BfP"y%ahKIx-Ψα@)[c?|k^s(__\cQ، CNM\1dV11nm3빮%㹡l̜.l4{9q  tDg/}^9_JEn̈pݭIL0!Z-3@%n$)E f,- uM `ƃPc ) SϾ:atMK-a,J5Kc/ d,C0}Y[r <`J?<4v+(Kh<`aZH9gB*,=k`grrJ Apƀy! bpѸk'81Ya6'hvLzpLcRNu`t0I<2ǩ葏|ETinw:dgj, /uA 36ɵ!:^zwwgYƿ1`^M<x,342~U9w9NQƲJ< wUp2&X(Td|k{^@' XÛ6lehjvc$Iqv}L“. u tY}fmns l cE8r~xүg(mmWjaN4ڈ(s\{;4=kpd>l7 \z|%&L,DYz\]cP(n`ʓMVxz9 |Kkmg~߼2`UXY6⥪Ĩy$)*0 8L`}C;>wyْ!h9Q~o|M2js)%eIgyfcZk1jر`"Ȟ3s]XNE@IfS&M#{Ț5oӁ2Z]ܘ-\wX5) ,`kC r%LpD9_?T.׻&ۢ6gqFm DrMo~'o2ᖼ+}ʳSq,} v4% ׏^W`KN9f;if5E!(x)1P\~ T΅"Y$GknV 7ƃ_p(Pm,Ps]ύ. oooM4P73O F7ޅx`sm1p 2m-}X6Tr޶*rWL@ =_09eKd_8xNmEk6bwx?p݊pz{ܣEi/ Kue!pF6Hȫ~5ovA,gh@-|ttL1!À](R)Oc`;(\(f(NW~W/PL%eGM^Sw݋:u :ІهZ!x3~mbu>f03g [Atyӑ]i4`|e6CVEnBw]fGsk 0p;9P`{Ú0+_f_2:@~p316SHm4.iP, u~$0T=-/I-}p XJf =x TfaM=ݎԕŒ"kM=yTL߹E}>mFj_eil!xPw ?SپQdw_V]&aGcփVLgc@Hږ2P~U;FU 䪼Nө-bp_..&Gx-6'N:fٌ/$\kf c7i\ZrBSQ 02oՒlRVB&=Q"fcRIGKE(E Z7IT<pj84x#G/Q{v=yLd6c myc'䳓ՆUۻ\u<%ҕN e>R|xئ Dp>?G]'cS\G^'sD4̵nj!rEm_h(gs 35/o9ocYz衍r 0V!]>e mA0tn88;p /wHk`, + ʙ6k* 2|YBBό-jŬkA Se2F U8Fת^!r7af{1D^8_j+~SwdܔpwCICν/0w蟾z$Mgg2ALƶ(}UM-_}pe8}PMz+`t?F]qD\ [u\ԁi:PB({S(lxDt)’o@Ҏ,Y<8P,}y:oIaʔ'bqx:F M. 0%{`H8m`z\i[RT1GyL!xL@ iSD&*t/.RhU c\u[SvN/D2$X`<% ӘQMMY2Qw38U=8?6 9N_x oxe1D׆Hy}T+0G9JQG켝K?(6 |,2_Jf'LVh.A言x<=2v

.=p@R]EE [F7jav+RP(H߳Y ^zn]<[o7s 0#!eFt]Mrh13͐)B\e͑ |KyGqXNe5Vtx(2}Qz:MAM沍i)USrmi? ؼyU\]͆&P&pu='-^ʚW@rG4kHԣ-M⑱Tut&]s7!S>a3>& gXJRR*;sv\:w<Oz֌dSZKFIIG7wr@`z;ʷmbW?vќ*婭gl!?kmetŐwHuz9>"9m*qĈra}(?jx͵2} ѩb:C'?kw}5E2T^+9EUVrsBةpؼ (a:P A,vb5}D1w;aeQLfv-V>2{ϞQG]XKMB^픝[Kf2* })#&%5/8ٸ uL EP yL;xHyu=ȃ' I}ms9[wsXw3j ~"IW0Ԓw1zDI2|.}]_#4k|1”Em#} fNa}Qf A)隣k9zLa!bScu.xcӜ&pW+-k@ \sԀO=]R]29g%K'2E^!ˎ $~1F?F&Rڀ](B9NOל(a#H(.=GǢL2F 2F2 zDe+6 ۳HC8EzȐvdx(.ФAOX=BdI/QY&E6DI<4cP cb/1yH9["GϕZ sޙ~85F4c!Z6'TeT`۳ԵE%%? 69*ӡ09|@/ٮL障#xΨK_fM-/{ܖ6GVh%jLEXXˈ0 .r`6@ٶyCض]cp7"LjL=}~w~"(YkR))V *z:[e2욝\>wND='dC>OzLgA5󀍯`<.,k L h:(ktyyÖI]&0YZG*ؼ>OX(ǒ*ܖc` ÂlW^!>ZW`Gi83#Qa, C! gzPjQ~G< r!WknK5R]DMh-JL2M4ϺmDeȪe}˷ʗ|hf%y+(Z>0cOmRY绎ˆM"S5˃3'/$:}K*CЩd;w +Д0A7aʌ[1F6$k(5i9Ik<$/ `JiCQ0v=)z[Sٗ皰UP f~(tcLy4PKgϔ%k} B4~<ygkCFA k0jKc5Ce wpʚŧ~z#]cI:/} lOfT t eC_!riE5oG}&m7 o`Vjw`k-, 1BCf}?O%[ ^f=.τ:K:}#=YJR[ǶYV yDdVbKNWGy `eR8Ʈb$Jp_xXYcGkd|Hx-xdOH]co5ojJۇxR+5с2o wU>Dz,^2=lwERZ< }Ψ ]Xaʐ7s]؊eJx!,' +dfiH`Jx3/)(Ĕa1JXNkǡiX%,rKL@bt:}Sp7ܺπrwtJEv4ʉw.6M@:E%51ڣ,U}0^טʔ wd rRay? `v230,94/uH>1ߵS29~jmi^M-61 Α1ttfkYAmVDKԥ^C'H)/}D/sd 4 I7&anBS :R @It*paY:pɞIX,1FZ'{\;~r46fArTd(*2Ia <.@@^PXOLanc} y6,=8o09Yf M~tC8(X"{Y.":YYgmzr2uqIK]Et s@_^Kv̑?՛ShZ"mNcƔ{@|wyxѕ5mGd(|ѯ1Op4DLy,!SY.:aw\zc 1U' N,7 +p6<`aZ͊,0a  Q@jh#(cYu)M)_i $yHv[򖃔|]k#^Ftt]/ik{2x 3UxT1O  4)+Uc&zꩭEdA4Xܚ,spx-HTp,ӏME)GTdPƤ2 )12u~J8p Ȓ#(63@Pf,}}$uچ܍!<+H3P C-)S.gl*Y/4VÌQe\Y.F=-Vls{ɹmo d,67(q`c9BPQz8{Mc7uW@yD˼|I夓N*/5Ǘk{iȺ˸, hɠuœx0i #c9$ˀF`8ΒV_pǽOF U.xxL8Ex\m:LK ^ef6kv +.b2 eK%焚΃e|/l b/ J0Qg&lءdt~YJ;$o җ2Rƚ>UkX~xy”Mb +<)OimˀW@WxS>[3Z;FI5 E# (\NuPZ}3e1RnI^y1Yz< c/SfS)T^q"`{߰NB~ls^nwf2ͱ~wo[ ځT<ޏQ6&|WRe^.c\(Kkh2NZ0cy6V__|I" &|Z(}a0Ӻv@i!CEO4_%hE!Gi^sԓ hֹ>BVP = h>K|KrJ,7𩵐@0QBb C松c#JSgCm) |U:ԁX0 s1Mr)|lQƺOx O XIk:_,5JY^QQuzmNҋW+{!C^ԅ2ReyS"lediΥb`yfW<꼟o w?sNF} ʹ Oײ \O 3dC܏~; Kǣx^~GxezϰCYI8XvzT' N?=։3⬤]f] '*e2T,:,ahHcQ c_}DAUsY tmc3Va{T:P j GqDQMRWխWlyҬG&L4`uRZH;hEּ4'P|cq <9[J,i18L̂7y9)]Zp% g3G2.(g8jNzƁcpFz+E@IDATmm}*RѮhޒr׵JK,iec5&7u!ToS vx73@BPvҜ8npDȁ2#,J`E1F$Tܼ/$D'W(W:%҄(^?ax׊t||K. X5OmwƃP@:WBBkK5,y.fySͳcfРNfe<|!ct(vd Gs9̔(y"<#rL>]垶w~7:9^1ʉX[m즾ur`OB%i6ErY`J3( ˬ\{C$<" [֡~>`>0@|o#/KѺx 9Ki-ӰM&~ ,,U {$섥erBH y/r̤v1SVrJ!"JO)t DW`"^}*>nPXQO'0 DiuKGXo}صgk%6ٕ~u os\ q-y*JFXeȡ_ʬMՃJ92#=NZ/'a>{6js_P \oa" IǗȤ JȯߑWm쳜HT UnRƴ1#YTץXKz]?:ﻮ-z1ڼ&}N{m.^m]է333fXF,YZ\<ߡaX&@!e_Ҕ2o V(0p.A<\oKeyBeQDQ~gq"㱔M fB}:_LL ~cz6<'J@bswEdao,e&C‚噀Cd5T΀ޕGr<Kĝ.ͤeV#'L?J?瑫'"jwJ#lwI$$0ز~#3)WywN_cwU3W2ȏ_GٔeRǡ^cVy@>E2ΥΙd5V6wW2UzBEϕW{ƖRDbؐXJwk PZo p ]| 5>Ch;N2:O~JMׄH>(<+mZ$yn10㎎,I{GC.ÐN!O1TAW2{C ])rK!]ِӗTtV0;CK!(4 NJTEֹ3Rb iK볒)#LC' K,س/N8PVaIj||56^'Pv ,#J&6P)3iROISetY}HQ 7:{2 U>ߜ0t}OF꠬0+Sr^)0`P,qĦ]8y66#@ _J M2&͏wA5?)q1 Ga%m~wWLLyc~D ]m0zCv!/?kt2. SώL R:. +x`FQ^©TtȀU@W7T}p"^:`Knqh/$JBQYא}=}`REM )\`jfeB:x:a@K,tXLҗFfUzRW/8v-JCt@y(UDQ))O%u1Z+!6aLoJE '床&y列^G􀳆 PR#7&bD۩|}=̵X!%+,I"<̇lƟr TK#SZ4u2ňSF W"0y/y>RIJG<`(RwL ii?1h BrQuL&7g|`syq"0!"K^vTBsBWvA\HI#ʉрO$I+Gu(ʞBcȤ.\*;_Q|<`eܵ)Rp)20 +ƒ1/9r/u 4W{9d)m,<ţޕEَ1#1 p;buՃD|@2-O̞s"->iF/ڲ%]|AgشEuC+w?#wy13.Ը^7NHwM<I/c>j|[Bԕɦ ^>BP…k|Ck7&Cjӆ$C&`^ʓhqmF2iS&xSyK̚ԡ9 4֟M#T+b+ G:`ʊG !D%usy?S<ʌt|{JXg 87DCH~]8ό=R,Mڼiu=/ "_e 1\:.6@Cس=.'fO,KNPt A Wah{EҪ8j:֐<"er4R:qƈhBVcy@;0X%Q$1\ ,Jy姭BfMD;g"\5#1"/_hJ03~61~wq塼Hy\pHvnK|`}xD5$'>1ʏM.wYZC+kce[I뙄7ekX dDSyjTZic\x30C_&c阡q-(*ZZd :9dtBc8 C g~ U)xQƓ 3vAB<82%ZMECzi,s擱r"y-1,KlC k_ JX>t'G~cֳ2D|.ivfc!1\;[S|s}#y (J+z6M#.TlK2yS6nYriMU=.(]!q½u,n'8# s^Pʳ%K7 a-gjG) >%Y*uz. }oS&_i sd9(A>h%260Ҧi_mlYe!dTA2`PD)e:SpM(2&:MS%6v=u /\[U!|˃jO`fYtκsSkc]W)V({H›<`Tjb eĊ,|>8,O8;!!)rLQ8yv1AyUo^EbNTx8QU& N葃xC'C!`LG,c5>P:@彶KW xlGey}p]N^&]K]R<1eUnU}#yJpj/{xw!cǎFwN)Tn8zfhP2kv3 ^\B )3:$}ϘQh_-cuΖBd W%gN3^eM}pdP3~`|l]ϓ3MY(gu xuwdFlOa7!wOh,H=#F:$:Zh}"S1ŝt-9Q`L"t~ ):ǔƪrok z7u{AYFب[PoJЂD?Jth9#L:{/v$cU=V8VKWG5kw74:ţh6@l+=|\#8%cBJj~T*M=Lzu}'>uD'fZ퉒n1Q)>+@)p=l_Xױp:9F]LNdVz׻.MB!/%< i3gW9ʐr3J;)+o{]H*?֯Aƀmhbwq$X6ф2|xK_KUt ! Hpe>蜢K ٓ.q׬+˄=B%DwIhe!,ZۊP5Q[-FF}.NcrSA>Q<`yY<#t#;CƁy x%"ke-﷝KG~6ڷ^`p! 5?-XT35mY{ `6hoaG!"{Z(O,4utkބ'4T]Rx'oX+ #Le7bomY"@?2q$KMީ5@J;)ֱ[um<`yqͧ_IƀM)f1Bi0Y(>x>26#Q٫X% vj 5 ˤ x+eUN0D`)$uRyl98Z΁.c GȍMQc Oڲޕe[<$C%mtwMS+Q,-8=2ViX1uϕW3?+[v )h:A뚒J(󔝳c)GWI'b]G-aF8XCyiBQƘ˝k'fcB+ Mi@q\4[*72Qpm/cPW8{-7 #ֺpQT&.c*Yz碉cj~ $  Rp0yqYX7Oiy^K]*3MJ2AJ@o׫0؁vƁ]2 J,x85cpw7ׅ}\-}2Ïڸ/ʲE[|*PHE߽NGj<،W:T oK83kN*}ҌOB0`[jM0}w_x; nzS/%Ѻis'7ћa SE%z,82z:cRm'3&4؇zXFC'>M9qi蓺 m٫{;{vx衇n- x 5 k)", s<X (tGW'X40hcenEx՞3($?~2GYO~琶Ft]qM%e)杖x`2onL*C6PFt7LD9PX=6~G<$1<^~eD¡F'HƋDBP;H9Q(ytMAMy,N8 5I)61ɶ>]0#l"E .#B:@|&y &X#E2Iʘ^+e/]% Nn6dЪ~`|o S)}W}'l3)  7=Uhh[:\<8M`<6|(顼M ѐ2#Mc!>xxB9n/𲗽ɧh1lEw]` 9O|>YuGJ_|sۄXB&J1̶֜ -$;.R`A0g&8^G*\0e?y0PӦxpg?H9!_OXsLz]EtxJ&%Ul@+\ ˎ`7Fj_IGͣy}cQpL_,^Y4mѕP @vwCkًjnr}ucB{TWv 8eT7i ?O_vn2_C#ebSJ[Ċj{f5N~OKg.=Xt=WHpSm2O]uoƘi[̧vքw^@Xa=@; g51vNsHֲؘ%0VUs{ .xMpg۹1i7kmi8$mϘEl36+7%[Kœc )(| ؁,&׼ LMfxSX/80ą5'ئ"h X^8sS*{K|ŒyEٍM|^hf,~arYKvG~,wE 0ls}V_a /C`Q s ` NAK1Ԫ(=ܕ+J>n-KCZp"}im^2d|m'=iq14{v5b4yž%GxD[g G)-kyX}\gE!ںGa2g٤Uyg5 2ѐ_M̯0)֕ӢxI9{tP]Cћ7䈢e8SQ+TɩMBdvLxMz~``5%Du>_1K8g yg>󙻌SDXht[bM~s&җ6efO7D16U ho*^~!+ɤCsPބyl_V6FB"^GuTqmjF~ Ǩv`hbY%H~w)U"xD49^%16OF$q5']8MߔC*c~@/+;7 [H3dͫ0./KY61Iǖk[{^0 Rג#g,X}sWeB[<>$M~n ~ƝsQ8IW[<1^lXmuXS{eD&l W$߀X+ezdQ6CaV_XV!R.iFE}3$e$-+y o^"V]UU'eer_>1d* RȧHXI~Q8:1xɩ8-&;(eV8 *'xl"U4io_&O. g3O`gdCuwQK?ѫgl~幬:\>N/Z2f+;4ύ!}WU>p2#ѽ]u5cBv`6`Љ5`>v{޳ 9':={&d'cj.; Zфw9ZúΞF7B-~UfezQ DŽQ5mKZ٤rm*sBF<)tE90^n+Wx&$Zꓶ7qm%H" mĠ/`z`4#Z%s/ĵl d'1y3@<3ZKV%|8evf9 5G^җ^<`۲@S`u &bMNO7~O!L;8:+C2%pR9{71O`lSᝮ ֏Xzz.ɦm|4?ј$etJ](腶!刬wy&`cA`koȒ۱cG=sZ rBQs Hxh;~);rP<`<5mOG$I MSV0( iDSqXD09%GMwf_L?3]_;hbQUcXO-{5}2&۵zQ*xo7 `!6 5-|d˽6VxF8oݦ{Mlȇ8ƫ:d&0,߀1J mlsYV3]{>GLCќJC6Uc# wov RBjaZ3)xr.KCsw勤J[u"Lv<`R/xu09dL3ɫ,skC  Ô'٘2ed/ѦO1\pT# }DE5s1fe7dž>na=F:),Ið:p;p,E/j{ݫ)*i6qNALJ#)Pt F9M]68j~=7a %N7l69i2i&J7)Am4v7e\oSQo:2{gڲa^3!@{B<0LG^Q^瑛Dlrxhڔe}/}ʋR~\Y^}c8S;:l6۝|;Ǐ;L _CFP2٫m R%<}-&"C,12 X{DgD̆+")넣}ׄeıX%06Yۗ0OJs6,} `|4p- 㱕/'|C,$Wd~qRmZҺl jYdf$/nH -GC,UZRN,#< i  I,jTo(Cނ%H׋f& =Y^A6~a<(&0o7Wr \iXVD887q{Ja+nI׵.RF:TPP|s(hzem~׻SuҌ1u^Ú Ox*yDecMY`iۦ͔er؅W#3DAQƪ}H2tJ}c&w& 'l:4SmbWy`Q8^Z~aرt*kg? d0"my2^f.66J6u}\t92Lb-Tzfa2Zvl3sqs@QŒhֳ>0!uY 0l3TX+8/b2-Kw)MLJ)k-{j3M͂H<;^erdFs>cɮ| $]3LyMd<23g^. )xl(׿y:PMTJ}&ʊ¶lsF8iy֧.3 ^o 3V6aKBdl&h$cW87dloMNH{0-'}T}qM&:裷ۚGlmY';^`ƜIT@z(Q>d!Eݥ00CNH2FeyT(&J%y.2_^&ǀpAu32Q[L_[z<.yZ5mbY/imɁ4=&<.t|ݨ !v˾}KѬnoV Ę74ZTG;F7}6X5( N@WGK(`wUd|bO,!3UQpHC"/nّ>֥00!gK)‚<I{cX"E5&͔wS1_R yV% "BoN9srX*kXR* *-( $ "k@YD$@ !фEP+bR~Lf̝y{>Ustst1f'y~~)W~jj[{A7ٛ92hSN Sbշӭ[_>.Q8^Ok,P`Yq~坽ɬP,!e*֬GnXT.Ps:r<8G0<1Mbx3mad4f2bW^UMkROFc"Y,R!Y6Ww"0u?l4]@fh̢a,`XM%z1dPX~^Xm*Ͳnt~ laZ6e̗o=,87] po}Dyhїfu D kmdL)2ꯋJ6?PuwM}m@~^? pES,E,o׺,`ƣ>`ɢ1G|"4ȸ#~m\hփ)lac*[W+㶲v%#O~`V YG ٹ$@j ȸ/Ĉβe(n,,7;oS@IDAT 0@2BI,ekև}J TT4 2ֳ֡qdQ~S2n.]4FN %=47, ۇF:\8!a|f49\1l4|"!̾J ̬%Z"2`Dz ܀o[JIw6;M|)]Џ7Gn{}o>Kk ?cZX\-i@ߔ)LCq3W3c\(wD'mwfٳW?sN0oJ|p\DC;;~W+,e:mxzK@v!~mXf~dMq}yu]?,`7MX_mS, ] F봼=LmeQ x^>7zYOY o6`h_h4ke>m1N(qK˾0p958,9-<aW+.m[ aF9 Y,-nh 1%pӷ9t?uF.mJ0V|wV//y3v[js[:?>E  R|_v,`)VdIزҍqAOL3_2( E'ն%.E%l[-F0Q5yPMHDf*UL ֔gi  .3#f~k<#;.Kv:p,`;~,]܀p{A,!&L=uSXǓE4V.KW8N`%yWҖ!m>/%Kۦe/x9XW/ BK;k(d~,M^̽TX,!C=eeλ+c[)0fӶG~9vL5ę mRpс.R)0+:ǣ@W! lm3¾`P %x( +],оg\'X7rq-G@yvV:$ 0sz,8cEr+ _l;֘-f!WS#],^0 'ca)%GXj ˒ %n{8QA$Vs=BZ &wm@C^Kz=gV=OK9S!϶?Sg[1i"Q=)y;&1i׵ƙqq7&/i[0P73,`JWq9F|>Y #i5{EE+\9ܦgX!A ڼ0v1׼5%% ZאBW9p%L|cZ(Q` :I]P@,(2)*,< y(,%"`<t"= 1( /!Iint%Es?z &\ ,ɳ:g,`ϵ izG`XmS4UQy׻(WvyK g ϱ\+@ }F Q呥p,{YJɊ̋`m(uۑnr\r`4L SJ@)OyJ.&P_6SIIc_]\?!At.2mw&KG}G,5h4HpJ_~.ͽOvĒXi2Cg=y\^^ZIײӸﲀu%lw1 Az,nަX.~8G4 b\KylۊN2KJɤ&m;ϡ4l\Yz*6ړ}^689{,lں] &^EZKV? _ϱ{{֡勤.#ۀP޹RX|gҕף8q)ʢsE!Q\f|‡yƣMQ `\uY;5m[fci=ovQoIOoV2'XۈbK.Q؀y9N<%-Vcؼ b+nk<*p@B\ ]6ZLܶjsqv0 уђ~,78+bJIW\P6([܎liִс !5]c?x}=0vtq0%}=Cf{ )_͸hSU'Sky `\\Z x,'^jRRT_c7Ȝ)%_]9g R"͕> XtA2M1 6|T\oq]ڼkii9,@eG'J XgKq91{2=G6ެ6XN׀T:Z{8s-ǃ`>wgךOi֊*&@#LXaa|%BMYg+S`nT3ύq_s)F+OY6ծӶ߉L_tEG&X7X+d [[CN*@'uyiDAw<ir4AfKN Qz"y` _5Ƕ8.hC[c}4RP^J`1 *K c(-`ɋ'(<1i6e\{!n+ؾ2k CMm0C& (ptT6FH md&0y`yݭ[;_iD٢=I uZʯPu3~K@9/w*z饗^ޮ{LI]#y(WsGQs5}IQ^3(OQQW[̂X*VpO[+e wpRerC+,U#cr’v﮺Rl1g8ibᆷnx|z>y+ӊ_r -D@ӤT$=q]1kXc7Ј f_a&a醒&ϵ$ /J(n.m7ysΥ?  ?@GɈT64'dױۨY\bERU GkTy0d<ȑ[:uly'˸dr `K[QytfJ% }9H{Z0f== j\cN?+N]s-`ŪMϜ3䫏*Z[x=_!kQHޕuĵ*}5hS \J; D&Pp$FP4.E࢜cSДٮ0W]&eזCޯUkmf h {ze8K$}W@jyE +N\(\_@B[('Km4ΒBW2` 3'xd~) ^P1nK㖥>"[A`2b$͜xf$c9OS'sZ^B dD ]D͍)8hmq[ф-:*g<)6زCS4oqJ O"?kƛp rlf,g|6 e4:K]#[#( 4Dy,K}y7/ᥱ2bjy7J[ .JWAJCh,Ad1z+>BQF_=+m[*L:º"M2Ģj +tm@'߱4pB>){I'8 V^0W6brZ,݆e=J+4YO\׿{,y8[  ۶#lK'J`%c7s{ T[pR1v0E58Xʘ3nm3KpwxoΡi33}3d9rP<׶t:0pѦN]+k8q8lrr"`:"+myX,{T/!XO0~@sKkow4(huVWn.w`m} Pg,R}W#Y*> ׃^lO&X<Xڅg/2+s5'%mi`ŊF<I 1D0k?xIK#,3YAgy{K+P3BQ;Xqsl-{ly|u)Ǻ.rp -`Xzg"ݛBƏq0` ۠{>c޶]KYZ^B|u~#;S6rB67/Es#seNdJ])d\EvX7kNyLy)WQJwc0%M)ܺ2m8bW-_~D@;ɟ6I#K?P"_g +L&ksz_BKMqXkܦC: GM֥20GQ{e^02c|(/_|qcZ.glYCNd 'lyꄸ.{:u0LupHצXYT8Tq]N Ǻm׻mxpv\d|QѤ/y~f7;9g^ؼ0'ې+}8Tדy n`7u~7 s=9>yeq̥+%% #0q,׹e9el0\=Xlq]ַO)3OȘg"Kz,1^\SUO@E?AπpVr?'=.v"ş:'ɸ-3ާ?m:jL{8Z~ b.;#q{4YM) *=ɃQ\NRu$o.E(-2mls-`ACc.Sh~x>-9%5~f '9]5`kM._"`E4t᪢^z6tDD̙'D::;묳F\sQW `(t?or  |.kB8I Lz<>63mD 噼}b`K|`c?~~D m]ꔈW߮꺧1)uj`}+(#ұNzm'W"3=S}/s[;,_<$/Ժq8{HƲ<6Ur}"}Sľ (c>s6e#Ɣ2asWixX6sB3coܸjSdVz~_9rMg&dvg{ʤ@!𹑻EVxPdpCdohxł%LЕʡDCs鸿fO#oc m\!de[s]u4}B LZm#S3fUN5!3_*u qn",c?WiF{'sP༜[][ bD 4Ɨq!+3ebҺi0p_28'ŔnNvIOzRx o%==&/2hKɯݍwey?"cx8sen(EK"sT6e޷5#&N$)/Bv@6a5D_O[bzlP,q&s~x%tY&'MI瞗#ˆ7rǂJΔ(H(WZ߇l1P~%j姾`CS!J0қ!a)#>x̶xAѕorgL]ixVę8bSZɝR1FgH ,(.#BDSL7IE`Pf=pKnsZfiH>'Q hv&_8`-]U>K}"ǐIk>m c](A6V"sOm;(sU_J효eVzPc r?kc>8ao~';c,3^ ~it,l2 )H+,fEqw<6|2 |Lؒ1O0=sB=ɳXMXE/5WU]xᅍ6!\sf"lLB֯?$p`2Z\pD6ť8uu6 8K\:%^fQJp'ɻ=MHY?9U_Bw6'<0 6``5|ë/֝-k7WYw,XeQ8@$]Ѭ }1Uns".Yʺq6 hs{G!I).>/2K6Yy}N38?pɝn3@cxʋM~U"S-eh=N0I`p1p M?vqm4hQޔ~j]]g$]o Ɛ5LGDr~}_Hg뷲K cAh-Js G=Q `;!l|?S<K\U2KQ>S1i"%(1F~zNe{|uhwP\CL}G렀Dt!6ׁ]4g=+|L+b3Pikq7̶O쎉!RVQKzJe!S^2+QdYkLl7mS]7xo<0xDviqE m7 !E4s% {D9E-@6KlG9$L[c%ML9w=e>zn5cԸ#-{C#k@D9wI3ǎ_`@t \@h5v A]i}Ƞ7MjZ΢'p9MkC4Nʍ9m 8m.sCYG XM:O>Kv<c|m Kc={!`,Ѿ;R`MN3@ | ʄv PX-r}#BEo[h9(J۞{_}1ꮼsz̋.9:ɺW-BGHd!GvXw˨Hii@kgP'@՗gy=XXil;9JD)l' _5koQP>g$T" C&hu4WؤzիanuwP718sʊFYC7u ;qViw]Y^SNҊ_ӷڗ\-m/(.2rl7 5dY2 4wWIc,e)u0g7\/{%m>hhY&7hS֏ymmRClb]ݖߘ`'4tL>Ci"hYo D7?&3 X\7N#ꝥTW'7׆>3ϻ"e (/)rW_KB7~KtdMdǔ2&;޵XKR(3G^U2טsT>W-=߁/ ZddܻGkҰn(E5M)l\zXsF&v;K-6i5u9/7Vu#oG)Վ;3U'͓5<1 x,1L釱eXahq-UiNM3Odlm#y`n,vy,Jki`Jp,MU |u_qo|cXK}c/(1@#xv$ GD~4r`5QKOqn. %)rk;+haJ;t-Vpi9J,_WiS})b2:-c)wg#C2Dͷ#ivyQxWNm6Xb}(,p[,]_3А } X9BZ,dI6k9u:q)8+kք8|-hMPLDv+-` ](4RhqO.eM9e—wuo%k͚dc=J1*=*c H BEPw}W.:/N`ef!v4'dIҮytxj9= KYYȀ.+ q,%\,| ysvjkm)JVMnwnq̳J`!585Q!LM<+yB)c3g=3~Kq虮{ڜ*S4 \09Q)VvZ9; x̏H>y!rMͅE)Z0Y|{k/M<5EB*K޶nb@ G-`3q&tA"R6yYkEo4R'и̸ܛ ˪'J7sY|Kl{Xa@iؼƤK9C}:&4Veqes[Xb9)Y[ش24fӕ.| gү[}_~o⽹Z\zm MREs)@˜sXbۡ$Aڑ!zEL~GmT&ܡ$Yؔ1۫<v)ZNfXƤlACnh n{6&@l.ЉP-J)NG_h!w~ǚ(xeɣpJso[;Z8wD_mYr}+:yDKc`U`=M@$gNDL_+#@Nr}.k+8cw*+?$36Dy4`yxO 5c[$YTd%>Ye<p4g4X *d袋6!b/F ғq쥳p@8D&6l츹h֜( ք.h-߾v3;wƥe=/ ` c)o9xOB%xB%oJ9uCv f*z9exqC.bE墹r-,wRJXqz:sgqMkSw;Py>y2?07'#wŁ+>ܼ̮],_šeUJsI R6b- wֹ??mŦO~7\nO}S Eȩr%xWP :m7.)guۧ›]<̏x8w֣1vm2s=*F\zflxn<|7- %;4kQ }Dž 2P"2!˧r,If[(axae[[gwDL$8ITTvm[:gw3 :22b+s p7ng1|y$qJI E^S>~`v?c8,}]Sȫo)YY\~H&R95i77,b/,oe'ps0rYuNh4ϬKn`[`Ľ}F]ږh๞O$ͫ |xFDT\豀KEenw#~EhYwD$.m\3R0GcGN.0T(+Z SXr "t;5jgM{ }0MM#=ϿJj Y`<& XMC 2KsNXbݙx12x;[ ~s}<@uK@--;K<)+kmzw>QvQ6GьJNq"sG˜ /e]x]]?r]Pr{9Px h\rr9X?7pEc\DEmm.50`:To[-vs`mL%JD`‘t)4K7rdפ.KY*ƶ10E1wTweD8c nyy~Bq2&"x ^yCz)?3 .%2:e/9e]|2-K׼CQ%,9LUJuxmeKQ)2ϛ AqZOGҮidnޖC" D8/U-{a(DHpz{3W ԞДU?s@_poo@J+~^ږ6 c]?)KGEN#mXG>?v$ hFmO`靾*e)r Cis |zOTA(ՔMz._r%Gn#Er`.22EV۟lQ醎fz,]&+aulO^,bD_ {@9Vx)q(^(K9)."[*DKs8Px-.Xf{g4&\!(-DJN]+ `S M~G= Oh^@wT?4$EJַ6kP UwUzX  *$0:nƫHk0"<璟`-mŷ˫@`Va t޺MnҜW~,`[2s9ya,n޸D؞ x a"&$yFp%(^=e@igaQ~O`9]zLE)6),,S)~w#;Z*@^lr/`[&sb_q`L9=AGe:(h/-#Y*R~\g{ār̛gsX.T(gyiiJD)5z%] Kns8Pxo@+ o`׽I`(^ '`nϜ2vΧM~ѤaywW}'JK]@Kq$/me;h \x _ˎk*%se @! L%k,~]qw5e]|Yks[จY>B)(kK0+; kxn"*7y*tЊP_Gs zQi Ti- |/ATF[fMT*/͏c>]++e@=3KFfb&ȣr.]Fo}T1Ƽ@1` <\UKkɬXyS0 0װ @oI-JcK5/; x N;(ǒCx98PHp)[Bg[]LoommKqlkB"h7 װKYa5_+5}M!ElpSkruM;)'޵FrKu8PױYKXߔc)_鸦-KOV“pGt3RάC{ɁX8+f]ckS̈4ck7e,=Eo{廔 +//3)/I\Y@t B9\j.9:' -o^ΰFWQp]v-=wS}v:*,lms)V+ b\p\KS4dI,>_5yV%#8/й[~N=j妵- h_60~闎^ fqu\[h $8Z.Or x kB9w-VArt.nҧT3KNJ}I*;GQZq`/֑y%/9:o/3xS XɿM^zkܸ 4s~`¤t,~Vg`wT \ρ.%km-8j{Q ț׀r)ʯWvkjJO.o*<.y睷yn矿y3qt9]攵(Ro~OOo(mk77%žǥP)ڥZZ?UZ1or ֩vxZ\ZE4n[^5Vm%XcN$oyZEqrn٤ pmoP˺׽!±m}l;{NsIJnvg5D] :]zWuƳ4k~Ks k%-]koCTr`{ \:{'>(zxQK C#bӎfbn~]_l8R]iʁ}@P~_nek0O ˥Qlk8\VU>GEXf"~{XuZ\.K Y Kw`'x6$qiKʁ6f t?,I,`v3cO=&s`HJ kP֠Ke<+qJ5_E/{V=X$kuw뭽‵}CE֗WL[T.XvZuVdltrWmŽ֒I\-keef 8z;w-3Cwd}dq Qkj@.(v[QKkF+s gsܭM@]Sx-kbuV,ilYu9Ϊh}r`5&G=j_{^Z] ް 7/}KwX>y oxu٥g<ڜ}ٻdsϾo<߼/|֥ztWNҵ9 _O){a}pr};߹9t}2/@>7m; w{ZEbWj****1vg~gn>?k{џI3:>>jٟٛ؏=Z^))gt9|'~bjbwOqwܽOOݰ5C]ˁ>خ8dT>ޫu8X|T\$n __w6nm׹uju{++TQÿky߿5ow5ek[7[Oǐ}MѽOOc3z{{G׆|}ѱ=OO/߷xҾ??hߧG0UVwlKV6|7wsZzjE+6??۔@h饗n5k>3ܼo޼e/kf닽/7} }~&}b߬TvM׾И''.}O|4a3v9/}r<ןoЇnj<Ї6l/*m8]Tcm{5 zeFg|z3ygケխnX~7oPEko|̓M5MӞo76`\؃Uu%47]t摏|=Z=ի67[eVP09>3雾i_W~Wnp;47& <?͹۴W(D }s{y{6vw{v^ tuꩧ6GNZX\+h9yʵ=e(#YN`iXƕ~pPv{n i*ER$ƌ/| 7_5_MnR^>c??m/sxR?.r2k涱~ymt;}W?=os!S?S=4$2í7h=FZ&wj43|4U5T_}z߼~kֆ_䩰n/4f7~[ǝZj:n|z@$} T*m(W՛//n]y6Xs|K^o߬os#Z{(N؞kran .h(Oӛ2^ '\ho֬ɥH|A|:UFCi3|Yk7d{99Wk7unbqՕzO?s?9^~'o }ݖ6`/s !.p Yvre@ 'ˬ)7-W!o%W֏G4׵GeӼ6˿lF;Kokӛ}m![qogh>s'~'?s|:zt_x+kE. %kl.1 b 1h}kx{(tѾ5~4x/8^_^5[@]aL\9P9P9P9P9&*ݚw@@@@@*0^Xnͻrrrrr{S/WTTTTɁ kr]9P9P9P9P9Á =+****\NIENDB`scales/man/figures/lifecycle-questioning.svg0000644000176200001440000000244414672302077021002 0ustar liggesusers lifecycle: questioning lifecycle questioning scales/man/figures/lifecycle-stable.svg0000644000176200001440000000247214706375506017715 0ustar liggesusers lifecycle: stable lifecycle stable scales/man/figures/logo.svg0000644000176200001440000026030114672302077015436 0ustar liggesusers scales/man/figures/lifecycle-experimental.svg0000644000176200001440000000245014706375506021134 0ustar liggesusers lifecycle: experimental lifecycle experimental scales/man/figures/lifecycle-deprecated.svg0000644000176200001440000000244014706375506020536 0ustar liggesusers lifecycle: deprecated lifecycle deprecated scales/man/figures/lifecycle-superseded.svg0000644000176200001440000000244014706375506020601 0ustar liggesusers lifecycle: superseded lifecycle superseded scales/man/figures/logo.png0000644000176200001440000007235314706713207015432 0ustar liggesusersPNG  IHDRޫh cHRMz&u0`:pQ<bKGDtIME 1H\t Cqf> Dw]^~ h_#Ã1?]z n vćT?>l#G`/qE``*C'U@ >{ cl  #tKpϮ:G !܈+?F ;>"?<\ | 0E@eoJ>7x6`),8\~ |>1܈k6s7 իW#2.\jvic y333( `03g{ |yǝ;w$ ABFTOr>" |exw <"<2rRR;v`b6QIKK 'OСCTVYQ|Q 5#hGQy=[\gӦMl߾xx,v}֭䣏>ɓ477uYQNx4#(Cu |wЈDzeؽ{73gDE})-B:eYΝ;۷k׮aنJd+p|D eyZdG>JAH7yٶm7o&<<qݿ=#"?~ÇS]]=T>"?|f؁\̯Wh吐6l;HJJg~0W3fqΜ9C[[PpuY}lqD#0CU8ĵX,,Zݻw3w\ C}n_/ݿ/.l͛7q8C%r;ݲkd 4e~)ϝiii޽+Wr2B`߉HGGϟ{tK>" >Elڬ֭[ٲe QQQ&{9!EQGr-6H]d#`# !{nq0i b͚5ڵg*юٿ?ϟcDv-[lqx-[">$T Rdvڵk r7 '=E6Μ9)-UC_E+>">?n [pi娨(y{1bccn{->|Ǐ8㫨Q>?>Fc-y0V\?Nzz95\5Rv/_ۣo>._<\èdX.g> d~-b yϑ$}DQfq5GnnpD D]'|qQr ̾d~#E\ E`Hss3'O䣏>r82 P}k G`z72A=FM{W-:tSN lQ[xlQǤ&q 2_Hc~oA$\˵kװC%r'%|I` %T_`o0&[t`dP8<AhTҾLl="" 8q?8vCwFd"!o;ry [~=;w|o0^'٣l4cIC O`2TnTՀ1ha<ؽ^l1++{r֭-:D8:BX.F~|l:Xhaس~S\\<JL/f&.O<-``.haس(R[[ѣG9zpo-[l.N4"^kFu{.丐Վڊؿ?.\.1cO=H<~{u-D<*@0FJ7Z6Y-޼y{=fԼ?C̓ L "^}<ˉvAAsLIIvh YwQimmeeevvk@vћ↠Ud?(hhn#<22т7س PSSñc8r ÑMB-eի'[}a=S̜9ͦ:Z;F#L>-ڀQϏϡ'{W=fݹE42sg.\HPPm3{&H@@vN_޽{Kv[<{ՃqtR[oΝ_dYd2a4}'ﯯFHx.w"ƺ)Η¬v /ŋ1: (r[>kAkBL&.KI1k,-Z(TWWcZBHԭjJMMxAf+-Vt}ʵMQ]B7 "J)[H=<~ z?K~,Yiooʲ:U 59[`eTM oڵڵ!|3Pf٢U)FQ8\^*4 [`{a޼y&xa8 lFP:[8D^ nTr`fVMf͚aM6{<7=>Bbeő yO mI?ʶhl3̲A\AY bS͛7O =7` <ĥWZ-f"%%k׮!;?ԀQN4 ȃ&qcQ62$ݧ><ؒ$ ̚5k;w.'OСCܻw(UT@PI=;ws-ZZZ$О̙3ٹs'K,نF:ӧՍW7LDGGdvIBB¸\M6o~Y}5٢ 56*ԙF,C>7==]vj*]7sرc455oHjI[[~nA>SNҢwV'N'ݣGyDAW_} .jut8ܽ{"y{Xd(bؿ?G<oZ~:w穧җaEQ_Wܾ}[/G[S$8p$%%Ye4Y|9sŋ|s! EGGevMTTTx' \x^{@QV+VU'̙3 /׿&'']X3dBB4uF^\A N'mmm`@$:`矿o;sA$Iҗf(BCC$&$ jwEe>֦&~_s֭yLpp0AϏm "##9s渜} '((ݻw3|:LJ*[pj e~ӦM# `\ K[[ cɒ%IKK EEE\zwpBFcUmӟBcdY`0BFF))) Ԑǝ;w>}:zdddPZZJll,gL:F#Ο?ӧ(9ryjժ!Ivݻ8_h۷og( ---dffrJJJ߿6lE:ymƌ3ev}6/_fڴiō[CN\\_Xr%ҥK-yt ܸqb} /cǎF$222زe $''xQiՖ䍍SW&<<%(vJJJ0=2A?~ۼy3̧L¼y1c/2y1oܸ}t≢c=s=GXXXqHBBs?9ٺ?$##CwFΞ=?KYYlַb諻tV^͎;Zf8x֬Y-t/k} I8N}69s&6lЉ3I#ŋk㏹yf򦦦K/1{l͈|M&3fQ,,\PWY7n޼B8FwRYYɴi}·~HkkZY|9_ M0uTy~Em5c.//Z~~~ڵH\.nQw?JIIyy$Id2zj̙éS8tz( O>$Ν; t:1N2OwB[=zT',DDD}ٳg7z+76#ie{6S] jk}>jϧ~Z?RlY1cWrxbz~Ϡ z5L=yy!!!޽feP˲իy牏A4h`-ϟV' l߾y=xa^Dz=$Irг… zhEQXliiiʲezX8áo&:Wy X_c_6lŢDd2ޣM:::vZ%w||<7nFw\T,wEqP/'mbl2],+BbbA LCmmm9s5n'(=1L0̝;W~3.^[Ԣ4TVVp &&fXW+/h*rssvΝ󴵵أk` ;t7MG_Go.*])))=C[o܌`1':!V(Š+8v>늢HAAʕ+ټy3ӧOal+**tFm8k,i:;;ٿ?uQdd2a4A:eYs로B\E!$$_|ٳg)تR>{1mۦgNVOZC|rx͛O;wpp89W:;;y8r&&&2k,MFLL W_իR{J"((KH[}`֬YuT^z%nӧ|2uuu:Y Fvܩz$I`gaȑ#z=dY&11ݻw|r#&.c{;E!--zjH/1ӚE)ݹs'K.… ?"l6["_t w"""&%'5hd…,\"N>ͱcJQ̚5tA4`iiir9tP@ZZIOO 9ThiM4(?˗/7hgZ ꣏>Jnn.{oDQƍ:t{nґ&1'vZ~?`޼y=Bs}ÿnS^&mx-糟,ӧOgpBE"""zI555֦a PuMųa~3:l{gϞG` ӧ)S cnnU#!!A?xȖ56Lͯ:##/ uvʔ)<Ј3<#<VW0=Vx*vj(:ua#p@@WZ=DQ$00з,pY]5 455q-6+igY9s&Vaq:[}dZN'+]G[\\|K8|^W6Z{WX'O8oG4yfyݧܳ. puZ[[6HÐw(̚5ŋ/x6~qQ, !!!X,f.7ʕ+=wf֬Y1h42ehnn=N'YYYa6 d2ѵ)))a٘ff3fok{'Okԣyݺu=&KP~u@e(,,PfY']{{;%%%9r=ܰ?)턄dBEF#fΞ=[oEgg^ٳgk׮!qן1 pU03[>^noo:X`vҗǎӍY pMիW3uT@MuwnOJJ9=b0KeVXO>o turrrHLL$%%(L&$Ƹjiiiaڵ_^'(ܺu|8tiiiL6HF#mmmdffrm=~v}v=x<wޥF WPP@AAA0I$Ibʔ)|_c@yۖ,Y7M~RVV÷tR^^mԄ?޽TE fS͘wя~f У?z<崴[Vnݺ?˺:jkkpBh$Zhdݺ}&)EtKzSh42o<> Zt)|\tI?qYw祈;wbZٻwl !<<ݻw{nJJJ0 l6]pazڴ{kz]O3uT}uA_=miz=gY/**={c]#$([d.]Dff&ݣC7"iYpp0ɬZ+Vڧ՝|d˖-\p;wP[[GV=3g/&%%Eqf3gHKKѡfϟϖ-[>}:0/_{Lާ ΰ/_cIڗ>QYz5gڵk\|bZZZL&DDD¼y;w+ y&W\fvN111̟?GOFZ¾ IO<_W ?$ h9ZVEy"22Rnn 455\ZpBCCu%gDLJUUttt`0 >>^+j3fXeYٿѽ^&iiigX "440=쭍NinnIpp׉A~_rZ' T#11$ =,fA "88~3Qr, L6Ȍut_A}Y"O0#W 5#>O<< -v~a*O]≫p߶qG EQ0"os5pIX+8x*6+>N<< NIt44(NvN E'|@knPd,٬2$ٷ hxA@AK̢@ms'0Fa|G (<؟ؔ0 ˈ#™dm>x|PQ;9|[p(A BȂ9C*r=^͵:_^/B"(TC 9}Rz=4"y,_ p.)<๳gI e^j $O$f`/ @E}up:u" 8i-@%j[y,\>NyȻ n%=>FM-;Էt<&|zTckiOF HR{ЯJcx`4#!dzу{`E!91 `lgaEcpOd i#Վ~XW0pdkFuEHAߝ-K$1kn~ԠI-sT$ưPdYaMTbƒ0?NrWE#O|"g=Zp%s$QolUڦm8% ?`bl 'OiS,|K[~I5yE1QA40m1.Qu 6'-5waGe-&"C $,AD#}:10Y&-Ap\l X,Ȳg-od`0`GԗS(ęr.T_QOCs;6YV[ffR&fn"ɱD0A(.^},UȝVSxh`skLggUvXdq&y(jÉ"+ a^j,Oeb@G(걤=CzsAh|{~[V 6Ep+wNpZ!j ۭ.,N4Pb2s'BINe|zlfMB4~&*f9udE@AD Cϭbd$YңsDN3edJkц䰢\(Jw"KWyH8Ӧg,vABT06i{dчa@Fz[ f>2A@L>B>9dE]$т(Q`:8dE.Wsb ո[vz8`ք U)3wҶZ9`Nx~'cc R V+d`kSujKRgv4/U\.{Yq N,Z Fz.#,ECw{/Ҁtk;75rJ>~~&Ga&Kol5(. fV~Ns=PMk訽5+G {C57Fn'W_fᇏmfu𻣷)/,ޢ σ#AE^. #M9p[Cmw؝7u몓dm4?h%nk3dxd;Zʑ6K̈2]ZDѠ:]KI/GvWEb0Ne~enP EQ:i5hhT$ITBw݄S\.u8w?mO᳛3 mɬno,lM5 }fTb"aAMcnz"SI ,8ɀ%Ieu#w*}*ۭ (*# .'y$́A=(č[9X{'ucNz"gN%mjQ!`;ojܢJTRZUͮ&2gO )&ķ&>g K?qM]2;l_tI-&fNu رaӓGAAگ\rY>lX6KfOo{35\!,7?V_@dh^7YQF0b#ز:.c߉kr&Q@%Sݫ'V#f!G}aub>Er7׃,A)#ƒYx&ںKg(H#sv$这}l_C>: t2Aͼ$F R?u Q< vn\L^I/aUgeW[3EYS}#Wr+֧(=NݤS:>eIWo\3hWlY`62}Z<7,b%dH"ߢeZOUE3y¿Wx/LMgԣ0 :qR7FIdHOn\?rWPЂl뤥p;/l_30%2K#r#p?`48%9'oSZXd`V,.cӊ$Ć# VK #BjodiVh_4 @dxOV@Ӓ kDrx?Ӟ:+Na͜~'qZ.9S_ǭޜkTRB`nϱ[Kҥ2 ,vچ6$ hpp9Z"ꫫ1lL e5l[ ڽٶ?>چV~w<ʊBLd(u#3dA QʛSTV'r8r7r9.^7)]X4#)&\.ZрL\d7|MrC{ͫԴ;%S)@^q%͍M)!|j-͒iDŽc2eo;6$MIZI#&I[cjq$ȗ>.\2·żsȟh'd}3V۳q% Lj@g@ T5 ͜?ssttf3k `%h϶lEr::"ӧr*O ֐+(YSY0;/?چV KSTI~Y-U*"<"3:lúwVLj+BhH `3~> ͮfTki=! ~cHl2`2Mf@BlIql\9pɓ7eE7u,c;;\Eu\I6=(Gc^>tsg0'%zve%u0 FÂP,tJ=~~f,f#nwu sL}K2*q3pfL䭺c+fun@Cc+HJ kۅɊII`EQA=EXXzi?g.ɛ A??L~_g˖ŔqK^R.LJk8{.Q!$&DrIT4y} qo9~dNdDj˯/Iik!+xp$BybjB9!>I˳:ڸ|._VA티@,L#*"g53i:fS 4tpusJ '>>0cůq7 jSx3l\?DJJ,#pfPVv ~g&=m $Ood)9j|^h缂JNgO3sF|LViSqӤ"z({{FLd !ܾS3&d "M˿")\>p)~9)iRX$I擓Xz.TTeU4QRZ3)XCԙ̙=s1h $A;\啓6-Ii̚Thm̹,9# ;,̞5hsJYkGFg3nb t+EVϟ8]e5\;)ѓok['PG^cZj|_A^~5MuFsv8TT#xfPIDRXTEiY.WL4֖xg `iM [6/3ld G Z\})b{<{EMc6ٸa/;z\ɂIA`͢yf\ ,,+Xf.N7D)+?tMX@ [`0$%xڟ ̚˹DFn~wֶIO‘C}%N'i̹l6[^azz}V;EU̞t`aqt&6,^gTY%zjķ7 pf!ϟ4gÓbU{F>yyHSO%,,K̂iյ?yRIF}߼3Eٳc2dYo_;LEe O`xUUH}C+_xn W\ }Ϊ^]ƓU >>P-46QZZ]+y%d$6&};|m,]2;ej3 Y~nb֥LFؽkSc|[˲Lz./~} L:#hA32qV;/Gf{P-,b޼i[ g#۟E=PDDŽ'(\sYܸU)% ņv\]ȡj4oф( ͫ+fY@XhAw&"CX&R[ JWhhhep].Gtx!EaͪX\KuU mkrj dM!5%CK"0gDGqV!y = N`5j *ٺe16&2dY!cn2q,ݷfhFҲZ2ٰ~>AA}&)DGPTTEbb42R~ږIa̚֌W/%3?'=k*&\cDdY~h9Foٳ;|a6ͫɛ|+Yz. =0F (S=%6H[Q3;}uEEUT4 :}7`BX{{ͫ0%)S"SV^_|Tظa>\tt& h.uq$Yf́yILJr,[JVN r,ngs+46M#촑Sʺxԥ;e25)f@焲6m ..{e!jR2llXj??3\Q@yy7^EhH9ژ5Y) WGYNf>܀+Ku UUȕfd!_"tx^=nxtPη_C`_o7OMMEUX1oUqUOA&n*dҦ#IDT}fw*t˖%ITFGq/GKf3?`A0CZ u"|M|jZDQ;2hm'F Q4W`@L&SIH~/c>i8΋]㹈&mmttxs_7~yל4L&}f2 7/o[—}/f$ñvo!0 C[fq(5$I? /'?GpP)̝(?''g9Šes9#q\IAh 0j{֦ľx1@HHC  >v?$"(dYȱkٝ{<{A~,\^?EzoNE+~ .s]֮@oN Pj$+DF5wOs] WÀTon:VKRbwueZu6^CLtXuH[dYM ty%We0Q;g4( s3/~u S"(\o"MEfv3gY3>p#)pZ?>-=$"w*xLOO=(ybj+/MP.O"Ǐ#)1U+fw;C/LTd=EQܾv+ڕj" H:9q+"!!JWuBBصci.}Y!8؟gnvLhN\'cn R1Ů |EQر}9)LF~,my8w!{ or.!!Y=뺺Er|6IIYVDhaMMm\3n6+`0[1VqEАSȪsp؝:47 &|nnn'33 JAPî\u\Ҡt3kVƍB**DfBN~A%V֬3 _nwJRW^+-|߸a>wr(+pcx5ApsM/Ob9)+#<"a,+X6o|}/r' 7 *UBCHKGJJkz_eM/4U\;!ux-ӷ9x2g646qjsfMZ-p$jjif.h̬b^8~E XuX,&OOG1]=Կ (LKfW?V#Wzk ,VK/meтt D!T'XÔ)þlfp>&"CypI mrmzr-kdN YVذ~>KΠYi S5+X xkk/@ɛ8x >,'np|6~ W~1 <p9߿q\ k1س1 tx3TޫߊqLM~ĝܲO^I`m\RZCG/}Qfw-aA1[V^Nj_݁hMRBܝ\=\DQFZ֬3"g .ĬIlۺKdyzW֮ͥJb$( 7o{tIױQNp$rrjq#VHG{g8z0 X~_Wc4Oe3XȉOnPUx_}E!""'v؉'y# pmBlDEo2 hImpDEz.^{yȲ9)XFT[ mX?{ V@/J **꼶g0D֮ 7P]ȣ,3pB/H'!! MV(sNVETd5i̙=}eYfƌDN UKW8]ޣ7. puJJ$(b0Do`]}Q _jjII\;)2<,S^^Ǎlټ DA}s7DFo&jzɩ[TGNEP/J;]Ə»ЄΧfQINQf:YVpI2mvjZy=.jtpp8%\$)nnu & Ʉ$0D&#f?? ? ?وdd4t A(|rz>?Ϛs Zh7 UiKEdݘ%aw;\XNlvvG?IjmvdYT^&,F$ińWIZz""`0t(޹7 8|*{v"66<鼎5HL&Jm^m35-5RTR(8N~ N'.$Ȳ^]39AEFQ f',$`b#CI '1.IÛ8{00 Qhlju6RSPUFiUUT4qhiӊP}EAMFL&#.d"(Џ7O 2,PĄNJ|$SIK›8k?mypb;vd߉|_ߠ{MttXN宐> o"Df3a!$'DmBMܬ(\y4I.?{5{]`g^Bb ,f‚~2+u W3#=ً:ʫ, U-쿒|dChY] eFJmU-u,JsVBLpM] oR\6G u$ z/O+٨Z2Y2-M HO^E`QXn>XD@l".k'ÎrRק>oQAD># HtGzdPKfQ&~.[Gw?IcOhPh`C ?1+Rw M\l6,].dB\(wdm/ŏ3ke$]{bhd2!(h4Q]dvI2Ӧ`'Y맸Pbc"hD!ڭd>R;<$ B'ɄhBO~24;= 5x eذ@d$RTՄht t;G+;@BT$o1o1g&Lp@?,u.(Zؼ(EWxmshP `T6'0->/ǸOA;?ff-GoqjA`fDQ@ FlV9%Un$qt;|}4ݖ=glhb(BQs[28YFЯdVϟ/bQufAk VN~*6͚>@<%*D=]ʧGšIg)fGh4#!=``O[ر)뵟$YaDeXO^E`bŽgWhF,w;xح2io72%2 [:5 {?DԸ>n#79\l$Fxm?yAMs 7ooGgbZ|CQp67 z]1-M[CJl;4u <~6~fsִ [?M%D7EQxTTjGN/?i^O^G`IݫgT"ʐeE!.ʹ,5\(2Z4lÎ鄇5oz« A?g&Gw_rb'nS\ݬ2Ps I=]7?Ypr>?|w `xvκS @$IPZ~=5z>i..sz UMXOal\_s$_/BXΕY??谉O-/)1Ms 9,N;.|g(Z=ڭKjxT6˘§7f՜D'F`1!O1O]/9Q|inTs>ՔմK? mg03)N;e|p:sEg:VI`Fb$~&}uD!"1l_֥hS^J&JF}K'VDڔk) -TS]yI|yĄGVT-x#E!BAewЛ;CxlY[LNEW?W7SNcvv1a|c2[ɫ^}+f9ĄG?MT@n6IHyA1̟HKqJ2`1 AdIz,]zTܜK:[f8w)6WEۋE#[Ht4B[{' ?ɀKY͒$~ ~ |#GUU ٛ =;Q:NЌ& 3&.k4L/GzZ< :3Ƿij!~z'uO~F͘dY%׾;N/hEjݻׯC ,"W^Ol  A;\ml.!q-[=FNѿMPEI_olCmSc0࣏>yf} `TgHMM=z4;K.QVVFDD=,;>N|tPF sdӷJ(k%1*)ᘌF㭭eY}6 ~!V {{aL=kp\pUZZZ'88GCE ~~!ެD2Sټ8X_KK9s-$E8nWNH`- ooPPPo 8|/̐ HbRFdʝ;wu o][;{.79*k6XTs$Ù7(-r]Ne3qĺy&k3 477s!^ynܸ,qdr۫n_N|2Fٳ b6"NP٬ZǴPPoB>(>(111n6/h:x㛼s*6 ^U3:5c=RpjLFFmYv'{Ohjj q%c#WCd,..k+i@@j--:::&33H||<e\X~w6i鰫7? t$Kbʙf$EQ\DNICJ)+ U\{32fa}ѣGy嗹|j<: +:*$/LKKP_:A%nqqدcy HLyڹXee%W\Xt˪FN౸?]P\ˣdD0 Ϭc; `5cDdh~|rX]Jw-I(g9Ac/jWcUX ??_wy `+$.[4A?vWL}}P5 j~T}m8v|գk`"(̚5'x˗< <Ϗ~ &NdɅ`0`0,f hhђvuGJT5'"+(3I Zdp9 F AAħN)OS5DQsαw^:H.0 {D |,1в4kK,aϞ=̜90)l04t|f5ͭӅdc%H>:K}s@0M&#.f3?L~&$_ڄisAeffw^n߾=TG&-@vq0l<7"Q l,-K#rXX7nd$$$+kHA!Ս}<~. V}1.I?|s1.%2"bߴ۳Tdj'[R‚ّ={5*KII ܹs(iT𐉫a>fQ1gNe\ڞfq]nܸ,0!:6 63?:O[g' ȝvQDFٵj~f#w+SdTF#bG.VC*pQ@gi9pJVj[8z.K񳘙:% y>{̀yWu.k(5@. @H/x,_E%9k,Ò%KX,d0(7x\*BvIzAkK A0,Wt^*9 EprP$EDt`$d{dM+ⳏ~- 1#?vvvrOaaP+]Y#=6iA[Vb vMzzNܶN+g9w=á6> `DdI۫ =WA~l[BC!>>hby}{, gl^&\[vڐ޽{y&v}(3n.R&]j QynD6QǛD\jȑl޼m۶5;qvg? XKz^|_UC>!DD-ӛ7s* ttͬвj1a߉m^[+wHNfNzF*}]~s]dY,qe,}?PJ"1#b.C-feed"..nLd o?ǿj/m( 8` 1.\s /3*ms'0QC9pF z-G-2bEEEő&( yp/. YFrBCF]c+j7efO<q䆘>]/3ha\֖&7oP7-`ڛYKu {1y"""FX@::cH)e ⳏU mV\޹;ykjj8rǎe~rjj/C ؉zv5zA>4Ivv6~~~a6 F;2BYbT6/Cp8]?[l.eԮUCqGJ'x9؆]m&&"W$n*2Ll :ۢ;gϚu9bk{G 0dV$%Yd@~E{vZ@@ ##?{AqW^^[oo# uPL j{0#@8 -'ЂM:;wn:BBBu~=N]?×nVO!EQ]VD0ԏɠuvImϯXv[)+%;q3{45n!,ZΓOee$&D Z>655q >cAU x>ApATEy nei{`ܹsm]p8[#9~&wijPZ.FQ%7QW@شz%$Dkk' T4RV^KqI5UR]D{KH.@$ 4SXv[]’E鄅lسՠ (.N4jFdXmq϶P ]yd)N$QB*kU𬋚pl66:v6'\XF`֌$.e35+Ȑ#y`6NT/zey Fd`Ac klEsK;u#?¢*먭m;vKIW2},BC %!!Ԕ8'6IDF* eɨ?F='IC`oY<Lyڬ?ի 2:%aik魯6hjj6+V;vSB%Qd4b6 OHH aAGLXX![0 ]IїCJӧOsA"%N8Y <<y?l6`CFFFqݝN#A (jw#ҝv7nw^rrr<|6 &q5LJkp#Xvځ|@Ј̺uعs'{3ܗʊPPPx"CY.QRrgT=nDv3l,###&P);|0Ǐl~W邃Ɏ=eu%l-=bzz:wfŊzʼnHdw⶷sY8@iiPFx 5#5D?bg͚`Waoz6?$@3GTgL=ݣgFdi {A#rhh(7ndǎ$$$޽?l~NPJwQCP;-LYڬٸq#aaa^v_.s19BMMP P.w1Dz: x8вdzgf,Y??qOdl~/^d߾}Ñͯ-j2)nDJ =-._ݻw3}qm3_NN{ƍC׎uF!D!^7"[PE':bDDDlĞ:ĩSOBM܄> >j0>h8d~w`F >D*[@8f2?-[K̯P##0C -s7jaeo߾}\re8d~P/1Id~Ռ3٢}ܳ}G%󻈺=[^!><ѨJoSHEQSNq!ˁ! j}~< LT?{۷*.;rx![\?(=e~۷od~QgGs':|E9n2([ܶm7o~lad~:|ex,Q#ei@l!;wd2W >9n-$ڡ?Fq'WxW0"0ޣ[W]wGq"T B8HZ}2q 1SOd~^9[d~^)[@ ;|2?^^dZŁl~?'ZEmQ.s2ɲM4E⩯l/&|%⟠9ZLl~ >O x7{l>ڦKtEXtSoftwareAdobe ImageReadyqe<IENDB`scales/man/figures/lifecycle-archived.svg0000644000176200001440000000243014672302077020215 0ustar liggesusers lifecycle: archived lifecycle archived scales/man/figures/lifecycle-defunct.svg0000644000176200001440000000242414672302077020063 0ustar liggesusers lifecycle: defunct lifecycle defunct scales/man/figures/lifecycle-soft-deprecated.svg0000644000176200001440000000246614672302077021512 0ustar liggesusers lifecycle: soft-deprecated lifecycle soft-deprecated scales/man/figures/README-palettes-1.png0000644000176200001440000007015715002111056017364 0ustar liggesusersPNG  IHDR l+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*i L@IDATx|TgKIH%H Y~b+@X@{w!@oܭwn[s=忛{Ι32 `L 0&Ujƕ1&`+`"0&( :W`L0`L VdL 0& L 0& +BU2&`&`@p!@*`L `L 0B sL 0&Xw 0&@!`\йJ&`;`L.\%`L 0V`L 0&PXt 0&.ŋnv&p@ll,iƭdb%L:F={T. 0&@ ըJŸ=g*w 0 pn6|>m+jՐc"!Q@S O@0M-@|I23urkvp~o&|M= b8q.6+`?L 6Z VU[4<;DtU&/ >uEIBjrm FXY`$P\,{H3s*h4*hٰ,h5lץ V 墙`KxltnU~}OAMbL 0'#.dඎ'C5K[*):ԩV"CNk᫐CXlFuʀZpk` _t^EØ-!2"T?e F8lS/VD'7Cl)ҿ$+H}\ \ h 7~Gy_}՘v'N }ra*(R~YrX6p3NomǞ-g!GzKu^mȶ_*.>E>7R$DzX\ j'7RO0ƎkE?8hܸ1TZU+W'Ev*'+8H?RIؔiҪ19-#.|=• }}<|?R߿_t᭷ނ֭[ôi`ĉPxqӧݻל@|/Ô[I(Q~ѥaTe{)C@~V-\AmO:7oW!C/ ۶mի×_~iuDOjᅧ)ֻ] ɘ&,4w ?C)X] bPڡU!CZrlz~`4><=ڭw } ˣF8|p2e]:'p C'nZ%W-3n!?v5T&VE"ֶ l= 9|KG˜[ZABWݬtjG hpff&7z .]CYv8hdAۏ%נw[]h0v&v$;8>&u|uܬ!S*\[v-DGGCӦMz_ {,/^#GٳgÀ/ Wn32t+fL (0M+TѯN`A@=(F[ N^/˗qʖ-h:t <h (A VL[]F)x]e^CT4z#Fz#x4 &IH]o{P[/#'4-'YYYD9z /[o:;=d~H|ХK?\RRR]vlR^(ۦJ>eL 0! 1zhR/(QΞ=$<-I @ iG@ A+`߸q\\KL 9[ny W4W<S[w0& AiMW\_ XE';_MˁKY 0" x̘1$Lxp} PRH9;}#o) IZ3&{R :tա,EN "̱I1;/n?tA֎;ƍ" 9Gu/Q0[ٱ2:ٗߊvn6_v~ZtN_e[ 3&VgU^=i$oA UV@ <997>re+Bb O( O;{!ϦnǮS7`^{>qn` &"w~O?s IXN1MM[X57UJUϋ*[ ѻu?gbL7 6{Kxx8~[v#+gaNUrpm8t" P4* F>ȭv-_w6@-n\L] ElgB䛷P,?=uiRy7˭yAUFOUǟ~)Z-wϡiE/sv+#sn }-! i۬a([(rs=f> zG=b85_LdNK,L X@h6ؼD+0Z4LRP4I^B1HSmd2YwkdI&A@  Âh׸7[@8hZ/A .T|$<~G@ s\ xM{'^vMCvХKi3&p>nÈvX0}Ph}V5ɒR d[Ћ /)êUEЬY3v/^.(8Zu/) wVhM gJ+ 866V( 1c fAZic\F|I ?Sx$KgVSw܁ɓ'[*[.[}vi(**rz PH͛>a&"oU+/*4<LN`.#(?C+`EG.IժUFî]lhw裏ފm*-ը 0Yx/?PnSM<tϟjܷo(8T˔)#ᅅmǒ30/8(]{ &5ƨڣiWHY@&nðw@ےqpJkïիÅ b֭,^5NdL_s^ʗsLZuWp%$dzhIf;o\q&$쇣89Xf(1;; 14#jHIIrQBt>aLpp7 c5k>hԺ^n칄Up/*p8y.V}qRPT?ði& ␐ K?lRJ`& =kr_!_w=E0Y5/\PJVSLR؅)B㞵84nkPED*uֳUC!.zQ[T9]"D6~R@Kq% ` ~1E|&H> lX8B-J$*B'7C6AuG=T\WQu蛙 l%FX+$Xں+pI/3)ƍSxC45M:4hB;ĉ~N@?} KOt?!~*f!l9 陨%2{xcDKsAknkVʗ]#D#}I YAo:.]8z)> ?t0 d*_ѿwV?+:.F)!7oeP-L͔&1`(Ν;'7nܹsO>KW_}/^ä-$&T֑8 Hbh*;QE !=Ym"R+AZ3")TX~lcذao)mBa֭b˒?]uKB=:T ^Ԭ}E ?;-:΄&+2LMh׬lq%5dS+܃jRCIo mLJT+ \)4D 9:#X-| *eAѮkL xE)RDL3ǫZ-)O:7ڼ?Fʱ0&9refRRIa'0}pB5'!"\ k*,B>{׋hu,XӮ? 8|:gfr߼4G71d1hk`=7ԁgnBl(W&-%z' ߪ% ^b1 P^ϗ (@tw^5jTX(XÊ+?|PQ&LcZC\\/ʕ+Rkn펽ֻ }%kvMΊ*_ߚXw k6V@gɰﻫ*7m.9hZ/-KE܀mr^ӧaȑK6&K~ER:nZcQN:uj:u>}`nE62%`9gY;-!Z mR6C߽o5>[cbu㎠.U^N]%.>Q߆vo;u6=ܠV0eAe,HN|8g#&O@`&l䒮F#EP* !#1 Ç lt>-]$S luqKNUpQUoބ;t<[-3n\gMF.R0*1vW7t{{b\ZL$0Ruxx4Ye>9|1m6AdD| d^S裏>_2v"/=RO4MLMN@M&O[Xamsڣ/Qs'N Kx~PFJ%Ӡ6vsJ?6FcتWݧQѨp)\ |SO=%":kʕhX"&&Fz1׮] 4-N_䅋z/qѾ?fϞ ~m™Su++BFr.idiʔ*1`{X_%æ{LT AkdgNiK$!dMCGɜ 0e {&w15Z& RdUx>, UqDA:|K&L `E+ iIM_EH?qܾuAN9\`$ɗp.:IցUOfAҋ=ChVFN sµ\zeXs(AX'SrlA[~PKWBB+_\)qdoL{*ܲwhxBU|?VRTѷKCA-Z7R2`@{&䎒 0{^SK/{&oXK*dE{}Ih꜔Km#jw<%JpXV"tt'pD"2TK&=Y';ۏ$8v?{10&נf ѪTY& Wogy~ɻ#SfS@˗/]tp!wӱc>L " GvBU 측8 X w=mw !!hK8AH 0&`Ok 5OMѣGC*U R<}|v,ٛ8OU"*-*p@(81XT3(tIuP>n# 4uRm{ ?y*)ÚUg]sbi}7 jaFXeòvYD {,V,L 6Wlgϊ2e%-_ׯ(7n4C%7vZZux_=x|1K+avGR=;\J2KLYd4I%Ir֬\Fj ind|נmRȿnL'?E'UmrZ/* 067DqО[Lk)`dۡgϞ@$/+BRD5j 4gmzi7w-{.AfQvKO-לhX4=>O{/rܩdZWFd DmvVw챜`y??~<?fΜ)iIB !EFڲeHF˗/ް1GҥE[^}UuAV8C?_lxL) BSW'(^[jk@E֛XڱP_J ۋP㊶9*lUt |vՒvtFH,5V$B!{i7ҡr\[@Si9nLLWP+\iii@#][5`rA Ch{Ν" 6(>`sO> }$@Co^AK8BC!uA97i0y?p: #%VKt}GU`ߑk띘|WF4 .իW_f {K#ׂ + }:4$6OISiLћX' "Pm|NjسB;!-/z ~ZR>VJƣ8*[O&sFW7[<G|I~XxnX\-'«ћUnҫ96 Q ^ TEp)yWUaCʹ .{CSr}IʗG\7E&2)frLAAi4,F'?Lu5oUf`̘1bdN۵k>3g_i&+*2ݸ@q Z*}AӠ4#Ǻ{2:=R}!^Z=v1&,_Ʋؕ8ږG$ʀLzP~JIѨ0W~%D<]98(/Ԙ9-[a(ʗ2j8)zi| xW0>]R>_UXS7Fׯ2 {駭FfKAhTL}*r6GnhiH{<1dѡdz BU\PYL6RJnΞ]/ tuJ2xhtQ7է E"pQ⃰뇋ȈPR `RlXwt ӛ>JFJ$-)OkE?4k*7ڔoޘ+4ʗӎ˴7^kYWS DhhO~oib1wrӓK5s&^W}"ç N깼G5yN5% 5c4#ݪ竺YOJcSЬ^dYo\wL*<Ғ.:q*)4daNkSоgCFTa6F4ۯaɧNP G"st֠͒4N )g*a&XçTmTk,ͼg.Zc'Φ37q]Y֬$9peMVp-`Nm ޘon]YVY#Bm(W`L'Ӛmȿàրf.S1/Ϗ(Pi[׉=Jue(`nfQ]啅hmHveE !1EG(5SECCh(뿪 eoX34|GGɇk+lGZ*tNh 0'ܱ:T|@i!OY; ViCZ'ΰ{.> PB#8˿F{/E+Kb+z͍7`Ქ(=' @DH;K?R!E|B4ɳJEhϴ_ՙOC jPCf:Z;SW2hЀo]>6K)|i|78((zڵkCLw|%WJðԦ2RPWV9 /rqjVn#A& ]S4qJ.$::ڭ>ܹSqŚX:D> 9& NAz2^M Zdܧn?xqJX!igc\tPz*3_ 1<~*5+xoӭ*_ СB0a^xIt9n^L 𣢯B>V ^茣\%iʄ!6L!wբVc !hncQj@䫹C)dK, {#{ __dM?>'-Ke(eyIP\ NU޽+ݻCʕ@5J`6m%i WmTߛv%^u"gػL+I Y=PTzń~ N pjj*knP,+tvy8v" /H',^nyE1lߙ?PL+Wm U )ĸP8yG*T9G4%jx0&`O@1l_ dEܠFG'u]q_2=JnqRwouVn<&O;g,o؃Uj́tw9UQeFLS5iȎ\/]9Y=T%gۚ_ BNleCH^ گˍx"pqȘ퇥}eVܶ#`}lc1OWΡƴ/CKArMUQb. ;z pDXZ}Htc^y2qT!2k6 z v)UuB%%~so|Q!ŷ>YA4f̘aaao~Q<ڵ֭)˷kqB3ktk>tz5g}*͕/x~vТOWŕjХѬ|D}}kns{͇a^Q4]n^bi[l  ß,'O}ۉ5TVJpcYQ{lvIml9&}Tt[͢ _~:>s΢:uM1m?*U,[L`!pf:p VjN5u'sZ@3:XatjJG-Z=$Çه$gZ  ~R\vqRMi{_198 smƵmcvP&AVuPmS].< fR.N#5` gΜ%KB/tӧ-|CTa^$K붟7k QOr5UqtI e*JM_Sbu"Ra :,IkA=!Ԥf{uD3QYЄbɽ@~7.3oz#̒7Ã7-@F^|ewD)p+;ˮ(i9H6_Q) Y|M fܶMs7 ;gpf._ 9=F g{}| ڧ^bK<]K` `,9 w}+ažebj8xm04_|E0)hږD5kV謀˗箲e6 }:}r/>l;Qag3 (D/~$)} !V6 AOVG]Q'j@PWm`U[3G֍A*%eJC9a&4MVם1(NW8T\n^}xc]NA;{''Fj~ڝ|{M?|M]6GRx-qo=^ܵ4nKѸVRo."k 5= )IJ*.xlܸQ>lF?ʠOݳ*U~M{Qjϱ|5 `kp]^UaţS%Ց2R)# T+ 4~N޾C9|IUF R+K<~LJBZ D?sbzQJ' lP柴- #^^6Wn@4 VQ}7+@mB)h&˓]'?!/z }E QC לU|G{% VU庠ŀ5)PD&`Oe+d4P *4vd?]ֆYΝ\DEꦹnu&ڗwOv-}7/@(dAG!AXD_hI~@>iW_'3ODSK7.*<TnlDeh:½ܽC*i}Sa`mWa3^e% HFooժ{t/Tl-Q 7pLh +"ɕhg#j(8|qt_HE'J,f&mW!Q> C{~B @NdtE ['ѯ<|Uj|loKJ$[Gs)_C F*]{Y}>stD\!:^QKu^ϼ  `#IQB{mKQq>|RWûifΜ)i/ )` @l"Ҽce Tt:F qvő(9uT\3Ou;nq2(+WigG~i ~UaQ` EU>E鱀Y_7*Srm1?1hVomu ;~*%hjW{;]B#`J. v…v\zUpa cx'OXK&IȸyF07A7 sFдdG S Z}ݮl\PHUn5%1!4۸7T-?Jx$KGKd4? SnݺI99򼹆! mߑSjOTSIuMW[Ln12RB[|uR}r b w}W4LlW Ҽ!&96 4;yg\AG+SD)/y?A>x𠰂&yMځY v^c#@[Xv\?N.g{3+ ];L{7%p 8-|mᤆI~}Nޫ89a'8++ VZm۶T@h R߾}aذaN~PaE_HHhW=@` P b&?'yl¯:'x|{`5k?r~mw1NekZmy =R3hUx9˹}:C z6aJ!P44߻h;wȟ? tLB^:߱cPЂ^x{=E;n䝋$!!Ђ0W0.E =)W \J%/UJʗdp$T|I}v]w<;mi84P ߱h&|5O1TsU"/Z v12ƍ)_>R#O',c+jt }FrzDSX@s|)eڬqco0^+^1|M13fҚ/9DOdN> H⥱_/t|]%"hKZ+37e[!?,#P=YE K5`tꔷ|͚5"s3e  J@0n^ )rS|Z jxwm:߇ncT!Qk%BRa<ƣ*.C=+և?E+ fpZkc w!+IDATV9!7)i"k uaP6ry?/)r Q^BpbD/_DqLXJڵS .(쟋~ "}wX?@;mPWkdI䁪XIywNn!nT1?lC q[;]h{N:~6|Aɽ#)_y}NxID(LTRԜ 8w*Nd qZ2%ƖyIPQLD4,;ύ09ġ#Z^zn$TfqM@)5jY/^X/_={x3 e^#v\ ETW6* /N@ӡ+$Q[R$FCFj-(Oِd5}.9ř^v]dөN{eB^{ &M$ :v+VL5e4m?z衇`ƌVF~3>xS)6ab0^B$6kX1<4AK=k/egm" X~n; q 6#ln]IbS'+T&`h,\["xnl^Ү{ "ZlUiCQqJrʭUPkȑ@/[-J (K|~ɏ89٠n >$w%p=ΰt:GP91D+5Ltpx։{<+b {l./fY-:Q8Ubxb8x"N 賨Ժ+ `Փl]1P=u%4P$NJVFB_*֏Z'E6l}a۴On/<-;~QOe>Sv-;;1-OyŔ!5:~F@qG;8鴮-'F囻Nʗĸc%D_?p|P 50Ú@kJ CD~]ZK=Kv])IB!?-kǧĨ\LGO`|)*\l#٪˱õ^\ra*E ULA|)_\#jlIEKmR$pABh] Uo,jBn/8ƉO@)hSPE,Zn={֭JLɗlܺhϔ|ɭn*uufr:'pzm^o(e<=FC4Җ 9\[8j=8JMq68Q/ieÀdsX+Scڿ'j߾=TXѭJaNu^ JN+h`[Q%>` H)icK\[t.벧tnB,i@f;v6z+Y<:08٪سyv9cX{ +Tu۾Hԭz:)oO-ptUD$hy;73zv91ᴞng3xE\7Mʣ0vZxeE L}Ji?j˭8_Y^S2-JWJB#X!5Bq͗|#Irl)Veb@|0 ?] wLi(:VU xnR:"_giXY>ť'X n\U|+Zg]&p}P$4ZUn(\Ļnk7Th :l 8}O9 Z_9o IuzؕP0,^*#΀Ut0^ Iu*ǔu4aKBVqb|qoX{JqۣReǴKV[֌Lػ\L7fSxL^>.Riۭ$-5hXХ&c5߷aW^y={<ÁC Z$#v߽%rGu˝W/ʯ/[_iVr8dr+)pi%L@J4YbmcI6uzuh`~}6vRv81d dC:h?qU>b v͇z Ս;K>.$DMʃFcwy]~'ahA]wFRp],p.9J0|jw5߷:!eN{Dk$;M.@xzuʰ# (Z+HqM|~צSEqVt15gqT\A ,&P BQŌ><^*Xwۂ{GR \:N+Kʹ}YzfED5Z Ck7'yրDKr& < \AFMŵ;@:/%v$(1& ? (DEqXזuq_drp{b _BZIiĂI$%岙J. WtsfÞER\H넪ЪtU\/zG7#l n U3w+o툆"(uISz. 7^ Ȁ#G@ѢE!)) -kCI!y?v/[i6ku}[FcBʻ=# :~F;hkn^8T\O0Ǝk?8hܸ1TZU+W'L t.WKDʯnT[ʗqzC<HI;IVJR沕 #Í7,tDMu}0L"X @PLtW޽ҥKvvn&*)_x/9ǻ֊0FVJJgR-濱JUwlVT>&NX)Q7Rڵk!::6m hkسg/^#GٳgÀ^1'tYVJ4kZN;ru67;2,EjgĽl<ҕ4zmga! IN<Zh٠jԩSҥK5:thA=:h_6\rh){M"ջq4RnuJL}Hμ /%fh-J cz#FzvAݻB!GD($0(=jQu:C)؁ᄔt˄2Eb!B(iZDD4{8,I1 t[pFٗq9:$0"Kv*x[zZ|yҥ ̟?ߒ͛7{YV2edS2B+'XKq\x$*|y3DY +9ʶ@ li˅O fG*Uo_~W8I>w =NKƆ&1`L v7n/j9rKZk$iUZf! $Jݛ0V3pG 24%.NRv,\#hktTc %xsLXPNOO(W>$MV>uBoRc(.SO M۱}}/4h* _sdO`XP$$̍;83eu.:2PZ՛ ‘ TJblx%!|n K>Du\&{A9ٳ?cǎ_|EqA2a^Nd @vϭmP1*aOHys&R_~+N/4\nN-X8|ׁIjMG6Wq* UrBdUNZۄ$}us9Lr zΜ9G E;h طo8p@(=66rNY@ahX?҄vZasg JT+z6#$mA#ģpaL PXVØ1ck׮SO%K`֬YPB@\FQ 8ߣb=1n䝥2]I]XCz191 )|Ɨי 5ݻwCZnݺ0sLZ0%@^UԉB\22WF^"3r,EQH4iC[)vRZ'3oH)EL_s}ٸ&NQ< &Ku`T~}%>f~I*-%Od"yv'um嗝F3?$#`gVdI;w4glpUbKmL O$hVi 0|)|L 0&%@vv6\z5bOGK(%۷%Ћ%)SW^y y2g| h4e5xݦMxg/Uk9 WXQe'(~(N. 0&{Xljs1&(VɅ1&p+`8q.&`% أ80&``'`LX{'`L=Ĺ`L x;(NF^ح=kA#"/qJNNA\\\Sp7n.t%}_HX{)`L@OA3L 0& rOAVCɗyz6+`ϱHIs΅ڵkCXX+V {1x˲qoUTyy{Ç{PhQ(R4nVZPF ^k.:&N͛7۵k۶mž={੧߱$xe +VCtt4ԪUKpof]1w(=eݺuVaݛ9s&o^5m֬Y#{gpMk>^xbx'|k.x(3y뭷@e9s:u򤚒]t\3eXd $$$.Ǚ8p= ={"%(B<{=<J(!ŰaC*M͛7~_RMuȐ!nN1b 0n M4 4,Hnݺ*Ud՚yќ T'`'X… I&,_ܒӦMپ}w1a4Ӌ/hI=m/9* 4H|`I=xwL8`̴\7n)>>ޔeITxd0,!Sz,:wl‡G.^0̀sq&Ʉ3&S3u&TVi|?<hj￷ʃ YS[GBCY.ӴYժUaٲe4>hРL4IoĴ*Mڵkb>uN#:OFr5;-s?~p$ C5ݻobFGwĜ/64;+3B/?ck)@Q+!%3Zs&qZp|gӵkG}M0aj .] ~)gNu3"iF4KЫW/8pӾiG.]Grz]xWr0tPNz Ѓ_|JV  "2jذKF#mkiWW[,iԩS⇒^/U-ZYȈ h4+XM:*ß8 fϞ-eh4G đЌ }oBzu ) V&k_CʦMO}eox ?/f m~vbD:/=a/ [ƍGPN10gRLb{FiN c௿'G?hLcwE'AÁ"+VzRM3L3V,|}ghznݺE#66-[J/5}޻w]~K n͎ыfHhͤH[ w|NY F Mh hF2111.?2]?.A i] h:ȇb}c  !2 .H-ǤTl'箦-Ν;Cąv 10OCKC팁S;?> X#1+`wĜIiCxg nA2 K'C@?6ld=wКUwMǓ5&~:; GSRҤi߅Ҟ_ ,!I1}g( n_rjg[3-wt`BKMzD\ۓ ׌M'8=jV"Մ&63= >Șpބ8&=lb*U TX\ߙ/„\L ľW^g NÚńZ&tbigc > -Gk.É_NpL+u pe@ ^?h%hu|2G&tE(F)rZn q %$'9Q 3OrAJ8PL8l7#Qp;PhC8,ZȄJF4 ̷;}cǎ\ą=wLr,7r6[ݙ._o:.OMC<Or1cƌBrړGkU%@ 20urz _G ]'}G9gOpPሽ@z'nT@Өr~Z O`jG #&`#FXŹ`L x+``B`L +L 0&;wŋ_1GF. xyRJʕ[ny~ihӦ$%_~J{Kģ3gΈEN?kΝUVӧO[呞<ЩS'KRrr2̘1r>l0hҤ`+ A?i]5S9Dk̙2{o[-$S E|| $E|09d,PR~~=رcupR4ΣС#zͿrے@6uII۷oݻFx۶m5 D HAA<|U(C._"^~} ?^Zjh L  <~СC5zܹs' .#m{/_.:u-ZҥKל͚5KN<^4{䉫R>^z2n8yqT$ lP$&L ߗ޽{ˆ $J* Zn=c0ĉeݺuK u{o޼+WȘ1c{۾~ZիW O>%KȪUr͛73{ faW^!Cb1>gwŊrJ Kc.{jW X,̘1# ]߸qC/^Q3gjߙFY%`HG6nhԩc}h} uz ^;|YlYǏaÆfz bf}:vxP1 C;|aaaTe"2bĈC&Mΐ5rD lP$ @('k֬wʖ-[2z32!p/!;}:[~I͚5gϞuV\t)#zغ@xah!u B\{wwH p~΁2 HBD,n(TaӅ}_}UVMfϞ-v9~kE*]v6{Ѿ֮])vJu(HË1*yfienNn67m<3:^$$$ !`d߾} 1t޽[ EEEFQ."&[Z^̙}@ .\(Ϟ=Khӯ_?=1DڵkojاƞuJΝ51#9 _~5W`GL"~66ji$T2 A BUoD"S>}.B $)!f! ' tӦM?=bahr|E]yx(揅Vł b"aj}؍wHl'$̘s PyxK** h%"kd n&xveH2󿓛{c!B#(p^$Ѷm4DCUR%^P+#I!tR~ ΃HH"_s˒8sv4G ? @Ac G!h$@$@$8eA$@$@ E  A2   " @Ac GaHHB1HHH#@H$@$@!PCP$@$@${@X$  (!(s   P= , @9 x(IHH  pHH<`$@$@$8eA$@$@^f2IENDB`scales/man/figures/README-transforms-1.png0000644000176200001440000006154315002111057017741 0ustar liggesusersPNG  IHDR l+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*i L@IDATx|Uׇ-鍄;UDPETD!UQA_+X("MAA@{LdwI6Nr.egr3=s9*`L T+j+cL 0&$A`L 0&}dL 0& &`> йJ&``L 0&WU"Vh,ohV],t: Yv!T*ȫ$$+Tߙl6d2y'RN׶̵^˥'@CDlwQ%BBBYI+I^.)\< Ja|ż+pCHv'aL 0& 7Vr`L A8 `L 0 (`L ݀I`L MD<&`nې`I`5tf TL&N 4XY*Chϟ& Z Z\`!кq,o;@WvjZaV&PI+ 3&_‚q}v%K Cn@$L 0&& Xn\`L 07v'aL 0& 7Vr`L A8 `L 0 (`~E૯O?W20@L 0& 'R7nHYb, F. 0&@!L 0&ϰct wy'z%IB,X 3A#@պtΝOpE'@ӦMTѪU+,Yw}7FO#)A`^%aÆoFzgΜ0aym{[o%Z1`deeaԨQBҥ N>-=~8{=}:ƍ')se˖xl2)˗a!'(`z6K Uh΀+gDDh!%%E{hi+e(E(mY ,bEu=xVRR+iRnnGv<*)3&&&Jsw}E2o`&M*JZ. 09\gbO{kAxeg x.CAH0ԩvkhsye] yx 00XLode̗Jh7n\:ժix|9Z?L:iΫ(MUؗLL}'r&|A BՎ=]+;lMh6\XX_~YLbϜL~;fjZv92mAfz)^8[Ug&04xq|wM%{wߍ<}Y)uӾRL.rPj&>,"## Y$!+W6=XtmΜ9nݺI'MÇKƳ+znfJ!pp)=x8oO¥yX>k5Zun~7wF12~OGT׬"3@(`Z]G@{ls׮]-d2I{R"~#ەCv>mٳRtNeҾ09- ڶzP2llK/HV9ݴ.d窨fu| uϤ@U W>c9e-/8tΟ?/pɜ rׯ֭['e۶mdلҪUA(;ƽc>‰c[Zu8HSs<9f? )_J\q ߞZOv=Z*&D7C*kko7PiΗ c g`Bi´iӊ2M*y#ܜBћ(:Kۣѭg knQF88,5+]q|dg^P&a&@}ŕ_el|F &6oϻO?0D VXF}ıbW}~ـC%;R.ʭ#8.)_Ldr^eH%Ыokd}VE= 拵f؊v֠reɃMhZfp2  9ᰁ<$[0 [Gs.N(/DnftN`pb}6cMwqqq-ez‘L6'XJxCOO޶' 00#cmF6 NcX3]?|\sl[ {+Vu]~ӢO,Er!Lv olĹVAN'jzvAU| `%"5hRNAl`PM`1WPfG\-!p| /+OjSEl<?w}?d= <)A ۵a(26qzH_Z|x#^}%p8FA+6A6jZkGI٫%F(1NÁ 0Y TvTfHr^tP/4 MBDkX{xh=rfR@6ݍZkbM 88+7B^pQWDrL4uIȕY.K4N,ɋ12xީ=GkBVxc9/VE3j!p㽃As&aNe&%eٮLEy= Pti~^zzMǸ=B|9f4?z ,^B tO}\0*$<1 `פoo4iΝ֭Esc\>%~^+ Eۛ~Y,pcp"4?]X7 (7Ʒ'B_`@pX/l$|k׮`{&{|=~gAHw tM$g:4O@9CAťܽ{wlذmڴV# JjCm(tT*38РF8}T!T+l+ ` |N`SR+`rL@'R1q I01*Eb/qb)XV ZxhWY98T rKsx<4& |\.욑cKʗY>+<(K[2+|j/ R;!ٖ V&3*8&,e9tɜeEDU(YLe [_BS*9T0HK  -6od8OVr km/323 # + mۋ % Pc׭kp,<i{]'RQBm:u]#W\kRx N%vCFݬfp}5רɍ74\`<>']Jxv(l~ RHsu*DPtAj>Z*}cp+`0q"&PyB޾|1>ٳ _|Uv k,$3c*L yv[_ ӏ+5-[a &wxjrE&\!h\8 xL`fzߵ7AOF:yB[VaG=9xOIF~tOH~:H'@ƗD:bq8/X΍s/թtOU5e@%/Fv2y[Sa`lgŷ #   VyŊ y8 0 t|*4k`Ii6GGLHHeva`udPy+Jp ;T|t(lxA4wP(F'c&$=`7Aq2&g}O UJ aSC-"m;4r(YcL%ɝ DIӼ-Y%CdFtB6^Z| E@7h0#0P#%8xa^xL22+C2r1ܪ FuZN ¼n; t$,Y2)_RwͪVHC0s&Pqso,7?π9އVm{Tu^^NI&A#/Qn <&sCo!Η':ilF:|/ ]u S  xᥘ4hMs"č#8a$N!ТA>QLC?h|cmF ::䢐P.5)%>&ԩu=O 0&+`E, `L Dk]61&9`E5_L$:a瞣%R!+Y䠁cq`L g~tY:W#7KoS䮜;˶`S0۱ޘ<\Xژ`[>y |I=g}>les|^? dX]C${f}rL (+`e?EK3b#h[o9vM>Ɩԃؑ~/YU;,OfN$ %zh*#&j_Z|n/  [4BKl:_c&|:z4Zr7곫T5yd ҕc4YR{\9` & X7OEx` 2Ï೦K +`rđ3S叉 E1+[$-Š [I69 0EX˥C 0HOLs䋙O CLlx9{qP N';TmGVxup9K6#ЀoO<"-Ϡ/Zaʮ]xsu `+wŤwbbШ`=Z7҆+/,B~;wO=?6JރHJ[TrV7W`Eߧ.O-f\6a8-K+/N CSh!}L 0" &D \r-tC}1`+}2~GovAl1m!*,vL xXG4b,s,\T1ڵàAJW6R k׮1i$\x={}WVVNdqlxIIT1C ),*1:xgЭJjM`xM()ύC/SNT=200n]w[9rÆ Crrؿh-܂^xYYYXj4hV "]Љ}z̛>]E>85-sm@ĵgːVG(aeda5x(&1`^ pr&Ô['ˢYf|N8W^y%._MJr,ZH._\nZD`_'VR[-a8p2^fcIwPh6`oI%V3vC1Dd@&O{K Xn)|޽*""JVr֯_3f?md0PCgx08cޚRv+r KPڕE5L xwud$,h[m#5hn^^^:>spDeu϶,L6Nbn>QB_PM›!>딃galѺa+kI9Ud,ήaVXaСxǰgI/[ }nb T=7D#ACJol>;~(zAj"!}gpL6ݡ)[)>NMEɂs֭[GBE!b͈rJ#GU{Bbш1c`ɒ%bK˩kd);**JZ&NYj!4@RRRZv9>^j @F1x}MbDQ1::wV5> ܌~qeœtfs^6##Ó&W[X7~*!(mz@\6lXњ4gb*̻ʓv --+J!qFk.l߾Gw.}LmymӺXP -ʷ*q͑CؗaJfs”sIhP*IŗG)mL kā "pYI/ߋ\׷nkZr8POjPOtekű Ӿ@<6pUU.o Ûnxb-jٲ%{=Ҭdoqq@隷Zѫq:Ah{Dd2+::;@x>W]R>ELL&[=`V뮻< Ο/ۻw4>'xd^_pAjy||4Lz)^;;4d"ܹs)^'C%uF laJ~hYrE31jGz.?_ǣEɽ-/8\WT~qP{mIWy>J 0ZM0"䀡Yf9J.,,ĸqJϜ9#}])?_0~xi~_6>=Z4|pmZr4 _KC4NsҮЖ)GAx86?ڃ<[F&8? IFu+}0ԁj>K715A: > mVX,xq B‹\6mgt. 0&P60y GC_.#M\\٥WpVQϝ;WJ`Ҫj wUF6i34 Ҧx D͹~rP=@m&54i!C.yMI¼d#2ӈM+ TܜIEտ#|NHW58/- sH Эg n}\qC_?(7ys@lzRFu奿yzv:*Ja+?ߔX?ҩS'lݺxYM@[C LuU5xѡC_*) [d暩>{dՉ+`ʦyb 4*ܝwމ+VTML_}Җ&B~衇mCdRr(zH$-`?"x¦(gB/Ӆ*Pٮ;۵]vY?f\;/Vd3O&VJgsf[1l7E齖U2.EN_~tV)zRU .])/4-슉>[4Z]n]7'[展AA(4G0YDkÚ7&8|$*9kϙ?N&(WI\ƍy+Tu؂]jZE_E6ma~ضmdCIߣo߾WYSg#4"T4޲0Q^eۄ‰Cdo˓1&"P--9u,yʥQFaʔ)2B0mڴG4/J4K'M$yh޼,+#t^8zT+"-zK"V R$ U(+;1V,Wb(RZ>7X~5̰-F|jzwf&Ӓ0y=.ݛ%S@{]{&QʖU3d}"ROϳL 27/ i#F{mF}}̟?_rDؓ4ez-hL@N Xˢ=7vÙ4X=4AN->6 j. 0߼%{%>"Eo^t=ĔJ_@nnd4m6srpK=d+_HȊ!kqR_$ F&xkr&_Ze)XÇ^+p(!p_ޮ# @"47|7|2"شi!%CR q MTT9RR\m|]@K>dMOܹsѨ-ZرcK'D=`rr]JIkSWHԜE60NϼBL 0L:Ζ&Ӵmی]3 ; B1۲u=6sy-2IʗҨ]H_o|| 0&34z(gp[Y)Us1eHOVb3` +>sToY|"spIY<~-bA7NP2!),k&Tb*]x=co)*/)W]YnAr 2籿Ģ͹LܻKw/_¸KAs`L (|({zv&iY/4aL$=;J*׫ /OCɧO^LI B͡ sLtP$;WlnQXMN`XhfL (w<zO4fbjfk4F5e?Z4|Sl 4p@2'B g4r^R8 0&eJ* ,heJLCx,)OV)mDd0 :t:5(|;;an!-SpmS}zEbP )ʚC*ӅaoR 0&T%Jm])2zF*G [pn mgcKlN!4=ajB]\G{j`HEds(^F4rNWxIVbЮY}8qA,dFEis]*ըyrJ*5n Ix<*| *oD_XG=u^v]޲*Uq&_`Wz18 c{n]=;b J(['椭☜i,Ӡj +N)`L@qX+y.0 C0aZ# I JRBĵ%L FJ1&Na)*X~-; FFU?c:PI n681&P, X'Kz4mA=<[CDe~(W.{/^B,m)Y<9x8IkHVD 0BpMJlJ#\}$nb* `L >Scٳ>J<]%l5+铗06 33_fk#Q+[.!ً]&!ݐ ME3EBmaٲe H}EU{UVs2=G,73.tZ .O'5_vp0(Gh4IUFNF.VF }6;$5 V9مع$nᚯN\m Y)(I^ B"[2:q(aS {1R%+`^/˽WdE!)Ytţ0 &> E~}=~# QЏ? 6688XzvM]mxoo^s0Y-[JvX8_yFEly?n;wWΓU%inL&vZMq KjH?EܵIMlOޖv"*I^%J-)`<ǃvGb_U1,=y$_.{1zR[8b:(_<0H1ARB%ӟm)],(`@8n|!B0uf&$$Dxx+ئ<-=1H 2 Ϛ5ɩG ШI! |c77TCE7A 2y;ЊAz'L 0//}X+N gYX700 %sL 0G 2R˵_4o?Y X)aߊA_SR\)Gz 0&Ps"s/+Ւ\l8~[NY2`K{/jR2.]@ZlVYat)bL 0&P=\=_2PZa͡7|,`LEXN۵nAh9}Df-RŞ8):< 0&P cN]zڜkqB+'_y3FkkG!U32&j8V Nž A߾ o| IF^|)<: 7`Lb_X~0 ZfA1||_ޕ`6d9TK:FnZRU =`ӪqE\۳}43& ]@(X< ~xC&;IVZ:#ZmXYue"-;!hFP!O`L5vbo[ q$<.ڢ]~"\\X|)jF~2s#w zxu *aN-lQ``\\2pJ`5`_#09~>^;RqaLN^`c2Ռ9hݾ){dX ߿5ɱ@>cL (%K渆|a.2Hzhl9ލ,SrLRkv.[U@%X;)`Qv9.:GګjM0!4́ 0& i|9(;VO>$Ξ=[Q*]g\%l՛K(vPa:&N6]%N V Kh1 $ޕ"eyL N,l}lyY9 0&5L̚tY譹ȶ\Jx \)G2rHJ '@^F&zԧu 4[V1P> Qp! @#PE -LY٥7_ _D`铗orE&Bi;h&*\/wU XV)bj6<6I|.%gઘ'PMKj5BVO CeaZ W^0L.S:7\uJBE6 dFbXˎTcBaTFY⓫OBGݧ!J&bЄɶ#޶Qq]J \`2a`V#zkOyzt>`^'&p:h"J&GZ+c`-uh:6*㝇%6bxwڭy&K<^%n׵nў?snU, .ӯ_ɢb߂z "`rh8IGAp1KgU!@Qd-8VЀǼsºEts +.1ЭM#l?x!A? 9}={cdQ74 :uǶt: Vn/vn_IDAT;<=:wkl 0&P=NA7!_XT7B^_XWy d\΂δsw9=̒a^[x#D> W]y*+gL 4C7J~},ѣG Ejj*~';v!N(O/F)R%RӐp_d9`@RRz}w`>s q9rXx8~8z)^{gwyfĉ8wt<ř@~r~nbU8W~Ɵuu٭ؖ!v-}U-a9`Lp _ ]v- DF:.ޙ3g^ut GƤI0|p\x۷oʕ+ٯK.̙3QV0Xᯁ-b݂0%1ɦr˸f$o{`{p Ez~J+/5؜6.u> &>WXp!͛'f6 .k"GHHAe͍ׯ/7O˖-iPQvkh*I?!-z1Ża,/$z $$ۧ~=˹{)zQ/4;Cr]PQ<)-}9 ,p۔}So://='ƅ& z#=)ڷjO`-5K^$"Z4!&ɷ\8f^ 7uXAgd YJڷZqA-i"''bU?J=ly U6**JĶN:bJ>+YI/m7^KARQFHNNYP|Æ Q^ ..TQ;DT/ m^JGHDr3lZIWaؒBP͡zҋz%WiЈQ&9؝z\y}28Q(!g%I[`hh4KaKޫJckX[^zצ4Qs[>y\Uθh_~Xnti۶m>}Cpym %ǹ>ߺz'ޚ4%+RM Dz8Y+2W5ęzvb4. y8B1́ 0&_ӦM+~D /^|E N2EZM&͛7Ǹqke.byCzdƱqxs Gt /ai-ΘK%FlT|Bmm"Xl{+q6e+V 0&e*1Lb7ڪP|ff&h9P Qܫs(+s::E]r1KTv}gS|Qd*"bxq2jta+YvNK#V.Map|ܳoCժ4 nr-;`O|`I(0wHhi~dd$+Ԉ"ߙ֫WOt~v%dvUsmRt˗d<2۶YZU rJ*ֲH9L7$ :oѺ02a`~ˌkv)SRb#wѳض0tέGSV{8 0&藜W [u&EL=a|i[si hK_\s:Dh ZR2u/8P횰-_cL x+`/¥w ,Zl[\\ *s2rXF8l)U$6it tl'^+ yn3 VFtdLJ{OL 0&~UN#㐘[l+!'QG{F}ymH|^QPY,) 7 Lۆ AB-6cIq4ů0W`L !{\ #HM>F}fWX0L;CKbQat,gbo#/N.O95r3x&@&@o4]|/0 m>yBPˌȤ Y+q hh:ό@O\tq_یh`LP[!:1֛x<@FyOqo'2(H+{C"E+ O R?"`^ئ#4b9C4$,Մf[wٷN$<7s3:-{uB"V063$uDI_13?Y/ &T!@WfK6pyL 0'z13jȧN͛l2޽ڵLX軮#R],W7:wkEoVRA t(Ze зuxAFiAV.-聶dL'1+V9 '+VKa,+҅KbcGvѾc;b1g{uVlA(d( յu#~cB 9 0&d!@wӦM { 9`9iSU״M#z+_JJ=ׇFr-\= a`"oўa^umLSJ1&@ {;pXn,]pc0aYC:DT7}K-o> ,Yhn#+Y:'gL 0% Ll|`r~!dgcƈqL 0ehذvSZVnjw_) 7' ?N-e'%}ؽo%勡indD& ju 0&B|hw,(_[4/dEAARzn- 3&@ % 7v}8zb9ڂ'9\<`L +`/Cy(A! G|9-Ƣ 4rF1WR|L 0&P3 }nhi/L|TVD$lal)ub0^gL 0_EX^nXT:9K W~ t Y)VL瞫,`@BHz~<ُHCE9Rd!z~p%`Lt5܍(1 =CaܛZ6Z oiBـ}'h19\&P>ZjK;Am 5qZLBZbMH;rva5LV3>š/ LTɃ#N$RdUQJc$y$+=jZ1mTC%5F5T/U" **P *IS\3TI-nVw-ʗ3U[Z ;EVC?8WR̅Vjd)R`t(Ħ$NU [jͭ-K%#V9S7//O}vkE/7٬FA# _}}-d&Grn(zsS_1)4JՙzJUAAA0 |!!!`mxxEz\[*1(ZyQQQ.:sN ;[aek[(¦NCfڟTڇ5No$`5/ªM?=[AROZ$zP#6X̃Z%ubw^cKAukd \ @pC`D~i 0&O{?S%E|PW*,z oag ׈!VXb90l:-!A:L7] kqwcWQ\,LG.c;;\&P>Vm"lK2?1+>yx>8`4 B 51O=ؗyEeσ`5AW{yztBOUe·ZvPNs>(Mpז9}E ޲K+cC9d+4 yԩ6lX:1ܖF ED./G^^v؁_7pC)& wpQӲeKԯ_/B|wxq=Tb裏"** | бcGnV[z̙˗/?C Qkb֬YqIziP|{aSL綃'NX"+̙3ꫯ}.s{Kג7|U4LˑEe+^h-bln/QFYO>-/Ç[Km)$^9j|٩ΪV?oѤIlܸ􆜟_|\=s\'4ptUJC# !!!HLL,3_"ĉ۰0,[ {=<sin= r F!8h * oOHHgN7{li9r4ҽ{wɦ_z%i+3<[~nx-ayOjW^yE+I=trwJ;Ҟ`"-mx"RRR@[9#wT)/\$mϖziO=cG<_|Ekpf;l0[֭O?~sKJLUrpM^RĪ}J*N4|i=[~nxZ\Es~/Ӣ̔+-K#+&#~nX^)ˣט`L x{ ,`L<ˣט`L x+`/b`L Gpyt`L 0/`%\,͌`I xLƼy<. `L;X{+|N? ,`e`g e+L@V6,)rSHAizGc\y啘1cdISo,%֭[Kd>zuN.&_,k[0&<'=`r LBU|zTp5*]2Oih^{YnR$}JɦdY$#@'ч g ^fV{5RVVzw]P_Z-k>{ȟ830bhrj{<>ԏGJki]VvS%ۤ KXv:6nkؖ˥]WN 級jbbbaZeica^(@~!>]@߷fivJsfQJ +8F#;%,m:Z=\)o$*7Y hT׈ρ9SoǤ q@   q@pA@88 @ @8(  GǙ^@@8  Y0́g*IENDB`scales/man/figures/lifecycle-maturing.svg0000644000176200001440000000243014672302077020256 0ustar liggesusers lifecycle: maturing lifecycle maturing scales/man/colour_manip.Rd0000644000176200001440000000303014705662053015261 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/colour-manip.R \name{colour_manip} \alias{colour_manip} \alias{col_shift} \alias{col_lighter} \alias{col_darker} \alias{col_saturate} \title{Colour manipulation} \usage{ col_shift(col, amount = 10) col_lighter(col, amount = 10) col_darker(col, amount = 10) col_saturate(col, amount = 10) } \arguments{ \item{col}{A character vector of colours or a colour palette function.} \item{amount}{A numeric vector giving the change. The interpretation depends on the function: \itemize{ \item \code{col_shift()} takes a number between -360 and 360 for shifting hues in HCL space. \item \code{col_lighter()} and \code{col_darker()} take a number between -100 and 100 for adding (or subtracting) to the lightness channel in HSL space. \item \code{col_saturate()} takes a number between -100 and 100 for adding to the saturation channel in HSL space. Negative numbers desaturate the colour. }} } \value{ A vector of colours. } \description{ These are a set of convenience functions for standard colour manipulation operations. } \details{ \code{col_shift()} considers the hue channel to be periodic, so adding 180 to a colour with hue 270 will result in a colour with hue 90. } \examples{ col_shift("red", 180) # teal col_lighter("red", 50) # light red col_darker("red", 50) # dark red col_saturate("red", -50) # brick-red } \seealso{ Other colour manipulation: \code{\link{alpha}()}, \code{\link{col2hcl}()}, \code{\link{col_mix}()}, \code{\link{muted}()} } \concept{colour manipulation} scales/man/scales-package.Rd0000644000176200001440000000174215002117537015436 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scales-package.R \docType{package} \name{scales-package} \alias{scales} \alias{scales-package} \title{scales: Scale Functions for Visualization} \description{ \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} Graphical scales map data to aesthetics, and provide methods for automatically determining breaks and labels for axes and legends. } \seealso{ Useful links: \itemize{ \item \url{https://scales.r-lib.org} \item \url{https://github.com/r-lib/scales} \item Report bugs at \url{https://github.com/r-lib/scales/issues} } } \author{ \strong{Maintainer}: Thomas Lin Pedersen \email{thomas.pedersen@posit.co} (\href{https://orcid.org/0000-0002-5147-4711}{ORCID}) Authors: \itemize{ \item Hadley Wickham \email{hadley@posit.co} \item Dana Seidel } Other contributors: \itemize{ \item Posit Software, PBC (03wc8by49) [copyright holder, funder] } } \keyword{internal} scales/man/pal_viridis.Rd0000644000176200001440000000255714672302077015114 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-viridis.R \name{pal_viridis} \alias{pal_viridis} \alias{viridis_pal} \title{Viridis palette} \usage{ pal_viridis(alpha = 1, begin = 0, end = 1, direction = 1, option = "D") viridis_pal(alpha = 1, begin = 0, end = 1, direction = 1, option = "D") } \arguments{ \item{alpha}{The alpha transparency, a number in [0,1], see argument alpha in \code{\link[grDevices]{hsv}}.} \item{begin, end}{The (corrected) hue in \verb{[0,1]} at which the color map begins and ends.} \item{direction}{Sets the order of colors in the scale. If 1, the default, colors are ordered from darkest to lightest. If -1, the order of colors is reversed.} \item{option}{A character string indicating the color map option to use. Eight options are available: \itemize{ \item \code{"magma"} (or \code{"A"}) \item \code{"inferno"} (or \code{"B"}) \item \code{"plasma"} (or \code{"C"}) \item \code{"viridis"} (or \code{"D"}) \item \code{"cividis"} (or \code{"E"}) \item \code{"rocket"} (or \code{"F"}) \item \code{"mako"} (or \code{"G"}) \item \code{"turbo"} (or \code{"H"}) }} } \description{ Viridis palette } \examples{ show_col(pal_viridis()(10)) show_col(pal_viridis(direction = -1)(6)) show_col(pal_viridis(begin = 0.2, end = 0.8)(4)) show_col(pal_viridis(option = "plasma")(6)) } \references{ \url{https://bids.github.io/colormap/} } scales/man/minor_breaks_width.Rd0000644000176200001440000000264014672302077016452 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/minor_breaks.R \name{minor_breaks_width} \alias{minor_breaks_width} \alias{minor_breaks_n} \title{Minor breaks} \usage{ minor_breaks_width(width, offset) minor_breaks_n(n) } \arguments{ \item{width}{Distance between each break. Either a number, or for date/times, a single string of the form \code{"{n} {unit}"}, e.g. "1 month", "5 days". Unit can be of one "sec", "min", "hour", "day", "week", "month", "year".} \item{offset}{Use if you don't want breaks to start at zero, or on a conventional date or time boundary such as the 1st of January or midnight. Either a number, or for date/times, a single string of the form \code{"{n} {unit}"}, as for \code{width}. \code{offset} can be a vector, which will accumulate in the order given. This is mostly useful for dates, where e.g. \code{c("3 months", "5 days")} will offset by three months and five days, which is useful for the UK tax year. Note that due to way that dates are rounded, there's no guarantee that \code{offset = c(x, y)} will give the same result as \code{offset = c(y, x)}.} \item{n}{number of breaks} } \description{ Generate minor breaks between major breaks either spaced with a fixed width, or having a fixed number. } \examples{ demo_log10(c(1, 1e6)) if (FALSE) { # Requires https://github.com/tidyverse/ggplot2/pull/3591 demo_log10(c(1, 1e6), minor_breaks = minor_breaks_n(10)) } } scales/man/pal_hue.Rd0000644000176200001440000000215214672302077014213 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-hue.R \name{pal_hue} \alias{pal_hue} \alias{hue_pal} \title{Hue palette (discrete)} \usage{ pal_hue(h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, direction = 1) hue_pal(h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, direction = 1) } \arguments{ \item{h}{range of hues to use, in [0, 360]} \item{c}{chroma (intensity of colour), maximum value varies depending on combination of hue and luminance.} \item{l}{luminance (lightness), in [0, 100]} \item{h.start}{hue to start at} \item{direction}{direction to travel around the colour wheel, 1 = clockwise, -1 = counter-clockwise} } \description{ Hue palette (discrete) } \examples{ show_col(pal_hue()(4)) show_col(pal_hue()(9)) show_col(pal_hue(l = 90)(9)) show_col(pal_hue(l = 30)(9)) show_col(pal_hue()(9)) show_col(pal_hue(direction = -1)(9)) show_col(pal_hue(h.start = 30)(9)) show_col(pal_hue(h.start = 90)(9)) show_col(pal_hue()(9)) show_col(pal_hue(h = c(0, 90))(9)) show_col(pal_hue(h = c(90, 180))(9)) show_col(pal_hue(h = c(180, 270))(9)) show_col(pal_hue(h = c(270, 360))(9)) } scales/man/pal_area.Rd0000644000176200001440000000074114672302077014344 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-area.R \name{pal_area} \alias{pal_area} \alias{area_pal} \alias{abs_area} \title{Area palettes (continuous)} \usage{ pal_area(range = c(1, 6)) area_pal(range = c(1, 6)) abs_area(max) } \arguments{ \item{range}{Numeric vector of length two, giving range of possible sizes. Should be greater than 0.} \item{max}{A number representing the maximum size.} } \description{ Area palettes (continuous) } scales/man/show_col.Rd0000644000176200001440000000152514672302077014416 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/colour-manip.R \name{show_col} \alias{show_col} \title{Show colours} \usage{ show_col(colours, labels = TRUE, borders = NULL, cex_label = 1, ncol = NULL) } \arguments{ \item{colours}{A character vector of colours} \item{labels}{Label each colour with its hex name?} \item{borders}{Border colour for each tile. Default uses \code{par("fg")}. Use \code{border = NA} to omit borders.} \item{cex_label}{Size of printed labels, as multiplier of default size.} \item{ncol}{Number of columns. If not supplied, tries to be as square as possible.} } \description{ A quick and dirty way to show colours in a plot. } \examples{ show_col(pal_hue()(9)) show_col(pal_hue()(9), borders = NA) show_col(pal_viridis()(16)) show_col(pal_viridis()(16), labels = FALSE) } \keyword{internal} scales/man/percent_format.Rd0000644000176200001440000000423314705655135015613 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-percent.R \name{percent_format} \alias{percent_format} \alias{percent} \title{Superseded interface to \code{label_percent()}} \usage{ percent_format( accuracy = NULL, scale = 100, prefix = "", suffix = "\%", big.mark = NULL, decimal.mark = NULL, trim = TRUE, ... ) percent( x, accuracy = NULL, scale = 100, prefix = "", suffix = "\%", big.mark = NULL, decimal.mark = NULL, trim = TRUE, ... ) } \arguments{ \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix}{Additional text to display before the number. The suffix is applied to absolute value before \code{style_positive} and \code{style_negative} are processed so that \code{prefix = "$"} will yield (e.g.) \verb{-$1} and \verb{($1)}.} \item{suffix}{Additional text to display after the number.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{...}{Other arguments passed on to \code{\link[base:format]{base::format()}}.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} These functions are kept for backward compatibility; you should switch to \code{\link[=label_percent]{label_percent()}} for new code. } \keyword{internal} scales/man/transform_exp.Rd0000644000176200001440000000111114672302077015457 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_exp} \alias{transform_exp} \alias{exp_trans} \title{Exponential transformation (inverse of log transformation)} \usage{ transform_exp(base = exp(1)) exp_trans(base = exp(1)) } \arguments{ \item{base}{Base of logarithm} } \description{ Exponential transformation (inverse of log transformation) } \examples{ plot(transform_exp(0.5), xlim = c(-2, 2)) plot(transform_exp(1), xlim = c(-2, 2)) plot(transform_exp(2), xlim = c(-2, 2)) plot(transform_exp(), xlim = c(-2, 2)) } scales/man/transform_probability.Rd0000644000176200001440000000170314672302077017212 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_probability} \alias{transform_probability} \alias{transform_logit} \alias{transform_probit} \alias{probability_trans} \alias{logit_trans} \alias{probit_trans} \title{Probability transformation} \usage{ transform_probability(distribution, ...) transform_logit() transform_probit() probability_trans(distribution, ...) logit_trans() probit_trans() } \arguments{ \item{distribution}{probability distribution. Should be standard R abbreviation so that "p" + distribution is a valid cumulative distribution function, "q" + distribution is a valid quantile function, and "d" + distribution is a valid probability density function.} \item{...}{other arguments passed on to distribution and quantile functions} } \description{ Probability transformation } \examples{ plot(transform_logit(), xlim = c(0, 1)) plot(transform_probit(), xlim = c(0, 1)) } scales/man/format_format.Rd0000644000176200001440000000122114672302077015432 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/labels-retired.R \name{format_format} \alias{format_format} \title{Label using \code{format()}} \usage{ format_format(...) } \arguments{ \item{...}{Arguments passed on to \code{\link[=format]{format()}}.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} This function is kept for backward compatiblity; you should either use \code{\link[=label_number]{label_number()}} or \code{\link[=label_date]{label_date()}} instead. } \keyword{internal} scales/man/rescale.Rd0000644000176200001440000000307714672302077014223 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bounds.R \name{rescale} \alias{rescale} \alias{rescale.numeric} \alias{rescale.dist} \alias{rescale.logical} \alias{rescale.POSIXt} \alias{rescale.Date} \alias{rescale.integer64} \alias{rescale.difftime} \alias{rescale.AsIs} \title{Rescale continuous vector to have specified minimum and maximum} \usage{ rescale(x, to, from, ...) \method{rescale}{numeric}(x, to = c(0, 1), from = range(x, na.rm = TRUE, finite = TRUE), ...) \method{rescale}{dist}(x, to = c(0, 1), from = range(x, na.rm = TRUE, finite = TRUE), ...) \method{rescale}{logical}(x, to = c(0, 1), from = range(x, na.rm = TRUE, finite = TRUE), ...) \method{rescale}{POSIXt}(x, to = c(0, 1), from = range(x, na.rm = TRUE, finite = TRUE), ...) \method{rescale}{Date}(x, to = c(0, 1), from = range(x, na.rm = TRUE, finite = TRUE), ...) \method{rescale}{integer64}(x, to = c(0, 1), from = range(x, na.rm = TRUE), ...) \method{rescale}{difftime}(x, to = c(0, 1), from = range(x, na.rm = TRUE, finite = TRUE), ...) \method{rescale}{AsIs}(x, to, from, ...) } \arguments{ \item{x}{continuous vector of values to manipulate.} \item{to}{output range (numeric vector of length two)} \item{from}{input range (vector of length two). If not given, is calculated from the range of \code{x}} \item{...}{other arguments passed on to methods} } \description{ Rescale continuous vector to have specified minimum and maximum } \details{ Objects of class \verb{} are returned unaltered. } \examples{ rescale(1:100) rescale(runif(50)) rescale(1) } \keyword{manip} scales/man/cbreaks.Rd0000644000176200001440000000337114672302077014214 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/breaks-retired.R \name{cbreaks} \alias{cbreaks} \title{Compute breaks for continuous scale} \usage{ cbreaks(range, breaks = extended_breaks(), labels = scientific_format()) } \arguments{ \item{range}{numeric vector of length 2 giving the range of the underlying data} \item{breaks}{either a vector of break values, or a break function that will make a vector of breaks when given the range of the data} \item{labels}{either a vector of labels (character vector or list of expression) or a format function that will make a vector of labels when called with a vector of breaks. Labels can only be specified manually if breaks are - it is extremely dangerous to supply labels if you don't know what the breaks will be.} } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} This function wraps up the components needed to go from a continuous range to a set of breaks and labels suitable for display on axes or legends. } \examples{ cbreaks(c(0, 100)) cbreaks(c(0, 100), breaks_pretty(3)) cbreaks(c(0, 100), breaks_pretty(10)) cbreaks(c(1, 100), log_breaks()) cbreaks(c(1, 1e4), log_breaks()) cbreaks(c(0, 100), labels = math_format()) cbreaks(c(0, 1), labels = percent_format()) cbreaks(c(0, 1e6), labels = comma_format()) cbreaks(c(0, 1e6), labels = dollar_format()) cbreaks(c(0, 30), labels = dollar_format()) # You can also specify them manually: cbreaks(c(0, 100), breaks = c(15, 20, 80)) cbreaks(c(0, 100), breaks = c(15, 20, 80), labels = c(1.5, 2.0, 8.0)) cbreaks(c(0, 100), breaks = c(15, 20, 80), labels = expression(alpha, beta, gamma) ) } \keyword{internal} scales/man/label_date.Rd0000644000176200001440000001373615002115042014642 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-date.R \name{label_date} \alias{label_date} \alias{label_date_short} \alias{label_time} \alias{label_timespan} \title{Label date/times} \usage{ label_date(format = "\%Y-\%m-\%d", tz = "UTC", locale = NULL) label_date_short( format = c("\%Y", "\%b", "\%d", "\%H:\%M"), sep = "\\n", leading = "0", tz = "UTC", locale = NULL ) label_time(format = "\%H:\%M:\%S", tz = "UTC", locale = NULL) label_timespan( unit = c("secs", "mins", "hours", "days", "weeks"), space = FALSE, ... ) } \arguments{ \item{format}{For \code{label_date()} and \code{label_time()} a date/time format string using standard POSIX specification. See \code{\link[=strptime]{strptime()}} for details. For \code{label_date_short()} a character vector of length 4 giving the format components to use for year, month, day, and hour respectively.} \item{tz}{a time zone name, see \code{\link[=timezones]{timezones()}}. Defaults to UTC} \item{locale}{Locale to use when for day and month names. The default uses the current locale. Setting this argument requires stringi, and you can see a complete list of supported locales with \code{\link[stringi:stri_locale_list]{stringi::stri_locale_list()}}.} \item{sep}{Separator to use when combining date formats into a single string.} \item{leading}{A string to replace leading zeroes with. Can be \code{""} to disable leading characters or \code{"\\u2007"} for figure-spaces.} \item{unit}{The unit used to interpret numeric input} \item{space}{Add a space before the time unit?} \item{...}{ Arguments passed on to \code{\link[=number]{number}} \describe{ \item{\code{accuracy}}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{\code{scale}}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{\code{prefix}}{Additional text to display before the number. The suffix is applied to absolute value before \code{style_positive} and \code{style_negative} are processed so that \code{prefix = "$"} will yield (e.g.) \verb{-$1} and \verb{($1)}.} \item{\code{suffix}}{Additional text to display after the number.} \item{\code{big.mark}}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{decimal.mark}}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_positive}}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_negative}}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{trim}}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} }} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ \code{label_date()} and \code{label_time()} label date/times using date/time format strings. \code{label_date_short()} automatically constructs a short format string sufficient to uniquely identify labels. It's inspired by matplotlib's \href{https://matplotlib.org/stable/api/dates_api.html#matplotlib.dates.ConciseDateFormatter}{\code{ConciseDateFormatter}}, but uses a slightly different approach: \code{ConciseDateFormatter} formats "firsts" (e.g. first day of month, first day of day) specially; \code{date_short()} formats changes (e.g. new month, new year) specially. \code{label_timespan()} is intended to show time passed and adds common time units suffix to the input (ns, us, ms, s, m, h, d, w). } \examples{ date_range <- function(start, days) { start <- as.POSIXct(start) c(start, start + days * 24 * 60 * 60) } two_months <- date_range("2020-05-01", 60) demo_datetime(two_months) demo_datetime(two_months, labels = label_date("\%m/\%d")) demo_datetime(two_months, labels = label_date("\%e \%b", locale = "fr")) demo_datetime(two_months, labels = label_date("\%e \%B", locale = "es")) # ggplot2 provides a short-hand: demo_datetime(two_months, date_labels = "\%m/\%d") # An alternative labelling system is label_date_short() demo_datetime(two_months, date_breaks = "7 days", labels = label_date_short()) # This is particularly effective for dense labels one_year <- date_range("2020-05-01", 365) demo_datetime(one_year, date_breaks = "month") demo_datetime(one_year, date_breaks = "month", labels = label_date_short()) } scales/man/rescale_mid.Rd0000644000176200001440000000304014672302077015042 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/bounds.R \name{rescale_mid} \alias{rescale_mid} \alias{rescale_mid.numeric} \alias{rescale_mid.logical} \alias{rescale_mid.dist} \alias{rescale_mid.POSIXt} \alias{rescale_mid.Date} \alias{rescale_mid.integer64} \alias{rescale_mid.AsIs} \title{Rescale vector to have specified minimum, midpoint, and maximum} \usage{ rescale_mid(x, to, from, mid, ...) \method{rescale_mid}{numeric}(x, to = c(0, 1), from = range(x, na.rm = TRUE), mid = 0, ...) \method{rescale_mid}{logical}(x, to = c(0, 1), from = range(x, na.rm = TRUE), mid = 0, ...) \method{rescale_mid}{dist}(x, to = c(0, 1), from = range(x, na.rm = TRUE), mid = 0, ...) \method{rescale_mid}{POSIXt}(x, to = c(0, 1), from = range(x, na.rm = TRUE), mid, ...) \method{rescale_mid}{Date}(x, to = c(0, 1), from = range(x, na.rm = TRUE), mid, ...) \method{rescale_mid}{integer64}(x, to = c(0, 1), from = range(x, na.rm = TRUE), mid = 0, ...) \method{rescale_mid}{AsIs}(x, to, from, ...) } \arguments{ \item{x}{vector of values to manipulate.} \item{to}{output range (numeric vector of length two)} \item{from}{input range (vector of length two). If not given, is calculated from the range of \code{x}} \item{mid}{mid-point of input range} \item{...}{other arguments passed on to methods} } \description{ Rescale vector to have specified minimum, midpoint, and maximum } \details{ Objects of class \verb{} are returned unaltered. } \examples{ rescale_mid(1:100, mid = 50.5) rescale_mid(runif(50), mid = 0.5) rescale_mid(1) } scales/man/transform_date.Rd0000644000176200001440000000074114672302077015610 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-date.R \name{transform_date} \alias{transform_date} \alias{date_trans} \title{Transformation for dates (class Date)} \usage{ transform_date() date_trans() } \description{ Transformation for dates (class Date) } \examples{ years <- seq(as.Date("1910/1/1"), as.Date("1999/1/1"), "years") t <- transform_date() t$transform(years) t$inverse(t$transform(years)) t$format(t$breaks(range(years))) } scales/man/transform_log.Rd0000644000176200001440000000266414672302077015462 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_log} \alias{transform_log} \alias{transform_log10} \alias{transform_log2} \alias{transform_log1p} \alias{log_trans} \alias{log10_trans} \alias{log2_trans} \alias{log1p_trans} \alias{transform_pseudo_log} \alias{pseudo_log_trans} \title{Log transformations} \usage{ transform_log(base = exp(1)) transform_log10() transform_log2() transform_log1p() log_trans(base = exp(1)) log10_trans() log2_trans() log1p_trans() transform_pseudo_log(sigma = 1, base = exp(1)) pseudo_log_trans(sigma = 1, base = exp(1)) } \arguments{ \item{base}{base of logarithm} \item{sigma}{Scaling factor for the linear part of pseudo-log transformation.} } \description{ \itemize{ \item \code{transform_log()}: \code{log(x)} \item \code{log1p()}: \code{log(x + 1)} \item \code{transform_pseudo_log()}: smoothly transition to linear scale around 0. } } \examples{ plot(transform_log2(), xlim = c(0, 5)) plot(transform_log(), xlim = c(0, 5)) plot(transform_log10(), xlim = c(0, 5)) plot(transform_log(), xlim = c(0, 2)) plot(transform_log1p(), xlim = c(-1, 1)) # The pseudo-log is defined for all real numbers plot(transform_pseudo_log(), xlim = c(-5, 5)) lines(transform_log(), xlim = c(0, 5), col = "red") # For large positives numbers it's very close to log plot(transform_pseudo_log(), xlim = c(1, 20)) lines(transform_log(), xlim = c(1, 20), col = "red") } scales/man/pal_identity.Rd0000644000176200001440000000045714672302077015271 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-identity.R \name{pal_identity} \alias{pal_identity} \alias{identity_pal} \title{Identity palette} \usage{ pal_identity() identity_pal() } \description{ Leaves values unchanged - useful when the data is already scaled. } scales/man/number.Rd0000644000176200001440000001023314705655135014070 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-number.R \name{number} \alias{number} \alias{cut_short_scale} \alias{cut_long_scale} \alias{cut_time_scale} \alias{cut_si} \title{A low-level numeric formatter} \usage{ number( x, accuracy = NULL, scale = 1, prefix = "", suffix = "", big.mark = NULL, decimal.mark = NULL, style_positive = NULL, style_negative = NULL, scale_cut = NULL, trim = TRUE, ... ) cut_short_scale(space = FALSE) cut_long_scale(space = FALSE) cut_time_scale(space = FALSE) cut_si(unit) } \arguments{ \item{accuracy}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix}{Additional text to display before the number. The suffix is applied to absolute value before \code{style_positive} and \code{style_negative} are processed so that \code{prefix = "$"} will yield (e.g.) \verb{-$1} and \verb{($1)}.} \item{suffix}{Additional text to display after the number.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{style_positive}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{style_negative}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{scale_cut}{Named numeric vector that allows you to rescale large (or small) numbers and add a prefix. Built-in helpers include: \itemize{ \item \code{cut_short_scale()}: [10^3, 10^6) = K, [10^6, 10^9) = M, [10^9, 10^12) = B, [10^12, Inf) = T. \item \code{cut_long_scale()}: [10^3, 10^6) = K, [10^6, 10^12) = M, [10^12, 10^18) = B, [10^18, Inf) = T. \item \code{cut_si(unit)}: uses standard SI units. } If you supply a vector \code{c(a = 100, b = 1000)}, absolute values in the range \verb{[0, 100)} will not be rescaled, absolute values in the range \verb{[100, 1000)} will be divided by 100 and given the suffix "a", and absolute values in the range \verb{[1000, Inf)} will be divided by 1000 and given the suffix "b". If the division creates an irrational value (or one with many digits), the cut value below will be tried to see if it improves the look of the final label.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{...}{Other arguments passed on to \code{\link[base:format]{base::format()}}.} \item{space}{Add a space before the scale suffix?} \item{unit}{SI unit abbreviation.} } \value{ A character vector of \code{length(x)}. } \description{ This function is a low-level helper that powers many of the labelling functions. You should generally not need to call it directly unless you are creating your own labelling function. } \keyword{internal} scales/man/Range.Rd0000644000176200001440000000052014672302077013627 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/range.R \name{Range} \alias{Range} \alias{DiscreteRange} \alias{ContinuousRange} \title{Mutable ranges} \description{ Mutable ranges have a two methods (\code{train} and \code{reset}), and make it possible to build up complete ranges with multiple passes. } scales/man/transform_atanh.Rd0000644000176200001440000000052414672302077015765 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_atanh} \alias{transform_atanh} \alias{atanh_trans} \title{Arc-tangent transformation} \usage{ transform_atanh() atanh_trans() } \description{ Arc-tangent transformation } \examples{ plot(transform_atanh(), xlim = c(-1, 1)) } scales/man/muted.Rd0000644000176200001440000000113614672302130013703 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/colour-manip.R \name{muted} \alias{muted} \title{Mute standard colour} \usage{ muted(colour, l = 30, c = 70) } \arguments{ \item{colour}{character vector of colours to modify} \item{l}{new luminance} \item{c}{new chroma} } \description{ Mute standard colour } \examples{ muted("red") muted("blue") show_col(c("red", "blue", muted("red"), muted("blue"))) } \seealso{ Other colour manipulation: \code{\link{alpha}()}, \code{\link{col2hcl}()}, \code{\link{col_mix}()}, \code{\link{colour_manip}} } \concept{colour manipulation} scales/man/train_continuous.Rd0000644000176200001440000000074114705417700016200 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scale-continuous.R \name{train_continuous} \alias{train_continuous} \title{Train (update) a continuous scale} \usage{ train_continuous(new, existing = NULL, call = caller_env()) } \arguments{ \item{new}{New data to add to scale} \item{existing}{Optional existing scale to update} \item{call}{A call to display in error messages} } \description{ Strips attributes and always returns a numeric vector } scales/man/transform_asn.Rd0000644000176200001440000000060314672302077015451 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-numeric.R \name{transform_asn} \alias{transform_asn} \alias{asn_trans} \title{Arc-sin square root transformation} \usage{ transform_asn() asn_trans() } \description{ This is the variance stabilising transformation for the binomial distribution. } \examples{ plot(transform_asn(), xlim = c(0, 1)) } scales/man/label_parse.Rd0000644000176200001440000000376314705661306015060 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-expression.R \name{label_parse} \alias{label_parse} \alias{label_math} \title{Label with mathematical annotations} \usage{ label_parse() label_math(expr = 10^.x, format = force) } \arguments{ \item{expr}{expression to use} \item{format}{another format function to apply prior to mathematical transformation - this makes it easier to use floating point numbers in mathematical expressions.} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ \code{label_parse()} produces expression from strings by parsing them; \code{label_math()} constructs expressions by replacing the pronoun \code{.x} with each string. } \examples{ # Use label_parse() with discrete scales greek <- c("alpha", "beta", "gamma") demo_discrete(greek) demo_discrete(greek, labels = label_parse()) # Use label_math() with continuous scales demo_continuous(c(1, 5)) demo_continuous(c(1, 5), labels = label_math(alpha[.x])) demo_continuous(c(1, 5), labels = label_math()) } \seealso{ \link{plotmath} for the details of mathematical formatting in R. Other labels for continuous scales: \code{\link{label_bytes}()}, \code{\link{label_currency}()}, \code{\link{label_glue}()}, \code{\link{label_number_auto}()}, \code{\link{label_number_si}()}, \code{\link{label_ordinal}()}, \code{\link{label_percent}()}, \code{\link{label_pvalue}()}, \code{\link{label_scientific}()} Other labels for discrete scales: \code{\link{label_dictionary}()}, \code{\link{label_glue}()}, \code{\link{label_wrap}()} } \concept{labels for continuous scales} \concept{labels for discrete scales} scales/man/alpha.Rd0000644000176200001440000000132214672302130013647 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/colour-manip.R \name{alpha} \alias{alpha} \title{Modify colour transparency} \usage{ alpha(colour, alpha = NA) } \arguments{ \item{colour}{colour} \item{alpha}{new alpha level in [0,1]. If alpha is \code{NA}, existing alpha values are preserved.} } \description{ Vectorised in both colour and alpha. } \examples{ alpha("red", 0.1) alpha(colours(), 0.5) alpha("red", seq(0, 1, length.out = 10)) alpha(c("first" = "gold", "second" = "lightgray", "third" = "#cd7f32"), .5) } \seealso{ Other colour manipulation: \code{\link{col2hcl}()}, \code{\link{col_mix}()}, \code{\link{colour_manip}}, \code{\link{muted}()} } \concept{colour manipulation} scales/man/compose_label.Rd0000644000176200001440000000232515002117500015363 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-compose.R \name{compose_label} \alias{compose_label} \title{Compose two or more label formatters together} \usage{ compose_label(..., call = caller_env()) } \arguments{ \item{...}{One or more labelling functions. These will be applied to breaks consecutively. \link[rlang:as_function]{Lambda syntax} is allowed.} \item{call}{A call to display in error messages.} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ This labeller provides a general mechanism for composing two or more labellers together. } \examples{ demo_continuous( c(-100, 100), labels = compose_label(abs, number, \(x) paste0(x, " foobar"), toupper) ) # Same result demo_continuous( c(-100, 100), labels = compose_label(abs, label_number(suffix = " FOOBAR")) ) } scales/man/label_dictionary.Rd0000644000176200001440000000336714706713437016117 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-dictionary.R \name{label_dictionary} \alias{label_dictionary} \title{Labels from lookup tables} \usage{ label_dictionary(dictionary = character(), nomatch = NULL) } \arguments{ \item{dictionary}{A named character vector of labels. The names are expected to match the breaks, and the values become the labels.} \item{nomatch}{A string to label breaks that do not match any name in \code{dictionary}. When \code{NULL} (default), the breaks are not translated but are kept as-is.} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Use \code{label_dictionary()} for looking up succinct breaks in a named character vector giving complete labels. } \examples{ # Example lookup table lut <- c( "4" = "four wheel drive", "r" = "rear wheel drive", "f" = "front wheel drive" ) # Typical usage demo_discrete(c("4", "r", "f"), labels = label_dictionary(lut)) # By default, extra values ('w') will remain as-is demo_discrete(c("4", "r", "f", "w"), labels = label_dictionary(lut)) # Alternatively, you can relabel extra values demo_discrete( c("4", "r", "f", "w"), labels = label_dictionary(lut, nomatch = "unknown") ) } \seealso{ Other labels for discrete scales: \code{\link{label_glue}()}, \code{\link{label_parse}()}, \code{\link{label_wrap}()} } \concept{labels for discrete scales} scales/man/label_ordinal.Rd0000644000176200001440000001233314705655135015372 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-ordinal.R \name{label_ordinal} \alias{label_ordinal} \alias{ordinal_english} \alias{ordinal_french} \alias{ordinal_spanish} \title{Label ordinal numbers (1st, 2nd, 3rd, etc)} \usage{ label_ordinal(prefix = "", suffix = "", big.mark = NULL, rules = NULL, ...) ordinal_english() ordinal_french(gender = c("masculin", "feminin"), plural = FALSE) ordinal_spanish() } \arguments{ \item{prefix, suffix}{Symbols to display before and after value.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{rules}{Named list of regular expressions, matched in order. Name gives suffix, and value specifies which numbers to match.} \item{...}{ Arguments passed on to \code{\link[=number]{number}} \describe{ \item{\code{accuracy}}{A number to round to. Use (e.g.) \code{0.01} to show 2 decimal places of precision. If \code{NULL}, the default, uses a heuristic that should ensure breaks have the minimum number of digits needed to show the difference between adjacent values. Applied to rescaled data.} \item{\code{scale}}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{\code{decimal.mark}}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_positive}}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_negative}}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{scale_cut}}{Named numeric vector that allows you to rescale large (or small) numbers and add a prefix. Built-in helpers include: \itemize{ \item \code{cut_short_scale()}: [10^3, 10^6) = K, [10^6, 10^9) = M, [10^9, 10^12) = B, [10^12, Inf) = T. \item \code{cut_long_scale()}: [10^3, 10^6) = K, [10^6, 10^12) = M, [10^12, 10^18) = B, [10^18, Inf) = T. \item \code{cut_si(unit)}: uses standard SI units. } If you supply a vector \code{c(a = 100, b = 1000)}, absolute values in the range \verb{[0, 100)} will not be rescaled, absolute values in the range \verb{[100, 1000)} will be divided by 100 and given the suffix "a", and absolute values in the range \verb{[1000, Inf)} will be divided by 1000 and given the suffix "b". If the division creates an irrational value (or one with many digits), the cut value below will be tried to see if it improves the look of the final label.} \item{\code{trim}}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} }} \item{gender}{Masculin or feminin gender for French ordinal.} \item{plural}{Plural or singular for French ordinal.} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Round values to integers and then display as ordinal values (e.g. 1st, 2nd, 3rd). Built-in rules are provided for English, French, and Spanish. } \examples{ demo_continuous(c(1, 5)) demo_continuous(c(1, 5), labels = label_ordinal()) demo_continuous(c(1, 5), labels = label_ordinal(rules = ordinal_french())) # The rules are just a set of regular expressions that are applied in turn ordinal_french() ordinal_english() # Note that ordinal rounds values, so you may need to adjust the breaks too demo_continuous(c(1, 10)) demo_continuous(c(1, 10), labels = label_ordinal()) demo_continuous(c(1, 10), labels = label_ordinal(), breaks = breaks_width(2) ) } \seealso{ Other labels for continuous scales: \code{\link{label_bytes}()}, \code{\link{label_currency}()}, \code{\link{label_glue}()}, \code{\link{label_number_auto}()}, \code{\link{label_number_si}()}, \code{\link{label_parse}()}, \code{\link{label_percent}()}, \code{\link{label_pvalue}()}, \code{\link{label_scientific}()} } \concept{labels for continuous scales} scales/man/label_currency.Rd0000644000176200001440000001266114705655135015600 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-currency.R \name{label_currency} \alias{label_currency} \title{Label currencies ($100, €2.50, etc)} \usage{ label_currency( accuracy = NULL, scale = 1, prefix = NULL, suffix = NULL, big.mark = NULL, decimal.mark = NULL, trim = TRUE, largest_with_fractional = 1e+05, ... ) } \arguments{ \item{accuracy, largest_with_fractional}{Number to round to. If \code{NULL}, the default, values will be rounded to the nearest integer, unless any of the values has non-zero fractional component (e.g. cents) and the largest value is less than \code{largest_with_fractional} which by default is 100,000.} \item{scale}{A scaling factor: \code{x} will be multiplied by \code{scale} before formatting. This is useful if the underlying data is very small or very large.} \item{prefix, suffix}{Symbols to display before and after value.} \item{big.mark}{Character used between every 3 digits to separate thousands. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{decimal.mark}{The character to be used to indicate the numeric decimal point. The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{trim}{Logical, if \code{FALSE}, values are right-justified to a common width (see \code{\link[base:format]{base::format()}}).} \item{...}{ Arguments passed on to \code{\link[=number]{number}} \describe{ \item{\code{style_positive}}{A string that determines the style of positive numbers: \itemize{ \item \code{"none"} (the default): no change, e.g. \code{1}. \item \code{"plus"}: preceded by \code{+}, e.g. \code{+1}. \item \code{"space"}: preceded by a Unicode "figure space", i.e., a space equally as wide as a number or \code{+}. Compared to \code{"none"}, adding a figure space can ensure numbers remain properly aligned when they are left- or right-justified. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{style_negative}}{A string that determines the style of negative numbers: \itemize{ \item \code{"hyphen"} (the default): preceded by a standard hyphen \code{-}, e.g. \code{-1}. \item \code{"minus"}, uses a proper Unicode minus symbol. This is a typographical nicety that ensures \code{-} aligns with the horizontal bar of the the horizontal bar of \code{+}. \item \code{"parens"}, wrapped in parentheses, e.g. \code{(1)}. } The default (\code{NULL}) retrieves the setting from the \link[=number_options]{number options}.} \item{\code{scale_cut}}{Named numeric vector that allows you to rescale large (or small) numbers and add a prefix. Built-in helpers include: \itemize{ \item \code{cut_short_scale()}: [10^3, 10^6) = K, [10^6, 10^9) = M, [10^9, 10^12) = B, [10^12, Inf) = T. \item \code{cut_long_scale()}: [10^3, 10^6) = K, [10^6, 10^12) = M, [10^12, 10^18) = B, [10^18, Inf) = T. \item \code{cut_si(unit)}: uses standard SI units. } If you supply a vector \code{c(a = 100, b = 1000)}, absolute values in the range \verb{[0, 100)} will not be rescaled, absolute values in the range \verb{[100, 1000)} will be divided by 100 and given the suffix "a", and absolute values in the range \verb{[1000, Inf)} will be divided by 1000 and given the suffix "b". If the division creates an irrational value (or one with many digits), the cut value below will be tried to see if it improves the look of the final label.} }} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Format numbers as currency, rounding values to monetary or fractional monetary using unit a convenient heuristic. } \examples{ demo_continuous(c(0, 1), labels = label_currency()) demo_continuous(c(1, 100), labels = label_currency()) # Customise currency display with prefix and suffix demo_continuous(c(1, 100), labels = label_currency(prefix = "USD ")) yen <- label_currency( prefix = "¥", suffix = "", big.mark = ".", decimal.mark = "," ) demo_continuous(c(1000, 1100), labels = yen) # Use style_negative = "parens" for finance style display demo_continuous(c(-100, 100), labels = label_currency(style_negative = "parens")) # Use scale_cut to use K/M/B where appropriate demo_log10(c(1, 1e16), breaks = log_breaks(7, 1e3), labels = label_currency(scale_cut = cut_short_scale()) ) # cut_short_scale() uses B = one thousand million # cut_long_scale() uses B = one million million demo_log10(c(1, 1e16), breaks = log_breaks(7, 1e3), labels = label_currency(scale_cut = cut_long_scale()) ) # You can also define your own breaks gbp <- label_currency( prefix = "\u00a3", scale_cut = c(0, k = 1e3, m = 1e6, bn = 1e9, tn = 1e12) ) demo_log10(c(1, 1e12), breaks = log_breaks(5, 1e3), labels = gbp) } \seealso{ Other labels for continuous scales: \code{\link{label_bytes}()}, \code{\link{label_glue}()}, \code{\link{label_number_auto}()}, \code{\link{label_number_si}()}, \code{\link{label_ordinal}()}, \code{\link{label_parse}()}, \code{\link{label_percent}()}, \code{\link{label_pvalue}()}, \code{\link{label_scientific}()} } \concept{labels for continuous scales} scales/man/transform_timespan.Rd0000644000176200001440000000254614672302077016520 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/transform-date.R \name{transform_timespan} \alias{transform_timespan} \alias{timespan_trans} \alias{transform_hms} \alias{hms_trans} \title{Transformation for times (class hms)} \usage{ transform_timespan(unit = c("secs", "mins", "hours", "days", "weeks")) timespan_trans(unit = c("secs", "mins", "hours", "days", "weeks")) transform_hms() hms_trans() } \arguments{ \item{unit}{The unit used to interpret numeric input} } \description{ \code{transform_timespan()} provides transformations for data encoding time passed along with breaks and label formatting showing standard unit of time fitting the range of the data. \code{transform_hms()} provides the same but using standard hms idioms and formatting. } \examples{ # transform_timespan allows you to specify the time unit numeric data is # interpreted in trans_min <- transform_timespan("mins") demo_timespan(seq(0, 100), trans = trans_min) # Input already in difftime format is interpreted correctly demo_timespan(as.difftime(seq(0, 100), units = "secs"), trans = trans_min) if (require("hms")) { # transform_hms always assumes seconds hms <- round(runif(10) * 86400) t <- transform_hms() t$transform(hms) t$inverse(t$transform(hms)) t$breaks(hms) # The break labels also follow the hms format demo_timespan(hms, trans = t) } } scales/man/pal_shape.Rd0000644000176200001440000000051714672302077014535 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pal-shape.r \name{pal_shape} \alias{pal_shape} \alias{shape_pal} \title{Shape palette (discrete)} \usage{ pal_shape(solid = TRUE) shape_pal(solid = TRUE) } \arguments{ \item{solid}{should shapes be solid or not?} } \description{ Shape palette (discrete) } scales/man/label_glue.Rd0000644000176200001440000000471414706713437014703 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/label-glue.R \name{label_glue} \alias{label_glue} \title{Interpolated labels} \usage{ label_glue(pattern = "{x}", ..., parse = FALSE, .envir = caller_env()) } \arguments{ \item{pattern}{A glue string used for formatting. The \code{x} variable holds the breaks, so that \code{"{x}"} (default) returns the breaks as-is.} \item{...}{Arguments passed on to \code{\link[glue:glue]{glue::glue()}}.} \item{parse}{Whether to return labels as expressions.} \item{.envir}{[\code{environment}: \code{parent.frame()}]\cr Environment to evaluate each expression in. Expressions are evaluated from left to right. If \code{.x} is an environment, the expressions are evaluated in that environment and \code{.envir} is ignored. If \code{NULL} is passed, it is equivalent to \code{\link[=emptyenv]{emptyenv()}}.} } \value{ All \code{label_()} functions return a "labelling" function, i.e. a function that takes a vector \code{x} and returns a character vector of \code{length(x)} giving a label for each input value. Labelling functions are designed to be used with the \code{labels} argument of ggplot2 scales. The examples demonstrate their use with x scales, but they work similarly for all scales, including those that generate legends rather than axes. } \description{ Use \code{label_glue()} to perform string interpolation using the \pkg{glue} package. Enclosed expressions will be evaluated as R code. } \examples{ # Example variables animal <- "penguin" species <- c("Adelie", "Chinstrap", "Emperor", "Gentoo") # Typical use, note that {x} will become the breaks demo_discrete(species, labels = label_glue("The {x}\n{animal}")) # It adapts to the breaks that are present demo_discrete(species[-3], labels = label_glue("The {x}\n{animal}")) # Contrary to directly glueing species + animal, which results in mislabelling! demo_discrete(species[-3], labels = glue::glue("The {species}\n{animal}")) } \seealso{ Other labels for continuous scales: \code{\link{label_bytes}()}, \code{\link{label_currency}()}, \code{\link{label_number_auto}()}, \code{\link{label_number_si}()}, \code{\link{label_ordinal}()}, \code{\link{label_parse}()}, \code{\link{label_percent}()}, \code{\link{label_pvalue}()}, \code{\link{label_scientific}()} Other labels for discrete scales: \code{\link{label_dictionary}()}, \code{\link{label_parse}()}, \code{\link{label_wrap}()} } \concept{labels for continuous scales} \concept{labels for discrete scales} scales/man/cscale.Rd0000644000176200001440000000207314672302077014032 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scale-continuous.R \name{cscale} \alias{cscale} \title{Continuous scale} \usage{ cscale(x, palette, na.value = NA_real_, trans = transform_identity()) } \arguments{ \item{x}{vector of continuous values to scale} \item{palette}{palette to use. Built in palettes: \Sexpr[results=rd,stage=build]{scales:::seealso_pal()}} \item{na.value}{value to use for missing values} \item{trans}{transformation object describing the how to transform the raw data prior to scaling. Defaults to the identity transformation which leaves the data unchanged. Built in transformations: \Sexpr[results=rd,stage=build]{scales:::seealso_transform()}.} } \description{ Continuous scale } \examples{ with(mtcars, plot(disp, mpg, cex = cscale(hp, pal_rescale()))) with(mtcars, plot(disp, mpg, cex = cscale(hp, pal_rescale(), trans = transform_sqrt() ))) with(mtcars, plot(disp, mpg, cex = cscale(hp, pal_area()))) with(mtcars, plot(disp, mpg, pch = 20, cex = 5, col = cscale(hp, pal_seq_gradient("grey80", "black")) )) } scales/DESCRIPTION0000644000176200001440000000272115002414662013234 0ustar liggesusersPackage: scales Title: Scale Functions for Visualization Version: 1.4.0 Authors@R: c( person("Hadley", "Wickham", , "hadley@posit.co", role = "aut"), person("Thomas Lin", "Pedersen", , "thomas.pedersen@posit.co", role = c("cre", "aut"), comment = c(ORCID = "0000-0002-5147-4711")), person("Dana", "Seidel", role = "aut"), person("Posit Software, PBC", role = c("cph", "fnd"), comment = c(ROR = "03wc8by49")) ) Description: Graphical scales map data to aesthetics, and provide methods for automatically determining breaks and labels for axes and legends. License: MIT + file LICENSE URL: https://scales.r-lib.org, https://github.com/r-lib/scales BugReports: https://github.com/r-lib/scales/issues Depends: R (>= 4.1) Imports: cli, farver (>= 2.0.3), glue, labeling, lifecycle, R6, RColorBrewer, rlang (>= 1.1.0), viridisLite Suggests: bit64, covr, dichromat, ggplot2, hms (>= 0.5.0), stringi, testthat (>= 3.0.0) Config/Needs/website: tidyverse/tidytemplate Config/testthat/edition: 3 Config/usethis/last-upkeep: 2025-04-23 Encoding: UTF-8 LazyLoad: yes RoxygenNote: 7.3.2 NeedsCompilation: no Packaged: 2025-04-23 18:27:04 UTC; thomas Author: Hadley Wickham [aut], Thomas Lin Pedersen [cre, aut] (), Dana Seidel [aut], Posit Software, PBC [cph, fnd] (03wc8by49) Maintainer: Thomas Lin Pedersen Repository: CRAN Date/Publication: 2025-04-24 11:00:02 UTC