Chapter 2 Spatial Point Pattern Analysis
2.1 Prerequisites
You need to have the following R packages installed and recalled into your library:
suppressPackageStartupMessages({
library(sf)
library(spatstat)
library(spatstat.data)
library(ggplot2)
library(sp)
library(animation)
library(plotrix)
library(tmap)})
2.2 Datasets - Readily Available, Imported, Simulated Datasets
2.2.1 Simple Feature Basics
library(sf)
sf
geometry types:
- point:
st_point()
- linestring:
st_linestring()
- polygon:
st_polygon()
- multipoint:
st_multipoint()
- multilinestring:
st_multilinestring()
- multipolygon:
st_multipolygon()
- collection of different geometry types:
st_geometrycollection()
2.2.1.1 sfg
- A single
point
andmultipoint
# Using the sf library for simple features
# Tarih Saat Enlem(N) Boylam(E) Derinlik(km) MD ML Mw Yer Çözüm Niteliği
# ---------- -------- -------- ------- ---------- ------------ -------------- --------------
# 2023.02.15 14:46:46 36.8803 36.6177 8.3 -.- 2.8 -.- ASAGIBILENLER-ISLAHIYE (GAZIANTEP)
# 2023.02.15 14:43:05 37.0218 28.8915 8.4 -.- 2.7 -.- OTMANLAR-KOYCEGIZ (MUGLA)
# sf::st_crs(4326), which means x and y positions are interpreted as longitude (E) and latitude (N), respectively, in the World Geodetic System 1984 (WGS84)
= c(36.6177, 36.8803) %>% st_point() # this will create a "sfg" class Geometry
point1_sg plot(point1_sg)
class(point1_sg)
## [1] "XY" "POINT" "sfg"
= c(28.8915, 37.0218) %>% st_point()
point2_sg plot(point2_sg)
class(point2_sg)
## [1] "XY" "POINT" "sfg"
= rbind(c(36.6177, 36.8803),c(28.8915, 37.0218)) %>% st_multipoint()
points_sg plot(points_sg)
class(points_sg)
## [1] "XY" "MULTIPOINT" "sfg"
st_crs(points_sg)
## Coordinate Reference System: NA
- A single
polygon
and amultipolygon
# polygon
= list(rbind(c(35.8337398, 37.8864154),
poly1 c(36.3281246, 36.7682256),
c(38.5803218, 37.7562395),
c(36.7346187, 38.5939762),
c(35.8337398, 37.8864154)))
= poly1 %>% st_polygon()
poly1_sg
= list(rbind(c(36.7346187, 38.5939762),
poly2 c(38.5913081, 39.3456266),
c(38.5803218, 37.7562395),
c(36.7346187, 38.5939762)))
= poly2 %>% st_polygon()
poly2_sg
plot(poly1_sg)
plot(poly2_sg)
# multipolygon
<- list(poly1, poly2)
polygons <- polygons %>% st_multipolygon()
polygons_sg
st_crs(polygons_sg) # we see that the sf geometry has no CRS set up.
## Coordinate Reference System: NA
2.2.1.2 sfc
- We usually work with multiple simple features and want to combine them. We have a multipolygon and points and want to combine these. We will use
st_sfc()
to merge
<- st_sfc(point1_sg, point2_sg) # with no CRS
points_sfc st_crs(points_sfc)
## Coordinate Reference System: NA
<- st_sfc(point1_sg, point2_sg, crs = 4326) # with appropriate CRS
points_sfc st_crs(points_sfc)
## Coordinate Reference System:
## User input: EPSG:4326
## wkt:
## GEOGCRS["WGS 84",
## DATUM["World Geodetic System 1984",
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["geodetic latitude (Lat)",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["geodetic longitude (Lon)",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## USAGE[
## SCOPE["Horizontal component of 3D system."],
## AREA["World."],
## BBOX[-90,-180,90,180]],
## ID["EPSG",4326]]
<- st_sfc(poly1_sg, poly2_sg, crs = 4326)
multipolygon_sfc st_crs(multipolygon_sfc)
## Coordinate Reference System:
## User input: EPSG:4326
## wkt:
## GEOGCRS["WGS 84",
## DATUM["World Geodetic System 1984",
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["geodetic latitude (Lat)",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["geodetic longitude (Lon)",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## USAGE[
## SCOPE["Horizontal component of 3D system."],
## AREA["World."],
## BBOX[-90,-180,90,180]],
## ID["EPSG",4326]]
2.2.1.3 sf
We usually have a data frame that stores the attributes of points, polygons, lines. Remember the earthquake magnitude, time, depth for the points; elevation, population, size for the polygons.
For point
s
= c(2.8, 2.7)
magnitude = c(8.3, 8.4)
depth = c(1446, 1443)
time
= data.frame(magnitude, depth, time)
earthquake_marks
<- earthquake_marks %>% st_sf(geometry = points_sfc) # sf object
earthquake_sf
= ggplot() +
plot1 geom_sf(data = earthquake_sf["magnitude"], color = "black") +
coord_sf()
plot1
2.2.2 External files (csv, shp etc)
We will use two layers:
- Location of earthquakes - earthquakes
- Boundaries of Turkey as a polygon - turkeyshp
One of the files is a shp file, the other one is just a simple csv file.
- Location of earthquakes - earthquakes (from a csv)
Read in the dataset as usual
<- read.csv("C:/Users/01438475/OneDrive - University of Cape Town/ASDA/DataSets/EarthquakesTR.csv")
earthquake_csv head(earthquake_csv)
## Tarih Saat Lat Long Derinlik_km MD ML Mw
## 1 2023.02.07 13:44:51 38.2452 37.9093 13.9 -.- 3.5 -.-
## 2 2023.02.07 13:41:44 38.1057 36.5072 5.0 -.- 3.9 -.-
## 3 2023.02.07 13:37:24 36.4372 35.6998 13.4 -.- 4.0 -.-
## 4 2023.02.07 13:32:27 37.2445 36.9277 5.4 -.- 2.5 -.-
## 5 2023.02.07 13:30:10 38.1428 37.8203 2.0 -.- 2.9 -.-
## 6 2023.02.07 13:27:30 38.3478 38.1357 6.5 -.- 4.7 -.-
## Yer
## 1 OREN-AKCADAG (MALATYA)
## 2 MAHMUTBEY-GOKSUN (KAHRAMANMARAS)
## 3 ISKENDERUN KORFEZI (AKDENIZ)
## 4 NAIMLER-NURDAGI (GAZIANTEP)
## 5 FINDIKKOY-DOGANSEHIR (MALATYA)
## 6 KUSDOGAN-YESILYURT (MALATYA)
<- earthquake_csv %>%
earthquake_sf st_as_sf(coords = c("Long", "Lat"), crs = 4326) %>% # convert to sf file %>%
#Here Long comes first.
st_transform("+proj=utm +zone=37 +datum=WGS84 +units=m +no_defs") # this could be a different CRS
st_crs(earthquake_sf)
## Coordinate Reference System:
## User input: +proj=utm +zone=37 +datum=WGS84 +units=m +no_defs
## wkt:
## PROJCRS["unknown",
## BASEGEOGCRS["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]]],
## CONVERSION["UTM zone 37N",
## METHOD["Transverse Mercator",
## ID["EPSG",9807]],
## PARAMETER["Latitude of natural origin",0,
## ANGLEUNIT["degree",0.0174532925199433],
## ID["EPSG",8801]],
## PARAMETER["Longitude of natural origin",39,
## ANGLEUNIT["degree",0.0174532925199433],
## ID["EPSG",8802]],
## PARAMETER["Scale factor at natural origin",0.9996,
## SCALEUNIT["unity",1],
## ID["EPSG",8805]],
## PARAMETER["False easting",500000,
## LENGTHUNIT["metre",1],
## ID["EPSG",8806]],
## PARAMETER["False northing",0,
## LENGTHUNIT["metre",1],
## ID["EPSG",8807]],
## ID["EPSG",16037]],
## CS[Cartesian,2],
## AXIS["(E)",east,
## ORDER[1],
## LENGTHUNIT["metre",1,
## ID["EPSG",9001]]],
## AXIS["(N)",north,
## ORDER[2],
## LENGTHUNIT["metre",1,
## ID["EPSG",9001]]]]
- Boundaries of Turkey as a polygon - turkeyshp
library(sf)
= "C:/Users/01438475/OneDrive - University of Cape Town/ASDA/DataSets/turkey_administrativelevels0_1_2/tur_polbnda_adm0.shp" %>%
turkeyshp st_read() %>%
st_transform("+proj=utm +zone=37 +datum=WGS84 +units=m +no_defs")
## Reading layer `tur_polbnda_adm0' from data source
## `C:\Users\01438475\OneDrive - University of Cape Town\ASDA\DataSets\turkey_administrativelevels0_1_2\tur_polbnda_adm0.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 1 feature and 5 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 25.66851 ymin: 35.80842 xmax: 44.81793 ymax: 42.10479
## Geodetic CRS: WGS 84
Plotting the two together in a simple plot:
plot(st_geometry(turkeyshp))
plot(st_geometry(earthquake_sf), add = TRUE, col = "red")
or using geom_sf()
in ggplot:
= ggplot() +
plot1 geom_sf(data = turkeyshp) +
geom_sf(data = earthquake_sf) +
theme_minimal()
Here you see that earthquakes outside of Turkey are also plotted. We can subset only the earthquakes that happened in Turkey:
= earthquake_sf[turkeyshp,]
earthquake_sf = ggplot() +
plot2 geom_sf(data = turkeyshp) +
geom_sf(data = earthquake_sf) +
theme_minimal()
Visualisations can be done via tmap
package as well, and can be saved as png, html files.
tmap_mode("view")
## tmap mode set to interactive viewing
= tm_shape(turkeyshp)+tm_polygons() +tm_shape(earthquake_sf) + tm_dots()
tmap1 tmap_save(tmap1, filename= "turkeyearthquakes.html")
## Interactive map saved to C:\Users\01438475\OneDrive - University of Cape Town\ASDA\bookdown-demo-master\turkeyearthquakes.html
2.2.3 Simulated Datasets
2.2.3.0.1 CSR Data Points
set.seed(135)
<- matrix(runif(80), ncol=2)
xy_csr <- as.ppp(xy_csr, c(0,1,0,1))
pp_csr plot(pp_csr)
2.2.3.0.2 CSR Data Points with Marks
set.seed(135)
<- matrix(runif(2000), ncol=2)
xy_csr = rexp(1000)
mark_numerical = sample(0:1,size=1000,replace=TRUE)
mark_categorical
# plot without marks
<- as.ppp(xy_csr, c(0,1,0,1))
pp_csr_m plot(pp_csr_m)
# plot with marks
= as.data.frame(cbind(xy_csr,mark_numerical, mark_categorical))
xy_csr_withmark
# The categorical variable needs to be set as factor with clearly defined levels
$mark_categorical = factor(xy_csr_withmark$mark_categorical, levels = c("0","1"))
xy_csr_withmark
# set as point pattern
= with(xy_csr_withmark, ppp(V1,V2,c(0,1),c(0,1),marks=xy_csr_withmark[,4]))
pp_csr_withmark plot(pp_csr_withmark)
2.2.4 Swedishpines Dataset from spatstat.data library
data(swedishpines)
= rescale.ppp(swedishpines)
swp swp
## Planar point pattern: 71 points
## window: rectangle = [0, 9.6] x [0, 10] metres
class(swp)
## [1] "ppp"
summary(swp)
## Planar point pattern: 71 points
## Average intensity 0.7395833 points per square metre
##
## Coordinates are given to 1 decimal place
## i.e. rounded to the nearest multiple of 0.1 metres
##
## Window: rectangle = [0, 9.6] x [0, 10] metres
## Window area = 96 square metres
## Unit of length: 1 metre
plot(swp)
2.2.5 External datasets - Turkey
Let us go back to Earthquake data that we converted to sf object.
Convert the sf
objects to ppp
point pattern object using function as.ppp
so that we can analyse them in R with spatstat.
# only the geometry
= as.ppp(st_geometry(earthquake_sf))
earthquake_ppp = as.owin(st_geometry(turkeyshp))
turkeyshp_owin
plot(earthquake_ppp)
plot(turkeyshp_owin)
The observation window and the point pattern can be combined, so that the custom window replaces the default rectangular window:
= earthquake_ppp[turkeyshp_owin]
earthquake_ppp plot(earthquake_ppp)
We might want to incorporate some marks to these points:
# if there are marks that need to be included:
<- ppp(earthquake_ppp$x, earthquake_ppp$y, window = turkeyshp_owin, marks =data.frame(earthquake_sf)$ML)
earthquake_ppp.marked_numeric
plot(earthquake_ppp.marked_numeric, use.marks=TRUE)
<- ppp(earthquake_ppp$x, earthquake_ppp$y, window = turkeyshp_owin, marks =ifelse(data.frame(earthquake_sf)$ML<5,"low","high"))
earthquake_ppp.marked_categorical
plot(earthquake_ppp.marked_categorical, use.marks=TRUE,
cols=c("red","blue","pink"),
markscale=0.1,
pch=21, cex=1)
https://rspatial.org/raster/rosu/Chapter5.html https://geobgu.xyz/r/point-pattern-analysis.html https://www.keene.edu/campus/maps/tool/ https://data.humdata.org/dataset/cod-ab-tur? https://www.jla-data.net/eng/merging-geometry-of-sf-objects-in-r/
2.2.5.0.1 External Datasets - Clinics Dataset SA
Download the data from the following:
https://web1.capetown.gov.za/web1/OpenDataPortal/DatasetDetail?DatasetName=Clinics
library(sf)
= "C:/Users/01438475/OneDrive - University of Cape Town/ASDA/DataSets/zafrds8ff5a/ZAF_roads.shp" %>%
RSA_roads st_read() %>% st_transform(4326)
## Reading layer `ZAF_roads' from data source
## `C:\Users\01438475\OneDrive - University of Cape Town\ASDA\DataSets\zafrds8ff5a\ZAF_roads.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 5559 features and 5 fields
## Geometry type: MULTILINESTRING
## Dimension: XY
## Bounding box: xmin: 16.48784 ymin: -34.82747 xmax: 32.85267 ymax: -22.17693
## Geodetic CRS: WGS 84
= "C:/Users/01438475/OneDrive - University of Cape Town/ASDA/DataSets/rsabiome4xkhi/RSA_biome.shp" %>%
RSA_biome st_read() %>% st_transform(4326)
## Reading layer `RSA_biome' from data source
## `C:\Users\01438475\OneDrive - University of Cape Town\ASDA\DataSets\rsabiome4xkhi\RSA_biome.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 3127 features and 1 field
## Geometry type: POLYGON
## Dimension: XY
## Bounding box: xmin: 16.45296 ymin: -34.8336 xmax: 32.8928 ymax: -22.12583
## Geodetic CRS: Hartebeesthoek94
= "C:/Users/01438475/OneDrive - University of Cape Town/ASDA/DataSets/Clinics/SL_CLNC.shp" %>%
clinics_sf st_read() %>% st_transform(4326)
## Reading layer `SL_CLNC' from data source
## `C:\Users\01438475\OneDrive - University of Cape Town\ASDA\DataSets\Clinics\SL_CLNC.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 149 features and 5 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 18.34268 ymin: -34.19491 xmax: 18.90847 ymax: -33.51262
## Geodetic CRS: WGS 84
<- "C:/Users/01438475/OneDrive - University of Cape Town/ASDA/DataSets/sa/CPT/electoral wards for cpt.shp" %>%
ct.wards_sf st_read(quiet = TRUE) %>%
st_set_crs(4326)
st_crs(ct.wards_sf)
## Coordinate Reference System:
## User input: EPSG:4326
## wkt:
## GEOGCRS["WGS 84",
## DATUM["World Geodetic System 1984",
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["geodetic latitude (Lat)",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["geodetic longitude (Lon)",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## USAGE[
## SCOPE["Horizontal component of 3D system."],
## AREA["World."],
## BBOX[-90,-180,90,180]],
## ID["EPSG",4326]]
st_crs(clinics_sf)
## Coordinate Reference System:
## User input: EPSG:4326
## wkt:
## GEOGCRS["WGS 84",
## DATUM["World Geodetic System 1984",
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433]],
## CS[ellipsoidal,2],
## AXIS["geodetic latitude (Lat)",north,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433]],
## AXIS["geodetic longitude (Lon)",east,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433]],
## USAGE[
## SCOPE["Horizontal component of 3D system."],
## AREA["World."],
## BBOX[-90,-180,90,180]],
## ID["EPSG",4326]]
class(clinics_sf)
## [1] "sf" "data.frame"
summary(clinics_sf)
## LCTN ATHY NAME CLASS
## Length:149 Length:149 Length:149 Length:149
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
## RGN geometry
## Length:149 POINT :149
## Class :character epsg:4326 : 0
## Mode :character +proj=long...: 0
2.2.6 Swedishpines Dataset from spatstat.data library
data(swedishpines)
= rescale.ppp(swedishpines)
swp class(swp)
## [1] "ppp"
summary(swp)
## Planar point pattern: 71 points
## Average intensity 0.7395833 points per square metre
##
## Coordinates are given to 1 decimal place
## i.e. rounded to the nearest multiple of 0.1 metres
##
## Window: rectangle = [0, 9.6] x [0, 10] metres
## Window area = 96 square metres
## Unit of length: 1 metre
plot(swp)
2.2.7 Clinics Dataset Using Simple Features (SF)
Download the data from the following:
https://web1.capetown.gov.za/web1/OpenDataPortal/DatasetDetail?DatasetName=Clinics
Extract the data frame into R:
library(sf)
= st_read("C:/Users/01438475/OneDrive - University of Cape Town/ASDA/DataSets/Clinics/SL_CLNC.shp") clinics_sf
## Reading layer `SL_CLNC' from data source
## `C:\Users\01438475\OneDrive - University of Cape Town\ASDA\DataSets\Clinics\SL_CLNC.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 149 features and 5 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 18.34268 ymin: -34.19491 xmax: 18.90847 ymax: -33.51262
## Geodetic CRS: WGS 84
clinics_sf
## Simple feature collection with 149 features and 5 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 18.34268 ymin: -34.19491 xmax: 18.90847 ymax: -33.51262
## Geodetic CRS: WGS 84
## First 10 features:
## LCTN ATHY
## 1 C/O Adam/ Liedeman Street Mamre PAWC
## 2 Cnr Hermes & GrosvenorAve CITY OF CAPE TOWN
## 3 Hassen Kahn Ave Rusthof Strand PAWC
## 4 61 Central Circle, Fish Hoek CITY OF CAPE TOWN
## 5 Simon Street, Nomzamo CITY OF CAPE TOWN
## 6 C/O Musical and Hospital Street Macassar PAWC
## 7 28 Church Street Somerset West CITY OF CAPE TOWN
## 8 Fagan Street Strand CITY OF CAPE TOWN
## 9 Karbonkel Road, CMC Building, Hout Bay PAWC
## 10 Midmar Street Groenvallei CITY OF CAPE TOWN
## NAME CLASS RGN
## 1 MAMRE CDC Community Day Centre Western
## 2 SAXON SEA CLINIC Clinic Western
## 3 GUSTROUW CDC Community Day Centre Eastern
## 4 FISH HOEK CLINIC Clinic Southern
## 5 IKWEZI CDC Community Day Centre Eastern
## 6 MACASSAR CDC Community Day Centre Eastern
## 7 SOMERSET WEST CLINIC Clinic Eastern
## 8 FAGAN STREET SATELLITE Satellite Eastern
## 9 HOUT BAY HARBOUR CDC Community Day Centre Southern
## 10 GROENVALLEI SATELLITE Satellite Tygerberg
## geometry
## 1 POINT (18.47692 -33.51262)
## 2 POINT (18.48881 -33.55012)
## 3 POINT (18.85211 -34.13472)
## 4 POINT (18.42632 -34.13669)
## 5 POINT (18.86622 -34.11375)
## 6 POINT (18.76369 -34.06105)
## 7 POINT (18.84814 -34.08579)
## 8 POINT (18.82979 -34.1162)
## 9 POINT (18.34268 -34.0549)
## 10 POINT (18.66701 -33.89165)
class(clinics_sf)
## [1] "sf" "data.frame"
summary(clinics_sf)
## LCTN ATHY NAME CLASS
## Length:149 Length:149 Length:149 Length:149
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
## RGN geometry
## Length:149 POINT :149
## Class :character epsg:4326 : 0
## Mode :character +proj=long...: 0
2.3 Plotting Datasets
2.3.2 Basic ggplot() function - (sf) object
library(ggplot2)
= ggplot() +
plot1 geom_sf(data = clinics_sf, size = .8, color = "black") +
ggtitle("Location of Cape Town clinics - 2016") +
# not specifying crs here, coord_sf will use the CRS defined in the first layer = "+proj=longlat +datum=WGS84 +no_defs"
coord_sf()
plot1
2.3.3 ggplot() function with a bounding box - (sf) object
library(ggplot2)
= ggplot() +
plot2 geom_sf(data = clinics_sf, size = .8, color = "black") +
ggtitle("Location of Cape Town clinics - 2016") +
coord_sf(xlim = c(18.34, 18.91), ylim = c(-34.19, -33.51262)) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_rect(colour = "black", size=1, fill=NA))
## Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
## ℹ Please use the `linewidth` argument instead.
plot2
2.3.4 ggplot() with Electoral Wards Shape File
In order to plot using the electoral wards polygons, we need the sf data frame to be converted into Spatial Points Data Frame (sp).
<- as(clinics_sf, Class = "Spatial")
clinics_sp class(clinics_sp)
## [1] "SpatialPointsDataFrame"
## attr(,"package")
## [1] "sp"
Download the CPT electoral wards and import the shape file as follows:
library(sf)
= st_read("C:/Users/01438475/OneDrive - University of Cape Town/ASDA/DataSets/sa/CPT/electoral wards for cpt.shp") ct.wards_sf
## Reading layer `electoral wards for cpt' from data source
## `C:\Users\01438475\OneDrive - University of Cape Town\ASDA\DataSets\sa\CPT\electoral wards for cpt.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 111 features and 9 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 18.30722 ymin: -34.35834 xmax: 19.00467 ymax: -33.47128
## CRS: NA
st_geometry_type(ct.wards_sf)
## [1] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [6] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [11] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [16] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [21] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [26] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [31] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [36] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [41] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [46] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [51] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [56] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [61] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [66] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [71] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [76] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [81] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [86] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [91] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [96] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [101] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [106] MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON MULTIPOLYGON
## [111] MULTIPOLYGON
## 18 Levels: GEOMETRY POINT LINESTRING POLYGON MULTIPOINT ... TRIANGLE
library(ggplot2)
ggplot() +
geom_sf(data = ct.wards_sf, size = .5, color = "black") +
geom_point(aes(x = clinics_sp@coords[,1], y = clinics_sp@coords[,2]),
data = clinics_sp@data, alpha = 1,size=2, color = "red")+
ggtitle("Spatial locations of Cape Town clinics within wards") +
coord_sf()
2.4 Quadrat Analysis - Quadrat Counts and Tests
2.4.1 Turkey Earthquake
= quadratcount(earthquake_ppp, nx = 7, ny = 7)
q plot(q)
= density(earthquake_ppp)
den plot(den)
2.4.2 swp dataset
Quadrat counts:
= quadratcount(swp, nx=3, ny=3)
Q3x3 plot(swp)
plot(Q3x3, add=TRUE, col="red", cex=1.5, lty=2)
# Plot the density
<- interp.colours(c("lightyellow", "orange" ,"red"), 20)
cl
plot( intensity(Q3x3, image=TRUE), las=1, col=cl, main=NULL)
plot(swp, pch=20, cex=0.6, col="black", add=TRUE) # Add points
Quadrat test
= quadrat.test(swp, 3,3)
Q3x3test Q3x3test
##
## Chi-squared test of CSR using quadrat counts
##
## data: swp
## X2 = 4.6761, df = 8, p-value = 0.4169
## alternative hypothesis: two.sided
##
## Quadrats: 3 by 3 grid of tiles
2.4.3 Simulated CSR Pattern
= quadratcount(pp_csr, nx=3, ny=3)
Q3x3_csr plot(pp_csr)
plot(Q3x3_csr, add=TRUE, col="red", cex=1.5, lty=2)
Test:
= quadrat.test(pp_csr, 3,3) Q3x3test_csr
## Warning: Some expected counts are small; chi^2 approximation may be inaccurate
Q3x3test_csr
##
## Chi-squared test of CSR using quadrat counts
##
## data: pp_csr
## X2 = 11.3, df = 8, p-value = 0.3705
## alternative hypothesis: two.sided
##
## Quadrats: 3 by 3 grid of tiles
2.4.4 Simulated Cluster Pattern
= quadratcount(pp_cluster, nx=3, ny=3)
Q3x3_cluster plot(pp_cluster)
plot(Q3x3_cluster, add=TRUE, col="red", cex=1.5, lty=2)
Test:
= quadrat.test(pp_cluster, 3,3) Q3x3test_cluster
## Warning: Some expected counts are small; chi^2 approximation may be inaccurate
Q3x3test_cluster
##
## Chi-squared test of CSR using quadrat counts
##
## data: pp_cluster
## X2 = 48.65, df = 8, p-value = 1.484e-07
## alternative hypothesis: two.sided
##
## Quadrats: 3 by 3 grid of tiles
2.4.5 Simulated Regular Pattern
= quadratcount(pp_regular, nx=4, ny=4)
Q3x3_regular plot(pp_regular)
plot(Q3x3_regular, add=TRUE, col="red", cex=1.5, lty=2)
Test:
= quadrat.test(pp_regular, 3,3) Q3x3test_regular
## Warning: Some expected counts are small; chi^2 approximation may be inaccurate
Q3x3test_regular
##
## Chi-squared test of CSR using quadrat counts
##
## data: pp_regular
## X2 = 4.55, df = 8, p-value = 0.3912
## alternative hypothesis: two.sided
##
## Quadrats: 3 by 3 grid of tiles
2.5 Kernel Density Smoothing
2.5.1 CSR Pattern
<- density(pp_csr, sigma = .1)
den plot(den, main = "CSR")
plot(pp_csr, add=TRUE)
contour(den, add = TRUE)
2.6 Kernel Smoothing with a Covariate
2.6.1 Tropical rain forest trees dataset
data("bei")
Assign the elevation covariate to a variable elev by typing
<- bei.extra$elev elev
Plot the trees on top of an image of the elevation covariate.
plot(elev, main = "")
plot(bei, add = TRUE, cex = 0.3, pch = 16, cols = "white")
For the tropical rainforest data bei, it might be useful to split the study region into several sub-regions according to the terrain elevation:
<- quantile(elev, probs=(0:4)/4, type=2)
b
<- cut(elev, breaks=b, labels=c("Low", "Med-Low", "Med-High", "High"))
Zcut textureplot(Zcut, main = "")
Convert the image from above to a tesselation, count the number of points in each region using quadratcount, and plot the quadrat counts.
<- tess(image=Zcut)
V <- quadratcount(bei, tess = V)
qc qc
## tile
## Low Med-Low Med-High High
## 714 883 1344 663
The output shows the number of trees in each region. Since the four regions have equal area, the counts should be approximately equal if there is a uniform density of trees. Obviously they are not equal; there appears to be a strong preference for higher elevations (dropping off for the highest elevations).
Estimate the intensity in each of the four regions.
intensity(qc)
## tile
## Low Med-Low Med-High High
## 0.005623154 0.006960978 0.010593103 0.005228707
Assume that the intensity of trees is a function ((u) = (e(u))) where (e(u)) is the terrain elevation at location u.
Compute a nonparametric estimate of the function () and plot it by
<- rhohat(bei, elev)
rh plot(rh)
Compute the predicted intensity based on this estimate of ().
<- predict(rh)
predictedrho plot(predictedrho, main = "")
plot(bei, add = TRUE, cols = "white", cex = .2, pch = 16)
Compute a non-parametric estimate by kernel smoothing and compare with the predicted intensity above.
The kernel density estimate of the points is computed and plotted with the following code:
<- density(bei, sigma = bw.scott)
kerneldensity plot(kerneldensity, main = "")
plot(kerneldensity, add = TRUE, cols = "white", cex = .2, pch = 16)
Compare the two
pairs(predictedrho, kerneldensity)
plot(eval.im(kerneldensity-predictedrho))
## Warning: the images 'kerneldensity' and 'predictedrho' were not compatible
Which seems to be quite different form the predicted intensity.
2.7 Distance Measures and Tests
2.7.1 e2e Distances
2.7.1.1 swp dataset
= pairdist(swp)
PD class(PD)
## [1] "matrix" "array"
<- as.matrix(PD)
dm 1:5, 1:5] dm[
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.000000 2.700000 3.701351 1.503330 5.433231
## [2,] 2.700000 0.000000 1.004988 1.204159 2.765863
## [3,] 3.701351 1.004988 0.000000 2.200000 1.772005
## [4,] 1.503330 1.204159 2.200000 0.000000 3.931921
## [5,] 5.433231 2.765863 1.772005 3.931921 0.000000
diag(dm) <- NA
#dm[1:5, 1:5]
<- apply(dm, 1, which.min)
wdmin
<- apply(dm, 1, min, na.rm=TRUE)
dmin head(dmin)
## [1] 1.5033296 0.8544004 1.0049876 0.9055385 1.0770330 0.8544004
# which is the same as nndist e2e=nndist(swp)
= nndist(swp)
dmin
plot(swp)
= cbind(swp$x, swp$y)
xy
<- rev(order(dmin))
ord <- ord[1:71]
far25 <- wdmin[far25]
neighbors points(xy[far25, ], col='blue', pch=20)
points(xy[neighbors, ], col='red')
# drawing the lines, easiest via a loop
for (i in far25) {
lines(rbind(xy[i, ], xy[wdmin[i], ]), col='red')
}
2.7.1.2 Simulated CSR Pattern
= nndist(pp_csr)
e2e_csr e2e_csr
## [1] 0.11056220 0.05419105 0.08163249 0.05574520 0.19907565 0.03191166
## [7] 0.10456756 0.15049858 0.16325765 0.02841510 0.05044346 0.05419105
## [13] 0.10456756 0.07525211 0.02471890 0.08651227 0.03700818 0.06471165
## [19] 0.12663659 0.08163249 0.06471165 0.07525211 0.14362670 0.03195288
## [25] 0.09669706 0.03195288 0.09731910 0.04284774 0.11297958 0.03191166
## [31] 0.13454666 0.02841510 0.02471890 0.06711512 0.10924574 0.04269836
## [37] 0.09947882 0.03815278 0.14362670 0.10235020
= pairdist(pp_csr)
PD class(PD)
## [1] "matrix" "array"
<- as.matrix(PD)
dm 1:5, 1:5] dm[
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.0000000 0.2930205 0.5163115 0.2844957 0.7955061
## [2,] 0.2930205 0.0000000 0.5975953 0.4633681 0.8993362
## [3,] 0.5163115 0.5975953 0.0000000 0.2546708 0.3017974
## [4,] 0.2844957 0.4633681 0.2546708 0.0000000 0.5130861
## [5,] 0.7955061 0.8993362 0.3017974 0.5130861 0.0000000
diag(dm) <- NA
#dm[1:5, 1:5]
<- apply(dm, 1, which.min)
wdmin
<- apply(dm, 1, min, na.rm=TRUE)
dmin head(dmin)
## [1] 0.11056220 0.05419105 0.08163249 0.05574520 0.19907565 0.03191166
# which is the same as nndist e2e=nndist(swp)
= nndist(pp_csr)
dmin
plot(pp_csr)
= cbind(pp_csr$x, pp_csr$y)
xy
<- rev(order(dmin))
ord <- ord[1:40]
far25 <- wdmin[far25]
neighbors points(xy[far25, ], col='blue', pch=20)
points(xy[neighbors, ], col='red')
# drawing the lines, easiest via a loop
for (i in far25) {
lines(rbind(xy[i, ], xy[wdmin[i], ]), col='red')
}
2.7.1.3 Simulated Cluster Pattern
= nndist(pp_cluster)
e2e_cluster e2e_cluster
## [1] 0.01854666 0.03502091 0.01854666 0.04969353 0.03502091 0.03390187
## [7] 0.01268286 0.05624330 0.01268286 0.03830134 0.04275255 0.02983313
## [13] 0.04275255 0.02983313 0.03774271 0.03774271 0.03391843 0.01376367
## [19] 0.01376367 0.03500058 0.08344093 0.06403124 0.05422191 0.08344093
## [25] 0.03500058 0.08988091 0.04304986 0.07202173 0.04586212 0.02906394
## [31] 0.08760076 0.11053898 0.04586212 0.02906394 0.05896243 0.07149045
## [37] 0.04361429 0.04361429 0.05745563 0.07483198
= pairdist(pp_cluster)
PD_cluster class(PD_cluster)
## [1] "matrix" "array"
<- as.matrix(PD_cluster)
dm_cluster 1:5, 1:5] dm_cluster[
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.00000000 0.09345138 0.01854666 0.04969353 0.07093497
## [2,] 0.09345138 0.00000000 0.08597921 0.13688899 0.03502091
## [3,] 0.01854666 0.08597921 0.00000000 0.05097721 0.05847323
## [4,] 0.04969353 0.13688899 0.05097721 0.00000000 0.10757315
## [5,] 0.07093497 0.03502091 0.05847323 0.10757315 0.00000000
diag(dm_cluster) <- NA
<- apply(dm_cluster, 1, which.min)
wdmin_cluster
<- apply(dm_cluster, 1, min, na.rm=TRUE)
dmin_cluster head(dmin-cluster)
## X Y
## 1 0.080388175 -0.4397788
## 2 0.018557146 -0.5894417
## 3 0.034750612 -0.4767600
## 4 -0.001070259 -0.4526473
## 5 0.141971489 -0.4168896
## 6 -0.048015500 -0.5340536
# which is the same as nndist e2e=nndist(swp)
= nndist(pp_cluster)
dmin_cluster
plot(pp_cluster)
= cbind(pp_cluster$x, pp_cluster$y)
xy_cluster
<- rev(order(dmin_cluster))
ord <- ord[1:40]
far25 <- wdmin_cluster[far25]
neighbors points(xy_cluster[far25, ], col='blue', pch=20)
points(xy_cluster[neighbors, ], col='red')
# drawing the lines, easiest via a loop
for (i in far25) {
lines(rbind(xy_cluster[i, ], xy_cluster[wdmin_cluster[i], ]), col='red')
}
2.7.1.4 Simulated Regular Pattern
= nndist(pp_regular)
e2e_regular e2e_regular
## [1] 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111
## [8] 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111
## [15] 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111
## [22] 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111
## [29] 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111
## [36] 0.1111111 0.1111111 0.1111111 0.1111111 0.1111111
= pairdist(pp_regular)
PD_regular class(PD_regular)
## [1] "matrix" "array"
<- as.matrix(PD_regular)
dm_regular 1:5, 1:5] dm_regular[
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.0000000 0.1666667 0.3333333 0.5000000 0.6666667
## [2,] 0.1666667 0.0000000 0.1666667 0.3333333 0.5000000
## [3,] 0.3333333 0.1666667 0.0000000 0.1666667 0.3333333
## [4,] 0.5000000 0.3333333 0.1666667 0.0000000 0.1666667
## [5,] 0.6666667 0.5000000 0.3333333 0.1666667 0.0000000
diag(dm_regular) <- NA
<- apply(dm_regular, 1, which.min)
wdmin_regular
<- apply(dm_regular, 1, min, na.rm=TRUE)
dmin_regular head(dmin-regular)
## X Y
## 1 -0.05610447 -0.0005489143
## 2 -0.27914228 -0.0569200607
## 3 -0.41836751 -0.0294786165
## 4 -0.61092147 -0.0553659112
## 5 -0.63425768 0.0879645408
## 6 -0.13475501 -0.1903105666
# which is the same as nndist e2e=nndist(swp)
= nndist(pp_regular)
dmin_regular
plot(pp_regular)
= cbind(pp_regular$x, pp_regular$y)
xy_regular
<- rev(order(dmin_regular))
ord <- ord[1:40]
far25 <- wdmin_regular[far25]
neighbors points(xy_regular[far25, ], col='blue', pch=20)
points(xy_regular[neighbors, ], col='red')
# drawing the lines, easiest via a loop
for (i in far25) {
lines(rbind(xy_regular[i, ], xy_regular[wdmin_regular[i], ]), col='red')
}
2.7.2 p2e Distances
Generate Random points
set.seed(23)
= matrix(runif(60),ncol=2)
randompoints #randompoints = matrix(runif(250),ncol=2)
2.7.2.1 CSR Pattern
plot(pp_csr)
points(randompoints, col = "blue", pch=3)
= NULL
p2e_distances_csr = NULL
mins_csr = cbind(pp_csr$x, pp_csr$y)
xy
# sqrt((xy[2,1]-randompoints[1,1])^2+(xy[2,2]-randompoints[1,2])^2)
# sqrt((xy[1,1]-randompoints[2,1])^2+(xy[1,2]-randompoints[2,2])^2)
for(i in 1:dim(randompoints)[1]){
= matrix(pairdist(rbind(randompoints[i,],xy)),41)
dist1
= c(p2e_distances_csr,min(dist1[2:41,1]))
p2e_distances_csr = c(mins_csr,which.min(dist1[2:41,1]))
mins_csr
}
plot(pp_csr)
<- rev(order(p2e_distances_csr))
ord <- 1:dim(randompoints)[1]
far25 <- mins_csr
neighbors points(randompoints, col='red', pch=4)
points(xy[mins_csr, ], col='blue', pch=20)
# drawing the lines, easiest via a loop
for (i in far25) {
lines(rbind(xy[mins_csr[i], ], randompoints[i, ]), col='red')
}
2.7.2.2 Cluster Pattern
plot(pp_cluster)
points(randompoints, col = "blue", pch=3)
= NULL
p2e_distances_cluster = NULL
mins_cluster = cbind(pp_cluster$x, pp_cluster$y)
xy_cluster
for(i in 1:dim(randompoints)[1]){
= matrix(pairdist(rbind(randompoints[i,],xy_cluster)),41)
dist1
= c(p2e_distances_cluster,min(dist1[2:41,1]))
p2e_distances_cluster = c(mins_cluster,which.min(dist1[2:41,1]))
mins_cluster
}
plot(pp_cluster)
<- rev(order(p2e_distances_cluster))
ord <- 1:dim(randompoints)[1]
far25 <- mins_cluster
neighbors points(randompoints, col='red', pch=4)
points(xy_cluster[mins_cluster, ], col='blue', pch=20)
# drawing the lines, easiest via a loop
for (i in far25) {
lines(rbind(xy_cluster[mins_cluster[i], ], randompoints[i, ]), col='red')
}
2.7.2.3 Regular Pattern
= NULL
p2e_distances_regular = NULL
p2e_mins_regular = cbind(pp_regular$x, pp_regular$y)
xy_regular
for(i in 1:dim(randompoints)[1]){
= matrix(pairdist(rbind(randompoints[i,],xy_regular)),41)
dist1
= c(p2e_distances_regular,min(dist1[2:41,1]))
p2e_distances_regular = c(p2e_mins_regular,which.min(dist1[2:41,1]))
p2e_mins_regular
}
plot(pp_regular)
<- rev(order(p2e_distances_regular))
ord <- 1:dim(randompoints)[1]
far25 <- p2e_mins_regular
neighbors points(randompoints, col='red', pch=4)
points(xy_regular[p2e_mins_regular, ], col='blue', pch=20)
# drawing the lines, easiest via a loop
for (i in far25) {
lines(rbind(xy_regular[p2e_mins_regular[i], ], randompoints[i, ]), col='red')
}
2.7.3 Clark and Evans Index and Test
2.7.3.1 CSR Pattern
clarkevans(pp_csr)
## naive Donnelly cdf
## 1.0135515 0.9443703 0.9719128
clarkevans.test(pp_csr)
##
## Clark-Evans test
## No edge correction
## Z-test
##
## data: pp_csr
## R = 1.0136, p-value = 0.8698
## alternative hypothesis: two-sided
2.10 Ripley’s K Function
2.10.1 Simulated CSR Pattern
<- Kest(pp_csr)
K plot(K, main=NULL, las=1, legendargs=list(cex=0.8, xpd=TRUE, inset=c(1.01, 0) ))
## Warning in min(D[scaledlegbox]): no non-missing arguments to min; returning Inf