Search code examples
rggplot2gghighlight

How do you map dynamic colors in ggplot using a highlighter column?


I'm attempting to use a highlighter column and gghighlight to only show show selected cars (from the mtcars dataset) in a plot. I'd expect the colors to match the car that's being highlighted given they're in the same row but the colors get mixed around.

Below is a fully reproducible sample using mtcars.

library(shiny)
library(tidyverse)
library(ggthemes)
library(gghighlight)

color_list <- c("darkred", "yellow3", "green4", "darkblue", "purple",
            "pink2", "burlywood1", "aquamarine", "orange3", "black")

mtcars_clean <- 
mtcars %>% 
rownames_to_column(var = "car") %>% 
head(10) %>% 
mutate(car_color = color_list) %>% 
glimpse()

View(mtcars_clean)

As you can see from the image link each car has a specific car_color that should display when the car is highlighted.

mtcars_clean table

selected_cars <- c("Mazda RX4", "Hornet 4 Drive", "Valiant", "Merc 240D", "Duster 360")

mtcars_test <- 
mtcars_clean %>% 
mutate(highlighter = case_when(car %in% selected_cars ~ "yes",
                               T ~ "no"),
       car_color = case_when(highlighter == "yes" ~ car_color,
                             T ~ "#C4CED4"))

p_test <-
mtcars_test %>%
ggplot(aes(x = mpg, y = reorder(car, mpg, max))) +
geom_col(aes(fill = car)) +
geom_text(data = mtcars_test %>%
              filter(car %in% selected_cars),
          aes(label = mpg, x = mpg + 1, col = highlighter)) +
theme_fivethirtyeight() +
theme(legend.position = "none") +
labs(title = "MPG by Car") +
scale_color_manual(values = c("black")) +
gghighlight(car %in% selected_cars)

p_test + scale_fill_manual(name = p_test$data$car, values = p_test$data$car_color)

However, as you can see from the plot below, the car 'Merc 240D' should be aquamarine, yet it's burlywood1. Valiant should be pink2, yet it's aquamarine. The cars don't keep the colors that belong to them from the car_color column.

mtcars_clean ggplot output

What's also bizarre is that the geom_text keeps the correct values, however the car_color moves around.


Solution

  • From the documentation in help(scale_fill_manual),

    Values: a set of aesthetic values to map data values to. The values will be matched in order (usually alphabetical) with the limits of the scale, or with breaks if provided. If this is a named vector, then the values will be matched based on the names instead. Data values that don't match will be given na.value.

    We can use this to change the code slightly and make it work as expected

    cols <- p_test$data$car_color
    names(cols) <- p_test$data$car
    p_test + scale_fill_manual(values = cols)
    

    enter image description here

    Alternatively we could use breaks

    breaks: One of:
    NULL for no breaks
    waiver() for the default breaks (the scale limits)
    A character vector of breaks
    A function that takes the limits as input and returns breaks as output

    eg. we could also do

    p_test + scale_fill_manual(values = p_test$data$car_color, breaks = p_test$data$car)
    

    Similar methods can be used together with existing aestethics within the aes object.