class: center, middle, inverse, title-slide .title[ # Visualizing spatial data II ] .author[ ### MACS 40700
University of Chicago ] --- class: inverse, middle # Setup --- ## Setup ``` r # load packages library(tidyverse) library(sf) library(rnaturalearth) library(colorspace) # more efficient to generate sf maps if (!identical(getOption("bitmapType"), "cairo") && isTRUE(capabilities()[["cairo"]])) { options(bitmapType = "cairo") } # set default theme for ggplot2 ggplot2::theme_set(ggplot2::theme_minimal(base_size = 16)) # set default figure parameters for knitr knitr::opts_chunk$set( fig.width = 8, fig.asp = 0.618, fig.retina = 2, dpi = 150 ) ``` --- ## Today's files ``` r # install sf if necessary # install.packages("sf") usethis::use_course("MACS40700/vector-maps") ``` --- ## Map data file formats * Vector files * Raster images * Numeric data * Popular formats * Shapefile * GeoJSON --- ## Shapefile * Encodes points, lines, and polygons * Collection of files * `.shp` - geographic coordinates * `.dbf` - data associated with the geographic features * `.prj` - projection of the coordinates in the shapefile --- ## GeoJSON * Uses **J**ava**S**cript **O**bject **N**otation (JSON) file format ```json { "type": "Feature", "geometry": { "type": "Point", "coordinates": [125.6, 10.1] }, "properties": { "name": "Dinagat Islands" } } ``` * Plain text files --- ## Simple Features for R <img src="images/sf.jpeg" alt="Simple features for R" width="60%" style="display: block; margin: auto;" /> .footnote[ Illustration by Allison Horst ] --- ## What is a feature? * Thing or an object in the real world * Sets of features * Geometry * Attributes --- ## Simple features <img src="images/simple-features.png" alt="Simple features" width="70%" style="display: block; margin: auto;" /> .footnote[ Source: [Simple Features for R](https://r-spatial.github.io/sf/articles/sf1.html#sf-objects-with-simple-features-1) ] --- ## Simple features in R * Uses basic R data structures * Data frame with one row per feature * Lots of list columns --- ## sf: getting started * Huge pain to get acclimated to * You can read in multiple layers for your map (e.g. state boundaries, geographic features, etc.) * Often need to deal with many, many files --- ## Importing shapefiles ``` r usa_shape <- st_read(dsn = here("data", "ex_shapefile.shp")) ``` .tiny[ ``` r usa_shape ``` ``` ## Simple feature collection with 56 features and 9 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: -179.1473 ymin: -14.55255 xmax: 179.7785 ymax: 71.35256 ## Geodetic CRS: NAD83 ## First 10 features: ## STATEFP STATENS AFFGEOID GEOID STUSPS NAME LSAD ALAND AWATER geometry ## 1 55 01779806 0400000US55 55 WI Wisconsin 00 140292246684 29343721650 MULTIPOLYGON (((-86.9562 45... ## 2 54 01779805 0400000US54 54 WV West Virginia 00 62266296765 489206049 MULTIPOLYGON (((-82.643 38.... ## 3 16 01779783 0400000US16 16 ID Idaho 00 214049923496 2391577745 MULTIPOLYGON (((-117.2427 4... ## 4 27 00662849 0400000US27 27 MN Minnesota 00 206232157570 18949864226 MULTIPOLYGON (((-97.23921 4... ## 5 19 01779785 0400000US19 19 IA Iowa 00 144659688848 1085996889 MULTIPOLYGON (((-96.6397 42... ## 6 10 01779781 0400000US10 10 DE Delaware 00 5046731558 1399179670 MULTIPOLYGON (((-75.5708 39... ## 7 72 01779808 0400000US72 72 PR Puerto Rico 00 8868948653 4922329963 MULTIPOLYGON (((-65.3375 18... ## 8 29 01779791 0400000US29 29 MO Missouri 00 178052563675 2487215790 MULTIPOLYGON (((-95.77355 4... ## 9 50 01779802 0400000US50 50 VT Vermont 00 23873081385 1030243281 MULTIPOLYGON (((-73.43774 4... ## 10 24 01714934 0400000US24 24 MD Maryland 00 25151895765 6979171386 MULTIPOLYGON (((-76.0494 37... ``` ] --- ## Importing GeoJSON files ``` r chi_json <- st_read(dsn = here("data", "ex_file.geojson")) ``` .tiny[ ``` r chi_json ``` ``` ## Simple feature collection with 77 features and 9 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: -87.94011 ymin: 41.64454 xmax: -87.52414 ymax: 42.02304 ## Geodetic CRS: WGS 84 ## First 10 features: ## community area shape_area perimeter area_num_1 area_numbe comarea_id comarea shape_len geometry ## 1 DOUGLAS 0 46004621.1581 0 35 35 0 0 31027.0545098 MULTIPOLYGON (((-87.60914 4... ## 2 OAKLAND 0 16913961.0408 0 36 36 0 0 19565.5061533 MULTIPOLYGON (((-87.59215 4... ## 3 FULLER PARK 0 19916704.8692 0 37 37 0 0 25339.0897503 MULTIPOLYGON (((-87.6288 41... ## 4 GRAND BOULEVARD 0 48492503.1554 0 38 38 0 0 28196.8371573 MULTIPOLYGON (((-87.60671 4... ## 5 KENWOOD 0 29071741.9283 0 39 39 0 0 23325.1679062 MULTIPOLYGON (((-87.59215 4... ## 6 LINCOLN SQUARE 0 71352328.2399 0 4 4 0 0 36624.6030848 MULTIPOLYGON (((-87.67441 4... ## 7 WASHINGTON PARK 0 42373881.4842 0 40 40 0 0 28175.3160866 MULTIPOLYGON (((-87.60604 4... ## 8 HYDE PARK 0 45105380.1732 0 41 41 0 0 29746.7082016 MULTIPOLYGON (((-87.58038 4... ## 9 WOODLAWN 0 57815179.512 0 42 42 0 0 46936.9592443 MULTIPOLYGON (((-87.57714 4... ## 10 ROGERS PARK 0 51259902.4506 0 1 1 0 0 34052.3975757 MULTIPOLYGON (((-87.65456 4... ``` ] --- ## Drawing maps with `sf` objects ``` r usa <- st_read(dsn = here("data", "cb_2020_us_state_5m", "cb_2020_us_state_5m.shp")) ``` .tiny[ ``` r usa_shape ``` ``` ## Simple feature collection with 56 features and 9 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: -179.1473 ymin: -14.55255 xmax: 179.7785 ymax: 71.35256 ## Geodetic CRS: NAD83 ## First 10 features: ## STATEFP STATENS AFFGEOID GEOID STUSPS NAME LSAD ALAND AWATER geometry ## 1 55 01779806 0400000US55 55 WI Wisconsin 00 140292246684 29343721650 MULTIPOLYGON (((-86.9562 45... ## 2 54 01779805 0400000US54 54 WV West Virginia 00 62266296765 489206049 MULTIPOLYGON (((-82.643 38.... ## 3 16 01779783 0400000US16 16 ID Idaho 00 214049923496 2391577745 MULTIPOLYGON (((-117.2427 4... ## 4 27 00662849 0400000US27 27 MN Minnesota 00 206232157570 18949864226 MULTIPOLYGON (((-97.23921 4... ## 5 19 01779785 0400000US19 19 IA Iowa 00 144659688848 1085996889 MULTIPOLYGON (((-96.6397 42... ## 6 10 01779781 0400000US10 10 DE Delaware 00 5046731558 1399179670 MULTIPOLYGON (((-75.5708 39... ## 7 72 01779808 0400000US72 72 PR Puerto Rico 00 8868948653 4922329963 MULTIPOLYGON (((-65.3375 18... ## 8 29 01779791 0400000US29 29 MO Missouri 00 178052563675 2487215790 MULTIPOLYGON (((-95.77355 4... ## 9 50 01779802 0400000US50 50 VT Vermont 00 23873081385 1030243281 MULTIPOLYGON (((-73.43774 4... ## 10 24 01714934 0400000US24 24 MD Maryland 00 25151895765 6979171386 MULTIPOLYGON (((-76.0494 37... ``` ] --- ## USA boundaries .panelset[ .panel[.panel-name[Code] ``` r ggplot(data = usa) + * geom_sf() ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-4-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- ## Plot a subset of a map .panelset[ .panel[.panel-name[Code] ``` r *usa_48 <- usa %>% * filter(NAME %in% state.name) %>% * filter(NAME != "Alaska", NAME != "Hawaii") ggplot(data = usa_48) + geom_sf() ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-5-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- ## Just another `ggplot()` .panelset[ .panel[.panel-name[Code] ``` r ggplot(data = usa_48) + geom_sf( * fill = "palegreen", * color = "black" ) ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-6-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- <img src="https://imgs.xkcd.com/comics/contiguous_41_states.png" width="60%" style="display: block; margin: auto;" /> .footnote[Source: [xkcd](https://imgs.xkcd.com/comics/contiguous_41_states.png)] --- ## Plotly: hello there! .panelset[ .panel[.panel-name[R Code] ``` r library(plotly) library(sf) nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE) ggplotly( ggplot(nc) + geom_sf(aes(fill = AREA))) ```
] .panel[.panel-name[Plot]  ] ] --- ## Getting resourceful: getting what you need * Packages abound with additional information, data, files, availability * Google around to see if you can locate what you need / want * ex: `urbnmapr` can give you us-focused shapefiles that can be merged with relevant data --- ## `urbnmapr` .panelset[ .panel[.panel-name[Code] ``` r # devtools::install_github("UrbanInstitute/urbnmapr") library(urbnmapr) states_sf <- get_urbn_map("states", sf = TRUE) ggplot(data = states_sf) + geom_sf() ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-7-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- class: inverse, middle # Identifying points on a map --- ## Points ``` r crimes <- read_csv("data/chicago-crimes.csv") #option, if latest version of c3s2 #crimes <- c3s2::`chicago-crimes` ``` ``` r crimes_homicide <- filter(.data = crimes, `Primary Type` == "HOMICIDE") crimes_homicide ``` ``` ## # A tibble: 675 × 22 ## ID `Case Number` Date Block IUCR `Primary Type` Description ## <dbl> <chr> <chr> <chr> <chr> <chr> <chr> ## 1 10826397 JA119425 01/18/2017 12:… 023X… 0142 HOMICIDE RECKLESS H… ## 2 10836558 JA138326 02/01/2017 06:… 013X… 0142 HOMICIDE RECKLESS H… ## 3 11177987 JA549346 12/14/2017 05:… 038X… 0142 HOMICIDE RECKLESS H… ## 4 23059 JA100252 01/01/2017 05:… 046X… 0110 HOMICIDE FIRST DEGR… ## 5 23060 JA100278 01/01/2017 06:… 046X… 0110 HOMICIDE FIRST DEGR… ## 6 23061 JA102602 01/03/2017 12:… 034X… 0110 HOMICIDE FIRST DEGR… ## 7 23062 JA103468 01/03/2017 11:… 032X… 0110 HOMICIDE FIRST DEGR… ## 8 23063 JA102602 01/04/2017 12:… 034X… 0110 HOMICIDE FIRST DEGR… ## 9 23064 JA103468 01/04/2017 05:… 032X… 0110 HOMICIDE FIRST DEGR… ## 10 23066 HZ564892 01/06/2017 01:… 086X… 0110 HOMICIDE FIRST DEGR… ## # ℹ 665 more rows ## # ℹ 15 more variables: `Location Description` <chr>, Arrest <lgl>, ## # Domestic <lgl>, Beat <chr>, District <chr>, Ward <dbl>, ## # `Community Area` <dbl>, `FBI Code` <chr>, `X Coordinate` <dbl>, ## # `Y Coordinate` <dbl>, Year <dbl>, `Updated On` <chr>, Latitude <dbl>, ## # Longitude <dbl>, Location <chr> ``` --- ## Points .panelset[ .panel[.panel-name[Code] ``` r ggplot(data = crimes_homicide, mapping = aes(x = Longitude, y = Latitude)) + geom_point() ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-8-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- ## Points .panelset[ .panel[.panel-name[Code] ``` r ggplot(data = chi_json) + * geom_sf() + geom_point( data = crimes_homicide, mapping = aes( x = Longitude, y = Latitude ), shape = 1 ) ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-9-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- ## Converting to `sf` data frame ``` r crimes_homicide_sf <- st_as_sf(x = crimes_homicide, coords = c("Longitude", "Latitude")) st_crs(crimes_homicide_sf) <- 4326 # set the coordinate reference system crimes_homicide_sf ``` ``` ## Simple feature collection with 675 features and 20 fields ## Geometry type: POINT ## Dimension: XY ## Bounding box: xmin: -87.83662 ymin: 41.65306 xmax: -87.53287 ymax: 42.02164 ## Geodetic CRS: WGS 84 ## # A tibble: 675 × 21 ## ID `Case Number` Date Block IUCR `Primary Type` Description ## * <dbl> <chr> <chr> <chr> <chr> <chr> <chr> ## 1 10826397 JA119425 01/18/2017 12:… 023X… 0142 HOMICIDE RECKLESS H… ## 2 10836558 JA138326 02/01/2017 06:… 013X… 0142 HOMICIDE RECKLESS H… ## 3 11177987 JA549346 12/14/2017 05:… 038X… 0142 HOMICIDE RECKLESS H… ## 4 23059 JA100252 01/01/2017 05:… 046X… 0110 HOMICIDE FIRST DEGR… ## 5 23060 JA100278 01/01/2017 06:… 046X… 0110 HOMICIDE FIRST DEGR… ## 6 23061 JA102602 01/03/2017 12:… 034X… 0110 HOMICIDE FIRST DEGR… ## 7 23062 JA103468 01/03/2017 11:… 032X… 0110 HOMICIDE FIRST DEGR… ## 8 23063 JA102602 01/04/2017 12:… 034X… 0110 HOMICIDE FIRST DEGR… ## 9 23064 JA103468 01/04/2017 05:… 032X… 0110 HOMICIDE FIRST DEGR… ## 10 23066 HZ564892 01/06/2017 01:… 086X… 0110 HOMICIDE FIRST DEGR… ## # ℹ 665 more rows ## # ℹ 14 more variables: `Location Description` <chr>, Arrest <lgl>, ## # Domestic <lgl>, Beat <chr>, District <chr>, Ward <dbl>, ## # `Community Area` <dbl>, `FBI Code` <chr>, `X Coordinate` <dbl>, ## # `Y Coordinate` <dbl>, Year <dbl>, `Updated On` <chr>, Location <chr>, ## # geometry <POINT [°]> ``` --- ## Plotting with two sf data frames .panelset[ .panel[.panel-name[Code] ``` r ggplot() + geom_sf(data = chi_json) + * geom_sf(data = crimes_homicide_sf, shape = 1) ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-10-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- class: inverse, middle # Application: Immigration and Choropleths --- <img src="https://media.giphy.com/media/If7M383oivlYY/giphy.gif" width="80%" style="display: block; margin: auto;" /> --- ## Fill (choropleths) ``` r fb_state <- read_csv(file = here("data", "foreign-born.csv")) ``` ``` r fb_state ``` ``` ## # A tibble: 52 × 6 ## GEOID NAME total native foreign pct_foreign ## <chr> <chr> <dbl> <dbl> <dbl> <dbl> ## 1 01 Alabama 4876250 4703303 172947 0.0355 ## 2 02 Alaska 737068 679401 57667 0.0782 ## 3 04 Arizona 7050299 6109648 940651 0.133 ## 4 05 Arkansas 2999370 2854323 145047 0.0484 ## 5 06 California 39283497 28736287 10547210 0.268 ## 6 08 Colorado 5610349 5063836 546513 0.0974 ## 7 10 Delaware 957248 865775 91473 0.0956 ## 8 11 District of Columbia 692683 597618 95065 0.137 ## 9 09 Connecticut 3575074 3054123 520951 0.146 ## 10 12 Florida 20901636 16576836 4324800 0.207 ## # ℹ 42 more rows ``` --- ## Join the data ``` r usa_fb <- left_join(x = usa_48, y = fb_state, by = c("STATEFP" = "GEOID", "NAME")) usa_fb ``` ``` ## Simple feature collection with 48 features and 13 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: -124.7332 ymin: 24.51496 xmax: -66.9499 ymax: 49.38436 ## Geodetic CRS: NAD83 ## First 10 features: ## STATEFP STATENS AFFGEOID GEOID STUSPS NAME LSAD ALAND ## 1 55 01779806 0400000US55 55 WI Wisconsin 00 140292246684 ## 2 54 01779805 0400000US54 54 WV West Virginia 00 62266296765 ## 3 16 01779783 0400000US16 16 ID Idaho 00 214049923496 ## 4 27 00662849 0400000US27 27 MN Minnesota 00 206232157570 ## 5 19 01779785 0400000US19 19 IA Iowa 00 144659688848 ## 6 10 01779781 0400000US10 10 DE Delaware 00 5046731558 ## 7 29 01779791 0400000US29 29 MO Missouri 00 178052563675 ## 8 50 01779802 0400000US50 50 VT Vermont 00 23873081385 ## 9 24 01714934 0400000US24 24 MD Maryland 00 25151895765 ## 10 33 01779794 0400000US33 33 NH New Hampshire 00 23190113978 ## AWATER total native foreign pct_foreign ## 1 29343721650 5790716 5500994 289722 0.05003215 ## 2 489206049 1817305 1787134 30171 0.01660206 ## 3 2391577745 1717750 1615307 102443 0.05963790 ## 4 18949864226 5563378 5090529 472849 0.08499315 ## 5 1085996889 3139508 2973069 166439 0.05301436 ## 6 1399179670 957248 865775 91473 0.09555831 ## 7 2487215790 6104910 5849191 255719 0.04188743 ## 8 1030243281 624313 594985 29328 0.04697644 ## 9 6979171386 6018848 5105961 912887 0.15167138 ## 10 1025973001 1348124 1265430 82694 0.06134005 ## geometry ## 1 MULTIPOLYGON (((-86.9562 45... ## 2 MULTIPOLYGON (((-82.643 38.... ## 3 MULTIPOLYGON (((-117.2427 4... ## 4 MULTIPOLYGON (((-97.23921 4... ## 5 MULTIPOLYGON (((-96.6397 42... ## 6 MULTIPOLYGON (((-75.5708 39... ## 7 MULTIPOLYGON (((-95.77355 4... ## 8 MULTIPOLYGON (((-73.43774 4... ## 9 MULTIPOLYGON (((-76.0494 37... ## 10 MULTIPOLYGON (((-72.55725 4... ``` --- ## Draw the map .panelset[ .panel[.panel-name[Code] ``` r ggplot(data = usa_fb) + * geom_sf(mapping = aes(fill = pct_foreign)) ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-12-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- ## Use better colors .panelset[ .panel[.panel-name[Code] ``` r ggplot(data = usa_fb) + geom_sf(mapping = aes(fill = pct_foreign)) + * scale_fill_continuous_sequential(palette = "mako") ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-13-1.png" width="70%" style="display: block; margin: auto;" /> ] (q: what would our reading say about this??) ] --- ## Spatial aggregation ``` r st_join(x = chi_json, y = crimes_homicide_sf) ``` ``` ## Simple feature collection with 686 features and 29 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: -87.94011 ymin: 41.64454 xmax: -87.52414 ymax: 42.02304 ## Geodetic CRS: WGS 84 ## First 10 features: ## community area shape_area perimeter area_num_1 area_numbe ## 1 DOUGLAS 0 46004621.1581 0 35 35 ## 1.1 DOUGLAS 0 46004621.1581 0 35 35 ## 1.2 DOUGLAS 0 46004621.1581 0 35 35 ## 1.3 DOUGLAS 0 46004621.1581 0 35 35 ## 2 OAKLAND 0 16913961.0408 0 36 36 ## 3 FULLER PARK 0 19916704.8692 0 37 37 ## 4 GRAND BOULEVARD 0 48492503.1554 0 38 38 ## 4.1 GRAND BOULEVARD 0 48492503.1554 0 38 38 ## 4.2 GRAND BOULEVARD 0 48492503.1554 0 38 38 ## 4.3 GRAND BOULEVARD 0 48492503.1554 0 38 38 ## comarea_id comarea shape_len ID Case Number Date ## 1 0 0 31027.0545098 23297 JA269803 05/18/2017 09:04:00 PM ## 1.1 0 0 31027.0545098 23316 JA283507 05/29/2017 10:56:00 AM ## 1.2 0 0 31027.0545098 23446 JA348138 07/14/2017 09:24:00 PM ## 1.3 0 0 31027.0545098 23499 JA383393 08/08/2017 11:17:00 PM ## 2 0 0 19565.5061533 NA <NA> <NA> ## 3 0 0 25339.0897503 23340 JA294107 06/05/2017 07:58:00 PM ## 4 0 0 28196.8371573 23116 JA137097 01/31/2017 08:02:00 PM ## 4.1 0 0 28196.8371573 23406 JA328468 06/30/2017 08:12:00 AM ## 4.2 0 0 28196.8371573 23407 JA328468 06/30/2017 10:51:00 AM ## 4.3 0 0 28196.8371573 23414 JA331015 07/02/2017 02:13:00 AM ## Block IUCR Primary Type Description ## 1 027XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## 1.1 029XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## 1.2 000XX W PERSHING RD 0110 HOMICIDE FIRST DEGREE MURDER ## 1.3 000XX E 37TH PL 0110 HOMICIDE FIRST DEGREE MURDER ## 2 <NA> <NA> <NA> <NA> ## 3 044XX S SHIELDS AVE 0110 HOMICIDE FIRST DEGREE MURDER ## 4 045XX S PRAIRIE AVE 0110 HOMICIDE FIRST DEGREE MURDER ## 4.1 041XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## 4.2 041XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## 4.3 042XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## Location Description Arrest Domestic Beat District Ward Community Area ## 1 CHA PARKING LOT FALSE FALSE 0133 001 3 35 ## 1.1 APARTMENT TRUE TRUE 0133 001 3 35 ## 1.2 AUTO FALSE FALSE 0213 002 3 38 ## 1.3 STREET FALSE FALSE 0213 002 3 35 ## 2 <NA> NA NA <NA> <NA> NA NA ## 3 STREET FALSE FALSE 0925 009 3 37 ## 4 ALLEY FALSE FALSE 0215 002 3 38 ## 4.1 AUTO FALSE FALSE 0213 002 3 38 ## 4.2 AUTO FALSE FALSE 0213 002 3 38 ## 4.3 STREET FALSE FALSE 0213 002 3 38 ## FBI Code X Coordinate Y Coordinate Year Updated On ## 1 01A 1176731 1886507 2017 03/19/2019 04:11:22 PM ## 1.1 01A 1176758 1885480 2017 03/19/2019 04:11:22 PM ## 1.2 01A 1176527 1879134 2017 03/19/2019 04:11:22 PM ## 1.3 01A 1177555 1880158 2017 03/19/2019 04:11:22 PM ## 2 <NA> NA NA NA <NA> ## 3 01A 1174721 1875349 2017 03/19/2019 04:11:22 PM ## 4 01A 1178802 1874963 2017 03/18/2019 04:08:09 PM ## 4.1 01A 1176956 1877748 2017 03/19/2019 04:11:22 PM ## 4.2 01A 1176956 1877748 2017 03/19/2019 04:11:22 PM ## 4.3 01A 1176979 1876907 2017 03/19/2019 04:11:22 PM ## Location geometry ## 1 (41.843922218, -87.6269207) MULTIPOLYGON (((-87.60914 4... ## 1.1 (41.841103444, -87.626852618) MULTIPOLYGON (((-87.60914 4... ## 1.2 (41.823694722, -87.627891537) MULTIPOLYGON (((-87.60914 4... ## 1.3 (41.826481438, -87.624089191) MULTIPOLYGON (((-87.60914 4... ## 2 <NA> MULTIPOLYGON (((-87.59215 4... ## 3 (41.813348838, -87.634629974) MULTIPOLYGON (((-87.6288 41... ## 4 (41.812197594, -87.619672538) MULTIPOLYGON (((-87.60671 4... ## 4.1 (41.819881744, -87.62635954) MULTIPOLYGON (((-87.60671 4... ## 4.2 (41.819881744, -87.62635954) MULTIPOLYGON (((-87.60671 4... ## 4.3 (41.817573449, -87.626300553) MULTIPOLYGON (((-87.60671 4... ``` --- count: false .panel1-crimes-agg-map-auto[ ``` r *chi_json ``` ] .panel2-crimes-agg-map-auto[ ``` ## Simple feature collection with 77 features and 9 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: -87.94011 ymin: 41.64454 xmax: -87.52414 ymax: 42.02304 ## Geodetic CRS: WGS 84 ## First 10 features: ## community area shape_area perimeter area_num_1 area_numbe ## 1 DOUGLAS 0 46004621.1581 0 35 35 ## 2 OAKLAND 0 16913961.0408 0 36 36 ## 3 FULLER PARK 0 19916704.8692 0 37 37 ## 4 GRAND BOULEVARD 0 48492503.1554 0 38 38 ## 5 KENWOOD 0 29071741.9283 0 39 39 ## 6 LINCOLN SQUARE 0 71352328.2399 0 4 4 ## 7 WASHINGTON PARK 0 42373881.4842 0 40 40 ## 8 HYDE PARK 0 45105380.1732 0 41 41 ## 9 WOODLAWN 0 57815179.512 0 42 42 ## 10 ROGERS PARK 0 51259902.4506 0 1 1 ## comarea_id comarea shape_len geometry ## 1 0 0 31027.0545098 MULTIPOLYGON (((-87.60914 4... ## 2 0 0 19565.5061533 MULTIPOLYGON (((-87.59215 4... ## 3 0 0 25339.0897503 MULTIPOLYGON (((-87.6288 41... ## 4 0 0 28196.8371573 MULTIPOLYGON (((-87.60671 4... ## 5 0 0 23325.1679062 MULTIPOLYGON (((-87.59215 4... ## 6 0 0 36624.6030848 MULTIPOLYGON (((-87.67441 4... ## 7 0 0 28175.3160866 MULTIPOLYGON (((-87.60604 4... ## 8 0 0 29746.7082016 MULTIPOLYGON (((-87.58038 4... ## 9 0 0 46936.9592443 MULTIPOLYGON (((-87.57714 4... ## 10 0 0 34052.3975757 MULTIPOLYGON (((-87.65456 4... ``` ] --- count: false .panel1-crimes-agg-map-auto[ ``` r chi_json %>% * st_join(y = crimes_homicide_sf) ``` ] .panel2-crimes-agg-map-auto[ ``` ## Simple feature collection with 686 features and 29 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: -87.94011 ymin: 41.64454 xmax: -87.52414 ymax: 42.02304 ## Geodetic CRS: WGS 84 ## First 10 features: ## community area shape_area perimeter area_num_1 area_numbe ## 1 DOUGLAS 0 46004621.1581 0 35 35 ## 1.1 DOUGLAS 0 46004621.1581 0 35 35 ## 1.2 DOUGLAS 0 46004621.1581 0 35 35 ## 1.3 DOUGLAS 0 46004621.1581 0 35 35 ## 2 OAKLAND 0 16913961.0408 0 36 36 ## 3 FULLER PARK 0 19916704.8692 0 37 37 ## 4 GRAND BOULEVARD 0 48492503.1554 0 38 38 ## 4.1 GRAND BOULEVARD 0 48492503.1554 0 38 38 ## 4.2 GRAND BOULEVARD 0 48492503.1554 0 38 38 ## 4.3 GRAND BOULEVARD 0 48492503.1554 0 38 38 ## comarea_id comarea shape_len ID Case Number Date ## 1 0 0 31027.0545098 23297 JA269803 05/18/2017 09:04:00 PM ## 1.1 0 0 31027.0545098 23316 JA283507 05/29/2017 10:56:00 AM ## 1.2 0 0 31027.0545098 23446 JA348138 07/14/2017 09:24:00 PM ## 1.3 0 0 31027.0545098 23499 JA383393 08/08/2017 11:17:00 PM ## 2 0 0 19565.5061533 NA <NA> <NA> ## 3 0 0 25339.0897503 23340 JA294107 06/05/2017 07:58:00 PM ## 4 0 0 28196.8371573 23116 JA137097 01/31/2017 08:02:00 PM ## 4.1 0 0 28196.8371573 23406 JA328468 06/30/2017 08:12:00 AM ## 4.2 0 0 28196.8371573 23407 JA328468 06/30/2017 10:51:00 AM ## 4.3 0 0 28196.8371573 23414 JA331015 07/02/2017 02:13:00 AM ## Block IUCR Primary Type Description ## 1 027XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## 1.1 029XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## 1.2 000XX W PERSHING RD 0110 HOMICIDE FIRST DEGREE MURDER ## 1.3 000XX E 37TH PL 0110 HOMICIDE FIRST DEGREE MURDER ## 2 <NA> <NA> <NA> <NA> ## 3 044XX S SHIELDS AVE 0110 HOMICIDE FIRST DEGREE MURDER ## 4 045XX S PRAIRIE AVE 0110 HOMICIDE FIRST DEGREE MURDER ## 4.1 041XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## 4.2 041XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## 4.3 042XX S STATE ST 0110 HOMICIDE FIRST DEGREE MURDER ## Location Description Arrest Domestic Beat District Ward Community Area ## 1 CHA PARKING LOT FALSE FALSE 0133 001 3 35 ## 1.1 APARTMENT TRUE TRUE 0133 001 3 35 ## 1.2 AUTO FALSE FALSE 0213 002 3 38 ## 1.3 STREET FALSE FALSE 0213 002 3 35 ## 2 <NA> NA NA <NA> <NA> NA NA ## 3 STREET FALSE FALSE 0925 009 3 37 ## 4 ALLEY FALSE FALSE 0215 002 3 38 ## 4.1 AUTO FALSE FALSE 0213 002 3 38 ## 4.2 AUTO FALSE FALSE 0213 002 3 38 ## 4.3 STREET FALSE FALSE 0213 002 3 38 ## FBI Code X Coordinate Y Coordinate Year Updated On ## 1 01A 1176731 1886507 2017 03/19/2019 04:11:22 PM ## 1.1 01A 1176758 1885480 2017 03/19/2019 04:11:22 PM ## 1.2 01A 1176527 1879134 2017 03/19/2019 04:11:22 PM ## 1.3 01A 1177555 1880158 2017 03/19/2019 04:11:22 PM ## 2 <NA> NA NA NA <NA> ## 3 01A 1174721 1875349 2017 03/19/2019 04:11:22 PM ## 4 01A 1178802 1874963 2017 03/18/2019 04:08:09 PM ## 4.1 01A 1176956 1877748 2017 03/19/2019 04:11:22 PM ## 4.2 01A 1176956 1877748 2017 03/19/2019 04:11:22 PM ## 4.3 01A 1176979 1876907 2017 03/19/2019 04:11:22 PM ## Location geometry ## 1 (41.843922218, -87.6269207) MULTIPOLYGON (((-87.60914 4... ## 1.1 (41.841103444, -87.626852618) MULTIPOLYGON (((-87.60914 4... ## 1.2 (41.823694722, -87.627891537) MULTIPOLYGON (((-87.60914 4... ## 1.3 (41.826481438, -87.624089191) MULTIPOLYGON (((-87.60914 4... ## 2 <NA> MULTIPOLYGON (((-87.59215 4... ## 3 (41.813348838, -87.634629974) MULTIPOLYGON (((-87.6288 41... ## 4 (41.812197594, -87.619672538) MULTIPOLYGON (((-87.60671 4... ## 4.1 (41.819881744, -87.62635954) MULTIPOLYGON (((-87.60671 4... ## 4.2 (41.819881744, -87.62635954) MULTIPOLYGON (((-87.60671 4... ## 4.3 (41.817573449, -87.626300553) MULTIPOLYGON (((-87.60671 4... ``` ] --- count: false .panel1-crimes-agg-map-auto[ ``` r chi_json %>% st_join(y = crimes_homicide_sf) %>% * group_by(community) ``` ] .panel2-crimes-agg-map-auto[ ``` ## Simple feature collection with 686 features and 29 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: -87.94011 ymin: 41.64454 xmax: -87.52414 ymax: 42.02304 ## Geodetic CRS: WGS 84 ## # A tibble: 686 × 30 ## # Groups: community [77] ## community area shape_area perimeter area_num_1 area_numbe comarea_id comarea ## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> ## 1 DOUGLAS 0 46004621.… 0 35 35 0 0 ## 2 DOUGLAS 0 46004621.… 0 35 35 0 0 ## 3 DOUGLAS 0 46004621.… 0 35 35 0 0 ## 4 DOUGLAS 0 46004621.… 0 35 35 0 0 ## 5 OAKLAND 0 16913961.… 0 36 36 0 0 ## 6 FULLER P… 0 19916704.… 0 37 37 0 0 ## 7 GRAND BO… 0 48492503.… 0 38 38 0 0 ## 8 GRAND BO… 0 48492503.… 0 38 38 0 0 ## 9 GRAND BO… 0 48492503.… 0 38 38 0 0 ## 10 GRAND BO… 0 48492503.… 0 38 38 0 0 ## # ℹ 676 more rows ## # ℹ 22 more variables: shape_len <chr>, ID <dbl>, `Case Number` <chr>, ## # Date <chr>, Block <chr>, IUCR <chr>, `Primary Type` <chr>, ## # Description <chr>, `Location Description` <chr>, Arrest <lgl>, ## # Domestic <lgl>, Beat <chr>, District <chr>, Ward <dbl>, ## # `Community Area` <dbl>, `FBI Code` <chr>, `X Coordinate` <dbl>, ## # `Y Coordinate` <dbl>, Year <dbl>, `Updated On` <chr>, Location <chr>, … ``` ] --- count: false .panel1-crimes-agg-map-auto[ ``` r chi_json %>% st_join(y = crimes_homicide_sf) %>% group_by(community) %>% * count() ``` ] .panel2-crimes-agg-map-auto[ ``` ## Simple feature collection with 77 features and 2 fields ## Geometry type: GEOMETRY ## Dimension: XY ## Bounding box: xmin: -87.94011 ymin: 41.64454 xmax: -87.52414 ymax: 42.02304 ## Geodetic CRS: WGS 84 ## # A tibble: 77 × 3 ## community n geometry ## * <chr> <int> <POLYGON [°]> ## 1 ALBANY PARK 1 ((-87.70454 41.97382, -87.70478 41.97395, -87.70501 41.… ## 2 ARCHER HEIGHTS 3 ((-87.71437 41.82632, -87.71523 41.82605, -87.71573 41.… ## 3 ARMOUR SQUARE 1 ((-87.62918 41.84592, -87.62919 41.84613, -87.62919 41.… ## 4 ASHBURN 6 ((-87.71278 41.75739, -87.71297 41.75743, -87.71308 41.… ## 5 AUBURN GRESHAM 27 ((-87.64028 41.75614, -87.64052 41.75613, -87.64058 41.… ## 6 AUSTIN 83 ((-87.79152 41.91813, -87.79258 41.91852, -87.79387 41.… ## 7 AVALON PARK 4 ((-87.58582 41.75151, -87.58582 41.75167, -87.58587 41.… ## 8 AVONDALE 3 ((-87.688 41.93611, -87.68804 41.93614, -87.68808 41.93… ## 9 BELMONT CRAGIN 8 ((-87.74135 41.91422, -87.74137 41.91491, -87.74137 41.… ## 10 BEVERLY 1 ((-87.67337 41.73566, -87.67347 41.73566, -87.67349 41.… ## # ℹ 67 more rows ``` ] --- count: false .panel1-crimes-agg-map-auto[ ``` r chi_json %>% st_join(y = crimes_homicide_sf) %>% group_by(community) %>% count() %>% * ggplot() ``` ] .panel2-crimes-agg-map-auto[ <img src="index_files/figure-html/crimes-agg-map_auto_05_output-1.png" width="80%" style="display: block; margin: auto;" /> ] --- count: false .panel1-crimes-agg-map-auto[ ``` r chi_json %>% st_join(y = crimes_homicide_sf) %>% group_by(community) %>% count() %>% ggplot() + * geom_sf(mapping = aes(fill = n)) ``` ] .panel2-crimes-agg-map-auto[ <img src="index_files/figure-html/crimes-agg-map_auto_06_output-1.png" width="80%" style="display: block; margin: auto;" /> ] <style> .panel1-crimes-agg-map-auto { color: black; width: 38.6060606060606%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel2-crimes-agg-map-auto { color: black; width: 59.3939393939394%; hight: 32%; float: left; padding-left: 1%; font-size: 80% } .panel3-crimes-agg-map-auto { color: black; width: NA%; hight: 33%; float: left; padding-left: 1%; font-size: 80% } </style> --- ## Comparison <img src="index_files/figure-html/crimes-agg-map-2-1.png" width="90%" style="display: block; margin: auto;" /> --- ## Exercise using household income - American Community Survey - [`tidycensus`](https://walker-data.com/tidycensus/) ```r # install sf if necessary # install.packages("sf") usethis::use_course("MACS40700/vector-maps") ```
--- ## Illinois examples <img src="vector_maps/images/il_counties_cities.png" width="70%" style="display: block; margin: auto;" /> --- ## SWITZERLAND <img src="vector_maps/images/switzerland.png" width="70%" style="display: block; margin: auto;" /> --- ## Bin data to discrete intervals * Continuous vs. discrete variables for color * Collapse to a discrete variable --- ## `cut_interval()` .panelset[ .panel[.panel-name[Code] ``` r usa_fb %>% * mutate(rate_cut = cut_interval(pct_foreign, n = 6)) %>% ggplot() + geom_sf(aes(fill = rate_cut)) + scale_fill_discrete_sequential(palette = "inferno") ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-17-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- # Slicing and dicing: * cut_number: divides range into set number of groups * cut_interval: divides range into set number of equal groups * cut_width: divides range into set widths * binned scale: pretties it up https://ggplot2.tidyverse.org/reference/cut_interval.html --- ## `cut_number()` .panelset[ .panel[.panel-name[Code] ``` r usa_fb %>% * mutate(rate_cut = cut_number(pct_foreign, n = 6)) %>% ggplot() + geom_sf(aes(fill = rate_cut)) + scale_fill_discrete_sequential(palette = "inferno") ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-18-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- ## `ggplot2::binned_scale()` .panelset[ .panel[.panel-name[Code] ``` r usa_fb %>% ggplot() + geom_sf(aes(fill = pct_foreign)) + * scale_fill_binned_sequential(palette = "inferno") ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-19-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- ## `ggplot2::binned_scale()` with quartiles .panelset[ .panel[.panel-name[Code] ``` r usa_fb %>% ggplot() + geom_sf(aes(fill = pct_foreign)) + scale_fill_binned_sequential( palette = "inferno", * n.breaks = 3 ) ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-20-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- ## `ggplot2::binned_scale()` with quartiles .panelset[ .panel[.panel-name[Code] ``` r usa_fb %>% ggplot() + geom_sf(aes(fill = pct_foreign)) + scale_fill_binned_sequential( palette = "inferno", * n.breaks = 3, * nice.breaks = FALSE ) ``` ] .panel[.panel-name[Plot] <img src="index_files/figure-html/unnamed-chunk-21-1.png" width="70%" style="display: block; margin: auto;" /> ] ] --- ## Map projections (again!) .center[ <iframe width="560" height="315" src="https://www.youtube.com/embed/vVX-PrBRtTY?si=SqNpncrF5PxLmsLo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>] --- ## Map projection <img src="https://imgs.xkcd.com/comics/mercator_projection.png" width="30%" style="display: block; margin: auto;" /> .footnote[Source: [xkcd](https://xkcd.com/2082/)] --- ## Map projection * Coordinate reference system * `proj4string` > <https://spatialreference.org/ref/epsg/> --- ## Mercator projection <img src="index_files/figure-html/mercator-sf-1.png" width="80%" style="display: block; margin: auto;" /> --- ## Projection using standard lines <img src="index_files/figure-html/projection-rest-1.png" width="80%" style="display: block; margin: auto;" /> --- # Recap * Multiple ways to deal with space / geography / maps * Shapefiles can provide great options for cool visualizations * Can also be challenging to get everything where/how it needs to be * Shapefiles seem to be very changeable in terms of how they're handled