Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transformation suffixes to prefixes (attempt 2) #410

Merged
merged 9 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ S3method(fullseq,Date)
S3method(fullseq,POSIXt)
S3method(fullseq,difftime)
S3method(fullseq,numeric)
S3method(lines,trans)
S3method(lines,transform)
S3method(offset_by,Date)
S3method(offset_by,POSIXt)
S3method(offset_by,difftime)
S3method(offset_by,numeric)
S3method(plot,trans)
S3method(print,trans)
S3method(plot,transform)
S3method(print,transform)
S3method(rescale,"NULL")
S3method(rescale,AsIs)
S3method(rescale,Date)
Expand All @@ -37,6 +37,7 @@ export(abs_area)
export(alpha)
export(area_pal)
export(as.trans)
export(as.transform)
export(asinh_trans)
export(asn_trans)
export(atanh_trans)
Expand Down Expand Up @@ -89,6 +90,7 @@ export(hue_pal)
export(identity_pal)
export(identity_trans)
export(is.trans)
export(is.transform)
export(label_bytes)
export(label_comma)
export(label_currency)
Expand Down Expand Up @@ -121,6 +123,7 @@ export(minor_breaks_n)
export(minor_breaks_width)
export(modulus_trans)
export(muted)
export(new_transform)
export(number)
export(number_bytes)
export(number_bytes_format)
Expand Down Expand Up @@ -185,6 +188,31 @@ export(trans_breaks)
export(trans_format)
export(trans_new)
export(trans_range)
export(transform_asinh)
export(transform_asn)
export(transform_atanh)
export(transform_boxcox)
export(transform_compose)
export(transform_date)
export(transform_exp)
export(transform_hms)
export(transform_identity)
export(transform_log)
export(transform_log10)
export(transform_log1p)
export(transform_log2)
export(transform_logit)
export(transform_modulus)
export(transform_probability)
export(transform_probit)
export(transform_pseudo_log)
export(transform_reciprocal)
export(transform_reverse)
export(transform_sqrt)
export(transform_time)
export(transform_timespan)
export(transform_yj)
export(trim_to_domain)
export(unit_format)
export(viridis_pal)
export(wrap_format)
Expand Down
23 changes: 14 additions & 9 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,27 @@
make it easier to align positive and negative values as figure space takes up
the same amount of space as `-` (#366)
* `label_dollar()` has been superseeded by `label_currency()` for clarity (#344)
* `sqrt_trans()` no longer returns an inverse for values outside of its domain
(#214)
* `transform_sqrt()` no longer returns an inverse for values outside of its
domain (#214)
* Add better support for `difftime` objects. `label_timespan()` adds
functionality for adding correct unit suffix to timespan data,
`breaks_timespan()` adds functionality for finding pleasant breakpoints across
the various bases in time units, while `timespan_trans()` wraps it all
together and provides an alternative to `hms_trans()` (#212)
* Add an inverse (area) hyperbolic sine transformation `asinh_trans()`, which
provides a logarithm-like transformation of a space, but which accommodates
negative values (#297)
* Correct the domain calculation for `compose_trans()` (@mjskay, #408).
the various bases in time units, while `transform_timespan()` wraps it all
together and provides an alternative to `transform_hms()` (#212)
* Add an inverse (area) hyperbolic sine transformation `transform_asinh()`,
which provides a logarithm-like transformation of a space, but which
accommodates negative values (#297)
* Correct the domain calculation for `transform_compose()` (@mjskay, #408).
* Transformation objects can optionally include the derivatives of the transform
and the inverse transform (@mjskay, #322).
* Transformation function have been renamed to `transform_*`-prefixed names
instead of `*_trans`-suffixed names. This allows for a better tab-completion
search of transformations. The S3 class of transformations has been
renamed from `"trans"` to `"transform"`. `new_transform()` replaces
`trans_new()` and `trim_to_domain()` replaces `trans_range()`.
* Palette functions now have the `pal_`-prefix. The old `_pal`-suffixed versions
are kept for backward compatibility.

# scales 1.2.1

* Re-document to fix HTML issues in `.Rd`.
Expand Down
2 changes: 1 addition & 1 deletion R/documentation.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ seealso <- function(pattern) {
paste0("\\code{\\link{", names, "}}", collapse = ", ")
}

seealso_trans <- function() seealso("_trans$")
seealso_transform <- function() seealso("^transform_")

seealso_pal <- function() seealso("^pal_")
6 changes: 3 additions & 3 deletions R/scale-continuous.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@
#' leaves the data unchanged.
#'
#' Built in transformations:
#' \Sexpr[results=rd,stage=build]{scales:::seealso_trans()}.
#' \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 = sqrt_trans()
#' 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 = identity_trans()) {
cscale <- function(x, palette, na.value = NA_real_, trans = transform_identity()) {
if (!is.trans(trans)) cli::cli_abort("{.arg trans} must be a {.cls trans} object")

x <- trans$transform(x)
Expand Down
12 changes: 8 additions & 4 deletions R/trans-compose.R → R/transform-compose.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
#' @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())
compose_trans <- function(...) {
trans_list <- lapply(list2(...), as.trans)
transform_compose <- function(...) {
trans_list <- lapply(list2(...), as.transform)
if (length(trans_list) == 0) {
cli::cli_abort("{.fun compose_trans} must include at least 1 transformer to compose")
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
Expand Down Expand Up @@ -42,7 +42,7 @@ compose_trans <- function(...) {
has_d_transform <- all(lengths(lapply(trans_list, "[[", "d_transform")) > 0)
has_d_inverse <- all(lengths(lapply(trans_list, "[[", "d_inverse")) > 0)

trans_new(
new_transform(
paste0("composition(", paste0(names, collapse = ","), ")"),
transform = function(x) compose_fwd(x, trans_list),
inverse = function(x) compose_rev(x, trans_list),
Expand All @@ -53,6 +53,10 @@ compose_trans <- function(...) {
)
}

#' @export
#' @rdname transform_compose
compose_trans <- transform_compose

compose_fwd <- function(x, trans_list) {
for (trans in trans_list) {
x <- trans$transform(x)
Expand Down
62 changes: 40 additions & 22 deletions R/trans-date.R → R/transform-date.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,28 @@
#' @export
#' @examples
#' years <- seq(as.Date("1910/1/1"), as.Date("1999/1/1"), "years")
#' t <- date_trans()
#' t <- transform_date()
#' t$transform(years)
#' t$inverse(t$transform(years))
#' t$format(t$breaks(range(years)))
date_trans <- function() {
trans_new("date",
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 date_trans} works with objects of class {.cls Date} only")
cli::cli_abort("{.fun transform_date} works with objects of class {.cls Date} only")
}
structure(as.numeric(x), names = names(x))
}
Expand All @@ -31,65 +36,69 @@ from_date <- function(x) {
#' @export
#' @examples
#' hours <- seq(ISOdate(2000, 3, 20, tz = ""), by = "hour", length.out = 10)
#' t <- time_trans()
#' t <- transform_time()
#' t$transform(hours)
#' t$inverse(t$transform(hours))
#' t$format(t$breaks(range(hours)))
time_trans <- function(tz = NULL) {
transform_time <- function(tz = NULL) {
force(tz)
to_time <- function(x) {
structure(x, class = c("POSIXt", "POSIXct"), tzone = tz)
}

from_time <- function(x) {
if (!inherits(x, "POSIXct")) {
cli::cli_abort("{.fun time_trans} works with objects of class {.cls POSIXct} only")
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))
}

trans_new("time",
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)
#'
#' `timespan_trans()` provides transformations for data encoding time passed
#' `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. `hms_trans()` provides the same but using standard hms
#' idioms and formatting.
#' the range of the data. `transform_hms()` provides the same but using standard
#' hms idioms and formatting.
#'
#' @inheritParams label_timespan
#' @export
#' @examples
#' # timespan_trans allows you to specify the time unit numeric data is
#' # transform_timespan allows you to specify the time unit numeric data is
#' # interpreted in
#' min_trans <- timespan_trans("mins")
#' demo_timespan(seq(0, 100), trans = min_trans)
#' 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 = min_trans)
#' demo_timespan(as.difftime(seq(0, 100), units = "secs"), trans = trans_min)
#'
#' if (require("hms")) {
#' # hms_trans always assumes seconds
#' # transform_hms always assumes seconds
#' hms <- round(runif(10) * 86400)
#' t <- hms_trans()
#' 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)
#' }
#'
timespan_trans <- function(unit = c("secs", "mins", "hours", "days", "weeks")) {
transform_timespan <- function(unit = c("secs", "mins", "hours", "days", "weeks")) {
unit <- arg_match(unit)
trans_new(
new_transform(
"timespan",
transform = function(x) {
structure(as.numeric(as.difftime(x, units = unit), units = "secs"), names = names(x))
Expand All @@ -103,10 +112,15 @@ timespan_trans <- function(unit = c("secs", "mins", "hours", "days", "weeks")) {
format = label_timespan(unit)
)
}
#' @rdname timespan_trans

#' @export
hms_trans <- function() {
trans_new(
#' @rdname transform_timespan
timespan_trans <- transform_timespan

#' @rdname transform_timespan
#' @export
transform_hms <- function() {
new_transform(
"hms",
transform = function(x) {
structure(as.numeric(x), names = names(x))
Expand All @@ -116,6 +130,10 @@ hms_trans <- function() {
)
}

#' @rdname transform_timespan
#' @export
hms_trans <- transform_hms

breaks_hms <- function(n = 5) {
base_breaks <- breaks_timespan("secs", n)
function(x) {
Expand Down
Loading
Loading