rggplot2geomggpattern

Maps & scale_*_manual for multiple geom types (geom_polygon & geom_pattern_polygon)


I am trying to create a map where only counties with missing data have a striped pattern. Ideally, the background of this pattern would be white and the stripes would be blue, but I have gotten totally stumped on how to achieve this. I have to combined geom_polygon and geom_polygon_pattern, and in both cases I map the fill aesthetic to the same value. The issue becomes how to specify the fill color for the geom_polygon_pattern, which is mapped using a dataframe of counties with only NA values for the fill color variable.

Here's a sample of some of the data below generated with the dput function intended to help with reproduction, but I think the principle should be the same for manipulating the fill of any geom_*_pattern geom:

library(maps)
library(ggplot2)
library(ggpattern)
library(dplyr) 

data(county.fips)

states <- map_data("state") 

counties <- structure(list(long = c(-111.050682067871, -111.491851806641, 
-111.5205078125, -111.5205078125, -111.537689208984, -111.577796936035, 
-111.606452941895, -111.606452941895, -111.600723266602, -111.640830993652, 
-111.629364013672, -111.594993591309, -111.600723266602, -111.572067260742, 
-111.577796936035, -111.612174987793, -111.600723266602, -111.594993591309, 
-111.600723266602, -111.617904663086), lat = c(41.9978065490723, 
41.9978065490723, 42.0035362243652, 42.043643951416, 42.0665626525879, 
42.0894813537598, 42.0952110290527, 42.1181259155273, 42.1467742919922, 
42.1926116943359, 42.2556381225586, 42.2728271484375, 42.3186645507812, 
42.3473091125488, 42.3759574890137, 42.4103355407715, 42.4275245666504, 
42.4389839172363, 42.4619026184082, 42.4733619689941), group = c(520, 
520, 520, 520, 520, 520, 520, 520, 520, 520, 520, 520, 520, 520, 
520, 520, 520, 520, 520, 520), indAnyDisaster_frequency_v2 = structure(c(NA_integer_, 
NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, 
NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, 
NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, 
NA_integer_, NA_integer_, NA_integer_, NA_integer_), levels = c("0", 
"1-2", "3-5", "6-8", "9-12", "13-19"), class = "factor")), row.names = 19621:19640, class = "data.frame")

indAnyDisaster_map_wNA_6groups <- 
  ggplot() + 
  coord_fixed(1.3) + 
  geom_polygon_pattern(data = filter(counties, is.na(indAnyDisaster_frequency_v2)), 
                       mapping = aes(x = long, 
                                     y = lat, 
                                     group = group, 
                                     fill = indAnyDisaster_frequency_v2),
                       color = "grey", linewidth = 0.05,
                       # fill = 'white',
                       pattern = 'stripe',
                       pattern_density = .01,
                       pattern_spacing = .01,
                       pattern_colour  = 'white',
                       pattern_size = .25,
                       na.rm = TRUE) + 
  geom_polygon(data = filter(counties, !is.na(indAnyDisaster_frequency_v2)), 
               mapping = aes(x = long, 
                             y = lat, 
                             group = group, 
                             fill = indAnyDisaster_frequency_v2),
               color = "grey", size = 0.05,
               na.rm = TRUE) + 
  geom_polygon(data = states, 
               mapping = aes(x = long, y = lat, group = group),
               color = "black", size = 0.1, fill = NA) + 
  theme_bw() +
  theme(axis.text = element_blank(),
        axis.line = element_blank(),
        axis.ticks = element_blank(),
        panel.border = element_blank(),
        panel.grid = element_blank(),
        axis.title = element_blank()) +
  labs(title = "All Disaster Types",
       fill = "Count") +
  scale_fill_manual(breaks = c("0", "1-2", "3-5", "6-8", "9-12", "13-19", NA),
                    values = c("white","#deebf7","#9ecae1","#4292c6","#08519c", "#08306b", "white")) +
  scale_pattern_fill_manual(na.value = c("white"))

enter image description here

I have resorted to using white stripes to stand out against the grey fill, but as you can (possibly) tell from my code, I would really prefer that the background is white so I can specify a shade of blue for the bars. I am a little confused about how to do this given that the fill parameter is in the aesthetic mapping of two different geoms, but clearly I can control the legend order in a single scale_fill_manual call. I also tried setting the na.value argument of scale_fill_manual to white, but I get the following error:

Error in UseMethod("depth") : 
  no applicable method for 'depth' applied to an object of class "NULL"

I tried setting fill directly in geom_polygon_pattern, but then this overrides the fill mapping to indAnyDisaster_frequency_v2 and it no longer appears in the legend. Any ideas on what I should be doing instead would be appreciated!


Solution

  • Instead of mapping indAnyDisaster_frequency_v2 on the fill aesthetic you could map an arbitrary character value on the fill aes, e.g. in the code below I use "NA_value". Then you can easily assign your desired blue color to this category:

    library(ggplot2)
    library(ggpattern)
    
    ggplot() +
      coord_fixed(1.3) +
      geom_polygon_pattern(
        data = dplyr::filter(counties, is.na(indAnyDisaster_frequency_v2)),
        mapping = aes(
          x = long,
          y = lat,
          group = group,
          fill = "NA_value"
        ),
        color = "grey", linewidth = 0.05,
        pattern = "stripe",
        pattern_density = .01,
        pattern_spacing = .01,
        pattern_colour = "white",
        pattern_size = .25,
        na.rm = TRUE
      ) +
      geom_polygon(
        data = dplyr::filter(counties, !is.na(indAnyDisaster_frequency_v2)),
        mapping = aes(
          x = long,
          y = lat,
          group = group,
          fill = indAnyDisaster_frequency_v2
        ),
        color = "grey", size = 0.05,
        na.rm = TRUE
      ) +
      # geom_polygon(
      #   data = states,
      #   mapping = aes(x = long, y = lat, group = group),
      #   color = "black", size = 0.1, fill = NA
      # ) +
      theme_bw() +
      theme(
        axis.text = element_blank(),
        axis.line = element_blank(),
        axis.ticks = element_blank(),
        panel.border = element_blank(),
        panel.grid = element_blank(),
        axis.title = element_blank()
      ) +
      labs(
        title = "All Disaster Types",
        fill = "Count"
      ) +
      scale_fill_manual(
        breaks = c("0", "1-2", "3-5", "6-8", "9-12", "13-19", "NA_value"),
        values = c("white", "#deebf7", "#9ecae1", "#4292c6", "#08519c", "#08306b", "blue")
      )
    #> Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
    #> ℹ Please use `linewidth` instead.
    #> This warning is displayed once every 8 hours.
    #> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
    #> generated.