tidyverse / ggplot2

An implementation of the Grammar of Graphics in R
https://ggplot2.tidyverse.org
Other
6.39k stars 2k forks source link

color_scale_manual is not functioning properly #5964

Closed zjwinn closed 6 days ago

zjwinn commented 6 days ago

Explanation

Hi creators/maintainers of ggplot2,

I wrote some code a while back that functioned properly in a previous version of ggplot2, and it seems that it has broken due to update. Essentially, what I see is that the color_scale_manual is not respecting the colors of levels of a factor that do not exist in the data. E.G., it will list the colors in the legend but the corresponding color will not be shown.

Minimal Reproducible Error Code

# Install old ggplot2 package
remotes::install_version("ggplot2", version = "3.4.4")

# Library
library(ggplot2)

# Sample data frame
a <- data.frame(
  chr = rep("1A", 9),
  start = seq(20, 100, by = 10),
  stop = seq(30, 110, by = 10),
  trait = c("A", "B", "C", "D", 
            "E", "F", "G", "H", "I")
)

# Color palette
color_palette <- c(
  "A" = "#0000FF",     # Blue
  "B" = "#2F4F4F",     # DarkSlateGray
  "C" = "#00FFFF",     # Cyan
  "D" = "#1E90FF",     # DodgerBlue
  "E" = "#5F9EA0",     # CadetBlue
  "F" = "#EE82EE",     # Violet
  "G" = "#BA55D3",     # MediumOrchid
  "H" = "#9932CC",     # DarkOrchid
  "I" = "#FF0000",     # Red
  "J" = "#8B0000"      # DarkRed
)

# Ensure the 'trait' levels are correctly ordered and match the color palette
a$trait <- factor(a$trait, levels = names(color_palette))

# Print data frame and factor levels for debugging
print("Data frame 'a':")
print(a)

print("Levels of a$trait:")
print(levels(a$trait))

print("Names of color_palette:")
print(names(color_palette))

# Generate the plot
debug_plot <- ggplot(data = a, aes(x = chr, y = start)) +
  geom_segment(aes(x = chr, xend = chr, y = start, yend = stop, color = trait), linewidth = 2) +
  ggplot2::scale_color_manual(values = color_palette, drop = FALSE) +
  theme_classic() +
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    axis.line.x = element_blank()
  ) +
  labs(title = "Debug Plot", color = "Trait Within Environment", y = "cM")

# Print the debug plot
print(debug_plot)

# detach 
detach("package:ggplot2", unload = TRUE)

# Install current build
remotes::install_version("ggplot2", version = "3.5.1")

# Library
library(ggplot2)

# Generate the plot
debug_plot <- ggplot(data = a, aes(x = chr, y = start)) +
  geom_segment(aes(x = chr, xend = chr, y = start, yend = stop, color = trait), linewidth = 2) +
  ggplot2::scale_color_manual(values = color_palette, drop = FALSE) +
  theme_classic() +
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    axis.line.x = element_blank()
  ) +
  labs(title = "Debug Plot", color = "Trait Within Environment", y = "cM")

# Print the debug plot
print(debug_plot)

# detach 
detach("package:ggplot2", unload = TRUE)

Output Images

3.4.4 Plot Example

3 4 4_plot_example

3.5.1 Plot Example

3 5 1_plot_example

Let me know if you need anything else from me to resolve this issue.

Thanks, Zach

karawoo commented 6 days ago

Hi @zjwinn, you can achieve the previous behavior by adding show.legend = TRUE in your call to geom_segment(). A simplified reprex:

library("ggplot2")

dat <- data.frame(
  x = 1:2,
  y = 1:2,
  z = factor(c(1, 2), levels = c("1", "2", "3"))
)

ggplot(dat, aes(x = x, y = y, color = z)) +
  geom_point(show.legend = TRUE) +
  scale_color_manual(values = c("1" = "goldenrod", "2" = "coral", "3" = "sienna"), drop = FALSE)

Created on 2024-06-28 with reprex v2.1.0

karawoo commented 6 days ago

You can also find more info on the change in this past issue: https://github.com/tidyverse/ggplot2/issues/5728