rggplot2r-sfr-sp

R: Legend for geom_polygon() with single value


I'm using ggplot2 for map plots in R. How do I add a legend entry for a layer without a scale, just for a uniform color:

geom_polygon(data = watercourses, fill = "#0055aa", alpha = .5) 

I just want to have the item title "Watercourses" and a color block representing the correct fill color. How does this work? So far, I only figured out how I can include scales to the legend.

Thank you!

EDIT: Here's an example with the NC dataset.

Map without centroids in legend

library(sf)
library(ggplot2)

demo(nc)

nc_centroids <- st_centroid(nc)

ggplot(nc) +
  geom_sf(aes(fill = BIR74)) +
  scale_fill_gradient(low = "white", high = "red") +
  geom_sf(data = nc_centroids, color = "blue") +
  coord_sf()

Map without legend for centroids

Wrong usage of aes() for legend

ggplot(nc) +
  geom_sf(aes(fill = BIR74)) +
  scale_fill_gradient(low = "white", high = "red") +
  geom_sf(data = nc_centroids, aes(color = "blue")) +
  coord_sf()

Wrong usage of aes() for legend

Trying to add the centroids to the legend (based on the answer of r2evans, https://stackoverflow.com/a/75346358/4921339)

ggplot(nc) +
  geom_sf(aes(fill = BIR74)) +
  scale_fill_gradient(low = "white", high = "red") +
  geom_sf(data = nc_centroids, aes(color = "County centroids")) +
  scale_fill_manual(name = "Centroids", values = c("County centroids" = "blue"))
  coord_sf()

Throws the following messages and an error:

Scale for fill is already present.
Adding another scale for fill, which will replace the existing scale.
Error: Continuous value supplied to discrete scale

In my original case I use sp package instead of sf, but the messages and error thrown in the end are the same.

I think I did not yet understand how things work here, unfortunately. Any helping hints are highly appreciated.


Solution

  • If you place your fill in an aes(.), it will create a legend. Since you want a specific color, I suggest also adding scale_fill_manual:

    ggplot(mtcars[-(1:3),], aes(mpg, disp)) +
      geom_point() +
      # placeholder for your `geom_polygon`:
      geom_point(data = mtcars[1:3,], aes(fill = "something"), alpha = 0.5) +
      scale_fill_manual(name = "something else", values = c("something" = "#0055aa"))
    

    ggplot with single-element legend


    Perhaps this to add your blue points:

    ggplot(nc) +
      geom_sf(aes(fill = BIR74)) +
      scale_fill_gradient(low = "white", high = "red") +
      geom_sf(data = transform(nc_centroids, col = "County centroids"), aes(colour = col)) +
      coord_sf() + 
      scale_colour_manual(name = NULL, values = c("County centroids" = "blue"))
    

    NC plot with blue centroids and a single-point nameless legend


    EDIT by @winnewoerp: Explanation of how it works, for those who have problems understanding it all (like me until now...):

    1. Add an extra column to the data frame with a unique value to be used within the legend, this can be done e.g. using the transform() function like in the given example or like df$col <- "Column unique value" prior to ggplot().

      The (sole?) advantage to using transform is that there is no need to alter the original data, which might affect other processes on it (outside of this image). One disadvantage to doing it this way is that one must hard-code the "Column unique value" in both the transform and the scale_colour_manual, below.

    2. Use scale_colour_manual() to add the legend item (blue colour example):

      scale_colour_manual(
        name = "Legend title",
        values = c("Column unique value" = "blue")
      )