The data we’ll use in this lab is from the 2020 presidential election and is publicly available on github and draws from Fox News, Politico, and the New York Times. I’ve included the code I used to download the county level results and wrangle it to be state-level. Note that reading the CSV from the web may slightly slow down the knitting process, but I think this is helpful to see as github can be a great source of data for projects!

county_level_2020 = read_csv("https://raw.githubusercontent.com/tonmcg/US_County_Level_Election_Results_08-20/master/2020_US_County_Level_Presidential_Results.csv")

state_level_2020 = county_level_2020 %>%
  group_by(state_name) %>%
  summarize(gop_votes = sum(votes_gop),
         dem_votes = sum(votes_dem),
         total_votes = sum(total_votes),
         diff = sum(diff)) %>%
  mutate(
    pct_gop = gop_votes/total_votes,
    pct_dem = dem_votes/total_votes
  ) %>%
  ungroup()

state_level_2020
## # A tibble: 51 x 7
##    state_name           gop_votes dem_votes total_votes     diff pct_gop pct_dem
##    <chr>                    <dbl>     <dbl>       <dbl>    <dbl>   <dbl>   <dbl>
##  1 Alabama                1441168    849648     2323304   591520  0.620    0.366
##  2 Alaska                  189892    153405      391346    36487  0.485    0.392
##  3 Arizona                1661686   1672143     3387326   -10457  0.491    0.494
##  4 Arkansas                760647    423932     1219069   336715  0.624    0.348
##  5 California             6005961  11109764    17495906 -5103803  0.343    0.635
##  6 Colorado               1364607   1804352     3256953  -439745  0.419    0.554
##  7 Connecticut             715291   1080680     1824280  -365389  0.392    0.592
##  8 Delaware                200603    296268      504010   -95665  0.398    0.588
##  9 District of Columbia     18586    317323      344356  -298737  0.0540   0.921
## 10 Florida                5668731   5297045    11067456   371686  0.512    0.479
## # … with 41 more rows

Part 1: Replicating 2016 maps using 2020 data

For this lab, we’re going to walk through Data Viz Ch 7.1 and 7.3 on making maps in R. All you need to do for the first part of the lab is replicate three graphs from the chapter, using the 2020 data above instead of 2016 data. All code is available in the text, so your job is to map the correct variables from state_level_2020 data to the existing map code. (pun intended) Don’t forget to install the necessary packaages (socviz, maps, ggthemes).

Replication 1: Figure 7.7

Note: You may have to install the mapproj package in order for coord_map() command to work. Election results by state

Replication 2: One of the maps in Figure 7.9

Election results by state using white midpoint and purple midpoint

Replication 3: Any of the statebins graphs in Figure 7.14 or 7.15

(Note: You’ll have to install the statebins package to use the code from the chapter)

Election results using statebins

A note on statebins: The package has changed since the text was written. Specifically, the brewer_pal argument has changed to palette, the text_color argument does not exist, and the legend_title can be changed using the labs() ggplot argument. Check out the documentation for some examples, and try to get as close as you can to any of the statebins maps in the chapter. I’ve included some template code below:

library(statebins)
# statebins(state_data = ???, 
#          state_col = ???,
#          value_col = ???,
#          palette = ???,
#          font_size = ???) +
#    labs(fill = ???) +
#  theme_statebins()

Part 2: Open-ended

Option 1: Customize one (or more) of your state maps even more!

E.g. choose a different color scheme, quantity to map, etc.

Option 2: Try making a county map!

Section 7.2 in the chapter walks through making county-level maps using FIPS codes. In the R chunk below, I’ve joined our county_level_2020 data to the county_map data by the FIPS code. Use this data to make a county-level map of the 2020 election results.

I want to point out by = c("id" = "county_fips") – this tells R to join the two datasets using the variable id in the first dataset (county_map) and county_fips in the second dataset (county_level_2020). This is super useful when you want to join two datasets that share a common ID variable but under a different name.

county_map_and_data = left_join(county_map, county_level_2020, by = c("id" = "county_fips"))

More on maps

There are many other approaches to making and working with maps in R, and what we’ve done here is the tip of the iceberg. For more on geospatial data, check out Chapter 17 of Modern Data Science with R!

LS0tCnRpdGxlOiAiTGFiMDM6IE1hcG1ha2luZyIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjc3M6IHN0YXQ0MS1sYWItdGhlbWUuY3NzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNvY3ZpeikKbGlicmFyeShtYXBzKQpsaWJyYXJ5KGdndGhlbWVzKQpgYGAKCgpUaGUgZGF0YSB3ZSdsbCB1c2UgaW4gdGhpcyBsYWIgaXMgZnJvbSB0aGUgMjAyMCBwcmVzaWRlbnRpYWwgZWxlY3Rpb24gYW5kIGlzIHB1YmxpY2x5IGF2YWlsYWJsZSBvbiBbZ2l0aHViXShodHRwczovL2dpdGh1Yi5jb20vdG9ubWNnL1VTX0NvdW50eV9MZXZlbF9FbGVjdGlvbl9SZXN1bHRzXzA4LTIwKSBhbmQgZHJhd3MgZnJvbSBGb3ggTmV3cywgUG9saXRpY28sIGFuZCB0aGUgTmV3IFlvcmsgVGltZXMuIEkndmUgaW5jbHVkZWQgdGhlIGNvZGUgSSB1c2VkIHRvIGRvd25sb2FkIHRoZSBjb3VudHkgbGV2ZWwgcmVzdWx0cyBhbmQgd3JhbmdsZSBpdCB0byBiZSBzdGF0ZS1sZXZlbC4gTm90ZSB0aGF0IHJlYWRpbmcgdGhlIENTViBmcm9tIHRoZSB3ZWIgbWF5ICpzbGlnaHRseSogc2xvdyBkb3duIHRoZSBrbml0dGluZyBwcm9jZXNzLCBidXQgSSB0aGluayB0aGlzIGlzIGhlbHBmdWwgdG8gc2VlIGFzIGdpdGh1YiBjYW4gYmUgYSBncmVhdCBzb3VyY2Ugb2YgZGF0YSBmb3IgcHJvamVjdHMhCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQpjb3VudHlfbGV2ZWxfMjAyMCA9IHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vdG9ubWNnL1VTX0NvdW50eV9MZXZlbF9FbGVjdGlvbl9SZXN1bHRzXzA4LTIwL21hc3Rlci8yMDIwX1VTX0NvdW50eV9MZXZlbF9QcmVzaWRlbnRpYWxfUmVzdWx0cy5jc3YiKQoKc3RhdGVfbGV2ZWxfMjAyMCA9IGNvdW50eV9sZXZlbF8yMDIwICU+JQogIGdyb3VwX2J5KHN0YXRlX25hbWUpICU+JQogIHN1bW1hcml6ZShnb3Bfdm90ZXMgPSBzdW0odm90ZXNfZ29wKSwKICAgICAgICAgZGVtX3ZvdGVzID0gc3VtKHZvdGVzX2RlbSksCiAgICAgICAgIHRvdGFsX3ZvdGVzID0gc3VtKHRvdGFsX3ZvdGVzKSwKICAgICAgICAgZGlmZiA9IHN1bShkaWZmKSkgJT4lCiAgbXV0YXRlKAogICAgcGN0X2dvcCA9IGdvcF92b3Rlcy90b3RhbF92b3RlcywKICAgIHBjdF9kZW0gPSBkZW1fdm90ZXMvdG90YWxfdm90ZXMKICApICU+JQogIHVuZ3JvdXAoKQoKc3RhdGVfbGV2ZWxfMjAyMApgYGAKCiMgUGFydCAxOiBSZXBsaWNhdGluZyAyMDE2IG1hcHMgdXNpbmcgMjAyMCBkYXRhCgpGb3IgdGhpcyBsYWIsIHdlJ3JlIGdvaW5nIHRvIHdhbGsgdGhyb3VnaCBbRGF0YSBWaXogQ2ggNy4xIGFuZCA3LjNdKGh0dHBzOi8vc29jdml6LmNvL21hcHMuaHRtbCNtYXBzKSBvbiBtYWtpbmcgbWFwcyBpbiBSLiBBbGwgeW91IG5lZWQgdG8gZG8gZm9yIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBsYWIgaXMgcmVwbGljYXRlIHRocmVlIGdyYXBocyBmcm9tIHRoZSBjaGFwdGVyLCB1c2luZyB0aGUgMjAyMCBkYXRhIGFib3ZlIGluc3RlYWQgb2YgMjAxNiBkYXRhLiBBbGwgY29kZSBpcyBhdmFpbGFibGUgaW4gdGhlIHRleHQsIHNvIHlvdXIgam9iIGlzIHRvICptYXAqIHRoZSBjb3JyZWN0IHZhcmlhYmxlcyBmcm9tIGBzdGF0ZV9sZXZlbF8yMDIwYCBkYXRhIHRvIHRoZSBleGlzdGluZyBtYXAgY29kZS4gKHB1biBpbnRlbmRlZCkgRG9uJ3QgZm9yZ2V0IHRvIGluc3RhbGwgdGhlIG5lY2Vzc2FyeSBwYWNrYWFnZXMgKGBzb2N2aXpgLCBgbWFwc2AsIGBnZ3RoZW1lc2ApLiAKCiMjIFJlcGxpY2F0aW9uIDE6IEZpZ3VyZSA3LjcgCgpOb3RlOiBZb3UgbWF5IGhhdmUgdG8gaW5zdGFsbCB0aGUgYG1hcHByb2pgIHBhY2thZ2UgaW4gb3JkZXIgZm9yIGBjb29yZF9tYXAoKWAgY29tbWFuZCB0byB3b3JrLgohW0VsZWN0aW9uIHJlc3VsdHMgYnkgc3RhdGVdKGltYWdlcy9EYXRhVml6LUZpZzctNy5wbmcpeyNpZCAuY2xhc3Mgd2lkdGg9NTAlIGhlaWdodD01MCV9CgojIyBSZXBsaWNhdGlvbiAyOiBPbmUgb2YgdGhlIG1hcHMgaW4gRmlndXJlIDcuOSAKCiFbRWxlY3Rpb24gcmVzdWx0cyBieSBzdGF0ZSB1c2luZyB3aGl0ZSBtaWRwb2ludCBhbmQgcHVycGxlIG1pZHBvaW50XShpbWFnZXMvRGF0YVZpekZpZzctOS5wbmcpeyNpZCAuY2xhc3Mgd2lkdGg9NTAlIGhlaWdodD01MCV9CgojIyBSZXBsaWNhdGlvbiAzOiBBbnkgb2YgdGhlIGBzdGF0ZWJpbnNgIGdyYXBocyBpbiBGaWd1cmUgNy4xNCBvciA3LjE1IAoKKE5vdGU6IFlvdSdsbCBoYXZlIHRvIGluc3RhbGwgdGhlIGBzdGF0ZWJpbnNgIHBhY2thZ2UgdG8gdXNlIHRoZSBjb2RlIGZyb20gdGhlIGNoYXB0ZXIpCgohW0VsZWN0aW9uIHJlc3VsdHMgdXNpbmcgc3RhdGViaW5zXShpbWFnZXMvRGF0YVZpei1GaWc3LTE1LnBuZyl7I2lkIC5jbGFzcyB3aWR0aD01MCUgaGVpZ2h0PTUwJX0KCkEgbm90ZSBvbiBgc3RhdGViaW5zYDogVGhlIHBhY2thZ2UgaGFzIGNoYW5nZWQgc2luY2UgdGhlIHRleHQgd2FzIHdyaXR0ZW4uIFNwZWNpZmljYWxseSwgdGhlIGBicmV3ZXJfcGFsYCBhcmd1bWVudCBoYXMgY2hhbmdlZCB0byBgcGFsZXR0ZWAsIHRoZSBgdGV4dF9jb2xvcmAgYXJndW1lbnQgZG9lcyBub3QgZXhpc3QsIGFuZCB0aGUgYGxlZ2VuZF90aXRsZWAgY2FuIGJlIGNoYW5nZWQgdXNpbmcgdGhlIGBsYWJzKClgIGdncGxvdCBhcmd1bWVudC4gQ2hlY2sgb3V0IHRoZSBbZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9naXRodWIuY29tL2hyYnJtc3RyL3N0YXRlYmlucykgZm9yIHNvbWUgZXhhbXBsZXMsIGFuZCB0cnkgdG8gZ2V0IGFzIGNsb3NlIGFzIHlvdSBjYW4gdG8gYW55IG9mIHRoZSBgc3RhdGViaW5zYCBtYXBzIGluIHRoZSBjaGFwdGVyLiBJJ3ZlIGluY2x1ZGVkIHNvbWUgdGVtcGxhdGUgY29kZSBiZWxvdzogCgpgYGB7cn0KbGlicmFyeShzdGF0ZWJpbnMpCiMgc3RhdGViaW5zKHN0YXRlX2RhdGEgPSA/Pz8sIAojICAgICAgICAgIHN0YXRlX2NvbCA9ID8/PywKIyAgICAgICAgICB2YWx1ZV9jb2wgPSA/Pz8sCiMgICAgICAgICAgcGFsZXR0ZSA9ID8/PywKIyAgICAgICAgICBmb250X3NpemUgPSA/Pz8pICsKIyAgICBsYWJzKGZpbGwgPSA/Pz8pICsKIyAgdGhlbWVfc3RhdGViaW5zKCkKCmBgYAoKIyBQYXJ0IDI6IE9wZW4tZW5kZWQKCiMjIE9wdGlvbiAxOiBDdXN0b21pemUgb25lIChvciBtb3JlKSBvZiB5b3VyIHN0YXRlIG1hcHMgZXZlbiBtb3JlISAKCkUuZy4gY2hvb3NlIGEgZGlmZmVyZW50IGNvbG9yIHNjaGVtZSwgcXVhbnRpdHkgdG8gbWFwLCBldGMuIAoKIyMgT3B0aW9uIDI6IFRyeSBtYWtpbmcgYSBjb3VudHkgbWFwISAKClNlY3Rpb24gNy4yIGluIHRoZSBjaGFwdGVyIHdhbGtzIHRocm91Z2ggbWFraW5nIGNvdW50eS1sZXZlbCBtYXBzIHVzaW5nIEZJUFMgY29kZXMuIEluIHRoZSBSIGNodW5rIGJlbG93LCBJJ3ZlIGpvaW5lZCBvdXIgYGNvdW50eV9sZXZlbF8yMDIwYCBkYXRhIHRvIHRoZSBgY291bnR5X21hcGAgZGF0YSBieSB0aGUgRklQUyBjb2RlLiBVc2UgdGhpcyBkYXRhIHRvIG1ha2UgYSBjb3VudHktbGV2ZWwgbWFwIG9mIHRoZSAyMDIwIGVsZWN0aW9uIHJlc3VsdHMuIAoKSSB3YW50IHRvIHBvaW50IG91dCBgYnkgPSBjKCJpZCIgPSAiY291bnR5X2ZpcHMiKWAgLS0gdGhpcyB0ZWxscyBSIHRvIGpvaW4gdGhlIHR3byBkYXRhc2V0cyB1c2luZyB0aGUgdmFyaWFibGUgYGlkYCBpbiB0aGUgZmlyc3QgZGF0YXNldCAoYGNvdW50eV9tYXBgKSBhbmQgYGNvdW50eV9maXBzYCBpbiB0aGUgc2Vjb25kIGRhdGFzZXQgKGBjb3VudHlfbGV2ZWxfMjAyMGApLiBUaGlzIGlzIHN1cGVyIHVzZWZ1bCB3aGVuIHlvdSB3YW50IHRvIGpvaW4gdHdvIGRhdGFzZXRzIHRoYXQgc2hhcmUgYSBjb21tb24gSUQgdmFyaWFibGUgYnV0IHVuZGVyIGEgZGlmZmVyZW50IG5hbWUuIAoKYGBge3J9CmNvdW50eV9tYXBfYW5kX2RhdGEgPSBsZWZ0X2pvaW4oY291bnR5X21hcCwgY291bnR5X2xldmVsXzIwMjAsIGJ5ID0gYygiaWQiID0gImNvdW50eV9maXBzIikpCmBgYAoKIyBNb3JlIG9uIG1hcHMKClRoZXJlIGFyZSBtYW55IG90aGVyIGFwcHJvYWNoZXMgdG8gbWFraW5nIGFuZCB3b3JraW5nIHdpdGggbWFwcyBpbiBSLCBhbmQgd2hhdCB3ZSd2ZSBkb25lIGhlcmUgaXMgdGhlIHRpcCBvZiB0aGUgaWNlYmVyZy4gRm9yIG1vcmUgb24gZ2Vvc3BhdGlhbCBkYXRhLCBjaGVjayBvdXQgQ2hhcHRlciAxNyBvZiBbTW9kZXJuIERhdGEgU2NpZW5jZSB3aXRoIFJdKGh0dHBzOi8vbWRzci1ib29rLmdpdGh1Yi5pby9tZHNyMmUvY2gtc3BhdGlhbC5odG1sI21vdGl2YXRpb24td2hhdHMtc28tZ3JlYXQtYWJvdXQtZ2Vvc3BhdGlhbC1kYXRhKSEgCg==