Proportional symbol maps (also known as graduate symbol maps) are a class of maps that use the visual variable of size to represent differences in the magnitude of a discrete, abruptly changing phenomenon, e.g. counts of people. Like choropleth maps, you can create classed or unclassed versions of these maps. The classed ones are known as range-graded or graduated symbols, and the unclassed are called proportional symbols, where the area of the symbols are proportional to the values of the attribute being mapped. In this hands-on exercise, you will learn how to create a proportional symbol map showing the number of wins by Singapore Pools’ outlets using an R package called tmap.
By the end of this hands-on exercise, you will acquire the following skills by using appropriate R packages:
Before we get started, we need to ensure that tmap package of R and other related R packages have been installed and loaded into R.
packages = c('sf', 'tmap', 'tidyverse')
for (p in packages){
if(!require(p, character.only = T)){
install.packages(p)
}
library(p,character.only = T)
}
The data set use for this hands-on exercise is called SGPools_svy21. The data is in csv file format.
Figure below shows the first 15 records of SGPools_svy21.csv. It consists of seven columns. The XCOORD and YCOORD columns are the x-coordinates and y-coordinates of SingPools outlets and branches. They are in Singapore SVY21 Projected Coordinates System.
The code chunk below uses read_csv() function of readr package to import SGPools_svy21.csv into R as a tibble data frame called sgpools.
sgpools <- read_csv("data/aspatial/SGPools_svy21.csv")
## Parsed with column specification:
## cols(
## NAME = col_character(),
## ADDRESS = col_character(),
## POSTCODE = col_double(),
## XCOORD = col_double(),
## YCOORD = col_double(),
## `OUTLET TYPE` = col_character(),
## `Gp1Gp2 Winnings` = col_double()
## )
After importing the data file into R, it is important for us to examine if the data file has been imported correctly.
The code chunk below shows list() is used to do the job.
list(sgpools)
## [[1]]
## # A tibble: 306 x 7
## NAME ADDRESS POSTCODE XCOORD YCOORD `OUTLET TYPE` `Gp1Gp2 Winning~
## <chr> <chr> <dbl> <dbl> <dbl> <chr> <dbl>
## 1 Livewire~ 2 Bayfront A~ 18972 30842. 29599. Branch 5
## 2 Livewire~ 26 Sentosa G~ 98138 26704. 26526. Branch 11
## 3 SportsBu~ Lotus Lounge~ 738078 20118. 44888. Branch 0
## 4 SportsBu~ 1 Selegie Rd~ 188306 29777. 31382. Branch 44
## 5 Prime Se~ Blk 542B Ser~ 552542 32239. 39519. Branch 0
## 6 Singapor~ 1A Woodlands~ 731001 21012. 46987. Branch 3
## 7 Singapor~ Blk 64 Circu~ 370064 33990. 34356. Branch 17
## 8 Singapor~ Blk 88 Circu~ 370088 33847. 33976. Branch 16
## 9 Singapor~ Blk 308 Anch~ 540308 33910. 41275. Branch 21
## 10 Singapor~ Blk 202 Ang ~ 560202 29246. 38943. Branch 25
## # ... with 296 more rows
Notice that the sgpools data in tibble data frame and not the common R data frame.
The code chunk below converts sgpools data frame into a simple feature data frame by using st_as_sf() of sf packages
sgpools_sf <- st_as_sf(sgpools,
coords = c("XCOORD", "YCOORD"),
crs= 3414)
Things to learn from the arguments above:
Figure below shows the data table of sgpools_sf. Notice that a new column called geometry has been added into the data frame.
You can display the basic information of the newly created sgpools_sf by using the code chunk below.
list(sgpools_sf)
## [[1]]
## Simple feature collection with 306 features and 5 fields
## geometry type: POINT
## dimension: XY
## bbox: xmin: 7844.194 ymin: 26525.7 xmax: 45176.57 ymax: 47987.13
## epsg (SRID): 3414
## proj4string: +proj=tmerc +lat_0=1.366666666666667 +lon_0=103.8333333333333 +k=1 +x_0=28001.642 +y_0=38744.572 +ellps=WGS84 +units=m +no_defs
## # A tibble: 306 x 6
## NAME ADDRESS POSTCODE `OUTLET TYPE` `Gp1Gp2 Winning~
## <chr> <chr> <dbl> <chr> <dbl>
## 1 Live~ 2 Bayf~ 18972 Branch 5
## 2 Live~ 26 Sen~ 98138 Branch 11
## 3 Spor~ Lotus ~ 738078 Branch 0
## 4 Spor~ 1 Sele~ 188306 Branch 44
## 5 Prim~ Blk 54~ 552542 Branch 0
## 6 Sing~ 1A Woo~ 731001 Branch 3
## 7 Sing~ Blk 64~ 370064 Branch 17
## 8 Sing~ Blk 88~ 370088 Branch 16
## 9 Sing~ Blk 30~ 540308 Branch 21
## 10 Sing~ Blk 20~ 560202 Branch 25
## # ... with 296 more rows, and 1 more variable: geometry <POINT [m]>
The output shows that sgppols_sf is in point feature class. It’s epsg ID is 3414. The bbox provides information of the extend of the geospatial data.
To create an interactive proportional symbol map in R, the view mode of tmap will be used.
The code churn below will turn on the interactive mode of tmap.
tmap_mode("view")
## tmap mode set to interactive viewing
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)
To draw a proportional symbol map, we need to assign a numerical variable to the size visual attribute. The code chunks below show that the variable Gp1Gp2Winnings is assigned to size visual attribute.
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.
The proportional symbol map can be further improved by using the colour visual attribute. In the code chunks below, OUTLET_TYPE variable is used as the colour attribute variable.
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.
An impressive and little-know feature of tmap’s view mode is that it also works with faceted plots. The argument sync in tm_facets() can be used in this case to produce multiple maps with synchronised zoom and pan settings.
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.
Before you end the session, it is wiser to switch tmap’s Viewer back to plot mode by using the code chunk below.
tmap_mode("plot")
## tmap mode set to plotting