dmt
dmt

Reputation: 2183

Manually change colour of one factor level in ggplot2 stacked barplot

I'm giving a presentation, and would like to highlight the rate of occurrence of one of my factor levels on a slide by retaining the colour of this particular factor level, whilst greying out the other factor levels across other variables.

enter image description here

Using the Arthritis data set in the vcd library as an example:

library(vcd)
ggplot(Arthritis, aes(x = Sex, fill = Improved)) + geom_bar(position = "fill")

When, for example, I’m telling the audience about the marked improvement in the males, can I have a version of the plot which retains the colour of marked improvement in males, but greys out everything else? Preferably by using different shades of grey to keep the boundaries?

Upvotes: 2

Views: 3417

Answers (4)

missuse
missuse

Reputation: 19716

Consider this example:

library(scales)
library(ggplot2)

ggplot(Arthritis)+
  geom_bar(aes(x = Sex, group = Improved), fill = c("red", "blue", "green", "yellow", "grey50", "black"), position = "fill")

enter image description here

To change the specified field, while others keep the default ggplot colors:

ggplot(Arthritis)+
  geom_bar(aes(x = Sex,
               group = Improved),
           fill = c(rev(hue_pal()(3)),
                    "black",
                    hue_pal()(3)[2:1]),
            position = "fill")

enter image description here

or to grey out the rest with shades

ggplot(Arthritis)+
  geom_bar(aes(x = Sex,
               group = Improved),
           fill = c(paste0("grey", 7:9*10),
                    hue_pal()(3)[3],
                    paste0("grey", 8:9*10)),
           position = "fill")

enter image description here

to keep the legend just plot the above over your initial layer:

ggplot(Arthritis)+
  geom_bar(aes(x = Sex, fill = Improved),  position = "fill")+
  geom_bar(aes(x = Sex,
               group = Improved),
           fill = c(paste0("grey", 7:9*10),
                    hue_pal()(3)[3],
                    paste0("grey", 8:9*10)),
           position = "fill")

enter image description here

Upvotes: 2

mpalanco
mpalanco

Reputation: 13570

Another option is to replace the data points we'd like to highlight by NAs and then use scale_fill_grey to colour them with the argument na.value. We relabel the legend manually to show the original nomenclature.

  • Highlight all Marked

    library(dplyr)    
    ggplot(Arthritis %>% 
                 mutate(Improved = replace(Improved, Improved == "Marked", NA))) + 
          geom_bar(position = "fill", aes(x = Sex, fill = Improved))+
          scale_fill_grey(start = 0.8, end = 0.6, na.value = "RoyalBlue", 
                          labels = c("None", "Some", "Marked"))
    

    enter image description here

  • Highlight Male Marked

    ggplot(Arthritis %>% 
             mutate(Improved = replace(Improved, Improved== "Marked" & Sex == "Male", NA))) + 
      geom_bar(position = "fill", aes(x = Sex, fill = Improved))+
      scale_fill_grey(start = 0.8, end = 0.2, na.value = "RoyalBlue",
                      labels = c("None", "Some", "Marked", "Marked"))
    

    enter image description here

    Upvotes: 1

  • yutannihilation
    yutannihilation

    Reputation: 808

    You can add a column which contains the map of colors and use it with scales_fill_identity().


    reprex::reprex_info()
    #> Created by the reprex package v0.1.1.9000 on 2017-11-18
    
    library(vcd)
    #> Loading required package: grid
    
    lvls <- levels(Arthritis$Improved)
    color_maps <- scales::grey_pal(start = 0.8, end = 0.9)(length(lvls))
    names(color_maps) <- lvls
    
    
    library(dplyr, warn.conflicts = FALSE)
    
    Arthritis_w_fill <- Arthritis %>%
      mutate(
        fill = if_else(
          Sex == "Male" & Improved == "Marked",
          "blue",
          color_maps[Improved]
      )
    )
    
    
    library(ggplot2)
    
    ggplot(Arthritis_w_fill, aes(x = Sex, fill = fill)) +
      geom_bar(position = "fill") +
      scale_fill_identity(guide = "legend",
                          breaks = c(color_maps, "blue"),
                          labels = c(lvls, 'Sex == "Male" & Improved == "Marked"'))
    

    Upvotes: 0

    Mako212
    Mako212

    Reputation: 7292

    Add

    scale_fill_manual(values=c("Marked" = "RoyalBlue", "Some" = "DarkGrey", "None"="LightGrey"))

    Full ggplot call:

    ggplot(Arthritis, aes(x = Sex, fill = Improved)) + 
      geom_bar(position = "fill")+
      scale_fill_manual(values=c("Marked" = "RoyalBlue", "Some" = "DarkGrey", "None"="LightGrey"))
    

    enter image description here

    Upvotes: 1

    Related Questions