I would like to change the default colours to a specific palette for all geom_*
type objects by using a function.
Below is an example for geom_lin
The following should do what you're after. Note that it only changes colours that are mapped to variables. Colour passed directly to the geom_*
won't be affected (there's an example below). For an approach that modifies colour
or fill
(whichever is mapped first), see the bottom half of this post.
change_colours <- function(p, palette) {
n <- nlevels(p$data[[deparse(p$mapping$group)]])
tryCatch(as.character(palette),
error=function(e) stop('palette should be a vector of colours', call.=FALSE))
if(n > length(palette)) stop('Not enough colours in palette.')
pal <- function(n) palette[seq_len(n)]
p + theme_light() + discrete_scale('colour', 'foo', pal)
}
# Here, df is from the OP's post
p <- ggplot(df, aes(x=TS, y=price, group=stock))
# NB: custom_pal is defined in the OP's post
change_colours(p + geom_line(aes(colour=stock)), custom_pal)
change_colours(p + geom_point(aes(colour=stock)), custom_pal)
And with a different palette:
change_colours(p + geom_smooth(aes(colour=stock)),
c('firebrick', 'midnightblue', 'violet', 'seagreen'))
As mentioned above, this will only change colour
and fill
that are mapped to variables. For example, it'll have no effect on the colours for the following:
change_colours(p + geom_point(colour=rep(c('tomato', 'hotpink', 'cadetblue'), each=300)),
custom_pal)
In response to the OP's comment, you can easily detect what types of mappings are being used (e.g. alpha
, colour
, fill
). Just look at p$layers[[1]]$mapping
.
If we assume that the first fill
or colour
mapping of the first layer is the mapping for which you want to change colours, you can do:
change_colours <- function(p, palette, type) {
n <- nlevels(p$data[[deparse(p$mapping$group)]])
tryCatch(as.character(palette),
error=function(e) stop('palette should be a vector of colours', call.=FALSE))
if(n > length(palette)) stop('Not enough colours in palette.')
if(missing(type))
type <- grep('colour|fill', names(p$layers[[1]]$mapping), value=TRUE)[1]
pal <- function(n) palette[seq_len(n)]
p + theme_light() + discrete_scale(type, 'foo', pal)
}
# Here, df is from the OP's post
p <- ggplot(df, aes(x=TS, y=price, group=stock))
Changing fill instead of colour:
change_colours(p + geom_point(aes(fill=stock), pch=21),
c('white', 'grey50', 'grey80'))
Showing priority of first mapped colour/fill aesthetic:
change_colours(p + geom_point(aes(fill=stock, color=stock), pch=21) +
geom_smooth(aes(color=stock)),
c('black', 'grey50', 'grey80'))
change_colours(p + geom_point(aes(color=stock, fill=stock), pch=21) +
geom_smooth(aes(color=stock)),
c('black', 'grey50', 'grey80'))
Override the priority of the first mapped aesthetic with the type
argument, e.g.:
change_colours(p + geom_point(aes(color=stock, fill=stock), pch=21) +
geom_smooth(aes(color=stock)),
c('black', 'grey50', 'grey80'), type='fill')