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

trans, reverse, and negatives #287

Closed
SimonDedman opened this issue Jul 16, 2020 · 2 comments · Fixed by #335
Closed

trans, reverse, and negatives #287

SimonDedman opened this issue Jul 16, 2020 · 2 comments · Fixed by #335
Labels
feature a feature request or enhancement
Milestone

Comments

@SimonDedman
Copy link

With marine data, one typically wants to present depth on the Y-axis, starting with 0 at the top and with values of greater depth increasing as you do down the axis, as a visual analogue to descending deeper into the ocean:
image
A simple, albeit a little hacky, way of achieving this is:
df$depth <- -df$depth
Then scaling to one's preference, noting the negative:
scale_y_continuous(breaks = seq(-600, 0, by = 100), limits = c(-600, 0)) +

For various biological & oceanographic reasons, many marine species spend a disproportionate amount of time near the surface, such that there's a heterogeneous distribution of importance and data-ink in the top bit, and a lot of wasted space below.
image

Subsequently it would be nice to transform the scale and keep the reverse orientation, but, as I understand it, this isn't natively possible with the current setup:

  1. Keep original depth data as positive continuous. Can use rescaling transforms (log1p, sqrt) (trans = "log1p") OR reverse (trans = "reverse"), but not both.

  2. Pre-convert depth data to negative. No need to use reverse transform, but can't use (some/all) rescaling transforms because they don't work on negative values (even though this says sqrt does due to a bug, it doesn't for me)

While I presume I could sort this with a custom trans_new, I suspect based on various StackOverflow posts that this is a common enough issue, in various guises, to warrant inclusion as a feature request.

Proposed solutions:

A. Add reverse = FALSE as a default parameter to all transforms, such that one can set this to true to rescale their cake and reverse it too (and thus remove reverse_trans),

B. Allow transform functions to operate on negatives by converting them to positives then converting the results back. This could be an optional parameter e.g. allowNegative.

Thanks in advance.

@hadley
Copy link
Member

hadley commented Mar 16, 2022

Another option would be to provide some easy way to combine transformers. I think this would be relatively straightforward to implement.

@hadley hadley added the feature a feature request or enhancement label Mar 16, 2022
@teunbrand
Copy link
Contributor

teunbrand commented Mar 16, 2022

Here is a rough sketch of something that might work. I've only tried combining a few transforms with reverse transforms so far, so no guarantees.

library(scales)
library(ggplot2)

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_trans <- function(...) {
  trans_list <- lapply(list(...), as.trans)
  
  # Resolve domains
  domains <- vapply(trans_list, `[[`, numeric(2), i = "domain")
  domains <- c(max(domains[1, ]), min(domains[2, ]))
  
  trans_new(
    "composed_transform",
    transform = function(x) compose_fwd(x, trans_list),
    inverse   = function(x) compose_rev(x, trans_list),
    breaks    = function(x) {
      x <- compose_fwd(x, trans_list)
      x <- extended_breaks()(x)
      compose_rev(x, trans_list)
    },
    domain = domains
  )
}

df <- data.frame(x = 1:7, y = 10^c(-2:4))

ggplot(df, aes(x, y)) +
  geom_point() +
  scale_y_continuous(
    trans  = compose_trans("log10", "reverse"),
    breaks = c(100, 0.1)
  )

Created on 2022-03-16 by the reprex package (v2.0.1)

At the moment it is not smart enough to recognise that compose_trans("log10", "reverse") is fine, whereas compose_trans("reverse", "log10") yields errors.

@hadley hadley added this to the v1.2.0 milestone Mar 19, 2022
hadley added a commit that referenced this issue Mar 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature a feature request or enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants