2

enter image description here

I'm producing a map of the world, filling countries with a shaded grey for different values of a variable. For countries with NA values, I want to fill them with zigzags, oblique lines, or hachures. The final map will be in black and white, so too many shades of grey or color will not produce distinguishable results. I want to have different shades of grey for values of the factor variable (0-3), and a pattern for NA values. Right now, the code says "blue" for na.value, but it has to change.

ggplot(CRSVmap, aes(map_id = region, fill = as.factor(SV)))+
geom_map(map = CRSVmap,  color = "black")+  
scale_fill_grey(start = 0.99, end = 0.1, na.value = "blue")
Jee Mok
  • 6,157
  • 8
  • 47
  • 80
Sally Sharif
  • 21
  • 1
  • 3

1 Answers1

6

This is a pretty hacky solution that will probably need some adjustments. I switched over to sf to make some of the spatial manipulation easier.

The first thing to do is make the map with the NA values blank—do that by mapping NA values to alpha, and set that alpha to 0.

I saw @JonSpring 's comment about the ggtextures package (which looks like it's still in beta) and started messing around with it. The trick is that as of now, ggtextures only makes bars and rectangles, not the more complex shapes needed to fill in missing areas in a map.

Instead, make a rectangle the size of the whole map and fill it with a texture (I made a little hatching SVG file here). On top of that, add a layer that will mask the water areas—otherwise the texture will be showing through there. I made the mask by taking the spatial difference between the map's bounding box and the land areas.

library(ggplot2)
library(dplyr)
library(sf)
library(ggtextures)

data(wrld_simpl, package = "maptools")

set.seed(10)
world <- st_as_sf(wrld_simpl) %>%
  select(name = NAME, geometry) %>%
  mutate(value = sample(c(letters[1:4], NA), size = nrow(.), replace = T))
world_bbox <- st_bbox(world)
world_inv <- st_difference(st_as_sfc(world_bbox), st_union(world)) %>%
  st_combine()

First, just the mask (could be cleaner):

ggplot(world) +
  geom_sf(data = world_inv, fill = "white")

map1

Add up all the layers, and build two legends together, one for color with NA missing, and one for image with NA marked off.

pattern <- tibble(
  xmin = world_bbox$xmin, xmax = world_bbox$xmax, ymin = world_bbox$ymin, ymax = world_bbox$ymax,
  image = "diagonals"
)

ggplot(world) +
  geom_textured_rect(aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, image = image),
    data = pattern, img_width = unit(0.8, "in"), img_height = unit(0.8, "in")) +
  geom_sf(aes(fill = value, alpha = is.na(value))) +
  geom_sf(data = world_inv, fill = "white") +
  scale_fill_grey(breaks = letters[1:4]) +
  scale_alpha_manual(values = c("TRUE" = 0, "FALSE" = 1), guide = NULL) +
  scale_image_manual(values = c("diagonals" = "hatching.svg"), name = NULL, labels = c("NA"))

map2

Definitely still some things you'll want to tweak, but hopefully it's a start.

camille
  • 16,432
  • 18
  • 38
  • 60
  • 1
    For this to work for me in Nov 2021 with latest versions of sf, etc I had to turn off the s2 processing via sf::sf_use_s2(FALSE). See the answer in this exchange - https://stackoverflow.com/questions/68478179/how-to-resolve-spherical-geometry-failures-when-joining-spatial-data/. – JerryN Nov 25 '21 at 18:04