2

I have NA values in a data set, which I would like to include in my ggplot as well as in the legend. I thought this would be easily done by specifying the na.values="somecolour" option, as shown e.g. in this post. However, for my example the code runs without plotting any of the NAs, nor including an entry in the legend. Instead rows with missing values are automatically removed. Here's some code for illustration:

set.seed(42)  
lat <- rnorm(10, 54, 12)
long <- rnorm(10, 44, 12)
val <- rnorm(6, 10, 3)
val <- c(val,NA,NA,NA,NA)

df <- as.data.frame(cbind(long, lat, val))

library(ggplot2)
library(scales)

ggplot() +
  geom_point(data=df, aes(x=lat, y=long, size=val, fill=val),shape=21,alpha=0.6) +
  scale_size_continuous(range = c(2, 12), breaks=pretty_breaks(4)) +
  scale_fill_distiller(direction = -1, palette="RdYlBu", breaks=pretty_breaks(4),na.value = "black") +     
  guides(fill = guide_legend(), size = guide_legend()) +
  theme_minimal()

What am I doing wrong?

camille
  • 16,432
  • 18
  • 38
  • 60
M.Teich
  • 575
  • 5
  • 22

1 Answers1

1

Problem comes from setting size in aes as you can't set size for NA values in scale_size_continuous.

My solution would be to plot NA values separately (not perfect, but works). To add them to legend set some dummy value within aes to call there guide.

However, there is a problem that NA legend doesn't align nicely with non-NA legend. To adjust the alignment we have to plot another set of invisible NA values with the size of maximum non-NA values.

ggplot(df, aes(lat, long, size = val, fill = val)) +
    geom_point(shape = 21,alpha = 0.6) +
    geom_point(data = subset(df, is.na(val)), aes(shape = "NA"),
               size = 1, fill = "black") +
    geom_point(data = subset(df, is.na(val)), aes(shape = "NA"),
               size = 14, alpha = 0) +
    scale_size_continuous(range = c(2, 12), breaks = pretty_breaks(4)) +
    scale_fill_distiller(direction = -1, palette = "RdYlBu", breaks = pretty_breaks(4)) +     
    labs(shape = "         val\n",
         fill = NULL,
         size = NULL) +
    guides(fill = guide_legend(), 
           size = guide_legend(),
           shape = guide_legend(order = 1)) +
    theme_minimal() +
    theme(legend.spacing.y = unit(-0.4, "cm"))

enter image description here

PS: requires ggplot2_3.0.0.

pogibas
  • 27,303
  • 19
  • 84
  • 117
  • Thanks @PoGibas for your suggestion. However, that is more or less where I started (see my previvious question [here](https://stackoverflow.com/questions/51100240/merging-legends-of-separate-layers-in-ggplot)). My aim ist to have all the information in one legend, but it seems that ggplot does not make this easy... – M.Teich Jul 13 '18 at 09:58
  • @M.Teich Is there any way I can improve my current answer? – pogibas Jul 13 '18 at 12:29