Search code examples
rggplot2dplyrr-sfgeom-sf

How to use fill aesthetic in geom_sf only for filtered values while ‘excluded’ and ‘NA’ values both presented on map with other colours


I want to use Spectral palette from RColorBrewer only for AREA greater than 0.1, but I also wanted to show AREA less than 0.1 with let’s say dark grey or even better with hatched. In addition to this, I want to render NA as light grey. So basically, no values left behind in the map; they only get different colors. I tried with two below way but none of them works the way I want. Would appreciate any help on this.

library(ggnewscale)
library(tidyverse)
library(sf)

nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), 
                  quiet = TRUE)

# add some NAs
nc$AREA[c(1,2,3)] <- NA

# first try
ggplot(nc) +
  geom_sf(aes(fill = AREA > 0.1)) +
  new_scale_fill() +
  geom_sf(aes(fill = AREA))+
  scale_fill_gradientn(colors = RColorBrewer::brewer.pal(9, "Spectral"),
                       na.value = "grey90")
# second try
remove_col <- "AREA"
remove_val <- 0.1

nc %>%
  filter(.data[[remove_col]] < remove_val) %>%
  ggplot() +
  geom_sf(aes(fill = AREA)) +
  new_scale_fill() +
  geom_sf(aes(fill = .data[[remove_col]]), color = "black") +
  scale_fill_gradientn(colors = RColorBrewer::brewer.pal(9, "Spectral"),
                       na.value = "grey90")

enter image description here enter image description here


Solution

  • If leaving NA and < .1 from legend is acceptable, we can skip ggnewscale. First lets set limits for scale_fill_gradientn() to c(.1, NA) , everything outside the limits is filled with na.value. Then add another layer, only polygons with missing AREA values and constant fill:

    library(dplyr)
    library(ggplot2)
    
    nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), 
                      quiet = TRUE)
    
    # add some NAs
    nc$AREA[c(1,2,3)] <- NA
    
    ggplot(nc) +
      geom_sf(aes(fill = AREA))  +
      scale_fill_gradientn(colors = RColorBrewer::brewer.pal(9, "Spectral"),
                           limits = c(.1, NA),
                           na.value = "darkgrey") +
      geom_sf(data = ~ filter(.x, is.na(AREA)), fill = "lightgrey") 
    

    Created on 2023-07-25 with reprex v2.0.2