How to customize a color palette in r for ggplot?
Asked Answered
A

2

7

I'm using this code to plot a map of temperature change in North America:

ggplot(maps, aes(y=Latitude, x=Longitude, z=variable)) +
  ggtitle(title)+
  scale_fill_brewer(palette = "Spectral")+
  geom_contour_filled(breaks = c(-Inf,-2., -1.5, -1., -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5, 7, 9, 11,Inf))+
  xlim(-146,-44)+
  ylim(35,90)+
  theme(plot.title = element_text(hjust = 0.5))

And I want to change the color palette for better visualization. Currently, it writes scale_fill_brewer(palette = "Spectral"), and I'm going to change it into a custom palette

colors <- c(rgb(10,40,100,max=255),rgb(51,102,217,max=255),rgb(105,138,236,max=255),rgb(151,180,250,max=255),rgb(204,217,255,max=255),rgb(255,245,204,max=255),rgb(255,224,153,max=255),rgb(255,203,102,max=255),rgb(255,180,51,max=255),rgb(255,140,51,max=255),rgb(255,85,0,max=255),rgb(230,40,30,max=255),rgb(191,0,0,max=255),rgb(140,0,0,max=255),rgb(108,0,0,max=255),rgb(110,0,70,max=255))

Using scale_fill_brewer(palette = colors)will end with error, I also tried palette(colors), and it also doesn't work.

How can I custom a palette that the argument can recognize?

Aquilegia answered 19/6, 2020 at 1:51 Comment(2)
Use scale_fill_manual(..., values=colors)Antoniaantonie
r-bloggers.com/creating-color-palettes-in-r this article may be helpful.Grissom
R
2

If I understand your question correctly, you want to create a custom scale_... function. In short, this is dipping somewhat deeper into the source code.

I will show one approach which will simply modify the existing functions in the packages RColorBrewer, scales, and of course ggplot2.

  1. The core is to modify RcolorBrewer::brewer.pal, which I guess is bascially what you want. Seeing the code, it selects from a list of colors the right one, depending on your "n". And this is what you need to manually create. I just copied the colors from the palette "YlOrBr". Something to consider: Brewer palettes are not random, they have been tested and created for being recognizable for printing, copying and colorblindness, so I am not sure if it is very clever to create your own palette. Have a look at https://colorbrewer2.org/ to find suitable palettes.
  2. modify the underlying color selector scales:::brewer_pal
  3. modify the scale_fill/scale_color function

I've boiled down the functions to the cores, so they won't make the usual checks and are less flexible. You can modify the original functions to get this functionality back.

library(ggplot2)

mybrewerpal <- function(n, name) {# modified RcolorBrewer::brewer.pal
## the first call to switch would not be necessary in this example,
## but I leave it in order to make the underlying structure in brewer.pal clearer
  switch(name, mypal = switch(n - 2, rgb(c(255, 254, 217), c(247, 196, 95), c(188, 79, 14), maxColorValue = 255),
    rgb(c(255, 254, 254, 204), c(255, 217, 153, 76), c(212, 142, 41, 2), maxColorValue = 255),
    rgb(c(255, 254, 254, 217, 153), c(255, 217, 153, 95, 52), c(212, 142, 41, 14, 4), maxColorValue = 255),
    rgb(c(255, 254, 254, 254, 217, 153), c(255, 227, 196, 153, 95, 52), c(212, 145, 79, 41, 14, 4), maxColorValue = 255),
    rgb(c(255, 254, 254, 254, 236, 204, 140), c(255, 227, 196, 153, 112, 76, 45), c(212, 145, 79, 41, 20, 2, 4), maxColorValue = 255),
    rgb(c(255, 255, 254, 254, 254, 236, 204, 140), c(255, 247, 227, 196, 153, 112, 76, 45), c(229, 188, 145, 79, 41, 20, 2, 4), maxColorValue = 255),
    rgb(c(255, 255, 254, 254, 254, 236, 204, 153, 102), c(255, 247, 227, 196, 153, 112, 76, 52, 37), c(229, 188, 145, 79, 41, 20, 2, 4, 6), maxColorValue = 255)
  ))
}

brewer_pal2 <- # modified from scales:::brewer_pal
  function() { # stripped down all arguments, just to show the core
    function(n) {
      mybrewerpal(n, "mypal") ##modified, usually this is selected by a function 
      ## with type and name as arguments, selecting a palette from a list called scales:::brewer
    }
  }

scale_fill_custom <- ### modified from scale_fill_brewer, removed some arguments
  function (..., aesthetics = "fill") {
    discrete_scale(aesthetics, "custom", brewer_pal2(), ...) ## give a new name to the
    ## scale, it will create a new Scale object.  
  }

p <- 
  ggplot(mtcars, aes(x = mpg, y = disp)) +
  scale_fill_custom()

p + geom_point(shape = 21, aes(fill = as.factor(cyl))) 

p + geom_point(shape = 21, aes(fill = as.factor(carb))) 

Rematch answered 19/6, 2020 at 11:17 Comment(3)
Genius, Thank you so much!Aquilegia
Interestingly I saw on the day you posted this ggplot2 3.3.2 came out. from 3.3.2 and forward has options to change colors see the help doc here: ggplot2.tidyverse.org/news/#ggplot2-332Cyna
Default discrete color scales are now configurable through the options() of ggplot2.discrete.colour and ggplot2.discrete.fill. When set to a character vector of colour codes (or list of character vectors) with sufficient length, these colours are used for the default scale. See help(scale_colour_discrete) for more details and examples (@cpsievert, #3833). - from the change logCyna
C
0

Other solution without build personal functions is this:

You can call directly discrete_scale() in ggplot and for creating n colors you have to call grDevices::colorRampPalette(YOUR_COLORS).

set.seed(1)
tibble(score = round(runif(100,1,10))) %>% 
  count(score) %>%
  ggplot(aes(x = score, y = n, fill = score %>% as.factor())) +
  geom_col() +
  scale_x_continuous(breaks = 1:10) +
  scale_y_continuous(labels = scales::percent_format(scale = 1)) +
  discrete_scale("fill", scale_name = "personal", palette = grDevices::colorRampPalette(c("#EE602D", "#FFCF26", "#01AEE6"))) +
  theme_minimal() +
  theme(legend.position = "none") +
  labs(x = NULL, y = NULL)

enter image description here

Complimentary answered 15/1 at 13:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.