Search code examples
rscaleggplot2

How to scale colour in ggplot for independent layer?


I have a data set that documents the energy use of three buildings. I have a melted data frame that can be mimicked from the diamonds set:

data <- melt(diamonds[,c('depth','table','cut','color')],id=c('cut','color'))

Essentially, I have heating ('depth') and cooling ('table') data for each month('cut') from three different buildings (7 'color' factors). I would like to plot the three buildings (7 'color' factors) side by side in a bar plot for each month ('cut').

I want the bars representing either cooling ('table') or heating ('depth') to vary their shade based on the building ('color' factor) while remaining grouped by month ('cut'). This is a bad way to visualize the diamonds data, but should work well for buildings as their heating and cooling months typically don't overlap. So far I have:

p <- ggplot(data,
        aes(color,value,group=cut))
p <- p + geom_bar(stat = 'identity',
              position = 'dodge',
              aes(fill = variable))
print(p)

I tried playing with scale_fill_manual, but couldn't think of a strategy that works:

colours <- c('#0000FF', '#0033FF', '#0066FF', '#FF0000', '#FF3300', '#FF6600')

p <- p + scale_fill_manual(values = colours,
                           group = data$variable)

Solution

  • With some trickery, it is possible. Deriving a data set based on diamonds was very good, but I want to work with a smaller data set

    set.seed(1234)
    data <-
    expand.grid(month = month.abb,
                building = c("Building A", "Building B", "Building C"),
                hc = c("Heating", "Cooling"))
    data$value <- rnorm(nrow(data), 60, 10)
    

    You want your fill colour to be based both on the variable (hc) and the building (building), so set it to that interaction.

    ggplot(data, aes(building,value,group=month)) + 
      geom_bar(stat = 'identity',
               position = 'dodge',
               aes(fill = interaction(building, hc)))
    

    enter image description here

    We can pick colors that represent different near shades to make these more like what you want. I used the middle of the "Blues" and "Reds" of the RColorBrewer palettes.

    colours <- c("#FC9272", "#FB6A4A", "#EF3B2C", "#9ECAE1", "#6BAED6", "#4292C6")
    # library("RColorBrewer")
    # colours <- c(brewer.pal(9,"Reds")[4:6], brewer.pal(9,"Blues")[4:6])
    

    and used scale_fill_manual to assign these colours.

    ggplot(data, aes(building,value,group=month)) + 
      geom_bar(stat = 'identity',
               position = 'dodge',
               aes(fill = interaction(building, hc))) +
      scale_fill_manual(values=colours)
    

    enter image description here

    The real trickery is in making the legend less convoluted. I just list 2 of the levels (the middle building in terms of color) and give them different names (and a different title for the legend).

    ggplot(data, aes(building,value,group=month)) + 
      geom_bar(stat = 'identity',
               position = 'dodge',
               aes(fill = interaction(building, hc))) +
      scale_fill_manual("Heating/cooling",
                        values=colours,
                        breaks=c("Building B.Heating", "Building B.Cooling"),
                        labels=c("Heating", "Cooling"))
    

    enter image description here