'How to avoid similar colors being picked for fill and color scales?

Context: I would like to use viridis color palette for a color scale and a fill scale within the same plot. The geoms I use do not all have a color or a fill argument so it is not possible to "blend" everything into one scale. In other words, I want to use the same palette but make sure that each color from this palette is used only once across scales, while keeping the properties of the viridis palette (printing and colorblind friendly).

Problem: when using scale_color_viridis_d() and scale_fill_viridis_d() I end up with colors being shared across the fill and the color scale which make the final plot difficult to read.

Question: is it possible to tell ggplot to pick different colors within the viridis palette across the fill and the color scales?

library(ggplot2)
# example dataset
zones <- data.frame(starts = c(1, 3, 4),
                    ends = c(2, 3.75, 5),
                    item = rep("A", 3))
# current plot, note that the same color from viridis scale is picked
ggplot(data = zones) +
  geom_rect(aes(xmin = starts, xmax = ends, ymin = -Inf, ymax = Inf, fill = "areas")) +
  geom_segment(aes(x = starts, xend = ends, y = item, yend = item, color = "segments")) +
  scale_color_viridis_d() +
  scale_fill_viridis_d(alpha = 0.5)

Expected output: different colors from the same palette being used for the fill and the color scales. Here I used begin = and end = arguments from the scale_*_viridis_d() functions but I feel this is not optimal as many colors are "lost" by spliting the palette like this.

# look of the expected output
ggplot(data = zones) +
  geom_rect(aes(xmin = starts, xmax = ends, ymin = -Inf, ymax = Inf, fill = "areas")) +
  geom_segment(aes(x = starts, xend = ends, y = item, yend = item, color = "segments")) +
  scale_color_viridis_d(begin = 0.5, end = 1) +
  scale_fill_viridis_d(alpha = 0.5, begin = 0, end = 0.49)

[EDIT] I got a step closer using aesthetics and guide arguments of scale_fill_viridis_d() but it messes the legend:

ggplot(data = zones) +
  geom_rect(aes(xmin = starts, xmax = ends, ymin = -Inf, ymax = Inf, fill = "areas")) +
  geom_segment(aes(x = starts, xend = ends, y = item, yend = item, color = "segments")) +
  # scale_color_viridis_d() +
  scale_fill_viridis_d(alpha = 0.5, 
                       aesthetics = c("color", "fill"), 
                       guide = guide_legend("Highlights")) 

Created on 2022-04-12 by the reprex package (v2.0.1)



Solution 1:[1]

I guess the simplest way would be to get the viridis color in reverse order. Normally it's from deep purple to yellow, with the direction = -1 argument, we can have it from yellow to deep purple.

library(ggplot2)
zones <- data.frame(starts = c(1, 3, 4),
                    ends = c(2, 3.75, 5),
                    item = rep("A", 3))

ggplot(data = zones) +
  geom_rect(aes(xmin = starts, xmax = ends, ymin = -Inf, ymax = Inf, fill = "areas")) +
  geom_segment(aes(x = starts, xend = ends, y = item, yend = item, color = "segments")) +
  scale_color_viridis_d(direction = -1) +
  scale_fill_viridis_d(alpha = 0.5)

Created on 2022-04-12 by the reprex package (v2.0.1)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 benson23