Skip to content

drop = FALSE does not maintain unused factors #5996

Closed
@brianmsm

Description

@brianmsm

This problem is associated with the scale_fill_ and scale_color functions, including their manual versions, which contain the drop argument. What is happening is that if you have data where any of the factors are not in use, and you are using drop = FALSE, these factors appear in the legend, but without any associated color.

library(dplyr, warn.conflicts = FALSE)
library(ggplot2)

mtcars_tbl <- mtcars %>% 
  as_tibble() %>% 
  mutate(
    cyl = factor(cyl,
                 levels = c("4", "6", "8", "10"))
  ) 

mtcars_tbl %>% 
  ggplot(aes(mpg, wt)) +
  geom_point(aes(colour = cyl)) +
  scale_color_brewer(drop = FALSE, palette = "Dark2")

Created on 2024-07-11 with reprex v2.1.1

I understand that the operation of associated with drop = FALSE has had continuous changes over time (#4511 , #4619 , #4723 , #5214), so I have tried different iterations on the above issues, but none of them work.

library(dplyr, warn.conflicts = FALSE)
library(ggplot2)

mtcars_tbl <- mtcars %>% 
  as_tibble() %>% 
  mutate(
    cyl = factor(cyl,
                 levels = c("4", "6", "8", "10"))
  ) 


# Colors manuals
colors <- RColorBrewer::brewer.pal(n = 4, name = "Dark2")
colors
#> [1] "#1B9E77" "#D95F02" "#7570B3" "#E7298A"

# With scale_color_manual
mtcars_tbl %>% 
  ggplot(aes(mpg, wt)) +
  geom_point(aes(colour = cyl)) +
  scale_color_manual(
    values = colors,
    drop = FALSE
  ) +
  theme_bw()

# With limits
mtcars_tbl %>% 
  ggplot(aes(mpg, wt)) +
  geom_point(aes(colour = cyl)) +
  scale_color_manual(
    values = colors,
    drop = FALSE,
    limits = c("4", "6", "8", "10")
  ) +
  theme_bw()

# With limits and breaks
mtcars_tbl %>% 
  ggplot(aes(mpg, wt)) +
  geom_point(aes(colour = cyl)) +
  scale_color_manual(
    values = colors,
    drop = FALSE,
    breaks = c("4", "6", "8", "10"),
    limits = c("4", "6", "8", "10")
  ) +
  theme_bw()

# With limits on force
mtcars_tbl %>% 
  ggplot(aes(mpg, wt)) +
  geom_point(aes(colour = cyl)) +
  scale_color_manual(
    values = colors,
    drop = FALSE,
    limits = force
  ) +
  theme_bw()

# With limits on identity
mtcars_tbl %>% 
  ggplot(aes(mpg, wt)) +
  geom_point(aes(colour = cyl)) +
  scale_color_manual(
    values = colors,
    drop = FALSE,
    limits = identity
  ) +
  theme_bw()

Created on 2024-07-11 with reprex v2.1.1

The only way to get what I am looking for is to add an empty row where the missing factors are mentioned, and plot waiting for them to be eliminated.

library(dplyr, warn.conflicts = FALSE)
library(ggplot2)

mtcars_tbl <- mtcars %>% 
  as_tibble() %>% 
  mutate(
    cyl = factor(cyl,
                 levels = c("4", "6", "8", "10"))
  ) 

mtcars_tbl %>% 
  tibble::add_case(
    cyl = factor("10",
                 levels = c("4", "6", "8", "10"))
  ) %>% 
  ggplot(aes(mpg, wt)) +
  geom_point(aes(colour = cyl)) +
  scale_color_brewer(drop = FALSE, palette = "Dark2")
#> Warning: Removed 1 row containing missing values or values outside the scale range
#> (`geom_point()`).

Created on 2024-07-11 with reprex v2.1.1

However, I think it is not an ideal solution, since add_case() or bind_rows() may have limitations when you have tibbles with list or different data type.

packageVersion("ggplot2")
#> [1] '3.5.1'

Created on 2024-07-11 with reprex v2.1.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions