class: center, middle, inverse, title-slide # Introduction to Geospatial Visualization with R ## R-Ladies Abuja + Abuja R Users ### Rami Krispin ### 2021/11/27 (updated: 2021-11-27) --- ## Agenda 1. Intro 1. Spatial Geometries 1. Data Manipulation 1. Merging sf objects with data 1. Choropleth Map 1. Q&A --- ## About Me * Data science manager * Focusing on time series analysis and forecasting * GIS analysis and maps as a hobby * Open source contributor - [TSstudio](https://github.com/RamiKrispin/TSstudio), [USgrid](https://github.com/RamiKrispin/USgrid), [USgas](https://github.com/RamiKrispin/USgas), [coronavirus](https://github.com/RamiKrispin/coronavirus), [covid19italy](https://github.com/RamiKrispin/covid19italy) * Get in touch on [LinkedIn](https://www.linkedin.com/in/rami-krispin/), [Twitter](https://twitter.com/Rami_Krispin), [Github](https://github.com/RamiKrispin) --- ## Workshop scope * Introduction to spatial data * Working with sf objects * Plot `sf` objects with **mapview**, **tmap**, and **ggplot2** * Create choropleth maps --- ## Packages In this workshop we will use the following packages: * GIS data: - **rnaturalearth** - provides access for the Natural Earth. The Natural Earth is a public domain map dataset including vector country and other administrative boundaries - **sf** - for setting the map object class and plot it * Tools for plotting maps: - **mapview** - A wrapper for the leaflet library - **tmap** - A package for creating a thematic maps - **ggplot2** - Is a system for declarative creating graphics - **viridis** - A package that provide a series of color maps * Datasets: - **coronavirus** to pull Covid19 data at different levels (e.g., region, country, etc.) --- class: middle, inverse ## The Geometry --- ## Point ```r plot(x = 1, y = 1, ylab = "", xlab = "", main = "Point") ``` <img src="index_files/figure-html/unnamed-chunk-1-1.png" style="display: block; margin: auto;" /> --- ## Line ```r plot(x = c(1, 2, 3), y = c(1, 4, 2), ylab = "", xlab = "", main = "Line", type = "l") ``` <img src="index_files/figure-html/unnamed-chunk-2-1.png" style="display: block; margin: auto;" /> --- ## Polygon ```r plot(x = c(1, 2, 4, 3, 1), y = c(2, 4, 3, 1, 2), ylab = "", xlab = "", main = "Polygon", type = "l") ``` <img src="index_files/figure-html/unnamed-chunk-3-1.png" style="display: block; margin: auto;" /> --- ## Polygon <img src="index_files/figure-html/unnamed-chunk-4-1.png" style="display: block; margin: auto;" /> --- ## Labels + Polygons = Map Boarders <img src="index_files/figure-html/world_map-1.png" /> --- ## Labels + Polygons + Data = Choropleth <img src="images/Nigeria pop by state.png" width="75%" align="center"/></a> --- class: middle, inverse ## Working with Spatial Data --- ## The rnaturalearth package The **rnaturalearth** is a great resource to pull GIS data from the Natural Earth API on a different levels (country, region, sub-region, etc.) The `ne_countries` will return an `sf` (or `sp`) object with a GIS (polygon) data: ```r library(rnaturalearth) world <- ne_countries(type = 'countries', scale = 'small', returnclass = "sf") ``` One of the main advantages of the `sf` object that it is also a data.frame object. Therefore, it is strightforward to work and manipulate the data with dplyr (or anything similar): ```r class(world) ``` ``` ## [1] "sf" "data.frame" ``` --- ```r str(world) ``` ``` ## Classes 'sf' and 'data.frame': 177 obs. of 64 variables: ## $ scalerank : int 1 1 1 1 1 1 1 3 1 1 ... ## $ featurecla: chr "Admin-0 country" "Admin-0 country" "Admin-0 country" "Admin-0 country" ... ## $ labelrank : num 3 3 6 4 2 6 4 6 2 4 ... ## $ sovereignt: chr "Afghanistan" "Angola" "Albania" "United Arab Emirates" ... ## $ sov_a3 : chr "AFG" "AGO" "ALB" "ARE" ... ## $ adm0_dif : num 0 0 0 0 0 0 0 1 1 0 ... ## $ level : num 2 2 2 2 2 2 2 2 2 2 ... ## $ type : chr "Sovereign country" "Sovereign country" "Sovereign country" "Sovereign country" ... ## $ admin : chr "Afghanistan" "Angola" "Albania" "United Arab Emirates" ... ## $ adm0_a3 : chr "AFG" "AGO" "ALB" "ARE" ... ## $ geou_dif : num 0 0 0 0 0 0 0 0 0 0 ... ## $ geounit : chr "Afghanistan" "Angola" "Albania" "United Arab Emirates" ... ## $ gu_a3 : chr "AFG" "AGO" "ALB" "ARE" ... ## $ su_dif : num 0 0 0 0 0 0 0 0 0 0 ... ## $ subunit : chr "Afghanistan" "Angola" "Albania" "United Arab Emirates" ... ## $ su_a3 : chr "AFG" "AGO" "ALB" "ARE" ... ## $ brk_diff : num 0 0 0 0 0 0 0 0 0 0 ... ## $ name : chr "Afghanistan" "Angola" "Albania" "United Arab Emirates" ... ## $ name_long : chr "Afghanistan" "Angola" "Albania" "United Arab Emirates" ... ## $ brk_a3 : chr "AFG" "AGO" "ALB" "ARE" ... ## $ brk_name : chr "Afghanistan" "Angola" "Albania" "United Arab Emirates" ... ## $ brk_group : chr NA NA NA NA ... ## $ abbrev : chr "Afg." "Ang." "Alb." "U.A.E." ... ## $ postal : chr "AF" "AO" "AL" "AE" ... ## $ formal_en : chr "Islamic State of Afghanistan" "People's Republic of Angola" "Republic of Albania" "United Arab Emirates" ... ## $ formal_fr : chr NA NA NA NA ... ## $ note_adm0 : chr NA NA NA NA ... ## $ note_brk : chr NA NA NA NA ... ## $ name_sort : chr "Afghanistan" "Angola" "Albania" "United Arab Emirates" ... ## $ name_alt : chr NA NA NA NA ... ## $ mapcolor7 : num 5 3 1 2 3 3 4 7 1 3 ... ## $ mapcolor8 : num 6 2 4 1 1 1 5 5 2 1 ... ## $ mapcolor9 : num 8 6 1 3 3 2 1 9 2 3 ... ## $ mapcolor13: num 7 1 6 3 13 10 NA 11 7 4 ... ## $ pop_est : num 28400000 12799293 3639453 4798491 40913584 ... ## $ gdp_md_est: num 22270 110300 21810 184300 573900 ... ## $ pop_year : num NA NA NA NA NA NA NA NA NA NA ... ## $ lastcensus: num 1979 1970 2001 2010 2010 ... ## $ gdp_year : num NA NA NA NA NA NA NA NA NA NA ... ## $ economy : chr "7. Least developed region" "7. Least developed region" "6. Developing region" "6. Developing region" ... ## $ income_grp: chr "5. Low income" "3. Upper middle income" "4. Lower middle income" "2. High income: nonOECD" ... ## $ wikipedia : num NA NA NA NA NA NA NA NA NA NA ... ## $ fips_10 : chr NA NA NA NA ... ## $ iso_a2 : chr "AF" "AO" "AL" "AE" ... ## $ iso_a3 : chr "AFG" "AGO" "ALB" "ARE" ... ## $ iso_n3 : chr "004" "024" "008" "784" ... ## $ un_a3 : chr "004" "024" "008" "784" ... ## $ wb_a2 : chr "AF" "AO" "AL" "AE" ... ## $ wb_a3 : chr "AFG" "AGO" "ALB" "ARE" ... ## $ woe_id : num NA NA NA NA NA NA NA NA NA NA ... ## $ adm0_a3_is: chr "AFG" "AGO" "ALB" "ARE" ... ## $ adm0_a3_us: chr "AFG" "AGO" "ALB" "ARE" ... ## $ adm0_a3_un: num NA NA NA NA NA NA NA NA NA NA ... ## $ adm0_a3_wb: num NA NA NA NA NA NA NA NA NA NA ... ## $ continent : chr "Asia" "Africa" "Europe" "Asia" ... ## $ region_un : chr "Asia" "Africa" "Europe" "Asia" ... ## $ subregion : chr "Southern Asia" "Middle Africa" "Southern Europe" "Western Asia" ... ## $ region_wb : chr "South Asia" "Sub-Saharan Africa" "Europe & Central Asia" "Middle East & North Africa" ... ## $ name_len : num 11 6 7 20 9 7 10 22 9 7 ... ## $ long_len : num 11 6 7 20 9 7 10 35 9 7 ... ## $ abbrev_len: num 4 4 4 6 4 4 4 10 4 5 ... ## $ tiny : num NA NA NA NA NA NA NA 2 NA NA ... ## $ homepart : num 1 1 1 1 1 1 1 NA 1 1 ... ## $ geometry :sfc_MULTIPOLYGON of length 177; first list element: List of 1 ## ..$ :List of 1 ## .. ..$ : num [1:69, 1:2] 61.2 62.2 63 63.2 64 ... ## ..- attr(*, "class")= chr [1:3] "XY" "MULTIPOLYGON" "sfg" ## - attr(*, "sf_column")= chr "geometry" ## - attr(*, "agr")= Factor w/ 3 levels "constant","aggregate",..: NA NA NA NA NA NA NA NA NA NA ... ## ..- attr(*, "names")= chr [1:63] "scalerank" "featurecla" "labelrank" "sovereignt" ... ``` --- ```r head(world) ``` ``` ## Simple feature collection with 6 features and 63 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: -73.41544 ymin: -55.25 xmax: 75.15803 ymax: 42.68825 ## CRS: +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 ## scalerank featurecla labelrank sovereignt sov_a3 adm0_dif ## 0 1 Admin-0 country 3 Afghanistan AFG 0 ## 1 1 Admin-0 country 3 Angola AGO 0 ## 2 1 Admin-0 country 6 Albania ALB 0 ## 3 1 Admin-0 country 4 United Arab Emirates ARE 0 ## 4 1 Admin-0 country 2 Argentina ARG 0 ## 5 1 Admin-0 country 6 Armenia ARM 0 ## level type admin adm0_a3 geou_dif ## 0 2 Sovereign country Afghanistan AFG 0 ## 1 2 Sovereign country Angola AGO 0 ## 2 2 Sovereign country Albania ALB 0 ## 3 2 Sovereign country United Arab Emirates ARE 0 ## 4 2 Sovereign country Argentina ARG 0 ## 5 2 Sovereign country Armenia ARM 0 ## geounit gu_a3 su_dif subunit su_a3 brk_diff ## 0 Afghanistan AFG 0 Afghanistan AFG 0 ## 1 Angola AGO 0 Angola AGO 0 ## 2 Albania ALB 0 Albania ALB 0 ## 3 United Arab Emirates ARE 0 United Arab Emirates ARE 0 ## 4 Argentina ARG 0 Argentina ARG 0 ## 5 Armenia ARM 0 Armenia ARM 0 ## name name_long brk_a3 brk_name ## 0 Afghanistan Afghanistan AFG Afghanistan ## 1 Angola Angola AGO Angola ## 2 Albania Albania ALB Albania ## 3 United Arab Emirates United Arab Emirates ARE United Arab Emirates ## 4 Argentina Argentina ARG Argentina ## 5 Armenia Armenia ARM Armenia ## brk_group abbrev postal formal_en formal_fr note_adm0 ## 0 <NA> Afg. AF Islamic State of Afghanistan <NA> <NA> ## 1 <NA> Ang. AO People's Republic of Angola <NA> <NA> ## 2 <NA> Alb. AL Republic of Albania <NA> <NA> ## 3 <NA> U.A.E. AE United Arab Emirates <NA> <NA> ## 4 <NA> Arg. AR Argentine Republic <NA> <NA> ## 5 <NA> Arm. ARM Republic of Armenia <NA> <NA> ## note_brk name_sort name_alt mapcolor7 mapcolor8 mapcolor9 ## 0 <NA> Afghanistan <NA> 5 6 8 ## 1 <NA> Angola <NA> 3 2 6 ## 2 <NA> Albania <NA> 1 4 1 ## 3 <NA> United Arab Emirates <NA> 2 1 3 ## 4 <NA> Argentina <NA> 3 1 3 ## 5 <NA> Armenia <NA> 3 1 2 ## mapcolor13 pop_est gdp_md_est pop_year lastcensus gdp_year ## 0 7 28400000 22270 NA 1979 NA ## 1 1 12799293 110300 NA 1970 NA ## 2 6 3639453 21810 NA 2001 NA ## 3 3 4798491 184300 NA 2010 NA ## 4 13 40913584 573900 NA 2010 NA ## 5 10 2967004 18770 NA 2001 NA ## economy income_grp wikipedia fips_10 iso_a2 ## 0 7. Least developed region 5. Low income NA <NA> AF ## 1 7. Least developed region 3. Upper middle income NA <NA> AO ## 2 6. Developing region 4. Lower middle income NA <NA> AL ## 3 6. Developing region 2. High income: nonOECD NA <NA> AE ## 4 5. Emerging region: G20 3. Upper middle income NA <NA> AR ## 5 6. Developing region 4. Lower middle income NA <NA> AM ## iso_a3 iso_n3 un_a3 wb_a2 wb_a3 woe_id adm0_a3_is adm0_a3_us adm0_a3_un ## 0 AFG 004 004 AF AFG NA AFG AFG NA ## 1 AGO 024 024 AO AGO NA AGO AGO NA ## 2 ALB 008 008 AL ALB NA ALB ALB NA ## 3 ARE 784 784 AE ARE NA ARE ARE NA ## 4 ARG 032 032 AR ARG NA ARG ARG NA ## 5 ARM 051 051 AM ARM NA ARM ARM NA ## adm0_a3_wb continent region_un subregion region_wb ## 0 NA Asia Asia Southern Asia South Asia ## 1 NA Africa Africa Middle Africa Sub-Saharan Africa ## 2 NA Europe Europe Southern Europe Europe & Central Asia ## 3 NA Asia Asia Western Asia Middle East & North Africa ## 4 NA South America Americas South America Latin America & Caribbean ## 5 NA Asia Asia Western Asia Europe & Central Asia ## name_len long_len abbrev_len tiny homepart geometry ## 0 11 11 4 NA 1 MULTIPOLYGON (((61.21082 35... ## 1 6 6 4 NA 1 MULTIPOLYGON (((16.32653 -5... ## 2 7 7 4 NA 1 MULTIPOLYGON (((20.59025 41... ## 3 20 20 6 NA 1 MULTIPOLYGON (((51.57952 24... ## 4 9 9 4 NA 1 MULTIPOLYGON (((-65.5 -55.2... ## 5 7 7 4 NA 1 MULTIPOLYGON (((43.58275 41... ``` --- ## Working with the sf package ```r library(sf) plot(world) ``` <img src="index_files/figure-html/unnamed-chunk-9-1.png" style="display: block; margin: auto;" /> --- ## Working with the sf package * The **sf** package has a plot method for `sf` objects * By default, it will plot a choropleth map for any numeric variable To simply plot the world map by country without data use: ```r plot(world$geometry) ``` <img src="index_files/figure-html/unnamed-chunk-10-1.png" style="display: block; margin: auto;" /> --- class: middle, inverse ## Data Manipulation --- ## Filtering Filtering `sf` object is as simple as filtering a `data.frame` object. Let's say we want to re-plot the the following map without Antarctica: ```r plot(world$geometry) ``` <img src="index_files/figure-html/unnamed-chunk-11-1.png" style="display: block; margin: auto;" /> --- ## Filtering We will use the continent field to filter Antarctica from the object: ```r library(dplyr) world1 <- world %>% filter(continent != "Antarctica") plot(world1$geometry) ``` <img src="index_files/figure-html/unnamed-chunk-12-1.png" style="display: block; margin: auto;" /> --- ## Subseting Likewise, we can subset a specific element of the sf object, for example let's pull Africa from the `world` object. We will use again the `continent` variable to subset the object: ```r africa <- world %>% filter(continent == "Africa") plot(africa$geometry) ``` <img src="index_files/figure-html/unnamed-chunk-13-1.png" style="display: block; margin: auto;" /> --- ## Country level The `ne_states` function enables you to pull a country/state level data. For example, let's pull Nigeria data: ```r nigeria <- ne_states(country = "Nigeria", returnclass = "sf") head(nigeria) ``` ``` ## Simple feature collection with 6 features and 83 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: 2.671082 ymin: 6.31685 xmax: 7.338085 ymax: 13.22813 ## CRS: +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 ## featurecla scalerank adm1_code diss_me iso_3166_2 wikipedia iso_a2 ## 485 Admin-1 scale rank 3 NGA-2879 2879 NG-KE <NA> NG ## 487 Admin-1 scale rank 3 NGA-2851 2851 NG-NI <NA> NG ## 489 Admin-1 scale rank 3 NGA-2849 2849 NG-KW <NA> NG ## 490 Admin-1 scale rank 3 NGA-2852 2852 NG-OG <NA> NG ## 493 Admin-1 scale rank 3 NGA-2856 2856 NG-OY <NA> NG ## 494 Admin-1 scale rank 3 NGA-2850 2850 NG-LA <NA> NG ## adm0_sr name name_alt name_local type type_en code_local code_hasc note ## 485 1 Kebbi <NA> <NA> State State <NA> NG.KE <NA> ## 487 1 Niger <NA> <NA> State State <NA> NG.NI <NA> ## 489 1 Kwara <NA> <NA> State State <NA> NG.KW <NA> ## 490 1 Ogun <NA> <NA> State State <NA> NG.OG <NA> ## 493 1 Oyo <NA> <NA> State State <NA> NG.OY <NA> ## 494 1 Lagos <NA> <NA> State State <NA> NG.LA <NA> ## hasc_maybe region region_cod provnum_ne gadm_level check_me datarank abbrev ## 485 <NA> <NA> <NA> 20003 1 20 2 <NA> ## 487 <NA> <NA> <NA> 20002 1 20 2 <NA> ## 489 <NA> <NA> <NA> 20006 1 20 2 <NA> ## 490 <NA> <NA> <NA> 20012 1 20 2 <NA> ## 493 <NA> <NA> <NA> 20005 1 20 2 <NA> ## 494 <NA> <NA> <NA> 20004 1 20 2 <NA> ## postal area_sqkm sameascity labelrank name_len mapcolor9 mapcolor13 fips ## 485 KE 0 NA 3 5 5 2 NI40 ## 487 NI 0 NA 3 5 5 2 NI31 ## 489 KW 0 NA 3 5 5 2 NI30 ## 490 OG 0 NA 3 4 5 2 NI16 ## 493 OY 0 NA 3 3 5 2 NI32 ## 494 LA 0 7 7 5 5 2 NI05 ## fips_alt woe_id woe_label woe_name latitude longitude sov_a3 ## 485 <NA> 2346368 Kebbi, NG, Nigeria Kebbi 11.77120 4.06548 NGA ## 487 <NA> 2346359 Niger, NG, Nigeria Niger 9.95553 5.45494 NGA ## 489 <NA> 2346358 Kwara, NG, Nigeria Kwara 8.80445 4.46906 NGA ## 490 <NA> 2346346 Ogun, NG, Nigeria Ogun 7.01845 3.29255 NGA ## 493 <NA> 2346360 Oyo, NG, Nigeria Oyo 8.18969 3.61681 NGA ## 494 <NA> 2346342 Lagos, NG, Nigeria Lagos 6.43313 3.52478 NGA ## adm0_a3 adm0_label admin geonunit gu_a3 gn_id gn_name gns_id ## 485 NGA 2 Nigeria Nigeria NGA 2597363 Kebbi State 9153499 ## 487 NGA 2 Nigeria Nigeria NGA 2328925 Niger State -2020892 ## 489 NGA 2 Nigeria Nigeria NGA 2332785 Kwara State -2017029 ## 490 NGA 2 Nigeria Nigeria NGA 2327546 Ogun State -2022272 ## 493 NGA 2 Nigeria Nigeria NGA 2325190 Oyo State -2024630 ## 494 NGA 2 Nigeria Nigeria NGA 2332453 Lagos State -2017361 ## gns_name gn_level gn_region gn_a1_code region_sub sub_code gns_level ## 485 Kebbi State 1 <NA> NG.40 <NA> <NA> 1 ## 487 Niger 1 <NA> NG.31 <NA> <NA> 1 ## 489 Kwara 1 <NA> NG.30 <NA> <NA> 1 ## 490 Ogun 1 <NA> NG.16 <NA> <NA> 1 ## 493 Oyo 1 <NA> NG.32 <NA> <NA> 1 ## 494 Lagos 1 <NA> NG.05 <NA> <NA> 1 ## gns_lang gns_adm1 gns_region min_label max_label min_zoom wikidataid ## 485 por NI40 <NA> 6.6 11 6.6 Q748523 ## 487 fra NI31 <NA> 6.6 11 6.6 Q503932 ## 489 fra NI30 <NA> 6.6 11 6.6 Q464953 ## 490 fra NI16 <NA> 6.6 11 6.6 Q836657 ## 493 fra NI32 <NA> 6.6 11 6.6 Q503905 ## 494 fra NI05 <NA> 6.6 11 6.6 Q815913 ## name_ar name_bn name_de name_en name_es name_fr name_el ## 485 <NA> <NA> Kebbi Kebbi State Kebbi État de Kebbi <NA> ## 487 <NA> <NA> Niger Niger State Níger État de Niger <NA> ## 489 <NA> <NA> Kwara Kwara State Kwara État de Kwara <NA> ## 490 <NA> <NA> Ogun Ogun State Ogun État d'Ogun <NA> ## 493 <NA> <NA> Oyo Oyo State Oyo État d'Oyo <NA> ## 494 <NA> <NA> Lagos Lagos Estado de Lagos État de Lagos <NA> ## name_hi name_hu name_id name_it name_ja name_ko name_nl name_pl name_pt ## 485 <NA> <NA> Kebbi Kebbi <NA> <NA> Kebbi Kebbi Kebbi ## 487 <NA> <NA> Niger Niger <NA> <NA> Niger Niger Níger ## 489 <NA> <NA> Kwara Kwara <NA> <NA> Kwara Kwara Kwara ## 490 <NA> <NA> Ogun Ogun <NA> <NA> Ogun Ogun Ogun ## 493 <NA> <NA> Oyo Oyo <NA> <NA> Oyo Oyo Oyo ## 494 <NA> <NA> Lagos Lagos <NA> <NA> Lagos Lagos Lagos ## name_ru name_sv name_tr name_vi name_zh ne_id ## 485 <NA> Kebbi Kebbi Eyaleti Bang Kebbi <NA> 1159313843 ## 487 <NA> Niger Niger Eyaleti Bang Niger <NA> 1159313785 ## 489 <NA> Kwara Kwara Eyaleti Bang Kwara <NA> 1159313781 ## 490 <NA> Ogun Ogun Eyaleti Bang Ogun <NA> 1159313789 ## 493 <NA> Oyo Oyo Eyaleti <NA> <NA> 1159313801 ## 494 <NA> Lagos Lagos Eyaleti <NA> <NA> 1159313783 ## geometry ## 485 MULTIPOLYGON (((3.694999 11... ## 487 MULTIPOLYGON (((3.756907 10... ## 489 MULTIPOLYGON (((2.722949 8.... ## 490 MULTIPOLYGON (((2.783323 7.... ## 493 MULTIPOLYGON (((2.671695 7.... ## 494 MULTIPOLYGON (((2.703841 6.... ``` --- ## Country level ```r plot(nigeria$geometry, col = sf.colors(37, categorical = TRUE), border = 'grey', axes = TRUE, main = "Nigeria") ``` <img src="index_files/figure-html/unnamed-chunk-15-1.png" style="display: block; margin: auto;" /> --- class: middle, inverse ## Merging sf objects with data --- ### Adding data - COVID19 cases In the following example we will pull COVID19 cases by country from the **coronavirus** package and merge it the `world` object we created before. ```r library(coronavirus) covid19_daily <- refresh_coronavirus_jhu() head(covid19_daily) ``` ``` ## date location location_type location_code location_code_type ## 1 2020-02-06 Afghanistan country AF iso_3166_2 ## 2 2020-02-26 Afghanistan country AF iso_3166_2 ## 3 2020-02-08 Afghanistan country AF iso_3166_2 ## 4 2020-02-25 Afghanistan country AF iso_3166_2 ## 5 2020-02-07 Afghanistan country AF iso_3166_2 ## 6 2020-02-19 Afghanistan country AF iso_3166_2 ## data_type value lat long ## 1 deaths_new 0 33.93911 67.70995 ## 2 deaths_new 0 33.93911 67.70995 ## 3 deaths_new 0 33.93911 67.70995 ## 4 deaths_new 0 33.93911 67.70995 ## 5 deaths_new 0 33.93911 67.70995 ## 6 deaths_new 0 33.93911 67.70995 ``` --- ### Adding data - COVID19 cases Next step is to prepare the data for merging with the `world` object: ```r library(tidyr) df <- covid19_daily %>% filter(location_type == "country") %>% group_by(location, location_code, data_type) %>% summarise(cases = sum(value), .groups = "drop") %>% pivot_wider(names_from = data_type, values_from = cases) %>% setNames(c("country", "country_code", "total_cases", "total_death")) head(df) ``` ``` ## # A tibble: 6 × 4 ## country country_code total_cases total_death ## <chr> <chr> <dbl> <dbl> ## 1 Afghanistan AF 157171 7307 ## 2 Albania AL 198732 3077 ## 3 Algeria DZ 209817 6046 ## 4 Andorra AD 16712 131 ## 5 Angola AO 65130 1733 ## 6 Antigua and Barbuda AG 4141 117 ``` --- ### Adding data - COVID19 cases Once the data is ready we can merge the `world` table with the cases table: ```r world_covid1 <- world %>% filter(continent != "Antarctica") %>% select(country = sovereignt, geometry) %>% left_join(df, by = "country") plot(world_covid1[, c("total_cases")]) ``` <img src="index_files/figure-html/unnamed-chunk-18-1.png" style="display: block; margin: auto;" /> --- ### Adding data - COVID19 cases We can try to merge the data with the country code (ISO code). ```r world_covid2 <- world %>% filter(continent != "Antarctica") %>% select(country_code = iso_a2, geometry) %>% left_join(df, by = "country_code") plot(world_covid2[, c("total_cases")]) ``` <img src="index_files/figure-html/unnamed-chunk-19-1.png" style="display: block; margin: auto;" /> --- ## Adding data - Nigeria population In the next example we will pull Nigeria population by state from Wikipedia and merge it with Nigeria state level `sf` object: <img src="images/Nigeria pop wiki.png" width="75%" align="center"/></a> --- ## Adding data - Nigeria population We will use the **rvest** package to pull the population data from Wikipedia: ```r library(rvest) url <- "https://en.wikipedia.org/wiki/List_of_Nigerian_states_by_population" page <- read_html(url) tables <- html_node(page, ".wikitable") pop_table <- html_table(tables, fill = TRUE) %>% select(state_temp = State, pop_2006_temp = `Population (2006)`, pop_2016_temp = `Population (2016)`) pop_table$pop_2006 <- as.numeric(gsub(x = pop_table$pop_2006_temp,pattern = ",", replacement = "")) pop_table$pop_2016 <- as.numeric(gsub(x = pop_table$pop_2016_temp,pattern = ",", replacement = "")) pop_table$state <- gsub(x = pop_table$state_temp,pattern = " State", replacement = "") pop_table <- pop_table %>% select(-state_temp, -pop_2006_temp, - pop_2016_temp) %>% select(state, pop_2006, pop_2016) %>% mutate(state_fix = state) ``` --- ## Adding data - Nigeria population ```r head(pop_table) ``` ``` ## # A tibble: 6 × 4 ## state pop_2006 pop_2016 state_fix ## <chr> <dbl> <dbl> <chr> ## 1 Kano 10401288 16076892 Kano ## 2 Lagos 7113605 11000598 Lagos ## 3 Kaduna 6113503 8252366 Kaduna ## 4 Katsina 5801584 7831319 Katsina ## 5 Oyo 5580894 7010864 Oyo ## 6 Rivers 5198605 7000924 Rivers ``` Before merging let's just modify the one of the labels: ```r pop_table$state_fix[which(pop_table$state_fix == "Nasarawa")] <- "Nassarawa" ``` Last but not least let's merge the tables: ```r nigeria_pop <- nigeria %>% left_join(pop_table, by = c("name" = "state_fix")) ``` --- ## Adding data - Nigeria population ```r plot(nigeria_pop["pop_2016"], key.pos = 1, axes = TRUE, main = "Nigeria Population by State", key.width = lcm(1.3), key.length = 1.0) ``` <img src="index_files/figure-html/unnamed-chunk-24-1.png" style="display: block; margin: auto;" /> --- class: middle, inverse ## Choropleth Map --- ## The mapview package ```r library(mapview) mapview(nigeria_pop, zcol = "pop_2016", legend = TRUE, layer.name = "Population") ```
--- ## The mapview package More examples available on the coronavirues vignette: https://ramikrispin.github.io/coronavirus/articles/geospatial_visualization.html --- ## The tmap package Let's plot COVID19 vaccine data: ```r library(coronavirus) library(tmap) sf_use_s2(FALSE) ``` ``` ## Spherical geometry (s2) switched off ``` ```r data("covid19_vaccine") head(covid19_vaccine) ``` ``` ## country_region date doses_admin people_partially_vaccinated ## 1 Afghanistan 2021-02-22 0 0 ## 2 Afghanistan 2021-02-23 0 0 ## 3 Afghanistan 2021-02-24 0 0 ## 4 Afghanistan 2021-02-25 0 0 ## 5 Afghanistan 2021-02-26 0 0 ## 6 Afghanistan 2021-02-27 0 0 ## people_fully_vaccinated report_date_string uid province_state iso2 iso3 code3 ## 1 0 2021-02-22 4 <NA> AF AFG 4 ## 2 0 2021-02-23 4 <NA> AF AFG 4 ## 3 0 2021-02-24 4 <NA> AF AFG 4 ## 4 0 2021-02-25 4 <NA> AF AFG 4 ## 5 0 2021-02-26 4 <NA> AF AFG 4 ## 6 0 2021-02-27 4 <NA> AF AFG 4 ## fips lat long combined_key population continent_name continent_code ## 1 <NA> 33.93911 67.70995 Afghanistan 38928341 Asia AS ## 2 <NA> 33.93911 67.70995 Afghanistan 38928341 Asia AS ## 3 <NA> 33.93911 67.70995 Afghanistan 38928341 Asia AS ## 4 <NA> 33.93911 67.70995 Afghanistan 38928341 Asia AS ## 5 <NA> 33.93911 67.70995 Afghanistan 38928341 Asia AS ## 6 <NA> 33.93911 67.70995 Afghanistan 38928341 Asia AS ``` --- ## The tmap package As before, we will merge the data from **rnaturalearth** with the vaccine data: ```r map <- ne_countries(returnclass = "sf") %>% select(name, iso2 = iso_a2, iso3 = iso_a3, geometry) df <- map %>% left_join( covid19_vaccine %>% filter(date == max(date), is.na(province_state)) %>% mutate(perc = round(100 * people_fully_vaccinated / population, 2)) %>% select(country_region, iso2, iso3, people_fully_vaccinated, perc, continent_name), by = c("iso2", "iso3") ) ``` --- ## The tmap package Let's remove underpopulated areas and plot it: ```r df1 <- df %>% filter(!name %in% c("Greenland", "Antarctica")) p1 <- tm_shape(df1) + tm_polygons(col = "perc", n = 8, title = "Fully Vaccinated %", palette = "Blues") ``` --- ## The tmap package ```r p1 ``` <img src="index_files/figure-html/unnamed-chunk-29-1.png" style="display: block; margin: auto;" /> --- ## The tmap package The `projection` argument enables you to set different projection: ```r p2 <- tm_shape(df1) + tm_polygons(col = "perc", n = 8, projection = 3857, title = "Fully Vaccinated %", palette = "Blues") ``` --- ## The tmap package ```r p2 ``` <img src="index_files/figure-html/unnamed-chunk-31-1.png" style="display: block; margin: auto;" /> --- ## The tmap package The **tmap** package provides different customization options, in the following example we will modify the background and add titles: ```r df2 <- df1 %>% filter(continent_name == "South America") p3 <- tm_shape(df2) + tm_polygons(col = "perc", n = 5, title = "Perc. Group", palette = "Blues") ``` --- ## The tmap package ```r p3 ``` <img src="index_files/figure-html/unnamed-chunk-33-1.png" style="display: block; margin: auto;" /> --- ## The tmap package ```r p4 <- tm_shape(df2) + tm_polygons(col = "perc", n = 5, title = "Perc. Group", palette = "Blues") + tm_style("cobalt") + tm_text("iso3", size = 0.7) + tm_layout( title= "% of Population Fully Vaccinated", title.position = c('right', 'top') , inner.margins = c(0.02, .02, .1, .25)) ``` --- ## The tmap package ```r p4 ``` <img src="index_files/figure-html/unnamed-chunk-35-1.png" style="display: block; margin: auto;" /> --- ## The tmap package In addition to static plots, the **tmap** package has an interactive version using the leaflet JS library. To get an interactive output use the `tmap_mode` function: ```r tmap_mode("view") p5 <- tm_shape(df2) + tm_polygons(col = "perc", n = 5, title = "Perc. Group", palette = "Blues") ``` --- ## The tmap package ```r p5 ```
--- ## The tmap package Let's re-plot the Nigerian States population with the tmap function: ```r tmap_mode("plot") nigeria_pop_plot <- tm_shape(nigeria_pop) + tm_polygons(col = "pop_2016", style = "order", title = "Population", palette = "Blues") + tm_style("cobalt") + tm_text("state", size = 0.7) + tm_credits("Source: Wikipedia - List of Nigerian states by population", position = c("LEFT", "BOTTOM")) + tm_layout(title= "Nigeria Population by States", title.position = c('right', 'top') , inner.margins = c(0.02, .02, .1, .15)) ``` --- ## The tmap package ```r nigeria_pop_plot ``` <img src="index_files/figure-html/unnamed-chunk-39-1.png" style="display: block; margin: auto;" /> --- ## The tmap package You can break down the object polygons with the `tm_facets` function: ```r nigeria_pop_plot_facets <- tm_shape(nigeria_pop) + tm_polygons(col = "pop_2016", n = 5, title = "Total Population", palette = "Greens") + tmap_options(limits = c(facets.view = 13)) + tm_facets(by = "name") ``` --- ## The tmap package ```r nigeria_pop_plot_facets ``` <img src="index_files/figure-html/unnamed-chunk-41-1.png" style="display: block; margin: auto;" /> --- ## The ggplot2 package Likewise, you can plot `sf` objects with the **ggplot2** package using the `geom_sf` function: ```r library(ggplot2) library(viridis) p1 <- ggplot(data = nigeria_pop, aes(fill = `pop_2016`)) + geom_sf() + scale_fill_viridis_b() ``` --- ## The ggplot2 package ```r p1 ``` <img src="index_files/figure-html/unnamed-chunk-43-1.png" style="display: block; margin: auto;" /> --- ## The ggplot2 package To add label for each polygon use the `geom_sf_label` function: ```r p2 <- ggplot(data = nigeria_pop, aes(fill = `pop_2016`)) + geom_sf(size = 0.1) + scale_fill_viridis(alpha = 0.9, begin = 0.01, discrete = FALSE, end = 0.9) + geom_sf_label(aes(label = state)) + labs(fill = "Population", title = "Population by State", caption = "Source: https://en.wikipedia.org/wiki/List_of_Nigerian_states_by_population") + theme_void() ``` --- ## The ggplot2 package ```r p2 ``` <img src="index_files/figure-html/unnamed-chunk-45-1.png" style="display: block; margin: auto;" /> --- ## Resources * Books: - Geocomputation with R - https://geocompr.robinlovelace.net/ - Geospatial Health Data: Modeling and Visualization with R-INLA and Shiny - https://www.paulamoraga.com/book-geospatial/ - Introduction to Spatial Data Programming with R - https://geobgu.xyz/r/ * Package documentation: - **sf** - https://r-spatial.github.io/sf/ - **rnaturalearth** - https://docs.ropensci.org/rnaturalearth/ - **mapview** - https://r-spatial.github.io/mapview/ - **tmap** - https://r-tmap.github.io/tmap/ - **ggplot2 (geom_sf)** - https://ggplot2.tidyverse.org/reference/ggsf.html * Examples - Geospatial Visualization (**coronavirus** package) - https://ramikrispin.github.io/coronavirus/articles/geospatial_visualization.html - Geospatial Visualization of the Covid19 Cases (**covid19sf** package) - https://ramikrispin.github.io/covid19sf/articles/geo.html - Visualization covid19italy with Choropleth Maps (**covid19italy** package) - https://ramikrispin.github.io/covid19Italy/articles/geospatial_visualization.html