Change colours to defined palette for ggplot objects
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 postp <- ggplot(df, aes(x=TS, y=price, group=stock))
Examples:
# NB: custom_pal is defined in the OP's postchange_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 postp <- ggplot(df, aes(x=TS, y=price, group=stock))
Examples:
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')