How do I use patterns instead of colors in a county map?

216 Views Asked by At

I want to use patterns (stripes, etc) in a county map of Nebraska to distinguish between the counties, rather than colors. The code below works, but I can't get the lines to just be nice, simple, solid lines. They always show up as these thick lines with borders, which is ugly. How do I get my patterns to just be simple lines, at different angles, with some dashed and some solid? The documentation for the ggpattern package is nothing but confusing for me.

ggplot(ne_counties_dataframe) + geom_sf(data = ne_counties_dataframe, color = 'black', lwd = 0.5) + 
geom_sf_pattern(aes(pattern = Both, pattern_color = 'white', pattern_fill = Both, pattern_density = 0.1))

"Both" is a column that contains 3 factors, 'Both', 'Neither', and 'Low_Income'. I want the patterns to vary by this column. Thank you.

2

There are 2 best solutions below

1
Allan Cameron On BEST ANSWER

One option is to map pattern_angle to, say, county name. You can make the pattern fill gray, turn off the pattern color, and decrease the pattern scale to make it smaller:

library(tidyverse)
library(tigris)
library(ggpattern)
library(sf)

ne_counties_dataframe <- counties("Nebraska")

ggplot(ne_counties_dataframe) + 
  geom_sf(data = ne_counties_dataframe, color = 'black', lwd = 0.5) + 
  geom_sf_pattern(aes(pattern_angle = NAME), pattern = "stripe",
                  pattern_fill = "gray50", pattern_colour = NA,
                  pattern_spacing = 0.02, fill = "white") +
  theme_minimal(base_size = 16) +
  theme(legend.position = "none") +
  ggtitle("Counties of Nebraska")

enter image description here

0
Ray On

You are almost there!

Try to understand the mechanics of {ggplot2}, in particular, read up on aesthetics. I recommend you split aesthetics into (mapped) aesthetics and (fixed) parameters.
This is not trivial ... but it helps you to navigate.

The extension {ggpattern} uses the same rules.

As a rule of thumb:

  • ggplot works well with "long" tables
  • you map aesthetics (read columns of your data table) inside aes()
  • you "set" parameters outside the aes() (think default/standard values)

The key point is: you normally want the mapping to be several values (aka differnt values in your column), while the parameters are fixed values/singletons (e.g. "white", NA, 0.5, etc).

You did not provide a reproducible example, so I used a quick set of European states and added - in a simple manner - the Both column. This we plug into ggplot & ggpattern:

library(tidyverse)
library(rnaturalearth) # for the map data
library(sf)
library(ggpattern) # for the pattern fill

# extract play data by selecting a set of European countries
Europe <- ne_countries(scale = 'medium', type = 'map_units', returnclass = 'sf', continent="Europe"
, country = c("Germany","France","Belgium", 
              "Luxembourg","Switzerland","Austria","Italy")
)
# add the "Both" values as arbitrary repetition
Europe <- Europe |> 
    select(sovereignt) |> 
    mutate(Both = rep(c("Both", 'Neither', 'Low_Income'),3)) #this works as Belgium comes as 3 Polygons

# plot the map
ggplot() +     # it is not required to reference the dataframe, if used in lower layers 
  geom_sf(        data = Europe, lwd = 0.5) +   # base map with borderlines, black is default color
  geom_sf_pattern(data = Europe,                # supply map sf object
                  aes(pattern = Both, pattern_fill = Both),  # map aesthetics
                  pattern_color = "NA", pattern_density = 0.5) # set parameters outside aes()

This yields a plot where the

  • the different values of the Both column are used to determine the cases of fills and then the actual fill pattern
  • "lines" of the stripes are removed (not shown) as we set it to a "fixed" value, i.e. NA (note here you could set the color similar to what you did in the base map)
  • the density of the pattern is set to a fixed value of your liking

corrected ggplot visualisation

If you plotted your chart, you will see that ggplot created a legend for pattern density and pattern fill. This is an indication that ggplot tried to map these values as aethetics. You should also notice that the "color" legend reads "white" (the text label you used), but is shown as "red" (ggplot's first discrete default color - as it maps a single value to the the first default [if you have not defined another palette).

For the dashed, solid, etc patterns, check the documentation of {ggpattern} or maybe somebody else can help here. I am not using this extension. But I am sure there is a way to control the type of stripes (solid, dashed, dot-dash) or define personal patterns and plug them in via a scale_magicstripetypes() layer.