Visualising Geospatial Point Data

Author

Sun Yiping

Published

February 28, 2024

Modified

February 28, 2024

1. Learning Outcome

In this hands-on exercise, we will learn how to create a proportional symbol map showing the number of wins by Singapore Pools’ outlets using an R package called tmap.

2. Getting Started

2.1 Installing and loading the required libraries

Firstly, let’s install and load the required packages:

  • tidyverse: an opinionated collection of R packages designed for data import, data wrangling and data exploration

  • sf: a standardized way to encode spatial vector data.

  • tmap: makes it easier to plot thematic maps.

pacman::p_load(tidyverse, sf, tmap)

2.2 Importing the data

In this exercise, SGPools_svy21.csv file will be used.

Let’s start by importing the data.

sgpools <- read_csv("../../Data/hands-on_ex07/aspatial/SGPools_svy21.csv")
Rows: 306 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): NAME, ADDRESS, OUTLET TYPE
dbl (4): POSTCODE, XCOORD, YCOORD, Gp1Gp2 Winnings

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
list(sgpools) 
[[1]]
# A tibble: 306 × 7
   NAME           ADDRESS POSTCODE XCOORD YCOORD `OUTLET TYPE` `Gp1Gp2 Winnings`
   <chr>          <chr>      <dbl>  <dbl>  <dbl> <chr>                     <dbl>
 1 Livewire (Mar… 2 Bayf…    18972 30842. 29599. Branch                        5
 2 Livewire (Res… 26 Sen…    98138 26704. 26526. Branch                       11
 3 SportsBuzz (K… Lotus …   738078 20118. 44888. Branch                        0
 4 SportsBuzz (P… 1 Sele…   188306 29777. 31382. Branch                       44
 5 Prime Serango… Blk 54…   552542 32239. 39519. Branch                        0
 6 Singapore Poo… 1A Woo…   731001 21012. 46987. Branch                        3
 7 Singapore Poo… Blk 64…   370064 33990. 34356. Branch                       17
 8 Singapore Poo… Blk 88…   370088 33847. 33976. Branch                       16
 9 Singapore Poo… Blk 30…   540308 33910. 41275. Branch                       21
10 Singapore Poo… Blk 20…   560202 29246. 38943. Branch                       25
# ℹ 296 more rows

There are 306 rows and 7 columns in the data file. The coordinates are stored in XCOORD and YCOORD columns, and they follow Singapore SVY21 Projected Coordinates System.

2.3 Data Preparation

Next, we’ll convert sgpools data frame into a simple feature data frame by using st_as_sf() of sf package.

sgpools_sf <- st_as_sf(sgpools, 
                       coords = c("XCOORD", "YCOORD"),
                       crs = 3414)

The crs argument required us to provide the coordinates system in EPSG format. EPSG: 3414 is Singapore SVY21 Projected Coordinate System. We can search for other country’s EPSG code by refering to epsg.io.

list(sgpools_sf)
[[1]]
Simple feature collection with 306 features and 5 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: 7844.194 ymin: 26525.7 xmax: 45176.57 ymax: 47987.13
Projected CRS: SVY21 / Singapore TM
# A tibble: 306 × 6
   NAME                         ADDRESS POSTCODE `OUTLET TYPE` `Gp1Gp2 Winnings`
 * <chr>                        <chr>      <dbl> <chr>                     <dbl>
 1 Livewire (Marina Bay Sands)  2 Bayf…    18972 Branch                        5
 2 Livewire (Resorts World Sen… 26 Sen…    98138 Branch                       11
 3 SportsBuzz (Kranji)          Lotus …   738078 Branch                        0
 4 SportsBuzz (PoMo)            1 Sele…   188306 Branch                       44
 5 Prime Serangoon North        Blk 54…   552542 Branch                        0
 6 Singapore Pools Woodlands C… 1A Woo…   731001 Branch                        3
 7 Singapore Pools 64 Circuit … Blk 64…   370064 Branch                       17
 8 Singapore Pools 88 Circuit … Blk 88…   370088 Branch                       16
 9 Singapore Pools Anchorvale … Blk 30…   540308 Branch                       21
10 Singapore Pools Ang Mo Kio … Blk 20…   560202 Branch                       25
# ℹ 296 more rows
# ℹ 1 more variable: geometry <POINT [m]>

The simple feature data frame now contains 306 rows and 6 columns. The original XCOORD and YCOORD columns have been converted to geometry column.

3. Drawing Proportional Symbol Map

Before ploting the map, let’s first turn on the interactive mode of tmap.

tmap_mode("view")
tmap mode set to interactive viewing

3.1 It all started with an interactive point symbol map

The code chunks below are used to create an interactive point symbol map.

tm_shape(sgpools_sf)+
tm_bubbles(col = "red",
           size = 1,
           border.col = "black",
           border.lwd = 1)

The red bubbles appeared at the locations where there are data and they are of the same size in the plot above.

3.2 Lets make it proportional

tm_shape(sgpools_sf)+
tm_bubbles(col = "red",
           size = "Gp1Gp2 Winnings",
           border.col = "black",
           border.lwd = 1)
Legend for symbol sizes not available in view mode.

Now the size of the bubbles vary according to the value of Gp1Gp2 Winnings column.

3.3 Lets give it a different colour

We can also assign the color of the bubbles based on another column.

tm_shape(sgpools_sf)+
tm_bubbles(col = "OUTLET TYPE", 
          size = "Gp1Gp2 Winnings",
          border.col = "black",
          border.lwd = 1)
Legend for symbol sizes not available in view mode.

Now, the bubbles are colored according to the outlet type. Green for branch and yellow for outlet.

3.4 I have a twin brothers :)

We can also put two plots side by side for easy comparison.

tm_shape(sgpools_sf) +
  tm_bubbles(col = "OUTLET TYPE", 
          size = "Gp1Gp2 Winnings",
          border.col = "black",
          border.lwd = 1) +
  tm_facets(by= "OUTLET TYPE",
            nrow = 1,
            sync = TRUE)
Legend for symbol sizes not available in view mode.

Instead of displaying both outlets on the same plot, we now have one plot for each outlet type. What’s more interesting? They are synchronized! If you change the scale of one plot, the other one will also change accordingly. A red circle is also appeared on the other plot pointing to the same area that you are looking at. Isn’t this amazing?

Before we end the session, always remember to switch tmap’s Viewer back to plot mode by using the code chunk below.

tmap_mode("plot")
tmap mode set to plotting

This comes to the end of this hands-on exercise. I have learned to plot proportional symbol map using R. Hope you enjoyed it, too!

See you in the next hands-on exercise 🥰