Search code examples
rggplot2legendscale-color-manualgeom-sf

ggplot of multiple geom_sf datasets gives mismatched legend colours


I am trying to create a ggplot map which includes two simple feature line datasets. I would like the lines to either appear in the same legend, or a separate legend. However the approach I am taking results in a mismatch between the plot colours and the legend colours.

Here is a simple example that shows the problem.

library("sf")
library("sfheaders")
library("ggplot2")

df1 <- data.frame(
  x = c(0,1,0,1,0,1), 
  y = c(1,1,2,2,3,3),
  id = c("A","A","B","B","D","D")
)
df2 <- data.frame(
  x = c(0,1), 
  y = c(4,4),
  id= c("C","C")
)

set1_sf <- sfheaders::sf_linestring(
  obj = df1, x = "x", y = "y", linestring_id = "id"
)
set2_sf <- sfheaders::sf_linestring(
  obj = df2, x = "x", y = "y", linestring_id = "id"
)

palette <- c("#7FC97F","#BEAED4","#FDC086")   

ggplot() +
  geom_sf(set1_sf, mapping=aes(colour=id), lwd=0.8) + 
  geom_sf(set2_sf, mapping=aes(colour=id), lwd=0.8) +
  scale_colour_manual(name="Lines",
                      values = c(palette,"black"),
                      labels = c(set1_sf$id, set2_sf$id))

With this result:

enter image description here

In the legend of the output plot, lines A, B and D are correctly coloured with the palette colours, and line C in black. However on the plot itself, the colours of D and C are incorrectly swapped.

If I change the id value in df2 to "X" the plot colours appear correctly.

What am I doing wrong? Is there a better way?


Solution

  • One way to return your desired outcome is to use breaks = to explicitly reorder the legend keys:

    library(ggplot2)
    
    # Legend order vector
    key_ord <- c(set1_sf$id, set2_sf$id)
    
    ggplot() +
      geom_sf(data = set1_sf, aes(colour = id), lwd = 0.8) + 
      geom_sf(data = set2_sf, aes(colour = id), lwd = 0.8) +
      scale_colour_manual(name = "Lines",
                          values = c(palette, "black"),
                          breaks = key_ord,
                          labels = key_ord)
    

    1