Change colours to defined palette for ggplot objects

前端 未结 1 698
你的背包
你的背包 2020-12-31 04:58

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

相关标签:
1条回答
  • 2020-12-31 05:35

    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)) 
    

    Examples:

    # 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))
    

    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')
    
    0 讨论(0)
提交回复
热议问题