Home > Enterprise >  Highlight top 3 in ggplot2 with vector of colors
Highlight top 3 in ggplot2 with vector of colors

Time:05-31

I have a code below and I would like to color the top 3 with the selected colors. Many thanks in advance.

    library(ggplot2)
library(dplyr)

df <- data.frame(dose = c("D0.5", "D1", "D2", "D3", "D4", "D5"),
                 len = c(4.2, 10, 29.5, 5, 7, 15))

df <- dplyr::mutate(df, top3 = rank(-len) %in% 1:3)


# Basic barplot
p <- ggplot(data = df, aes(x = reorder(dose, -len), y = len))  
  geom_bar(stat = "identity", fill = ifelse(df$top3 == TRUE,  c("blue", "yellow", "green"), "grey50"))   
           #color = ifelse(df$top3 == TRUE,  c("red", "yellow", "green"), "grey50"))  
  coord_flip()
p

CodePudding user response:

You could do something like this:

df <- data.frame(dose = c("D0.5", "D1", "D2", "D3", "D4", "D5"),
                 len = c(4.2, 10, 29.5, 5, 7, 15))

df <- df |> 
  dplyr::arrange(desc(len)) |>
  dplyr::mutate(
    rank = factor(dplyr::row_number(), labels = dose)
  )

fill_colors = c("blue", "yellow", "green")
other_colors = rep("grey50", nrow(df)-length(fill_colors))
my_scale  <- c(fill_colors, other_colors)

withr::with_options(
  list(ggplot2.discrete.fill = my_scale),
  ggplot(data = df, aes(x = reorder(dose, -len), y = len))  
  geom_bar(stat = "identity", aes(fill = rank))  
  scale_fill_discrete()  
  coord_flip()
)

enter image description here

CodePudding user response:

you can add an additional color rank column in you data frame and change the colors accordinly with scale_fill_manual:

library(ggplot2)
library(dplyr)

df <- data.frame(dose = c("D0.5", "D1", "D2", "D3", "D4", "D5"),
                 len = c(4.2, 10, 29.5, 5, 7, 15))

df <- dplyr::mutate(df, top3 = rank(-len))
df <- dplyr::mutate(df, col_rank = as.character( ifelse(top3 > 3, 4, top3)))

# Basic barplot
p <- ggplot(data = df, aes(x = reorder(dose, -len), y = len, fill = col_rank))  
  geom_bar(stat = "identity")   
  coord_flip()  
  scale_fill_manual(values = c("1" = "blue", "2" = "yellow", "3" = "green", "4" = "grey50"))
p

CodePudding user response:

A slight twist to the other suggested options, with less code. I think your idea of an if else statement is generally ok - however, your use with $ in aes seems dangerous. The reason we can do this is that the number of top rows matches the length of your color vector (in this case: 3)

library(ggplot2)
library(dplyr)
df <- data.frame(dose = c("D0.5", "D1", "D2", "D3", "D4", "D5"),
                 len = c(4.2, 10, 29.5, 5, 7, 15))

mycols <- c("blue", "yellow", "green")

df <- df %>%
  arrange(desc(len)) %>%
  mutate(fills = ifelse(row_number() <= length(mycols), mycols, "grey50"))

## swapping x and y makes coord_flip obsolete
## using I in aes is the same as adding "scale_fill_identity" at the end
ggplot(data = df, aes(x = len, y = reorder(dose, -len)))  
  geom_col(aes(fill = I(fills))) 

Created on 2022-05-30 by the reprex package (v2.0.1)

  • Related