r-lib / scales

Tools for ggplot2 scales
https://scales.r-lib.org
Other
395 stars 107 forks source link

Feature request: rescale transformation #415

Open teunbrand opened 9 months ago

teunbrand commented 9 months ago

I'd like to propose a new transformation function that essentially wraps the rescale() function. It's definition can be something like the following:

library(scales)

transform_rescale <- function(to = c(0, 1), from = c(0, 1)) {
  force(to)
  force(from)
  new_transform(
    "rescaling",
    transform = function(x) rescale(x, to = to, from = from),
    inverse   = function(x) rescale(x, to = from, from = to) 
  )
}

It should be able to handle a bunch of 'scale and translate' transformations, like unit conversions. Going from metres to inches is simply a scale transformation.

metres_to_inches <- transform_rescale(to = c(0, 100/2.54))
metres_to_inches$transform(1)
#> [1] 39.37008

Whereas going from degrees celcius to degrees fahrenheit is a 'scale and translate' transformation.

celsius_to_fahrenheit <- transform_rescale(to = c(32, 212), from = c(0, 100))
celsius_to_fahrenheit$transform(-5)
#> [1] 23
celsius_to_fahrenheit$transform(32)
#> [1] 89.6

Created on 2023-12-15 with reprex v2.0.2

Given that it is suitable for plenty of unit conversions, I think this transformation may have a bunch of applications.

mjskay commented 9 months ago

In case it is desired, adding derivative support for this should entail something like:

transform_rescale <- function(to = c(0, 1), from = c(0, 1)) {
  force(to)
  force(from)
  new_transform(
    "rescaling",
    transform = function(x) rescale(x, to = to, from = from),
    inverse   = function(x) rescale(x, to = from, from = to),
    d_transform = function(x) rep(diff(to) / diff(from), length(x)),
    d_inverse = function(x) rep(diff(from) / diff(to), length(x))
  )
}
teunbrand commented 9 months ago

Ah yes, of course! Thanks for weighing in, it was a little oversight on my part