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

side effect errors since 3.4.0 : scale_x_continuous() with user provided trans object now explicitly calls the transform function with domain edges as input #5105

Closed
phauchamps opened this issue Dec 12, 2022 · 6 comments

Comments

@phauchamps
Copy link

Hi,

Since 3.4.0 I am getting error messages from some extensions of scale_x_continuous() that are implemented in third parties packages. For the record, the 3rd party package I am using is ggcyto and the function I am using is scale_x_logicle() which just provides a specific transformation function to scale_x_continuous using trans = scales::trans_new(ggcyto_object).

Digging into the issue, I found that when displaying the plot, ggplot2 now calls, among the numerous calls to the transformation function or its inverse, the transformation function explicitely with the domain edges as input, which is by default c(-Inf, +Inf). This has as side effect that the transformation functions that are not robust for extreme values, may crash or raise an error message. This explicit call to the transform function, with the domain edges values as input, was not done in version 3.3.6, so I don't get why this might now be necessary.

Herebelow is a minimal reprex, using a dummy transformation function, which just implements the identity function, but raises an error when extreme values are passed. This example works without any concern with ggplot2 version 3.3.6, but raises the error message "extreme value passed => convergence problem!" with ggplot2 version 3.4.0

Could you possibly have a look and advise ?

Thx,

Philippe

# reprex
library(ggplot2)

myDummyTrans <- function(x) {
    if (any(x < -1.0e99 | x > 1.0e99, na.rm = TRUE))
        stop("extreme value passed => convergence problem!")
    return(x)    
}

myDummyInverseTrans <- function(x) {
    return(x)
}

myTrans <- scales::trans_new("myDummy",
                             transform = myDummyTrans,
                             inverse = myDummyInverseTrans)

set.seed(1)
values <- rnorm(10000, mean = 0, sd = 1)
myData <- data.frame(value = values)

p <- ggplot(data = myData,
            aes(x = value)) + 
    geom_density()

#debug(myDummyTrans)

sc <- scale_x_continuous(limits = c(-6, 6),
                         trans = myTrans)

p + sc
@clauswilke
Copy link
Member

Do you happen to know where in the ggplot2 code this additional call was inserted? It may help us figure out why this change was introduced.

@phauchamps
Copy link
Author

I found it here:

# Ensure limits don't exceed domain (#980)

@teunbrand
Copy link
Collaborator

teunbrand commented Dec 12, 2022

This was done as part of #4775, to ensure break calculations can be performed when expanded limits exceeded the domain. I think if a transformation has known limits, e.g. [-1.0e99, 1.0e99], than that should be the domain of the transformation. However, I don't know whether the logicle transformation has known limits.

@phauchamps
Copy link
Author

The domain of the logicle transformation is ]-Inf, +Inf[
I don't think that calling the transformation explicitly on the edges of the domain is good practice as, in many cases, the transformation will not be defined on the edges themselves. For example, the log() transformation has ]0, +Inf[ as domain, but log(0) will potentially fail, and the result of calling the transformation object is likely to be implementation dependent. If the transformtion returns NA, then you are ready to go, but if it complains you will be stuck.

@clauswilke
Copy link
Member

I think it's reasonable to expect transformations to be able to transform their domain. Inf values are allowed, so the log transformation for example should return -Inf, Inf when asked to transform its domain.

I can't think of any mathematical situation where a transformation wouldn't be able to handle its domain edges, under the condition that infinite values are possible as return values.

Maybe this should be adopted as a formal position and added to the documentation in the scales package.

@phauchamps
Copy link
Author

Issue closed and replaced by: r-lib/scales#375

Specific problem with ggcyto was handled in: RGLab/ggcyto#88

Thanks @clauswilke and @teunbrand for your help !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants