-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Vignette ggplot2-in-packages does not cover programmatically passing NULL to aes() #6208
Comments
Here is the duct-tape work around I came up with, based on some of the solutions people posted in this StackExchange question: plot_workaround <- function(dat,xvar,yvar,colorvar=NULL,shapevar=NULL) {
aes_args <- list(x=xvar,y=yvar,color=colorvar,shape=shapevar)
aes_args <- lapply(aes_args, function(x) { if(!is.null(x)) rlang::data_sym(x) } )
myplot <- ggplot(dat,aes(!!!aes_args)) + geom_point()
return(myplot)
}
# Scenario 1: Passing NULL for an unused aesthetic
plot_workaround(plotdat,'weight','height',colorvar='employment',shapevar=NULL) # This works
# Scenario 2: The variable used for shape isn't determined until the code runs
whichvar <- sample(c('sex','employment'),1)
plot_workaround(plotdat,'weight','height',colorvar='age',shapevar=whichvar) # This works
# Scenario 3: Both things at once
whichvar <- NULL
plot_workaround(plotdat,'weight','height',colorvar='age',shapevar=whichvar) # This works Hopefully there's a shorter/cleaner "best practices" way to achieve this that can be added to the documentation/vignette, but in the meantime I'm sharing this work-around in case it's of use to anyone else. |
Thanks for the report! I'm not sure if Currently, I don't see a clear path to do this the tidy eval way, as the I'm personally in favour of recognising or making this intended usage. I use it all the time to escape a particular global aesthetic in single layers. |
You're right!! And my work-around only covers the more limited situation "sometimes this function makes ggplots with this aesthetic and sometimes without" (a way to do that programmatically seems like an essential feature). But in a situation like you describe (something is set at as a global aesthetic, but then you want to disable it for one layer), it would take a longer/more complex workaround than mine, since mine just silently drops/omits NULLs. Since setting an aesthetic to NULL is useful for both situations, I hope it's recognized as (or made) an intended usage and gets a supported tidy eval way to do it. |
one concept that I always need to explain to newcomers to ggplot2 is the "precedence" between what is inside aes and what is outside library(ggplot2) ggplot(mtcars,aes(cylf,mpg,col=cylf))+ ggplot(mtcars,aes(cylf,mpg,col=cylf))+ ggplot(mtcars,aes(cylf,mpg,col=cylf))+ ggplot(mtcars,aes(cylf,mpg,col=cylf))+ ggplot(mtcars,aes(cylf,mpg,col=cylf))+ ggplot(mtcars,aes(cylf,mpg,col=cylf))+ errorsggplot(mtcars,aes(cylf,mpg,col=cylf))+ there is also a use case when you want to transform your variable inline example: |
Interesting point about the precedence, but it still doesn’t cover the basic scenario of “sometimes this function makes ggplots with this aesthetic and sometimes without”. When a user passes a function variable names to map to ggplot aesthetics, that should include being able to pass something that says not to map that aesthetic. Even a basic scatter plot with three “optional” aesthetics (fill, color, shape) would need 2^3 = 8 if statements to handle all possible combinations of NULL/non-NULL values if the NULLs couldn’t be passed on to aes(), eg. if(!is.null(colorvar) & is.null(fillvar) & is.null(shapevar)) {
myplot <- ggplot(dat,aes(x=.data[[xvar]],y=.data[[yvar]],color=.data[[colorvar]])) + geom_point()
} else if(!is.null(colorvar) & !is.null(fillvar) & is.null(shapevar)) {
myplot <- ggplot(dat,aes(x=.data[[xvar]],y=.data[[yvar]],color=.data[[colorvar]],fill=.data[[fillvar]])) + geom_point()
} else if(!is.null(colorvar) & !is.null(fillvar) & !is.null(shapevar)) {
myplot <- ggplot(dat,aes(x=.data[[xvar]],y=.data[[yvar]],color=.data[[colorvar]],fill=.data[[fillvar]],shape=.data[[shapevar]])) + geom_point()
} else if(is.null(colorvar) & !is.null(fillvar) & !is.null(shapevar)) {
myplot <- ggplot(dat,aes(x=.data[[xvar]],y=.data[[yvar]],fill=.data[[fillvar]],shape=.data[[shapevar]])) + geom_point()
}
# And so on for the rest of the combinations aes() itself has no trouble with an aesthetic being set to NULL, the problem is just that there’s no documented tidy eval way to pass a NULL contained in a variable to aes(). Which was an important thing aes_string() could handle. |
you also have the size aes that apply to scatter plots and if we add lines then you add group, linewidth and linetype... |
I was also able to find an example of aesthetics being mapped to NULL in the ggplot2 documentation, which suggests this is an intended usage:
So hopefully if setting aesthetics to NULL in aes() is an intended usage, there can be a documented tidy eval way to take a NULL contained in a variable and pass it to aes(). |
Thanks for finding this, that settles the 'is it intended' question then as 'yes'.
We'd first need to find a way before we can document it.
I'm not sure what exactly the intent is here? In dev ggplot2 this no longer errors, but throws a warning: "Ignoring empty aesthetic: |
apologies yes I am using latest released ( I also remembered when I had to use shquote https://stackoverflow.com/questions/28777626/how-do-i-combine-aes-and-aes-string-options ) my intent is that we cover all potential programming needs showing how to move away from ae_string once and for all |
Yeah that tracks, but I what is the intent of |
I remember needing this when I was programming a shiny app and then user had several ways to select options in the UI: |
Thanks that makes sense. I suppose with the dev version, you could just use However, that is a different issue from programatically passing |
I found a problem with the ggplot2-in-packages vignette.
I expected it to cover how to fully replace all behaviors from the now-deprecated aes_string() function. However, both of its recommended solutions (the .data pronoun and the embrace operator) have limitations that make them difficult to use to replace aes_string(), and the vignette does not cover how to work around these limitations.
Here is some test data for demonstrations:
The problem with using the .data pronoun is that the .data pronoun cannot handle situations where an aesthetic is set to NULL to indicate it should not be used:
The embrace operator can handle NULL, but the problem with using the embrace operator is that it does not work when the variable name (or NULL) that will be used for an aesthetic is determined when the code runs and cannot be written into the function call:
Both of these scenarios could be handled easily and seamlessly by aes_string():
Please consider updating the ggplot2-in-packages vignette to demonstrate how tidy evaluation idioms can be used to allow a function which uses ggplot() to handle both of these scenarios.
(I am submitting this as a bug report rather than a StackExchange question because, while I can figure out a duct-tape work around for these issues, I think it is important that the ggplot authors' intended/best practice solution to these issues be included in the official documentation. Or if there is currently no best practice solution that can handle both scenarios, there may be a need to create one to help users move away from aes_string().)
The text was updated successfully, but these errors were encountered: