0

I am plotting point data from two separate layers on a map and would like to display the information of both layers in one legend.

Here's some code to illustrate the problem:

set.seed(42)  
lat1 <- rnorm(10, 54, 12)
long1 <- rnorm(10, 44, 12)
val1 <- rnorm(10, 10, 3)
lat2 <- rnorm(10, 54, 12)
long2 <- rnorm(10, 44, 12)
val2 <- rnorm(10, 10, 3)

df1 <- as.data.frame(cbind(long1, lat1, val1))
df2 <- as.data.frame(cbind(long2, lat2, val2))

library(ggplot2)
library(scales)

f <- ggplot() +
     geom_point(data=df1, aes(x=lat1, y=long1, size=val1, fill=val1), 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)) +     
     guides(fill = guide_legend(), size = guide_legend()) +
     theme_minimal()
p <- f + geom_point(data=df2, aes(x=lat2, y=long2, color="val2"), shape=17, size=3) +
     scale_color_manual(values="black",name="")
p

The best I can manage, is to create two separate legends and to then remove one of the legend titles. Ideally, both the filled circles and the black diamond would be part of the same legend called e.g. "Value" and the black diamond would read e.g. "NA". Any help is much appreciated!

pogibas
  • 27,303
  • 19
  • 84
  • 117
M.Teich
  • 575
  • 5
  • 22
  • Maybe something along the lines of [this answer](https://stackoverflow.com/a/42380983/2461552)? It involves pre-processing things to establish the color groups. – aosmith Jun 29 '18 at 14:18

1 Answers1

2

We have to plot two different legends, but move them close to each other (using negative value in legend.spacing.y requires ggplot2_3.0.0). This approach creates another problem - two legends doesn't align, therefore we have to plot another set of diamonds (larger to match non-diamonds, but invisible alpha = 0)

ggplot() +
    geom_point(data = df1, 
               aes(lat1, long1, size = val1, fill = val1), 
               shape = 21, alpha = 0.6) +
    geom_point(data = df2, 
               aes(lat2, long2, color = "val2"), 
               shape = 17, size = 3) +
    geom_point(data = df2, 
               aes(lat2, long2, color = "val2"), 
               shape = 17, size = 11.5, alpha = 0) +
    scale_size_continuous(range = c(2, 12), breaks = pretty_breaks(4)) +
    scale_fill_distiller(direction = -1, palette = "RdYlBu", breaks = pretty_breaks(4)) +     
    scale_color_manual(values = "black", name = "Value\n") +
    labs(fill = NULL,
         size = NULL) +
    guides(fill = guide_legend(), 
           size = guide_legend(),
           color = guide_legend(order = 1)) +
   theme_minimal() +
   theme(legend.spacing.y = unit(-0.4, "cm"))

enter image description here

pogibas
  • 27,303
  • 19
  • 84
  • 117
  • Is it possible to specify a different name for "val2" within the legend? – M.Teich Jul 13 '18 at 13:34
  • 1
    @M.Teich do it within two `geom_point`'s: change `color = "val2"` to `color = "new name"` – pogibas Jul 13 '18 at 13:38
  • Thanks again for your solution. I'm tweaking a few more things and have now defined my own breaks rather than letting `pretty_breaks` do it for me. However, that has now messed up the order of the legend, i.e. legend title and the diamond/val2 now appear below the circle legend. Unfortunately I was not able to reproduce this error in the dummy code. Do you have any idea what I could change? – M.Teich Sep 11 '18 at 07:01
  • @M.Teich can you try renaming diamonds `val2` to something like `aaa` or `000` (ie, something that on alpha numeric ranking would go first). Let me know how it goes. – pogibas Sep 11 '18 at 07:11
  • That doesn't seem to be the Problem, as I've produced several maps with the same code, i.e. same legend names and sometimes it works and sometimes it doesn't. It seems to depend on the number of legend entries. When the number of entries is small (<5), the title, etc. is moved to the bottom. – M.Teich Sep 11 '18 at 07:57