Fill and Color Legend Disappear while Adding Layers

Viewed 333

I have discovered an unexpected behavior while playing with changing layers in a ggplot object. I start with an initial plot.

library(ggplot2)

p <-
  ggplot(iris, aes(x = Sepal.Length, y =  Sepal.Width, color = Petal.Width, size = Petal.Length)) + 
  geom_point() +
  scale_x_continuous(position = 'top') +
  scale_size_area('Size Name', max_size = 12) +
  scale_color_gradientn(
    'Color Name',
    colors = scales::brewer_pal(type = 'div')(7),
    limits = c(-3, 3),
    breaks = c(-3,  -1.5, 0 , 1.5, 3)
  ) 

print(p)

Plot 1

I then decide that I want to change the points layer to a points layer with a different shape, 21. Shape 21 has fill instead of color. However, I want to keep everything else the same. To save typing, I first remove the initial points layer, and then add the new one in. However, I find that the legend for fill does not display when it should.


p$layers
#> [[1]]
#> geom_point: na.rm = FALSE
#> stat_identity: na.rm = FALSE
#> position_identity



p$layers[[1]] <- NULL


p_with_name <-
  p + 
  geom_point(aes(fill = Petal.Width), shape = 21, color = 'black') +
  scale_fill_gradientn(
    'Color Name',
    colors = scales::brewer_pal(type = 'div')(7),
    limits = c(-3, 3),
    breaks = c(-3,  -1.5, 0 , 1.5, 3)
  )

print(p_with_name)

Plot 2

However, when I add the fill scale without a title, or with a different title from the color scale, it display properly.

p_no_name <-
  p + 
  geom_point(aes(fill = Petal.Width), shape = 21, color = 'black') +
  scale_fill_gradientn(
    colors = scales::brewer_pal(type = 'div')(7),
    limits = c(-3, 3),
    breaks = c(-3,  -1.5, 0 , 1.5, 3)
  )

print(p_no_name)

Plot 3


p_diff_name <-
  p + 
  geom_point(aes(fill = Petal.Width), shape = 21, color = 'black') +
  scale_fill_gradientn(
    'Diff Name',
    colors = scales::brewer_pal(type = 'div')(7),
    limits = c(-3, 3),
    breaks = c(-3,  -1.5, 0 , 1.5, 3)
  )

print(p_diff_name)


Created on 2020-05-28 by the reprex package (v0.3.0)

Plot 4

Is it possible to add a fill scale with the same name as the color scale and have it appear? It would help me to simplify my code a lot.

1 Answers

By default ggplot2 tries to minimze the number of legend by merging legends for different aesthetics if they have the same name, ... . After some trials I found a hack to prevent the merging of legends and have two "identical" legends with the same name. I simply add a NA to the vector of breaks in scale_fill_gradientn which breaks the identity of the color and fill scales and prevents the legends from being merged. Try this:

library(ggplot2)

ggplot(iris, aes(x = Sepal.Length, y =  Sepal.Width, color = Petal.Width, size = Petal.Length)) + 
  geom_point() +
  scale_x_continuous(position = 'top') +
  scale_size_area('Size Name', max_size = 12) +
  scale_color_gradientn(
    'Color Name',
    colors = scales::brewer_pal(type = 'div')(7),
    limits = c(-3, 3),
    breaks = c(-3,  -1.5, 0 , 1.5, 3)
  ) + 
  geom_point(aes(fill = Petal.Width), shape = 21, color = 'black') +
  scale_fill_gradientn(
    'Color Name',
    colors = scales::brewer_pal(type = 'div')(7),
    limits = c(-3, 3),
    breaks = c(-3,  -1.5, 0 , 1.5, 3, NA)
  )

Created on 2020-05-28 by the reprex package (v0.3.0)

EDIT: "Clean" solution to the problem

# clean solution
p <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, size = Petal.Length)) + 
  scale_x_continuous(position = 'top') +
  scale_size_area('Size Name', max_size = 12)

p +
  geom_point(aes(color = Petal.Width))  +
  scale_color_gradientn(
    'Color Name',
    colors = scales::brewer_pal(type = 'div')(7),
    limits = c(-3, 3),
    breaks = c(-3,  -1.5, 0 , 1.5, 3) 
  )

p + 
  geom_point(aes(fill = Petal.Width), color = "black", shape = 21)  +
  scale_fill_gradientn(
    'Color Name',
    colors = scales::brewer_pal(type = 'div')(7),
    limits = c(-3, 3),
    breaks = c(-3,  -1.5, 0 , 1.5, 3)
  )
Related