Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing colour schemes between facets

Tags:

r

ggplot2

I have a data.frame, something like the following:

set.seed(100)

df <- data.frame(year = rep(2011:2014, 3), 
                 class = rep(c("high", "middle", "low"), each = 4), 
                 age_group = rep(1:3, each = 4), 
                 value = sample(1:2, 12, rep = TRUE))

and I am looking to produce, by facet-ing (by the variable age_group) three plots which look similar to those produced by the following code:

library(ggplot2)
blue <- c("#bdc9e1", "#74a9cf", "#0570b0")
ggplot(df) + geom_bar(aes(x = year, y = value, 
                          fill = factor(class, levels = c("high", "middle", "low"))), 
                      stat = "identity") + 
  scale_fill_manual(values = c(blue)) +
  guides(fill = FALSE)

however, where each facet has a different colour scheme where all the colours are specified by myself.

I appear to want a more specific version of what is going on here: ggplot2: Change color for each facet in bar chart

So, using the data I have provided, I am looking to get three facet-ed plots, split by age_group where the fill is given in each plot by the level of class, and all colours (9 total) would be specified manually by myself.

Edit: For clarification, the facet that I would like to end up with is indeed provided by the following code:

ggplot(df) + geom_bar(aes(x = year, y = value, 
                          fill = factor(class, levels = c("high", "middle", "low"))), 
                      stat = "identity") + 
  scale_fill_manual(values = c(blue)) +
  guides(fill = FALSE) + 
  facet_wrap(~ age_group)

with the added level of control of colour subset by the class variable.

like image 731
Ross Avatar asked Jan 05 '17 19:01

Ross


1 Answers

I'm not entirely sure why you want to do this, so it is a little hard to know whether or not what I came up with addresses your actual use case.

First, I generated a different data set that actually has each class in each age_group:

set.seed(100)

df <- data.frame(year = rep(2011:2014, 3), 
                 class = rep(c("high", "middle", "low"), each = 12), 
                 age_group = rep(1:3, each = 4), 
                 value = sample(1:2, 36, rep = TRUE))

If you are looking for a similar dark-to-light gradient within each age_group you can accomplish this directly using alpha and not worry about adding extra data columns:

ggplot(df) +
  geom_bar(aes(x = year, y = value, 
               fill = factor(age_group)
               , alpha = class ), 
           stat = "identity") + 
  facet_wrap(~age_group) +
  scale_alpha_discrete(range = c(0.4,1)) +
  scale_fill_brewer(palette = "Set1"
                    , name = "age_group")

Here, I set the range of the alpha to give reasonably visible colors, and just chose a default palette from RColorBrewer to show the idea. This gives:

enter image description here

It also gives a relatively usable legend as a starting point, though you could modify it further (here is a similar legend answer I gave to a different question: https://stackoverflow.com/a/39046977/2966222 )

Alternatively, if you really, really want to specify the colors yourself, you can add a column to the data, and base the color off of that:

df$forColor <-
  factor(paste0(df$class, " (", df$age_group , ")")
         , levels = paste0(rep(c("high", "middle", "low"), times = 3)
                           , " ("
                           , rep(1:3, each = 3)
                           , ")") )

Then, use that as your fill. Note here that I am using the RColorBrewer brewer.pal to pick colors. I find that the first color is too light to show up for bars like this, so I excluded it.

ggplot(df) +
  geom_bar(aes(x = year, y = value, 
               fill = forColor), 
           stat = "identity") + 
  scale_fill_manual(values = c(brewer.pal(4, "Blues")[-1]
                               , brewer.pal(4, "Reds")[-1]
                               , brewer.pal(4, "Purples")[-1]
                               )
                    , name = "Class (age_group)") +
  facet_wrap(~age_group)

gives:

enter image description here

The legend is rather busy, but could be modified similar to the other answer I linked to. This would then allow you to set whatever 9 (or more, for different use cases) colors you wanted.

like image 200
Mark Peterson Avatar answered Sep 30 '22 06:09

Mark Peterson