Search code examples
ggplot2usmap

Map of New York State counties with binned colors and legend


I am trying to make a county-level map of the state of New York. I would like to color each county based on their level of unionization. I need the map and legend to have four discrete colors of red, rather than a red gradient. I need the legend to display these four different colors with non-overlapping labels/ranges (e.g. 0-25; 26-50; 51-75; 76-100).

Here is my data:

    fips unionized
1  36001  33.33333
2  36005  86.11111
3  36007   0.00000
4  36017   0.00000
5  36021   0.00000
6  36027  66.66667
7  36029  40.00000
8  36035  50.00000
9  36039   0.00000
10 36047  82.85714
11 36051   0.00000
12 36053 100.00000
13 36055  30.76923
14 36057   0.00000
15 36059  84.37500
16 36061  81.81818
17 36063  60.00000
18 36065  50.00000
19 36067  71.42857
20 36069   0.00000
21 36071  55.55556
22 36073   0.00000
23 36079 100.00000
24 36081  92.15686
25 36083  50.00000
26 36085 100.00000
27 36087  87.50000
28 36101   0.00000
29 36103  63.88889
30 36105   0.00000
31 36107   0.00000
32 36111  50.00000
33 36113  50.00000
34 36115 100.00000
35 36117   0.00000
36 36119  73.33333
37 36121   0.00000
38 36123   0.00000

I have successfully made the map with a gradient of colors, but cannot figure out how to make discrete colors in the map and legend.

Here is my code:

library(usmap)
library(ggplot2)
plot_usmap(regions = "counties", include = c("NY"), data = Z, values = "unionized") +
  labs(title = "Percent Unionized", subtitle = "") + 
  scale_fill_continuous(low = "white", high = "red", na.value="light grey", name = "Unionization") + theme(legend.position = "right")

Thanks!


Solution

  • This could be achieved via scale_fill_binned and guide_bins. Try this:

    library(usmap)
    library(ggplot2)
    
    plot_usmap(
      regions = "counties", include = c("NY"), data = Z,
      values = "unionized"
    ) +
      labs(title = "Percent Unionized", subtitle = "") +
      scale_fill_binned(
        low = "white", high = "red",
        na.value = "light grey", name = "Unionization",
        guide = guide_bins(axis = FALSE, show.limits = TRUE)
      ) +
      theme(legend.position = "right")
    #> Warning: Ignoring unknown argument to `guide_bins()`: `axis`.
    

    A second option would be to bin the variable manually and use scale_fill_manual to set the fill colors which makes it easy to set the labels and has the advantage that it adds the NAs automatically. For the color scale I make use of colorRampPalette (By default colorRampPalette interpolates in rgb color space. To get fill colors like the one using scale_fill_binned you can add the argument space = "Lab".).

    
    Z$union_bin <- cut_interval(Z$unionized,
      n = 4,
      labels = c("0-25", "26-50", "51-75", "76-100")
    )
    
    plot_usmap(
      regions = "counties", include = c("NY"), data = Z,
      values = "union_bin"
    ) +
      labs(title = "Percent Unionized", subtitle = "") +
      scale_fill_manual(
        values = colorRampPalette(c("white", "red"))(5)[2:5],
        na.value = "light grey", name = "Unionization"
      ) +
      theme(legend.position = "right")
    

    DATA

    Z <- structure(list(fips = c(
      36001L, 36005L, 36007L, 36017L, 36021L,
      36027L, 36029L, 36035L, 36039L, 36047L, 36051L, 36053L, 36055L,
      36057L, 36059L, 36061L, 36063L, 36065L, 36067L, 36069L, 36071L,
      36073L, 36079L, 36081L, 36083L, 36085L, 36087L, 36101L, 36103L,
      36105L, 36107L, 36111L, 36113L, 36115L, 36117L, 36119L, 36121L,
      36123L
    ), unionized = c(
      33.33333, 86.11111, 0, 0, 0, 66.66667,
      40, 50, 0, 82.85714, 0, 100, 30.76923, 0, 84.375, 81.81818, 60,
      50, 71.42857, 0, 55.55556, 0, 100, 92.15686, 50, 100, 87.5, 0,
      63.88889, 0, 0, 50, 50, 100, 0, 73.33333, 0, 0
    )), class = "data.frame", row.names = c(
      "1",
      "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13",
      "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24",
      "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35",
      "36", "37", "38"
    ))