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

Manual scales for specific levels only #2627

Closed
Freguglia opened this issue May 17, 2018 · 10 comments
Closed

Manual scales for specific levels only #2627

Freguglia opened this issue May 17, 2018 · 10 comments
Labels
feature a feature request or enhancement

Comments

@Freguglia
Copy link

As an example:

library(ggplot2)
ggplot(iris,aes(x=Petal.Length,y=Petal.Width,color=Species)) +
  geom_point() + 
  scale_color_manual(values=c("versicolor" = "pink",
                              "virginica" = "red",
                              "setosa" = "green"))

This piece of code works fine, but let's say I want to have pink color for versicolor and I really don't care what color is picked for the others. There could be some kind of "auto-completion" for manual scales so that when I try something like the code below, the levels I don't care about have their color value automatically picked (possibly with a warning). Right now an incomplete manual color scale throws an error. This might be specially useful if (a) you're too lazy to type too many color names you don't really care or (b) the number of levels may vary but there is always one you're most interested in.

library(ggplot)
ggplot(iris,aes(x=Petal.Length,y=Petal.Width,color=Species)) +
  geom_point() + 
  scale_color_manual(values=c("versicolor" = "pink"))
@clauswilke
Copy link
Member

I would speak out against this proposal. It will lead to some really ugly plots. Picking colors that work well with an existing color scale is even more difficult than just creating an entire color scale from scratch, so whoever would use this functionality would unlikely have the skills to actually pick appropriate colors.

If somebody wants to implement this in an extension package they are free to do so. But even there, I think what would be needed is a highlight scale that allows the user to define the highlighted categories and then picks all the colors, both highlighted and not.

@clauswilke clauswilke added the feature a feature request or enhancement label May 17, 2018
@Freguglia
Copy link
Author

I built an extension package as @clauswilke suggested. In case someone else is interested: https://github.com/Freguglia/ggfocus

@clauswilke
Copy link
Member

@Freguglia I think this is a good idea. I would encourage you, however, to think whether you can implement this within the regular grammar rather than providing a special function that wraps the entire plot. Is there any reason why you can't simply write a scale_focus() scale that takes a list of aesthetics as an argument?

@Freguglia
Copy link
Author

Freguglia commented May 25, 2018

Yes, I do agree that the regular grammar would be a better option. I was first trying to implement color_scale_focus() for example until I realized that in order to create the appropriate color scale I would need to access the data. The idea was requiring the typing for levels of interest only, but the other levels names are necessary to create the appropriate color scale.

In short, the function wraps the entire plot because I can't figure out how to (a) create the color scale without the complete list of levels or (b) access the data from the function without having the plot as an argument. But I will think more about it to see if I can figure out a solution with the regular grammar.

@clauswilke
Copy link
Member

clauswilke commented May 25, 2018

You may have to reimplement the train_df() or train() functions for your scale.

ggplot2/R/scale-.r

Lines 40 to 57 in 1f9ef73

# Train scale from a data frame.
#
# @return updated range (invisibly)
# @seealso [scale_train()] for scale specific generic method
train_df = function(self, df) {
if (empty(df)) return()
aesthetics <- intersect(self$aesthetics, names(df))
for (aesthetic in aesthetics) {
self$train(df[[aesthetic]])
}
invisible()
},
# Train an individual scale from a vector of data.
train = function(self, x) {
stop("Not implemented", call. = FALSE)
},

@Freguglia
Copy link
Author

@clauswilke Do you think creating a new class, ggf for example, writing that scale_focus() function returning an object of this class and then modifying "+.ggf"() to return the function that wraps everything (only when one argument is a ggplot and the other is a ggf) is a valid approach to implement the regular grammar?

If built appropriately, the regular grammar would work, as calling a ggplot + a ggf would be exactly the same as calling the function that wraps everything, but this seems a 'hacky' solution.

@clauswilke
Copy link
Member

You should probably coordinate with @yutannihilation's gghighlight:
https://github.com/yutannihilation/gghighlight

@yutannihilation
Copy link
Member

returning an object of this class and then modifying "+.ggf"() to return the function that wraps everything

In this approach, you may find ggplot_add() interesting.

c.f. https://yutani.rbind.io/post/2017-11-07-ggplot-add/

@hadley
Copy link
Member

hadley commented Jun 18, 2019

Closing, since development seems to be happening in an extension package.

@hadley hadley closed this as completed Jun 18, 2019
@lock
Copy link

lock bot commented Dec 15, 2019

This old issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with reprex) and link to this issue. https://reprex.tidyverse.org/

@lock lock bot locked and limited conversation to collaborators Dec 15, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature a feature request or enhancement
Projects
None yet
Development

No branches or pull requests

4 participants