I would like to define a color palette for every plot built in a markdown document. In essence this would overwrite the default choices.
There are several very old answers -- thanks for the links here and here suggested by @dww -- that solve for old versions (specifically calling out a solution on 0.8.2 when the modern release several major releases ahead, currently at 3.2.x).
I'll illustrate the closest use case, setting themes. In the case of general purpose themes, this is trivial: rather than appending + theme_minimal()
on every plot, I can instead set the theme which persists across all plots.
library(ggplot2)
d <- diamonds[sample(1:nrow(diamonds), 1000), ]
## without theming
ggplot(d, aes(x=carat, y=price, color=clarity)) +
geom_point() +
theme_minimal() # must set this theme call for every plot
## setting theme
theme_set(theme_minimal())
ggplot(d, aes(x=carat, y=price, color=clarity)) +
geom_point() # plot in theme, for all subsequent plots
Is there a similar, modification that exists to set the color palette throughout? For example, a theme-based replacement for calling,
ggplot(d, aes(x=carat, y=price, color=clarity)) +
geom_point() +
scale_color_brewer(palette='Set2') # requesting a global option to set this for all plots
The linked solution that does not depend on old versions instead overloads the entire ggplot function. That seems risky.
ggplot <- function(...) ggplot2::ggplot(...) + scale_color_brewer(palette = 'Set1')
There is a ggplot_global
environment which is used internally within ggplot2
but isn't exported. You can see its structure by temporarily unlocking the bindings of a ggplot function and modifying it to return the contents of the environment as a list. You can do this non-destructively like this:
library(ggplot2)
get_ggplot_global <- function()
{
unlockBinding("theme_set", as.environment("package:ggplot2"))
backup <- body(theme_set)[[5]]
body(theme_set)[[5]] <- substitute(return(as.list(ggplot_global)))
global_list <- theme_set(theme_bw())
body(theme_set)[[5]] <- backup
lockBinding("theme_set", as.environment("package:ggplot2"))
return(global_list)
}
global_list <- get_ggplot_global()
names(global_list)
#> [1] "date_origin" "element_tree" "base_to_ggplot" "all_aesthetics"
#> [5] "theme_current" "time_origin"
By examining this you can see that ggplot global environment has an object called theme_current
, which is why you can set the various line, text and axis elements globally including their colours.
When you are talking about a colour scheme in your question, you are referring to the colours defined in a scale object. This is not part of the ggplot_global environment, and you can't change the default scale object because there isn't one. When you create a new ggplot()
, it has an empty slot for "scales".
You therefore have a few options:
my_ggplot <- function(...) ggplot2::ggplot(...) + scale_color_brewer()
The best thing might be to just write a wrapper around ggplot. However, the third option is also quite clean and idiomatic. You could achieve it like this:
set_scale <- function(...)
{
if(!exists("doc_env", where = globalenv()))
assign("doc_env", new.env(parent = globalenv()), envir = globalenv())
doc_env$scale <- (ggplot() + eval(substitute(...)))$scales$scales[[1]]
}
my_scale <- function() if(exists("doc_env", where = globalenv())) return(doc_env$scale)
You would use this by doing (for example)
set_scale(scale_color_brewer(palette = "Set2"))
At the start of your document.
So now you can just do + my_scale()
for each plot:
d <- diamonds[sample(1:nrow(diamonds), 1000), ]
ggplot(d, aes(x=carat, y=price, color=clarity)) +
geom_point() +
my_scale()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With