Visualizing spatial data and maps


36-315: Statistical Graphics and Visualization, Summer 2026

Spatial data and maps

2D coordinate representation with latitude and longitude


Latitude Longitude
Direction North/South East/West
Range \((-90^\circ, 90^\circ)\) \((-180^\circ, 180^\circ)\)
Reference line Equator (\(0^\circ\)) Prime (Greenwich) meridian (\(0^\circ\))
Hemispheres \((0^\circ, 90^\circ)\): Northern
\((-90^\circ, 0^\circ)\): Southern
\((0^\circ, 180^\circ)\): Eastern
\((-180^\circ, 0^\circ)\): Western

Types of spatial data

  • Point pattern data: record locations (latitude/longitude coordinates) of points (e.g., events, objects, etc.) in space

    • Where are the points?

    • e.g., locations of crime incidents, locations of lightning strikes, etc.

  • Simply records the locations of events (i.e., only the locations are of interest)

  • Data typically contain 2 variables: latitude and longitude

  • Display locations as points on a map (often called dot map or bubble map)

  • Common goal: understand how the distribution/density of points varies across space

    • Can be visualized using density estimation methods
  • Point-referenced data (or geostatistical data): record locations along with one or more variables measured at those locations

    • What values are measured at each point?

    • e.g., temperature measured at weather stations, air quality measured at sensor locations, etc.

  • Goal: understand how the measured variable(s) (e.g., altitude, temperature, rainfall, etc.) vary across space

  • Display locations as points and measured variables as visual attributes such as color, size, shape, or transparency

  • For a single variable, color gradient or varying point size are commonly used to display spatial variation

  • Areal data: data aggregated over geographic regions (e.g., counties, states, census tracts), where one or more variables are associated with each region

    • What values are associated with each region?

    • e.g., COVID cases by county, average home prices by ZIP code, etc.

  • Choropleth maps for areal data: color regions by variable(s) of interest

Polygon maps

  • Simplest approach to plotting maps

  • Draw geographic boundaries for different region

  • Use the map_data() function in ggplot2 to get latitude/longitude coordinates

    • e.g., map_data("world"), map_data("state"), map_data("county"), etc.
library(tidyverse)
theme_set(theme_light())
us_counties <- map_data("county")
pa_counties <- us_counties |>  
  filter(region == "pennsylvania")
head(pa_counties)
       long      lat group order       region subregion
1 -77.44670 39.96954  2213 64743 pennsylvania     adams
2 -77.42952 39.98672  2213 64744 pennsylvania     adams
3 -77.37222 40.00391  2213 64745 pennsylvania     adams
4 -77.32065 40.01537  2213 64746 pennsylvania     adams
5 -77.23471 40.02683  2213 64747 pennsylvania     adams
6 -77.18887 40.03256  2213 64748 pennsylvania     adams

Polygon maps

pa_counties |> 
  ggplot(aes(x = long, y = lat, group = group)) +
  geom_polygon(fill = "white", color = "lightgray")

Simple features maps

  • The simple latitude/longitude data format is not typically used in real-world mapping

Simple features maps

  • Example: Australia state boundaries via the ozmaps package

    • geometry: contains multipolygon objects that specify polygon vertices that set the region border
library(ozmaps)
library(sf)
ozmap_states
Simple feature collection with 9 features and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 105.5507 ymin: -43.63203 xmax: 167.9969 ymax: -9.229287
Geodetic CRS:  GDA94
# A tibble: 9 × 2
  NAME                                                                  geometry
* <chr>                                                       <MULTIPOLYGON [°]>
1 New South Wales              (((150.7016 -35.12286, 150.6611 -35.11782, 150.6…
2 Victoria                     (((146.6196 -38.70196, 146.6721 -38.70259, 146.6…
3 Queensland                   (((148.8473 -20.3457, 148.8722 -20.37575, 148.85…
4 South Australia              (((137.3481 -34.48242, 137.3749 -34.46885, 137.3…
5 Western Australia            (((126.3868 -14.01168, 126.3625 -13.98264, 126.3…
6 Tasmania                     (((147.8397 -40.29844, 147.8902 -40.30258, 147.8…
7 Northern Territory           (((136.3669 -13.84237, 136.3339 -13.83922, 136.3…
8 Australian Capital Territory (((149.2317 -35.222, 149.2346 -35.24047, 149.271…
9 Other Territories            (((167.9333 -29.05421, 167.9188 -29.0344, 167.93…

Simple features maps

  • geom_sf() relies on a specialized geometry aesthetic

  • Map the geometry aesthetic to a geometry column

Code
ozmap_states |> 
  ggplot(aes(geometry = geometry)) +
  geom_sf() +
  coord_sf()

Map projections

  • Is drawing maps by plotting longitude and latitude on a Cartesian plane an accurate representation?

Map projections

  • Map projections: transformation of the latitude/longitude coordinates on a sphere (the earth) to a 2D plane

    • Not possible to perform map projection without some distortion or cutting

    • Need to make assumptions

  • Map projections are often classified in terms of the geometric properties that they preserve, e.g.

    • Area-preserving projections: preserve relative area (regions of equal area on the globe are represented with equal area on the map)

    • Shape-preserving (conformal) projections: preserve local shape and angles

    • Not possible for any projection to be both area- and shape-preserving

Coordinate reference systems

  • Specify both projection catalog (ESRI or EPSG) and projection number (see here)

    • EPSG:3395 Mercator projection (for the world)

    • ESRI:54009 Mollweide projection (for the world)

    • ESRI:54030 Robinson projection (for the world)

    • ESRI:102003 Albers projection (for the contiguous United States)

    • and many more…

  • Alternatively, specify projection names (see here)

    • "+proj=merc": Mercator

    • "+proj=robin": Robinson

    • "+proj=moll": Mollweide

    • and many more…

Coordinate reference systems

library(rnaturalearth)
world <- ne_countries(returnclass = "sf") |> 
  filter(sovereignt != "Antarctica")
class(world)
[1] "sf"         "data.frame"
head(world)
Simple feature collection with 6 features and 168 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -180 ymin: -18.28799 xmax: 180 ymax: 83.23324
Geodetic CRS:  WGS 84
       featurecla scalerank labelrank                  sovereignt sov_a3
1 Admin-0 country         1         6                        Fiji    FJI
2 Admin-0 country         1         3 United Republic of Tanzania    TZA
3 Admin-0 country         1         7              Western Sahara    SAH
4 Admin-0 country         1         2                      Canada    CAN
5 Admin-0 country         1         2    United States of America    US1
6 Admin-0 country         1         3                  Kazakhstan    KA1
  adm0_dif level              type tlc                       admin adm0_a3
1        0     2 Sovereign country   1                        Fiji     FJI
2        0     2 Sovereign country   1 United Republic of Tanzania     TZA
3        0     2     Indeterminate   1              Western Sahara     SAH
4        0     2 Sovereign country   1                      Canada     CAN
5        1     2           Country   1    United States of America     USA
6        1     1       Sovereignty   1                  Kazakhstan     KAZ
  geou_dif                  geounit gu_a3 su_dif        subunit su_a3 brk_diff
1        0                     Fiji   FJI      0           Fiji   FJI        0
2        0                 Tanzania   TZA      0       Tanzania   TZA        0
3        0           Western Sahara   SAH      0 Western Sahara   SAH        1
4        0                   Canada   CAN      0         Canada   CAN        0
5        0 United States of America   USA      0  United States   USA        0
6        0               Kazakhstan   KAZ      0     Kazakhstan   KAZ        0
                      name      name_long brk_a3      brk_name brk_group
1                     Fiji           Fiji    FJI          Fiji      <NA>
2                 Tanzania       Tanzania    TZA      Tanzania      <NA>
3                W. Sahara Western Sahara    B28     W. Sahara      <NA>
4                   Canada         Canada    CAN        Canada      <NA>
5 United States of America  United States    USA United States      <NA>
6               Kazakhstan     Kazakhstan    KAZ    Kazakhstan      <NA>
   abbrev postal                        formal_en formal_fr     name_ciawf
1    Fiji     FJ                 Republic of Fiji      <NA>           Fiji
2   Tanz.     TZ      United Republic of Tanzania      <NA>       Tanzania
3 W. Sah.     WS Sahrawi Arab Democratic Republic      <NA> Western Sahara
4    Can.     CA                           Canada      <NA>         Canada
5  U.S.A.     US         United States of America      <NA>  United States
6    Kaz.     KZ           Republic of Kazakhstan      <NA>     Kazakhstan
  note_adm0                        note_brk                name_sort name_alt
1      <NA>                            <NA>                     Fiji     <NA>
2      <NA>                            <NA>                 Tanzania     <NA>
3      <NA> Self admin.; Claimed by Morocco           Western Sahara     <NA>
4      <NA>                            <NA>                   Canada     <NA>
5      <NA>                            <NA> United States of America     <NA>
6      <NA>                            <NA>               Kazakhstan     <NA>
  mapcolor7 mapcolor8 mapcolor9 mapcolor13   pop_est pop_rank pop_year   gdp_md
1         5         1         2          2    889953       11     2019     5496
2         3         6         2          2  58005463       16     2019    63177
3         4         7         4          4    603253       11     2017      907
4         6         6         2          2  37589262       15     2019  1736425
5         4         5         1          1 328239523       17     2019 21433226
6         6         1         6          1  18513930       14     2019   181665
  gdp_year                   economy             income_grp fips_10 iso_a2
1     2019      6. Developing region 4. Lower middle income      FJ     FJ
2     2019 7. Least developed region          5. Low income      TZ     TZ
3     2007 7. Least developed region          5. Low income      WI     EH
4     2019   1. Developed region: G7   1. High income: OECD      CA     CA
5     2019   1. Developed region: G7   1. High income: OECD      US     US
6     2019      6. Developing region 3. Upper middle income      KZ     KZ
  iso_a2_eh iso_a3 iso_a3_eh iso_n3 iso_n3_eh un_a3 wb_a2 wb_a3   woe_id
1        FJ    FJI       FJI    242       242   242    FJ   FJI 23424813
2        TZ    TZA       TZA    834       834   834    TZ   TZA 23424973
3        EH    ESH       ESH    732       732   732   -99   -99 23424990
4        CA    CAN       CAN    124       124   124    CA   CAN 23424775
5        US    USA       USA    840       840   840    US   USA 23424977
6        KZ    KAZ       KAZ    398       398   398    KZ   KAZ      -90
  woe_id_eh                                                    woe_note
1  23424813                                  Exact WOE match as country
2  23424973                                  Exact WOE match as country
3  23424990                                  Exact WOE match as country
4  23424775                                  Exact WOE match as country
5  23424977                                  Exact WOE match as country
6  23424871 Includes Baykonur Cosmodrome as an Admin-1 states provinces
  adm0_iso adm0_diff adm0_tlc adm0_a3_us adm0_a3_fr adm0_a3_ru adm0_a3_es
1      FJI      <NA>      FJI        FJI        FJI        FJI        FJI
2      TZA      <NA>      TZA        TZA        TZA        TZA        TZA
3      B28      <NA>      B28        SAH        MAR        SAH        SAH
4      CAN      <NA>      CAN        CAN        CAN        CAN        CAN
5      USA      <NA>      USA        USA        USA        USA        USA
6      KAZ      <NA>      KAZ        KAZ        KAZ        KAZ        KAZ
  adm0_a3_cn adm0_a3_tw adm0_a3_in adm0_a3_np adm0_a3_pk adm0_a3_de adm0_a3_gb
1        FJI        FJI        FJI        FJI        FJI        FJI        FJI
2        TZA        TZA        TZA        TZA        TZA        TZA        TZA
3        SAH        SAH        MAR        SAH        SAH        SAH        SAH
4        CAN        CAN        CAN        CAN        CAN        CAN        CAN
5        USA        USA        USA        USA        USA        USA        USA
6        KAZ        KAZ        KAZ        KAZ        KAZ        KAZ        KAZ
  adm0_a3_br adm0_a3_il adm0_a3_ps adm0_a3_sa adm0_a3_eg adm0_a3_ma adm0_a3_pt
1        FJI        FJI        FJI        FJI        FJI        FJI        FJI
2        TZA        TZA        TZA        TZA        TZA        TZA        TZA
3        SAH        SAH        MAR        MAR        SAH        MAR        SAH
4        CAN        CAN        CAN        CAN        CAN        CAN        CAN
5        USA        USA        USA        USA        USA        USA        USA
6        KAZ        KAZ        KAZ        KAZ        KAZ        KAZ        KAZ
  adm0_a3_ar adm0_a3_jp adm0_a3_ko adm0_a3_vn adm0_a3_tr adm0_a3_id adm0_a3_pl
1        FJI        FJI        FJI        FJI        FJI        FJI        FJI
2        TZA        TZA        TZA        TZA        TZA        TZA        TZA
3        SAH        SAH        SAH        SAH        MAR        MAR        MAR
4        CAN        CAN        CAN        CAN        CAN        CAN        CAN
5        USA        USA        USA        USA        USA        USA        USA
6        KAZ        KAZ        KAZ        KAZ        KAZ        KAZ        KAZ
  adm0_a3_gr adm0_a3_it adm0_a3_nl adm0_a3_se adm0_a3_bd adm0_a3_ua adm0_a3_un
1        FJI        FJI        FJI        FJI        FJI        FJI        -99
2        TZA        TZA        TZA        TZA        TZA        TZA        -99
3        SAH        SAH        MAR        SAH        SAH        SAH        -99
4        CAN        CAN        CAN        CAN        CAN        CAN        -99
5        USA        USA        USA        USA        USA        USA        -99
6        KAZ        KAZ        KAZ        KAZ        KAZ        KAZ        -99
  adm0_a3_wb     continent region_un        subregion
1        -99       Oceania   Oceania        Melanesia
2        -99        Africa    Africa   Eastern Africa
3        -99        Africa    Africa  Northern Africa
4        -99 North America  Americas Northern America
5        -99 North America  Americas Northern America
6        -99          Asia      Asia     Central Asia
                   region_wb name_len long_len abbrev_len tiny homepart
1        East Asia & Pacific        4        4          4  -99        1
2         Sub-Saharan Africa        8        8          5  -99        1
3 Middle East & North Africa        9       14          7  -99        1
4              North America        6        6          4  -99        1
5              North America       24       13          6  -99        1
6      Europe & Central Asia       10       10          4  -99        1
  min_zoom min_label max_label    label_x    label_y      ne_id wikidataid
1      0.0       3.0       8.0  177.97543 -17.826099 1159320625       Q712
2      0.0       3.0       8.0   34.95918  -6.051866 1159321337       Q924
3      4.7       6.0      11.0  -12.63030  23.967592 1159321223      Q6250
4      0.0       1.7       5.7 -101.91070  60.324287 1159320467        Q16
5      0.0       1.7       5.7  -97.48260  39.538479 1159321369        Q30
6      0.0       2.7       7.0   68.68555  49.054149 1159320967       Q232
           name_ar         name_bn            name_de                  name_en
1             فيجي            ফিজি            Fidschi                     Fiji
2          تنزانيا       তানজানিয়া           Tansania                 Tanzania
3  الصحراء الغربية    পশ্চিম সাহারা         Westsahara           Western Sahara
4             كندا          কানাডা             Kanada                   Canada
5 الولايات المتحدة মার্কিন যুক্তরাষ্ট্র Vereinigte Staaten United States of America
6        كازاخستان       কাজাখস্তান         Kasachstan               Kazakhstan
            name_es             name_fa           name_fr
1              Fiyi                فیجی             Fidji
2          Tanzania            تانزانیا          Tanzanie
3 Sahara Occidental          صحرای غربی Sahara occidental
4            Canadá              کانادا            Canada
5    Estados Unidos ایالات متحده آمریکا        États-Unis
6        Kazajistán            قزاقستان        Kazakhstan
                      name_el      name_he          name_hi
1                       Φίτζι        פיג'י             फ़िजी
2                    Τανζανία       טנזניה          तंज़ानिया
3               Δυτική Σαχάρα סהרה המערבית     पश्चिमी सहारा
4                     Καναδάς         קנדה            कनाडा
5 Ηνωμένες Πολιτείες Αμερικής  ארצות הברית संयुक्त राज्य अमेरिका
6                   Καζακστάν       קזחסטן        कज़ाख़िस्तान
                    name_hu         name_id               name_it
1           Fidzsi-szigetek            Fiji                  Figi
2                  Tanzánia        Tanzania              Tanzania
3            Nyugat-Szahara    Sahara Barat    Sahara Occidentale
4                    Kanada          Kanada                Canada
5 Amerikai Egyesült Államok Amerika Serikat Stati Uniti d'America
6                Kazahsztán      Kazakhstan            Kazakistan
         name_ja    name_ko                      name_nl           name_pl
1       フィジー       피지                         Fiji             Fidżi
2     タンザニア   탄자니아                     Tanzania          Tanzania
3       西サハラ   서사하라            Westelijke Sahara  Sahara Zachodnia
4         カナダ     캐나다                       Canada            Kanada
5 アメリカ合衆国       미국 Verenigde Staten van Amerika Stany Zjednoczone
6   カザフスタン 카자흐스탄                   Kazachstan        Kazachstan
         name_pt         name_ru    name_sv                     name_tr
1           Fiji           Фиджи       Fiji                        Fiji
2       Tanzânia        Танзания   Tanzania                    Tanzanya
3 Sara Ocidental Западная Сахара Västsahara                  Batı Sahra
4         Canadá          Канада     Kanada                      Kanada
5 Estados Unidos             США        USA Amerika Birleşik Devletleri
6    Cazaquistão       Казахстан  Kazakstan                  Kazakistan
                  name_uk                name_ur    name_vi    name_zh name_zht
1                   Фіджі                    فجی       Fiji       斐济     斐濟
2                Танзанія                تنزانیہ   Tanzania   坦桑尼亚 坦尚尼亞
3          Західна Сахара            مغربی صحارا Tây Sahara   西撒哈拉 西撒哈拉
4                  Канада                 کینیڈا     Canada     加拿大   加拿大
5 Сполучені Штати Америки ریاستہائے متحدہ امریکا     Hoa Kỳ       美国     美國
6               Казахстан               قازقستان Kazakhstan 哈萨克斯坦   哈薩克
          fclass_iso tlc_diff         fclass_tlc fclass_us    fclass_fr
1    Admin-0 country     <NA>    Admin-0 country      <NA>         <NA>
2    Admin-0 country     <NA>    Admin-0 country      <NA>         <NA>
3 Admin-0 dependency     <NA> Admin-0 dependency      <NA> Unrecognized
4    Admin-0 country     <NA>    Admin-0 country      <NA>         <NA>
5    Admin-0 country     <NA>    Admin-0 country      <NA>         <NA>
6    Admin-0 country     <NA>    Admin-0 country      <NA>         <NA>
  fclass_ru fclass_es fclass_cn fclass_tw    fclass_in fclass_np fclass_pk
1      <NA>      <NA>      <NA>      <NA>         <NA>      <NA>      <NA>
2      <NA>      <NA>      <NA>      <NA>         <NA>      <NA>      <NA>
3      <NA>      <NA>      <NA>      <NA> Unrecognized      <NA>      <NA>
4      <NA>      <NA>      <NA>      <NA>         <NA>      <NA>      <NA>
5      <NA>      <NA>      <NA>      <NA>         <NA>      <NA>      <NA>
6      <NA>      <NA>      <NA>      <NA>         <NA>      <NA>      <NA>
  fclass_de fclass_gb fclass_br fclass_il    fclass_ps    fclass_sa fclass_eg
1      <NA>      <NA>      <NA>      <NA>         <NA>         <NA>      <NA>
2      <NA>      <NA>      <NA>      <NA>         <NA>         <NA>      <NA>
3      <NA>      <NA>      <NA>      <NA> Unrecognized Unrecognized      <NA>
4      <NA>      <NA>      <NA>      <NA>         <NA>         <NA>      <NA>
5      <NA>      <NA>      <NA>      <NA>         <NA>         <NA>      <NA>
6      <NA>      <NA>      <NA>      <NA>         <NA>         <NA>      <NA>
     fclass_ma fclass_pt fclass_ar fclass_jp fclass_ko fclass_vn    fclass_tr
1         <NA>      <NA>      <NA>      <NA>      <NA>      <NA>         <NA>
2         <NA>      <NA>      <NA>      <NA>      <NA>      <NA>         <NA>
3 Unrecognized      <NA>      <NA>      <NA>      <NA>      <NA> Unrecognized
4         <NA>      <NA>      <NA>      <NA>      <NA>      <NA>         <NA>
5         <NA>      <NA>      <NA>      <NA>      <NA>      <NA>         <NA>
6         <NA>      <NA>      <NA>      <NA>      <NA>      <NA>         <NA>
     fclass_id    fclass_pl fclass_gr fclass_it    fclass_nl fclass_se
1         <NA>         <NA>      <NA>      <NA>         <NA>      <NA>
2         <NA>         <NA>      <NA>      <NA>         <NA>      <NA>
3 Unrecognized Unrecognized      <NA>      <NA> Unrecognized      <NA>
4         <NA>         <NA>      <NA>      <NA>         <NA>      <NA>
5         <NA>         <NA>      <NA>      <NA>         <NA>      <NA>
6         <NA>         <NA>      <NA>      <NA>         <NA>      <NA>
  fclass_bd fclass_ua                       geometry
1      <NA>      <NA> MULTIPOLYGON (((180 -16.067...
2      <NA>      <NA> MULTIPOLYGON (((33.90371 -0...
3      <NA>      <NA> MULTIPOLYGON (((-8.66559 27...
4      <NA>      <NA> MULTIPOLYGON (((-122.84 49,...
5      <NA>      <NA> MULTIPOLYGON (((-122.84 49,...
6      <NA>      <NA> MULTIPOLYGON (((87.35997 49...

Coordinate reference systems

Code
world |> 
  ggplot(aes(geometry = geometry)) +
  geom_sf() +
  coord_sf(crs = "EPSG:3395")

Code
world |> 
  ggplot(aes(geometry = geometry)) +
  geom_sf() +
  coord_sf(crs = "+proj=robin")

Code
usa <- ne_states(country = "United States of America", returnclass = "sf") |> 
  filter(!name %in% c("Alaska", "Hawaii"))

usa |> 
  ggplot(aes(geometry = geometry)) +
  geom_sf() +
  coord_sf(crs = "+proj=merc")

Code
usa |> 
  ggplot(aes(geometry = geometry)) +
  geom_sf() +
  coord_sf(crs = "ESRI:102003")

Case study: haunted places in the United States

  • Examples adopted from here
haunted_places <- read_csv("https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2023/2023-10-10/haunted_places.csv") |> 
  filter(!state %in% c("Alaska", "Hawaii"))
head(haunted_places)
# A tibble: 6 × 10
  city    country     description location state state_abbrev longitude latitude
  <chr>   <chr>       <chr>       <chr>    <chr> <chr>            <dbl>    <dbl>
1 Ada     United Sta… "Ada witch… Ada Cem… Mich… MI               -85.5     43.0
2 Addison United Sta… "A little … North A… Mich… MI               -84.4     42.0
3 Adrian  United Sta… "If you ta… Ghost T… Mich… MI               -84.0     41.9
4 Adrian  United Sta… "In the 19… Siena H… Mich… MI               -84.0     41.9
5 Albion  United Sta… "Kappa Del… Albion … Mich… MI               -84.7     42.2
6 Albion  United Sta… "A mysteri… Riversi… Mich… MI               -84.8     42.2
# ℹ 2 more variables: city_longitude <dbl>, city_latitude <dbl>
  • Count the number of haunted places in each state
haunted_states <- haunted_places |>
  count(state, state_abbrev)
head(haunted_states)
# A tibble: 6 × 3
  state       state_abbrev     n
  <chr>       <chr>        <int>
1 Alabama     AL             224
2 Arizona     AZ             156
3 Arkansas    AR             119
4 California  CA            1070
5 Colorado    CO             166
6 Connecticut CT             185

Choropleth map

Code
usa |> 
  left_join(haunted_states, by = join_by(postal == state_abbrev)) |> 
  ggplot(aes(geometry = geometry)) +
  geom_sf(aes(fill = n), linewidth = 0.1) +
  scale_fill_gradient2() +
  labs(fill = "Count",
       title = "Haunted places in the US")

Choropleth map

Code
usa |> 
  left_join(haunted_states, by = join_by(postal == state_abbrev)) |> 
  ggplot(aes(geometry = geometry)) +
  geom_sf(aes(fill = n), linewidth = 0.1) +
  coord_sf(crs = "ESRI:102003") +
  scale_fill_gradient(low = "#1a1a24", high = "white") +
  theme_void() +
  theme(legend.position = "none",
        plot.background = element_rect(fill = "black"))

Hexbin map

Code
# https://team.carto.com/u/andrew/tables/andrew.us_states_hexgrid/public/map
us_hex <- read_sf("https://raw.githubusercontent.com/qntkhvn/36-315-summer26/refs/heads/master/data/us_states_hexgrid.geojson") |> 
  st_transform(crs = 3857)

states_hex <- us_hex |> 
  inner_join(haunted_states, by = join_by(iso3166_2 == state_abbrev))

states_centroid <- states_hex |> 
  st_centroid()

states_hex |> 
  ggplot(aes(geometry = geometry)) +
  geom_sf(aes(fill = n), linewidth = 0.1) +
  geom_sf_text(data = states_centroid, aes(label = iso3166_2), vjust = -0.5, size = 3) +
  geom_sf_text(data = states_centroid, aes(label = n), vjust = 1, size = 3.5, fontface = "bold") +
  scale_fill_gradient(low = "#F2EA79", high = "#D92B04") +
  theme_void() +
  theme(legend.position = "none",
        plot.background = element_rect(fill = "black"))

Bubble map

Code
map_data("state") |> 
  ggplot() +
  geom_polygon(aes(long, lat, group = group),
               fill = "gray75", color = "gray20", alpha = 0.1) +
  geom_point(data = haunted_places, 
             aes(x = city_longitude, y = city_latitude),
             color = "white", alpha = 0.1, size = 0.3) +
  coord_map("albers", lat0 = 39, lat1 = 45, xlim = c(-118, -75)) +
  theme_void() +
  theme(legend.position = "none",
        plot.background = element_rect(fill = "black"),
        plot.margin = margin(0, 0, 0, 0))

Bubble map

Code
map_data("state") |> 
  ggplot() +
  geom_polygon(aes(long, lat, group = group),
               fill = "gray75", color = "gray20", alpha = 0.1) +
  geom_point(data = count(haunted_places, city, city_longitude, city_latitude), 
             aes(x = city_longitude, y = city_latitude, size = n),
             color = "white", alpha = 0.1) +
  coord_map("albers", lat0 = 39, lat1 = 45, xlim = c(-118, -75)) +
  theme_void() +
  theme(legend.position = "none",
        plot.background = element_rect(fill = "black"),
        plot.margin = margin(0, 0, 0, 0))

Data art

Code
haunted_places |> 
  ggplot(aes(x = city_longitude, y = city_latitude, alpha = after_stat(level))) +
  geom_density_2d_filled(bins = 50, color = NA, show.legend = FALSE) +
  scale_fill_manual(values = colorRampPalette(c("#1a1a24", "#4a5568", "#cbd5e1", "white"))(50)) + 
  scale_alpha_manual(values = seq(0.4, 0.8, length.out = 50)) +
  theme_void() +
  theme(plot.background = element_rect(fill = "black"),
        panel.background = element_rect(fill = "black"))

Bivariate choropleth maps

See tutorials here, here and here

Interactive maps with Leaflet

  • Leaflet is an open-source JavaScript library for interactive maps
library(leaflet)
  • Create a map widget by with leaflet()

  • Add layers

    • addTiles(): add default basemap tiles to map

    • addMarkers(): put markers at the specified longitude and latitude coordinates

      • lng and lat: specify longitude and latitude of the markers

      • popup: add description about each location

    • and more…

  • More examples here and here

Basic leaflet map

pgh_leaflet <- leaflet() |> 
  setView(lng = -79.9972, lat = 40.4387, zoom = 12)
pgh_leaflet |> 
  addTiles()

Basemaps

Type leaflet::providers or see here for all basemap options

pgh_leaflet |> 
  addTiles()
pgh_leaflet |> 
  addProviderTiles(providers$Stadia.StamenToner)
pgh_leaflet |> 
  addProviderTiles(providers$OpenTopoMap)
pgh_leaflet |> 
  addProviderTiles(providers$CartoDB.DarkMatter)
pgh_leaflet |> 
  addProviderTiles(providers$USGS)

More leaflet annotations

leaflet() |> 
  addTiles() |> 
  addMarkers(lng = c(-83.813, -87.658, -79.944),
             lat = c(39.935, 42.000, 40.443),
             popup = c("Wittenberg", "Loyola Chicago", "Carnegie Mellon"))

Geocoding

  • Use the tidygeocoder package
library(tidygeocoder)
  • Address geocoding with geocode()

  • Reverse geocoding with reverse_geocode()

  • Many geocoding services (see here)

Address geocoding

school_addresses <- tibble(
  school_name = c("Wittenberg", "Loyola Chicago", "Carnegie Mellon"),
  school_address = c("200 W Ward St, Springfield, OH 45504", "1032 W Sheridan Rd, Chicago, IL 60660", "5000 Forbes Ave, Pittsburgh, PA")
)
school_addresses
# A tibble: 3 × 2
  school_name     school_address                       
  <chr>           <chr>                                
1 Wittenberg      200 W Ward St, Springfield, OH 45504 
2 Loyola Chicago  1032 W Sheridan Rd, Chicago, IL 60660
3 Carnegie Mellon 5000 Forbes Ave, Pittsburgh, PA      
school_addresses |> 
  geocode(address = school_address)
# A tibble: 3 × 4
  school_name     school_address                          lat  long
  <chr>           <chr>                                 <dbl> <dbl>
1 Wittenberg      200 W Ward St, Springfield, OH 45504   39.9 -83.8
2 Loyola Chicago  1032 W Sheridan Rd, Chicago, IL 60660  42.0 -87.7
3 Carnegie Mellon 5000 Forbes Ave, Pittsburgh, PA        40.4 -79.9

Use street, city, county, state, postalcode, country

head(louisville)
# A tibble: 6 × 6
  street                 city       state      zip latitude longitude
  <chr>                  <chr>      <chr>    <dbl>    <dbl>     <dbl>
1 2722 ELLIOTT AVE       Louisville Kentucky 40211     38.3     -85.8
2 850 WASHBURN AVE       Louisville Kentucky 40222     38.3     -85.6
3 1449 ST JAMES CT       Louisville Kentucky 40208     38.2     -85.8
4 9007 SAGEBRUSH CT      Louisville Kentucky 40228     38.1     -85.6
5 376 FLIRTATION WALK    Louisville Kentucky 40219     38.2     -85.7
6 3429 CATHE DYKSTRA WAY Louisville Kentucky 40216     38.2     -85.9
louisville |> 
  head(3) |> 
  geocode(street = street, city = city, state = state, postalcode = zip, method = "arcgis")
# A tibble: 3 × 8
  street           city       state      zip latitude longitude   lat  long
  <chr>            <chr>      <chr>    <dbl>    <dbl>     <dbl> <dbl> <dbl>
1 2722 ELLIOTT AVE Louisville Kentucky 40211     38.3     -85.8  38.3 -85.8
2 850 WASHBURN AVE Louisville Kentucky 40222     38.3     -85.6  38.3 -85.6
3 1449 ST JAMES CT Louisville Kentucky 40208     38.2     -85.8  38.2 -85.8

Reverse geocoding

school_coordinates <- tibble(school_name = c("Wittenberg", "Loyola Chicago", "Carnegie Mellon"),
                             school_latitiude = c(39.935, 42.000, 40.443),
                             school_longitude = c(-83.813, -87.658, -79.944))
school_coordinates
# A tibble: 3 × 3
  school_name     school_latitiude school_longitude
  <chr>                      <dbl>            <dbl>
1 Wittenberg                  39.9            -83.8
2 Loyola Chicago              42              -87.7
3 Carnegie Mellon             40.4            -79.9
school_coordinates |> 
  reverse_geocode(lat = school_latitiude, long = school_longitude, method = "osm", full_results = TRUE)
# A tibble: 3 × 30
  school_name     school_latitiude school_longitude address     place_id licence
  <chr>                      <dbl>            <dbl> <chr>          <int> <chr>  
1 Wittenberg                  39.9            -83.8 Wittenberg…   3.40e8 Data ©…
2 Loyola Chicago              42              -87.7 Rogers Par…   3.72e8 Data ©…
3 Carnegie Mellon             40.4            -79.9 5000, Forb…   3.50e8 Data ©…
# ℹ 24 more variables: osm_type <chr>, osm_id <dbl>, osm_lat <chr>,
#   osm_lon <chr>, class <chr>, type <chr>, place_rank <int>, importance <dbl>,
#   addresstype <chr>, name <chr>, amenity <chr>, road <chr>, city <chr>,
#   county <chr>, state <chr>, `ISO3166-2-lvl4` <chr>, postcode <chr>,
#   country <chr>, country_code <chr>, boundingbox <list>, suburb <chr>,
#   municipality <chr>, house_number <chr>, neighbourhood <chr>

Graphic replication

south <- read_csv("https://raw.githubusercontent.com/qntkhvn/36-315-summer26/refs/heads/master/data/south.csv")