Mahdi Salehi
salehi2sms@gmail.com
Associate professor at
University of Neyshabur
Last update: 2025
- Part I: Various spatial data classes in R
- Part II: Creating maps and visualization of spatial data using
tmap package
- Part III: Creating maps and
visualization of spatial data using ggplot2 package
Various spatial data classes in R
SpatialSpatialPointsSpatialLinesSpatialPolygonsSpatial classSpatial class is the base spatial data class in R
provided by sp package. It has only two slots. The first is
a bounding box, a matrix of numerical coordinates with column names
c(‘min’, ‘max’), and at least two rows, with the first row eastings
(x-axis) and the second northings (y-axis). Most often the bounding box
is generated automatically from the data in subclasses of Spatial. The
second is a CRS class object defining the coordinate reference system
[Roger et al., 2008].
## Class "Spatial" [package "sp"]
##
## Slots:
##
## Name: bbox proj4string
## Class: matrix CRS
##
## Known Subclasses:
## Class "SpatialPoints", directly
## Class "SpatialMultiPoints", directly
## Class "SpatialGrid", directly
## Class "SpatialLines", directly
## Class "SpatialPolygons", directly
## Class "SpatialPointsDataFrame", by class "SpatialPoints", distance 2
## Class "SpatialPixels", by class "SpatialPoints", distance 2
## Class "SpatialMultiPointsDataFrame", by class "SpatialMultiPoints", distance 2
## Class "SpatialGridDataFrame", by class "SpatialGrid", distance 2
## Class "SpatialLinesDataFrame", by class "SpatialLines", distance 2
## Class "SpatialPixelsDataFrame", by class "SpatialPoints", distance 3
## Class "SpatialPolygonsDataFrame", by class "SpatialPolygons", distance 2
CRS: Coordinate
reference systemThis class has a character string as its only slot value, which may be a missing value. If it is not missing, it should be a PROJ.4-format string describing the projection [see Roger et al., Section, 2008]
## Class "CRS" [package "sp"]
##
## Slots:
##
## Name: projargs
## Class: character
For geographical coordinates, the simplest such string is “+proj=longlat”, using “longlat”, which also shows that eastings always go before northings in sp classes.
For more details on crs, see https://www.earthdatascience.org/courses/earth-analytics/spatial-data-r/intro-to-coordinate-reference-systems/
m <- matrix(c(0, 0, 1, 1), ncol = 2, dimnames = list(NULL, c("min", "max")))
crs <- CRS(projargs = as.character(NA))
crs## Coordinate Reference System:
## Deprecated Proj.4 representation: NA
## An object of class "Spatial"
## Slot "bbox":
## min max
## [1,] 0 1
## [2,] 0 1
##
## Slot "proj4string":
## Coordinate Reference System:
## Deprecated Proj.4 representation: NA
SpatialPoints classIt is the first subclass of Spatial and is very important. A
two-dimensional point can be described by a pair of numbers
(x, y), defined over a known region. To represent
geographical phenomena, the maximum known region is the earth, and the
pair of numbers measured in degrees are a geographical coordinate,
showing where our point is on the globe. The pair of numbers define the
location on the sphere exactly, but if we represent the globe more
accurately by an ellipsoid model, such as the World Geodetic System 1984
(WGS84), that position shifts slightly. Geographical
coordinates can extend from latitude 90 to -90 in the north–south
direction, and from longitude -180 to 180 in the east-west
direction.
## Class "SpatialPoints" [package "sp"]
##
## Slots:
##
## Name: coords bbox proj4string
## Class: matrix matrix CRS
##
## Extends: "Spatial"
##
## Known Subclasses:
## Class "SpatialPointsDataFrame", directly
## Class "SpatialPixels", directly
## Class "SpatialPixelsDataFrame", by class "SpatialPixels", distance 2
Indeed, the SpatialPoints class extends the
Spatial class by adding a coords slot, into which a matrix
of point coordinates can be inserted.
CRAN_df <- read.table("http://www.asdar-book.org/datasets/CRAN051001a.txt", header = TRUE)
head(CRAN_df)## place north east loc long lat
## 1 Brisbane 27d28'S 153d02'E Australia 153.03333 -27.46667
## 2 Melbourne 37d49'S 144d58'E Australia 144.96667 -37.81667
## 3 Wien 48d13'N 16d20'E Austria 16.33333 48.21667
## 4 Curitiba 25d25'S 49d16'W Brazil -49.26667 -25.41667
## 5 Vi\xe7oza 20d45'S 42d52'W Brazil -42.86667 -20.75000
## 6 Rio de Janeiro 22d54'S 43d12'W Brazil -43.20000 -22.90000
We extract the two columns with the longitude and latitude values into a matrix:
## num [1:54, 1:2] 153 145 16.3 -49.3 -42.9 ...
## - attr(*, "dimnames")=List of 2
## ..$ : chr [1:54] "1" "2" "3" "4" ...
## ..$ : NULL
SpatialPoints class:crs <- CRS("+proj=longlat +ellps=WGS84")
CRAN_sp <- SpatialPoints(CRAN_mat, proj4string = crs)
summary(CRAN_sp)## Object of class SpatialPoints
## Coordinates:
## min max
## coords.x1 -122.95000 153.0333
## coords.x2 -37.81667 57.0500
## Is projected: FALSE
## proj4string : [+proj=longlat +ellps=WGS84 +no_defs]
## Number of points: 54
## [1] -122.9500 153.0333
## [1] -37.81667 57.05000
Spatial object## min max
## coords.x1 -122.95000 153.0333
## coords.x2 -37.81667 57.0500
proj4string slot of a
Spatial object## [1] "+proj=longlat +ellps=WGS84 +no_defs"
SpatialPoints
object## [1] 34 35
## coords.x1 coords.x2
## 34 18.36667 -33.91667
## 35 26.51667 -33.31667
## Object of class SpatialPoints
## Coordinates:
## min max
## coords.x1 18.36667 26.51667
## coords.x2 -33.91667 -33.31667
## Is projected: FALSE
## proj4string : [+proj=longlat +ellps=WGS84 +no_defs]
## Number of points: 2
SpatialPointsDataFrame classHere you will see how SpatialPoints object can be taught
to behave like a data.frame. To this end,
SpatialPointsDataFrame is employed.
## Class "SpatialPointsDataFrame" [package "sp"]
##
## Slots:
##
## Name: data coords.nrs coords bbox proj4string
## Class: data.frame numeric matrix matrix CRS
##
## Extends:
## Class "SpatialPoints", directly
## Class "Spatial", by class "SpatialPoints", distance 2
##
## Known Subclasses:
## Class "SpatialPixelsDataFrame", directly, with explicit coerce
There are some approaches for reaching to this goal including the following two:
Whether they are equivalent?
## [1] TRUE
SpatialLines classLine \(\longrightarrow\) Lines\(\longrightarrow\) SpatialLines
## Class "SpatialLines" [package "sp"]
##
## Slots:
##
## Name: lines bbox proj4string
## Class: list matrix CRS
##
## Extends: "Spatial"
##
## Known Subclasses: "SpatialLinesDataFrame"
Interested readers may refer to Roger et al. (2008, Section 2.5)
SpatialPolygons classPolygon \(\longrightarrow\)
Polygons\(\longrightarrow\)
SpatialPolygons
## Class "SpatialPolygons" [package "sp"]
##
## Slots:
##
## Name: polygons plotOrder bbox proj4string
## Class: list integer matrix CRS
##
## Extends: "Spatial"
##
## Known Subclasses:
## Class "SpatialPolygonsDataFrame", directly, with explicit coerce
Interested readers may refer to Roger et al. (2008, Section 2.6)
sp data into R?## Formal class 'SpatialPolygonsDataFrame' [package "sp"] with 5 slots
## ..@ data :'data.frame': 31 obs. of 3 variables:
## ..@ polygons :List of 31
## ..@ plotOrder : int [1:31] 18 4 15 2 24 25 5 14 20 13 ...
## ..@ bbox : num [1:2, 1:2] 44 25.1 63.3 39.8
## .. ..- attr(*, "dimnames")=List of 2
## ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
## ..$ comment: chr "FALSE"
## Province Area Cases
## 1 Znj 21782.87 50
## 2 Yzd 128464.45 57
## 3 Azr_q 37392.98 11
## 4 S_B 178850.47 21
## 5 Smn 97192.69 114
## 6 Qom 11513.63 523
## min max
## x 44.03878 63.32185
## y 25.06415 39.77122
## [1] "+proj=longlat +datum=WGS84 +no_defs"
Creating maps and visualization of spatial data using
tmap package
library(tmap)
iran_spdf <- sf::st_as_sf(iran_spdf) # The latest version of tamp does not support sp objects. So, we need to convert such objects to sf or tera objects.
tm_shape(iran_spdf) +
tm_fill()map1 <- tm_shape(iran_spdf) +
tm_fill()
map2 <- tm_shape(iran_spdf) +
tm_borders()
map3 <- tm_shape(iran_spdf) +
tm_polygons()
tmap_arrange(map1, map2, map3, ncol = 3)## 0% 25% 50% 75% 100%
## 5 20 57 145 1234
map1 <- tm_shape(iran_spdf) +
tm_polygons(col = "Cases", style = "cont", palette = "viridis")
map2 <- tm_shape(iran_spdf) +
tm_polygons(col = "Cases", style = "cont", palette = "-viridis")
tmap_arrange(map1, map2)tm_shape(iran_spdf) +
tm_polygons(col = "Cases", style = "quantile", n = 4) +
tm_bubbles(size = "Area", scale = 1.5, col = "white")cities_df: The coordinates of Iran’s citieslibrary(data.table)
cities_df <- fread("Iran-Cities.csv", data.table = F)[6:5]
names(cities_df) <- c("longitude", "latitude")
str(cities_df)## 'data.frame': 1132 obs. of 2 variables:
## $ longitude: num 48.3 47.4 48.6 48.3 47.9 ...
## $ latitude : num 38.2 39.4 38.3 39.4 39.6 ...
cities_df to a SpatialPoints object## Coordinate Reference System:
## Deprecated Proj.4 representation: +proj=longlat +datum=WGS84 +no_defs
## WKT2 2019 representation:
## GEOGCRS["unknown",
## DATUM["World Geodetic System 1984",
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]],
## ID["EPSG",6326]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433],
## ID["EPSG",8901]],
## CS[ellipsoidal,2],
## AXIS["longitude",east,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433,
## ID["EPSG",9122]]],
## AXIS["latitude",north,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433,
## ID["EPSG",9122]]]]
## class : SpatialPoints
## features : 1132
## extent : 44.15311, 62.70073, 25.29452, 39.64579 (xmin, xmax, ymin, ymax)
## crs : +proj=longlat +datum=WGS84 +no_defs
## xmin ymin xmax ymax
## 44.03878 25.06415 63.32185 39.77122
## xmin ymin xmax ymax
## 44.15311 25.29452 62.70073 39.64579
# First we should convert cities_spp object to an sf or tera object.
cities_spp <- sf::st_as_sf(cities_spp)
tm_shape(iran_spdf) +
tm_polygons() +
tm_shape(cities_spp) +
tm_dots()tm_shape(iran_spdf) +
tm_polygons(col = "Cases") +
tm_bubbles(size = "Area") +
tm_shape(cities_spp) +
tm_dots(col = "blue")tm_shape(iran_spdf) +
tm_polygons(col = "Cases") +
tm_bubbles(size = "Area") +
tm_facets(by = "Province") +
tm_shape(cities_spp) +
tm_dots(col = "blue")iran_spdf at
locations given by cities_spp## [1] 1121 4
## Simple feature collection with 6 features and 3 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 48.06386 ymin: 36.13613 xmax: 49.22454 ymax: 36.99288
## Geodetic CRS: +proj=longlat +datum=WGS84 +no_defs
## Province Area Cases geometry
## 1 Znj 21782.87 50 POINT (49.22454 36.13613)
## 2 Znj 21782.87 50 POINT (48.37194 36.97815)
## 3 Znj 21782.87 50 POINT (48.95617 36.92785)
## 4 Znj 21782.87 50 POINT (48.77853 36.99288)
## 5 Znj 21782.87 50 POINT (48.06386 36.29621)
## 6 Znj 21782.87 50 POINT (49.19539 36.21146)
## [1] "sf" "data.frame"
library(dplyr)
library(ggplot2)
library(plotly)
count_cities <- pip %>%
as_tibble() %>%
transmute(Province = Province) %>%
group_by(Province) %>%
summarise(cities = n())
count_cities %>%
arrange(desc(cities))## # A tibble: 31 × 2
## Province cities
## <chr> <int>
## 1 Isf 100
## 2 Frs 93
## 3 Khr_r 76
## 4 Krm 64
## 5 Khz 62
## 6 Azr_s 58
## 7 Mzn 52
## 8 Gil 51
## 9 Thr 42
## 10 Azr_q 39
## # ℹ 21 more rows
## # A tibble: 31 × 2
## Province cities
## <chr> <int>
## 1 Qom 6
## 2 Alb 15
## 3 Khk 16
## 4 Smn 17
## 5 Khr_s 18
## 6 Znj 18
## 7 Ilm 21
## 8 Khr_j 21
## 9 Ard 24
## 10 Gol 24
## # ℹ 21 more rows
count_cities to the
SpatialPolygonsDataFrame iran_spdf## Simple feature collection with 6 features and 3 fields
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: 44.03878 ymin: 25.06415 xmax: 63.32185 ymax: 39.77122
## Geodetic CRS: +proj=longlat +datum=WGS84 +no_defs
## Province Area Cases geometry
## 1 Znj 21782.87 50 POLYGON ((48.33729 37.2415,...
## 2 Yzd 128464.45 57 POLYGON ((57.50605 35.06421...
## 3 Azr_q 37392.98 11 POLYGON ((44.42939 39.49004...
## 4 S_B 178850.47 21 POLYGON ((61.20754 31.43992...
## 5 Smn 97192.69 114 POLYGON ((55.80516 37.31446...
## 6 Qom 11513.63 523 POLYGON ((50.74857 35.09618...
## # A tibble: 6 × 2
## Province cities
## <chr> <int>
## 1 Alb 15
## 2 Ard 24
## 3 Azr_q 39
## 4 Azr_s 58
## 5 Bsh 29
## 6 Chr 27
## [1] "sf" "data.frame"
## Simple feature collection with 31 features and 4 fields
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: 44.03878 ymin: 25.06415 xmax: 63.32185 ymax: 39.77122
## Geodetic CRS: +proj=longlat +datum=WGS84 +no_defs
## First 10 features:
## Province Area Cases cities geometry
## 1 Alb 5833.00 302 15 POLYGON ((50.49693 36.34204...
## 2 Ard 17901.83 40 24 POLYGON ((47.90934 39.65886...
## 3 Azr_q 37392.98 11 39 POLYGON ((44.42939 39.49004...
## 4 Azr_s 45756.70 75 58 POLYGON ((47.36301 39.42653...
## 5 Bsh 22765.52 5 29 POLYGON ((50.20877 30.28699...
## 6 Chr 16304.64 14 27 POLYGON ((49.62089 32.78621...
## 7 Frs 122779.33 81 93 POLYGON ((52.20103 31.67056...
## 8 Gil 14086.49 424 51 POLYGON ((48.58556 38.44509...
## 9 Gol 20205.54 104 24 POLYGON ((55.68318 38.10304...
## 10 Hmd 19329.05 23 27 POLYGON ((48.24969 35.71867...
cities
variabletm_shape(iran_spdf) +
tm_polygons(col = "cities", title = "Number of cities") +
tm_bubbles(size = "Cases")map1 <- tm_shape(iran_spdf) +
tm_polygons(col = "cities") +
tm_style("albatross")
map2 <- tm_shape(iran_spdf) +
tm_polygons(col = "Cases") +
tm_style("natural")
map3 <- tm_shape(iran_spdf) +
tm_polygons(col = "Cases") +
tm_style("cobalt")
map4 <- tm_shape(iran_spdf) +
tm_polygons(col = "Cases") +
tm_style("gray")
tmap_arrange(map1, map2, map3, map4, ncol = 4)tm_shape(iran_spdf) +
tm_polygons(col = "Cases") +
tm_text("Province", size = 0.7) +
tm_logo("R_logo.png", position = c("right", "top")) +
tm_scale_bar(position = c("center", "bottom")) +
tm_compass(position = c("center", "top"), size = 2)map1 <- tm_shape(iran_spdf) +
tm_polygons(fill = "cities")
map2 <- tm_shape(iran_spdf) +
tm_borders(col = "white") +
tm_fill(
col = "cities",
title = "Number of cities",
legend.hist = TRUE,
legend.hist.title = "Non-Spatial distribution"
) +
tm_compass(position = c("right", "top")) +
tm_layout(
main.title = "Iran map",
title = "Spatial distribution of cities",
title.bg.color = "yellow",
bg.color = "gray90",
frame = FALSE,
compass.type = "8star",
legend.hist.bg.color = "white",
legend.hist.height = 0.15,
scale = 0.7
)
tmap_arrange(map1, map2)Creating maps and visualization of spatial data using
ggplot2 package
ggplot2 based on sf
objectsggplot(data = iran_spdf) +
geom_sf() +
geom_point(data = cities_df, aes(longitude, latitude)) +
coord_sf()library(viridis)
ggplot(data = iran_spdf, aes(fill = Cases)) +
geom_sf(alpha = 0.5) +
scale_fill_continuous(type = "viridis", direction = -1)ggplot(data = iran_spdf, aes(fill = Cases)) +
geom_sf() +
scale_fill_gradient(low = "white", high = "red")For more customization on maps created by ggplot2, refere to the
following slide:
https://mahdisalehi.shinyapps.io/Modern_Data_Visualization
Creating maps and visualization of spatial data using
leafletmapdeckmapviewrayshaderplotly
[1] Bivand, R.S.; Pebesma E; Gómez-Rubio, V. (2013). Applied Spatial Data Analysis with R (Use R!). Springer; 2nd Edition.
[2] Hijmans, R. J. and Ghosh, A. (2019). Spatial Data Analysis with R (lecture note)
[3] Tennekes M (2018). “tmap: Thematic Maps in R.” Journal of Statistical Software, 84(6), 1-39. doi: 10.18637/jss.v084.i06 (URL: https://doi.org/10.18637/jss.v084.i06).
[4] H. Wickham (2016). ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York.
A guide to R programming for beginners and experienced users (in
Persian)
https://www.dibagaranpakhsh.ir/index.php?route=product/product&product_id=1489
Spatial data visualization using tmap and
ggplot2 (the current slide):
https://mahdisalehi.shinyapps.io/Spatial_Data_Visualization
Data visualization using ‘ggplot2’ package:
https://mahdisalehi.shinyapps.io/Modern_Data_Visualization
A quick tour to R-Shiny:
https://mahdisalehi.shinyapps.io/shiny
A
synergetic R-Shiny portal for modeling and tracking of COVID-19 data:
https://mahdisalehi.shinyapps.io/covid19dashboard